LR 2 年之前
父節點
當前提交
48e3ca3fdd
共有 31 個文件被更改,包括 2489 次插入1253 次删除
  1. 1051 155
      package-lock.json
  2. 3 0
      package.json
  3. 24 0
      src/components/Base/Dialog/ImagePreview.vue
  4. 115 39
      src/components/Base/Dialog/index.vue
  5. 27 12
      src/components/Base/Page/index.vue
  6. 3 3
      src/components/Base/Table/index.vue
  7. 35 11
      src/components/Base/Title/index.vue
  8. 20 8
      src/components/Base/index.ts
  9. 7 4
      src/main.ts
  10. 40 40
      src/styles/base.scss
  11. 18 2
      src/utils/request.ts
  12. 2 1
      src/views/spectrum/configuration/api/common.ts
  13. 2 11
      src/views/spectrum/configuration/api/standard.ts
  14. 203 203
      src/views/spectrum/configuration/device/DeviceForm.vue
  15. 19 19
      src/views/spectrum/configuration/device/QueryForm.vue
  16. 106 106
      src/views/spectrum/configuration/device/widget.vue
  17. 90 72
      src/views/spectrum/configuration/point/PointForm/BasisForm.vue
  18. 7 1
      src/views/spectrum/configuration/point/PointForm/DeviceForm.vue
  19. 108 0
      src/views/spectrum/configuration/point/PointForm/StandardSaveAs.vue
  20. 35 21
      src/views/spectrum/configuration/point/PointForm/ThresholdForm.vue
  21. 360 343
      src/views/spectrum/configuration/point/PointForm/index.vue
  22. 33 33
      src/views/spectrum/configuration/standard/StandardForm.vue
  23. 1 1
      src/views/spectrum/configuration/standard/widget.vue
  24. 47 34
      src/views/spectrum/configuration/team/TeamForm.vue
  25. 97 98
      src/views/spectrum/configuration/type/TypeForm.vue
  26. 12 7
      src/views/spectrum/configuration/utils.ts
  27. 1 1
      src/views/spectrum/health/utils.ts
  28. 15 17
      src/views/spectrum/reform/statistics/ChartItem.vue
  29. 3 9
      src/views/spectrum/reform/statistics/DayAndHourChart.vue
  30. 1 1
      src/views/spectrum/reform/utils.ts
  31. 4 1
      tsconfig.json

文件差異過大導致無法顯示
+ 1051 - 155
package-lock.json


+ 3 - 0
package.json

@@ -12,6 +12,8 @@
   },
   "dependencies": {
     "@turf/turf": "^6.5.0",
+    "@volar-plugins/vetur": "^0.1.0",
+    "@vue/compiler-dom": "^3.2.40",
     "@vue/eslint-config-prettier": "^7.0.0",
     "animate.css": "^4.1.1",
     "axios": "^0.27.2",
@@ -27,6 +29,7 @@
     "html2canvas": "^1.0.0-rc.7",
     "jquery": "^3.5.1",
     "js-cookie": "2.2.0",
+    "json-bigint": "^1.0.0",
     "jspdf": "^2.5.1",
     "moment": "^2.29.2",
     "normalize.css": "7.0.0",

+ 24 - 0
src/components/Base/Dialog/ImagePreview.vue

@@ -0,0 +1,24 @@
+<template>
+  <tf-dialog
+    :visible.sync="dialogVisible"
+    width="80vw"
+    :footer="false"
+    :gutter="false"
+    v-bind="$attrs"
+    v-on="$listeners"
+  >
+    <img v-if="src" :src="src" alt="" style="display: block; width: 100%" />
+  </tf-dialog>
+</template>
+
+<script lang="ts">
+  import { Vue, Component, Prop, PropSync } from 'vue-property-decorator'
+  import TfDialog from './index.vue'
+
+  @Component({ name: 'TfImagePreview', components: { TfDialog } })
+  export default class TfImagePreview extends Vue {
+    @Prop({ type: String }) src!: string
+    @Prop({ type: String }) alt!: string
+    @PropSync('visible', { type: Boolean }) dialogVisible!: boolean
+  }
+</script>

+ 115 - 39
src/components/Base/Dialog/index.vue

@@ -1,71 +1,149 @@
 <template>
   <el-dialog
+    ref="dialog"
     v-dialogDrag
     :class="{ dialog: true, 'no-gutter': !gutter }"
     :visible.sync="dialogVisible"
     v-bind="{ appendToBody: true, width: '368px', ...$attrs }"
-    v-on="listeners"
-    @open="onOpen"
     @closed="onClosed"
-    ref="dialog"
+    @open="onOpen"
+    @opened="onOpened"
+    v-on="listeners"
   >
-    <div slot="title">
-      <span class="title">{{ title }}</span>
-    </div>
+    <slot name="title">
+      <div slot="title">
+        <span class="title">{{ title }}</span>
+      </div>
+    </slot>
     <slot />
-    <span slot="footer" v-if="footer">
-      <el-button size="small" @click="dialogVisible = false" style="min-width: 70px">取 消</el-button>
-
-      <el-button
-        type="primary"
-        size="small"
-        @click="$emit('submit')"
-        :loading="loading"
-        :disabled="disabled"
-        style="min-width: 70px"
-      >
-        提 交
-      </el-button>
-    </span>
+    <slot name="footer">
+      <span slot="footer" v-if="footer">
+        <el-button type="primary" size="small" @click="onSubmit" :loading="loading" :disabled="disabled || submitted">
+          提 交
+        </el-button>
+        <el-button size="small" @click="onCancel">取 消</el-button>
+      </span>
+    </slot>
   </el-dialog>
 </template>
 
 <script lang="ts">
+  import { ElDialog } from 'element-ui/types/dialog'
   import { ElForm } from 'element-ui/types/form'
   import { Vue, Component, Prop, PropSync } from 'vue-property-decorator'
 
   @Component({ name: 'TfDialog', inheritAttrs: false })
-  export default class Dialog extends Vue {
-    @PropSync('visible', { type: Boolean }) dialogVisible!: boolean
+  export default class TfDialog extends Vue {
+    @PropSync('visible', { type: Boolean, default: false }) dialogVisible!: boolean
     @Prop({ type: String }) title!: string
-    @Prop({ type: Boolean }) loading!: boolean
     @Prop({ type: Boolean }) disabled!: boolean
+    @Prop({ type: Boolean, default: false }) loading!: boolean
     @Prop({ type: Boolean, default: true }) clear!: boolean
     @Prop({ type: Boolean, default: true }) footer!: boolean
     @Prop({ type: Boolean, default: true }) gutter!: boolean
 
+    timer: number = null
+    submitted: boolean = false
+
+    $refs!: { dialog: ElDialog }
+
     get listeners() {
-      const { open, closed, submit, ...rest } = this.$listeners
+      const { open, opened, closed, submit, ...rest } = this.$listeners
       return rest
     }
 
     onOpen() {
-      if (this.clear) {
-        const { clearValidate } = (this.$parent.$refs['form'] as ElForm) || {}
+      try {
+        if (this.clear) {
+          const { clearValidate } = (this.$parent.$refs['form'] as ElForm) || {}
+          setTimeout(() => {
+            clearValidate && clearValidate()
+          }, 0)
+        }
+      } catch (error) {
+        console.log(error)
+      }
+
+      this.$emit('open')
+    }
+
+    onOpened() {
+      try {
         setTimeout(() => {
-          clearValidate && clearValidate()
+          ;(this.$slots.default || []).forEach(({ componentInstance }) => {
+            const { clearValidate } = (componentInstance as any) || {}
+            if (clearValidate) {
+              clearValidate()
+            }
+          })
         }, 0)
+      } catch (error) {
+        console.log(error)
       }
-      this.$emit('open')
+      this.$emit('opened')
     }
 
     onClosed() {
-      if (this.clear) {
-        const { resetFields } = (this.$parent.$refs['form'] as ElForm) || {}
-        resetFields && resetFields()
+      try {
+        if (this.clear) {
+          Object.keys(this.$parent.$refs)
+            .filter((key) => String(key).startsWith('form'))
+            .forEach((key) => {
+              const { resetFields } = (this.$parent.$refs[key] as ElForm) || {}
+              resetFields && resetFields()
+            })
+        }
+      } catch (error) {
+        console.log(error)
+      }
+
+      try {
+        if (this.clear) {
+          ;(this.$slots.default || []).forEach(({ componentInstance }) => {
+            const { resetFields } = (componentInstance as any) || {}
+            if (resetFields) {
+              resetFields()
+            }
+          })
+        }
+      } catch (error) {
+        console.log(error)
       }
       this.$emit('closed')
+      this.submitted = false
+
+      try {
+        // 重置拖到过的dialog位置
+        const dialogDom = this.$refs.dialog.$el.querySelector('.el-dialog') as HTMLElement
+        if (dialogDom) {
+          dialogDom.style.removeProperty('left')
+          dialogDom.style.removeProperty('top')
+        }
+      } catch (error) {
+        console.log(error)
+      }
+    }
+
+    onSubmit() {
+      if (!this.timer) {
+        this.$emit('submit')
+        this.submitted = true
+        setTimeout(() => {
+          this.submitted = false
+        }, 1000)
+      } else {
+        clearTimeout(this.timer)
+        this.timer = window.setTimeout(() => {
+          this.timer = null
+        }, 1000)
+      }
+    }
+
+    onCancel() {
+      this.dialogVisible = false
+      this.$emit('cancel')
     }
+
     updated() {
       this.$nextTick(() => {
         /**我也不知道为什么title会被传到html上 */
@@ -91,25 +169,23 @@
       background-color: transparent;
       max-width: 85vw;
       margin-top: 0 !important;
-      transition: width 300ms ease;
-      .title {
-        font-size: $--font-size-medium;
-        color: $font-color;
-        font-weight: 500;
-      }
 
       &__header {
         background-color: $bg-color;
         color: $font-color;
         border-bottom-color: $bg-color;
-        height: 54px;
         text-indent: 0;
-        padding: 0 $gutter-medium;
+        padding: $gutter + 1px;
         display: flex;
         align-items: center;
         justify-content: space-between;
         border-top-left-radius: $radius;
         border-top-right-radius: $radius;
+        .title {
+          font-size: $--font-size-medium;
+          color: $font-color;
+          font-weight: 500;
+        }
         &btn {
           position: relative;
           top: 0;

+ 27 - 12
src/components/Base/Page/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div :class="{ container: true, 'no-gutter': !gutter }">
+  <div :class="{ container: true, 'no-gutter': !gutter, 'no-flex': noFlex }">
     <div :class="{ actions: true, hidden: !$slots.action }">
       <slot name="action" />
     </div>
@@ -14,9 +14,10 @@
 <script lang="ts">
   import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
   @Component({ name: 'TfPage', inheritAttrs: false })
-  export default class Page extends Vue {
+  export default class TfPage extends Vue {
     @Prop({ type: Boolean, default: false }) isActive!: boolean
     @Prop({ type: Boolean, default: true }) gutter!: boolean
+    @Prop({ type: Boolean, default: false }) noFlex!: boolean
     $parent!: Vue & { preparing?: Function }
     @Watch('isActive')
     refetchData(active: boolean) {
@@ -38,16 +39,7 @@
     flex-direction: column;
     background-color: $--background-color-base !important;
     @include base-scroll-bar();
-    &.no-gutter {
-      .actions {
-        margin-bottom: 0;
-      }
-      .content {
-        >>> .tf-table {
-          padding-top: 0;
-        }
-      }
-    }
+
     .actions {
       flex: 0 0 auto;
       position: relative;
@@ -86,5 +78,28 @@
         z-index: 99;
       }
     }
+
+    &.no-gutter {
+      .actions {
+        margin-bottom: 0;
+      }
+      .content {
+        >>> .tf-table {
+          padding-top: 0;
+        }
+      }
+    }
+
+    &.no-flex {
+      display: block;
+      height: 100%;
+      overflow: hidden auto;
+      .content {
+        position: relative;
+      }
+    }
+    >>> .el-checkbox-group {
+      display: inline-flex;
+    }
   }
 </style>

+ 3 - 3
src/components/Base/Table/index.vue

@@ -63,7 +63,7 @@
     _slot: boolean
   }
   @Component({ name: 'TfTable', inheritAttrs: false })
-  export default class Table extends Vue {
+  export default class TfTable extends Vue {
     @Prop({ type: Array, default: () => [] }) columns!: ICol[]
     @Prop({ type: Object, default: () => ({}) }) pagination!: ElPagination & IPagination
     @Prop({ type: Array, default: () => [] }) data!: ElTable['data']
@@ -158,7 +158,7 @@
 <style lang="scss" scoped>
   .tf-table {
     height: 100%;
-    min-height: 74px;
+    min-height: 93px;
     display: flex;
     flex-direction: column;
     position: relative;
@@ -166,7 +166,7 @@
     padding: $gutter $gutter 0;
     background-color: #fff;
     z-index: 99;
-    transition: height 500ms ease;
+    transition: height 300ms ease;
 
     >>> .el-table {
       .el-table__header {

+ 35 - 11
src/components/Base/Title/index.vue

@@ -1,51 +1,65 @@
 <template>
-  <div :class="{ 'tf-title': true, 'tf-title--top': alignTop }">
+  <div :class="{ 'tf-title': true, 'tf-title--collapse': isCollapse !== undefined }" @click="isCollapse = !isCollapse">
     <div :class="{ content: true, 'content--bold': isBold }"><slot /></div>
     <div class="append"><slot name="append" /></div>
+    <i
+      v-if="isCollapse !== undefined"
+      :class="{ icon: true, 'el-icon-arrow-up': true, 'icon--down': isCollapse === false }"
+    />
   </div>
 </template>
 <script lang="ts">
-  import { Vue, Component, Prop } from 'vue-property-decorator'
+  import { Vue, Component, Prop, PropSync } from 'vue-property-decorator'
 
-  @Component({ name: 'Title' })
-  export default class Title extends Vue {
+  @Component({ name: 'TfTitle' })
+  export default class TfTitle extends Vue {
     @Prop({ type: Boolean, default: true }) isBold!: boolean
-    @Prop({ type: Boolean, default: false }) alignTop!: boolean
+    @PropSync('collapse', { type: Boolean, default: undefined }) isCollapse!: boolean
   }
 </script>
 
 <style lang="scss" scoped>
   .tf-title {
-    padding: 4px 0 4px 10px;
-    margin-bottom: 15px;
-    font-size: 16px;
+    padding: 4px 0 4px 14px;
+    margin-bottom: $gutter;
+    font-size: $--font-size-medium;
     position: relative;
     text-transform: capitalize;
     display: flex;
     align-items: center;
     justify-content: space-between;
-    color: $--color-text-primary;
     &--top {
       align-items: center;
     }
+
     &::before {
       content: '';
       display: block;
       width: 4px;
-      height: 16px;
+      height: $--font-size-medium;
       position: absolute;
       left: 0;
       top: 50%;
       transform: translateY(-50%);
       background-color: $--color-primary;
     }
+    &--collapse {
+      padding: 10px $--font-size-medium 10px $--font-size-medium * 2;
+      background-color: rgba($--color-primary, 0.16);
+      cursor: pointer;
+      line-height: 1.25;
+      &::before {
+        left: $--font-size-medium;
+      }
+    }
     .content {
       flex: 1 1 auto;
       text-overflow: ellipsis;
       overflow: hidden;
       white-space: nowrap;
-      margin-right: 3em;
       font-weight: 600;
+      display: flex;
+      align-items: center;
     }
     .append {
       flex: 0 0 auto;
@@ -56,5 +70,15 @@
         color: $--color-primary;
       }
     }
+    .icon {
+      flex: 0 0 auto;
+      color: $--color-primary;
+      font-size: $--font-size-medium;
+      transform: rotate(0);
+      transition: transform ease 300ms;
+      &--down {
+        transform: rotate(180deg);
+      }
+    }
   }
 </style>

+ 20 - 8
src/components/Base/index.ts

@@ -1,10 +1,22 @@
 import Vue from 'vue'
-import Page from './Page/index.vue'
-import Table from './Table/index.vue'
-import Dialog from './Dialog/index.vue'
-import Title from './Title/index.vue'
+// import Page from '../Base/Page/index.vue'
+// import Table from '../Base/Table/index.vue'
+// import Dialog from '../Base/Dialog/index.vue'
+// import Title from '../Base/Title/index.vue'
+// import ImagePreview from '../Base/Dialog/ImagePreview.vue'
 
-Vue.component('tf-page', Page)
-Vue.component(`tf-table`, Table)
-Vue.component(`tf-dialog`, Dialog)
-Vue.component(`tf-title`, Title)
+// Vue.component('tf-page', Page)
+// Vue.component(`tf-table`, Table)
+// Vue.component(`tf-dialog`, Dialog)
+// Vue.component(`tf-title`, Title)
+// Vue.component(`tf-image-preview`, ImagePreview)
+
+export default {
+  install(vue: typeof Vue): void {
+    const requireComponent = require.context('@/components/Base', true, /\.vue$/)
+    requireComponent.keys().forEach((fileName) => {
+      const Component = requireComponent(fileName)
+      vue.component(Component.default.name, Component.default)
+    })
+  }
+}

+ 7 - 4
src/main.ts

@@ -14,7 +14,6 @@ import './directives'
 import App from './App.vue'
 import store from './store'
 import router from './router'
-import '@/components/Base'
 
 import { comMethod } from '@/utils/comMethod'
 import '@/icons'
@@ -23,6 +22,9 @@ import '@/permission' // 权限控制
 import '@/assets/iconfont/iconfont.js'
 import '@/assets/iconfont/iconfont.css'
 
+import baseComponents from '@/components/Base'
+Vue.use(baseComponents)
+
 import Moment from 'vue-moment'
 //全局接口
 import PortApi from './api/APIs'
@@ -32,7 +34,8 @@ import lodash from 'lodash'
 Object.defineProperty(Vue.prototype, '$_', {
   value: lodash
 })
-// 
+
+//
 import html2pdf from '@/utils/html2pdf'
 Vue.use(html2pdf)
 
@@ -89,7 +92,7 @@ Vue.directive('selectLoadMore', {
   bind(el, binding) {
     // 获取element-ui定义好的scroll盒子
     const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
-    SELECTWRAP_DOM.addEventListener('scroll', function() {
+    SELECTWRAP_DOM.addEventListener('scroll', function () {
       if (this.scrollHeight - this.scrollTop < this.clientHeight + 1) {
         binding.value()
       }
@@ -100,7 +103,7 @@ Vue.directive('selectLoadMore', {
 Vue.directive('scrollMore', {
   bind(el, binding) {
     // 获取element-ui定义好的scroll盒子
-    el.addEventListener('scroll', function() {
+    el.addEventListener('scroll', function () {
       if (this.scrollHeight - this.scrollTop < this.clientHeight + 1) {
         binding.value()
       }

+ 40 - 40
src/styles/base.scss

@@ -273,50 +273,50 @@ div:focus {
   max-width: 80vw;
 }
 
-.page-container {
-  height: calc(100% - 43px);
-  width: 100%;
-  overflow: hidden auto;
-  position: absolute;
-  background-color: #f5f5f6 !important;
-  display: flex;
-  flex-direction: column;
-  @include base-scroll-bar();
-  > .actions {
-    padding-top: 22px;
-    padding-left: 15px;
-    padding-right: 15px;
-    margin-bottom: 15px;
-    &.small {
-      padding-top: 10px;
-      margin-bottom: 10px;
-    }
-
-    background: #fff;
-    flex: 0 0 auto;
-    position: relative;
-    position: sticky;
-    top: 0;
-    z-index: 100;
-  }
-  > .el-row {
-    flex: 1 1 100%;
-    display: flex;
-    position: relative;
-    z-index: 99;
-    > .el-col {
-      display: flex;
-      height: 100%;
-      overflow: auto;
-      @include base-scroll-bar();
-    }
-  }
-}
+// .page-container {
+//   height: calc(100% - 43px);
+//   width: 100%;
+//   overflow: hidden auto;
+//   position: absolute;
+//   background-color: #f5f5f6 !important;
+//   display: flex;
+//   flex-direction: column;
+//   @include base-scroll-bar();
+//   > .actions {
+//     padding-top: 22px;
+//     padding-left: 15px;
+//     padding-right: 15px;
+//     margin-bottom: 15px;
+//     &.small {
+//       padding-top: 10px;
+//       margin-bottom: 10px;
+//     }
+
+//     background: #fff;
+//     flex: 0 0 auto;
+//     position: relative;
+//     position: sticky;
+//     top: 0;
+//     z-index: 100;
+//   }
+//   > .el-row {
+//     flex: 1 1 100%;
+//     display: flex;
+//     position: relative;
+//     z-index: 99;
+//     > .el-col {
+//       display: flex;
+//       height: 100%;
+//       overflow: auto;
+//       @include base-scroll-bar();
+//     }
+//   }
+// }
 .el-dialog__wrapper.dialog .el-dialog__body {
   max-height: 75vh;
   overflow: hidden auto;
 }
-.el-tree{
+.el-tree {
   @include base-scroll-bar();
 }
 .el-table__body-wrapper,

+ 18 - 2
src/utils/request.ts

@@ -4,6 +4,22 @@ import store from '@/store'
 import { geteSessionStorage } from '@/utils/auth'
 import qs from 'qs'
 import router from '@/router'
+const JSONbigString = require('json-bigint')({
+  storeAsString: true
+  // objectBaseClass: Object
+})
+// console.log(JSONbigString)
+const transformResponse = [
+  (res) => {
+    try {
+      return JSON.parse(JSON.stringify(JSONbigString.parse(res)))
+    } catch (error) {
+      console.log(error)
+      return JSON.parse(res)
+    }
+  }
+]
+
 declare module 'axios' {
   export interface AxiosRequestConfig {
     /**
@@ -38,7 +54,8 @@ export const baseAddress = IP
 const service = axios.create({
   baseURL: IP,
   withCredentials: true, // 跨域请求时发送cookiesokies
-  timeout: 30000 // 请求超时
+  timeout: 30000, // 请求超时
+  transformResponse
 })
 
 let requestTimes = 0
@@ -159,7 +176,6 @@ service.interceptors.response.use(
     }
   }
 )
-
 // 森鑫炬接口
 export function getSXJList(data) {
   return service({

+ 2 - 1
src/views/spectrum/configuration/api/common.ts

@@ -88,6 +88,7 @@ export interface IDevice extends ICreator, IUpdater {
   deviceSn: string
   deviceType: number
   deviceTypeName: string
+  deviceState: number
   fileTypeID: number
   filesPath: string
   firmLiaison: string
@@ -250,7 +251,7 @@ export interface IPointDetailResult {
     deviceTypeName: string
   }
   targetVos: {
-    id: number
+    id: number | string
     sid: string
     typeId: number
     siteId: number

+ 2 - 11
src/views/spectrum/configuration/api/standard.ts

@@ -14,21 +14,12 @@ const uris = {
 }
 
 export const addStandard = (data: Omit<IStandard, 'id'>) =>
-  axios.request<IRes<boolean>>({
-    url: uris.base,
-    method: 'post',
-    data: serialize(data)
-  })
+  axios.request<IRes<boolean>>({ url: uris.base, method: 'post', data })
 
 export const deleteStandard = (id: string) =>
   axios.request<IRes<boolean>>({ url: `${uris.base}/${id}`, method: 'delete' })
 
-export const updateStandard = (data: IStandard) =>
-  axios.request<IRes<boolean>>({
-    url: uris.base,
-    method: 'put',
-    data: serialize(data)
-  })
+export const updateStandard = (data: IStandard) => axios.request<IRes<boolean>>({ url: uris.base, method: 'put', data })
 
 export const getStandard = (id: string) =>
   axios.request<IResult<IStandard>>({ url: `${uris.base}/${id}`, method: 'get' })

+ 203 - 203
src/views/spectrum/configuration/device/DeviceForm.vue

@@ -37,7 +37,7 @@
               clearable
               v-bind="rest"
               @change="onChange"
-              style="width:100%"
+              style="width: 100%"
             >
               <el-option v-for="item in options" :key="item.id" :label="item.deviceTypeName" :value="item.id" />
             </el-select>
@@ -56,8 +56,8 @@
       </el-col>
       <el-col :span="12">
         设备照片
-        <span style="margin-left:5px; color:#ccc">(最多上传9张)</span>
-        <div style="margin-top:20px" class="upload">
+        <span style="margin-left: 5px; color: #ccc">(最多上传9张)</span>
+        <div style="margin-top: 20px" class="upload">
           <el-upload
             list-type="picture-card"
             :on-preview="handlePictureCardPreview"
@@ -82,223 +82,223 @@
 </template>
 
 <script lang="ts">
-import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
-import { ElForm } from 'element-ui/types/form'
-import { getRemoteImg } from '@/api/ftp'
-import { ElUploadInternalFileDetail } from 'element-ui/types/upload'
-import { deviceTypeParamPage } from '../api/deviceType'
-import { IDevice, IDeviceType } from '../api/common'
-import { telAndMobileReg } from '@/utils/constant'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+  import { ElForm } from 'element-ui/types/form'
+  import { getRemoteImg } from '@/api/ftp'
+  import { ElUploadInternalFileDetail } from 'element-ui/types/upload'
+  import { deviceTypeParamPage } from '../api/deviceType'
+  import { IDevice, IDeviceType } from '../api/common'
+  import { telAndMobileReg } from '@/utils/constant'
 
-const getDefaultValue = (): Partial<IDevice> => ({
-  deviceName: undefined,
-  deviceSn: undefined,
-  deviceModel: undefined,
-  deviceType: undefined,
-  deviceFirm: undefined,
-  firmLiaison: undefined,
-  liaisonPhone: undefined,
-  buyTime: undefined,
-  remark: undefined
-})
+  const getDefaultValue = (): Partial<IDevice> => ({
+    deviceName: undefined,
+    deviceSn: undefined,
+    deviceModel: undefined,
+    deviceType: undefined,
+    deviceFirm: undefined,
+    firmLiaison: undefined,
+    liaisonPhone: undefined,
+    buyTime: undefined,
+    remark: undefined
+  })
 
-@Component({ name: 'TypeForm', components: {} })
-export default class TypeForm extends Vue {
-  @Prop({ type: Object, default: () => ({}) }) data!: object
-  @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
-  $refs!: { form: ElForm }
-  dialogVisible = false
-  dialogImageUrl = ''
-  formData: Partial<Omit<IDevice, 'filesPath'>> & {
-    filesPath?: Partial<ElUploadInternalFileDetail>[]
-    param?: string
-  } = {
-    ...getDefaultValue(),
-    filesPath: [],
-    param: ''
-  }
+  @Component({ name: 'TypeForm', components: {} })
+  export default class TypeForm extends Vue {
+    @Prop({ type: Object, default: () => ({}) }) data!: IDevice
+    @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
+    $refs!: { form: ElForm }
+    dialogVisible = false
+    dialogImageUrl = ''
+    formData: Partial<Omit<IDevice, 'filesPath'>> & {
+      filesPath?: Partial<ElUploadInternalFileDetail>[]
+      param?: string
+    } = {
+      ...getDefaultValue(),
+      filesPath: [],
+      param: ''
+    }
 
-  get listeners() {
-    const { submit, ...rest } = this.$listeners
-    return rest
-  }
+    get listeners() {
+      const { submit, ...rest } = this.$listeners
+      return rest
+    }
 
-  get formItems() {
-    return [
-      {
-        label: '设备名称',
-        name: 'deviceName',
-        required: true,
-        maxlength: 50
-      },
-      {
-        /** ②	设备出厂唯一编号: 必填,自定义录入文本,要求与设备上的信息一致。 */
-        label: '设备SN码',
-        name: 'deviceSn',
-        maxlength: 64
-      },
-      {
-        /** ③	设备型号: 必填,自定义录入文本。 */
-        label: '设备型号',
-        name: 'deviceModel',
-        maxlength: 50
-      },
-      {
-        /** ④	设备类型: 必填,下拉框,在【设备类型配置】中配置的设备类型。 */
-        label: '设备类型',
-        name: 'deviceType',
-        type: 'select',
-        required: true,
-        options: this.types,
-        onChange: this.getAllTypeParams
-      },
-      {
-        /** ⑤	监测参数: 系统自动显示,根据设备类型关联显示该设备监测参数。 */
-        label: '监测指标',
-        name: 'param',
-        type: 'textarea',
-        rows: 3,
-        disabled: true
-      },
-      {
-        /** ⑥	设备厂商: 必填,自定义录入文本。 */
-        label: '设备厂家',
-        name: 'deviceFirm',
-        maxlength: 50
-      },
-      {
-        /** ⑦	厂家联系人: 必填,自定义录入文本。 */
-        label: '厂家联系人',
-        name: 'firmLiaison',
-        maxlength: 50
-      },
-      {
-        /** ⑧	联系方式: 必填,自定义录入文本。 */
-        label: '联系方式',
-        name: 'liaisonPhone',
-        maxlength: 50
-      },
-      {
-        /** ⑨	采购时间: 必填,自定义录入文本。 */
-        label: '采购时间',
-        name: 'buyTime',
-        type: 'date',
-        style: 'width:100%'
-      },
-      {
-        label: '备注',
-        name: 'remark',
-        type: 'textarea',
-        maxlength: 256
-      }
-    ]
-  }
+    get formItems() {
+      return [
+        {
+          label: '设备名称',
+          name: 'deviceName',
+          required: true,
+          maxlength: 50
+        },
+        {
+          /** ②	设备出厂唯一编号: 必填,自定义录入文本,要求与设备上的信息一致。 */
+          label: '设备SN码',
+          name: 'deviceSn',
+          maxlength: 64
+        },
+        {
+          /** ③	设备型号: 必填,自定义录入文本。 */
+          label: '设备型号',
+          name: 'deviceModel',
+          maxlength: 50
+        },
+        {
+          /** ④	设备类型: 必填,下拉框,在【设备类型配置】中配置的设备类型。 */
+          label: '设备类型',
+          name: 'deviceType',
+          type: 'select',
+          required: true,
+          options: this.types,
+          onChange: this.getAllTypeParams
+        },
+        {
+          /** ⑤	监测参数: 系统自动显示,根据设备类型关联显示该设备监测参数。 */
+          label: '监测指标',
+          name: 'param',
+          type: 'textarea',
+          rows: 3,
+          disabled: true
+        },
+        {
+          /** ⑥	设备厂商: 必填,自定义录入文本。 */
+          label: '设备厂家',
+          name: 'deviceFirm',
+          maxlength: 50
+        },
+        {
+          /** ⑦	厂家联系人: 必填,自定义录入文本。 */
+          label: '厂家联系人',
+          name: 'firmLiaison',
+          maxlength: 50
+        },
+        {
+          /** ⑧	联系方式: 必填,自定义录入文本。 */
+          label: '联系方式',
+          name: 'liaisonPhone',
+          maxlength: 50
+        },
+        {
+          /** ⑨	采购时间: 必填,自定义录入文本。 */
+          label: '采购时间',
+          name: 'buyTime',
+          type: 'date',
+          style: 'width:100%'
+        },
+        {
+          label: '备注',
+          name: 'remark',
+          type: 'textarea',
+          maxlength: 256
+        }
+      ]
+    }
 
-  rules = {
-    deviceName: [
-      { required: true, message: '设备名称不能为空!' },
-      { max: 50, message: '设备名称不超过50个字符' },
-      { pattern: /^[\u4e00-\u9fa5\w -]+$/, message: '允许输入汉字、英文、数字' }
-    ],
-    deviceType: [{ required: true, message: '请选择设备类型' }],
-    deviceFirm: [{ required: true, message: '请输入设备厂家' }],
-    deviceModel: [{ required: true, message: '请输入设备型号' }],
-    deviceSn: [{ required: true, message: '请输入设备SN码' }],
-    firmLiaison: [{ required: true, message: '请输入厂家联系人' }],
-    liaisonPhone: [
-      { required: true, message: '请输入联系方式' },
-      { pattern: telAndMobileReg(), message: '请输入正确的联系方式' }
-    ],
-    buyTime: [{ required: true, message: '请选择采购时间' }]
-  }
-  /** 没有查询全部类型参数的接口, 暂用分页接口 */
-  async getAllTypeParams(typeId: number) {
-    try {
-      const {
-        result: { records }
-      } = await deviceTypeParamPage({ typeId, current: 1, size: 9999 })
-      this.formData = {
-        ...this.formData,
-        param: records.length ? records.map((item) => item.targetName).join(', ') : '无'
+    rules = {
+      deviceName: [
+        { required: true, message: '设备名称不能为空!' },
+        { max: 50, message: '设备名称不超过50个字符' },
+        { pattern: /^[\u4e00-\u9fa5\w -]+$/, message: '允许输入汉字、英文、数字' }
+      ],
+      deviceType: [{ required: true, message: '请选择设备类型' }],
+      deviceFirm: [{ required: true, message: '请输入设备厂家' }],
+      deviceModel: [{ required: true, message: '请输入设备型号' }],
+      deviceSn: [{ required: true, message: '请输入设备SN码' }],
+      firmLiaison: [{ required: true, message: '请输入厂家联系人' }],
+      liaisonPhone: [
+        { required: true, message: '请输入联系方式' },
+        { pattern: telAndMobileReg(), message: '请输入正确的联系方式' }
+      ],
+      buyTime: [{ required: true, message: '请选择采购时间' }]
+    }
+    /** 没有查询全部类型参数的接口, 暂用分页接口 */
+    async getAllTypeParams(typeId: number) {
+      try {
+        const {
+          result: { records }
+        } = await deviceTypeParamPage({ typeId, current: 1, size: 9999 })
+        this.formData = {
+          ...this.formData,
+          param: records.length ? records.map((item) => item.targetName).join(', ') : '无'
+        }
+      } catch (error) {
+        console.log(error)
       }
-    } catch (error) {
-      console.log(error)
     }
-  }
 
-  onSubmit() {
-    this.$refs.form.validate((valid) => {
-      if (valid) {
-        const { param, filesPath, ...rest } = this.formData
-        this.$emit('submit', { ...rest, filesPath: filesPath.map(({ raw }) => raw) })
+    onSubmit() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          const { param, filesPath, ...rest } = this.formData
+          this.$emit('submit', { ...rest, filesPath: filesPath.map(({ raw }) => raw) })
+        }
+      })
+    }
+
+    onFileChange(file, filesPath) {
+      console.log(filesPath)
+      const isJPG = file.raw.type === 'image/jpeg'
+      const isPng = file.raw.type === 'image/png'
+      const isLt2M = file.size / 1024 / 1024 < 2
+      let needRemove = false
+      if (!isJPG && !isPng) {
+        this.$message.error('上传图片只能是 JPG/JPEG或png 格式!')
+        needRemove = true
+      }
+      if (!isLt2M) {
+        this.$message.error('上传头像图片大小不能超过 2MB!')
+        needRemove = true
+      }
+      if (filesPath.length > 9) {
+        this.$message.error('最多可以上传9张图片!')
+        needRemove = true
       }
-    })
-  }
 
-  onFileChange(file, filesPath) {
-    console.log(filesPath)
-    const isJPG = file.raw.type === 'image/jpeg'
-    const isPng = file.raw.type === 'image/png'
-    const isLt2M = file.size / 1024 / 1024 < 2
-    let needRemove = false
-    if (!isJPG && !isPng) {
-      this.$message.error('上传图片只能是 JPG/JPEG或png 格式!')
-      needRemove = true
-    }
-    if (!isLt2M) {
-      this.$message.error('上传头像图片大小不能超过 2MB!')
-      needRemove = true
-    }
-    if (filesPath.length > 9) {
-      this.$message.error('最多可以上传9张图片!')
-      needRemove = true
+      this.formData.filesPath = needRemove ? filesPath.filter((item) => item.uid !== file.uid) : [...filesPath]
     }
 
-    this.formData.filesPath = needRemove ? filesPath.filter((item) => item.uid !== file.uid) : [...filesPath]
-  }
-
-  handleRemovePic(file, filesPath) {
-    this.formData.filesPath = filesPath.filter((item) => item.uid !== file.uid)
-  }
+    handleRemovePic(file, filesPath) {
+      this.formData.filesPath = filesPath.filter((item) => item.uid !== file.uid)
+    }
 
-  handlePictureCardPreview(file) {
-    this.dialogImageUrl = file.url
-    this.dialogVisible = true
-  }
+    handlePictureCardPreview(file) {
+      this.dialogImageUrl = file.url
+      this.dialogVisible = true
+    }
 
-  @Watch('data', { immediate: true })
-  setDefaultData(val: IDevice) {
-    this.formData = val.id
-      ? {
-          ...val,
-          filesPath: (val.thumbnailUploadFiles || []).map((file) => ({
-            name: file.fileName || file.filePath,
-            url: getRemoteImg(file.filePath),
-            uid: file.id
-          }))
-        }
-      : { ...getDefaultValue(), param: '', filesPath: [] }
-    if (val.deviceType) this.getAllTypeParams(val.deviceType)
+    @Watch('data', { immediate: true })
+    setDefaultData(val: IDevice) {
+      this.formData = val.id
+        ? {
+            ...val,
+            filesPath: (val.thumbnailUploadFiles || []).map((file) => ({
+              name: file.fileName || file.filePath,
+              url: getRemoteImg(file.filePath),
+              uid: file.id
+            }))
+          }
+        : { ...getDefaultValue(), param: '', filesPath: [] }
+      if (val.deviceType) this.getAllTypeParams(val.deviceType)
+    }
   }
-}
 </script>
 <style lang="scss" scoped>
-.upload {
-  /deep/ .el-upload-list--picture-card .el-upload-list__item,
-  /deep/ .el-upload--picture-card {
-    width: 120px;
-    height: 120px;
-  }
-  /deep/ .el-upload--picture-card {
-    line-height: normal;
-    display: inline-flex;
-    align-items: center;
-    justify-content: center;
+  .upload {
+    /deep/ .el-upload-list--picture-card .el-upload-list__item,
+    /deep/ .el-upload--picture-card {
+      width: 120px;
+      height: 120px;
+    }
+    /deep/ .el-upload--picture-card {
+      line-height: normal;
+      display: inline-flex;
+      align-items: center;
+      justify-content: center;
+    }
   }
-}
-.preview {
-  /deep/ .el-dialog .el-dialog__header {
-    border-bottom: 0;
+  .preview {
+    /deep/ .el-dialog .el-dialog__header {
+      border-bottom: 0;
+    }
   }
-}
 </style>

+ 19 - 19
src/views/spectrum/configuration/device/QueryForm.vue

@@ -1,6 +1,6 @@
 <template>
   <el-form class="form" ref="form" v-bind="{ labelWidth: 'auto', size: 'small' }" :model="formData" inline>
-    <el-form-item label="出厂编号" prop="deviceSn">
+    <el-form-item label="SN序列号" prop="deviceSn">
       <el-input v-model="formData.deviceSn" placeholder="请输入出厂编号" size="small" clearable />
     </el-form-item>
     <el-form-item label="设备名称" prop="deviceName">
@@ -67,27 +67,27 @@
 </template>
 
 <script lang="ts">
-import { Vue, Component, Prop } from 'vue-property-decorator'
-import { IDevice, IDeviceType } from '../api/common'
+  import { Vue, Component, Prop } from 'vue-property-decorator'
+  import { IDevice, IDeviceType } from '../api/common'
 
-export interface ILoading {
-  query: boolean
-  add: boolean
-  update: boolean
-  del: boolean
-  export: boolean
-}
+  export interface ILoading {
+    query: boolean
+    add: boolean
+    update: boolean
+    del: boolean
+    export: boolean
+  }
 
-@Component({ name: 'QueryForm' })
-export default class QueryForm extends Vue {
-  @Prop({ type: Object, default: () => ({}) }) loading!: ILoading
-  @Prop({ type: Array, default: () => [] }) selected!: IDevice[]
-  @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
+  @Component({ name: 'QueryForm' })
+  export default class QueryForm extends Vue {
+    @Prop({ type: Object, default: () => ({}) }) loading!: ILoading
+    @Prop({ type: Array, default: () => [] }) selected!: IDevice[]
+    @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
 
-  formData: Partial<IDevice> = {}
+    formData: Partial<IDevice> = {}
 
-  get ids() {
-    return this.selected.map((item) => item.id).join()
+    get ids() {
+      return this.selected.map((item) => item.id).join()
+    }
   }
-}
 </script>

+ 106 - 106
src/views/spectrum/configuration/device/widget.vue

@@ -21,7 +21,7 @@
       @selection-change="onSelectionChange"
       @page-change="onPageChange"
     >
-      <template v-slot:deviceState="{ row }">
+      <!-- <template v-slot:deviceState="{ row }">
         <el-switch
           :active-value="1"
           :inactive-value="0"
@@ -29,7 +29,7 @@
           size="small"
           style="user-select:none"
         />
-      </template>
+      </template> -->
     </tf-table>
     <DeviceForm
       :visible.sync="visible"
@@ -43,137 +43,137 @@
 </template>
 
 <script lang="ts">
-import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
-import QueryForm, { ILoading } from './QueryForm.vue'
-import DeviceForm from './DeviceForm.vue'
-import { updateDevice, addDevice, deleteDeviceBatch, devicePage } from '../api/device'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+  import QueryForm, { ILoading } from './QueryForm.vue'
+  import DeviceForm from './DeviceForm.vue'
+  import { updateDevice, addDevice, deleteDeviceBatch, devicePage } from '../api/device'
 
-import { getDefaultPagination } from '@/utils/constant'
-import { deviceCols } from '../utils'
-import { IDevice, IDeviceType } from '../api/common'
-import { IPagination } from '@/api/common'
-import { deviceTypePage } from '../api/deviceType'
+  import { getDefaultPagination } from '@/utils/constant'
+  import { deviceCols } from '../utils'
+  import { IDevice, IDeviceType } from '../api/common'
+  import { IPagination } from '@/api/common'
+  import { deviceTypePage } from '../api/deviceType'
 
-@Component({ name: 'Device', components: { QueryForm, DeviceForm } })
-export default class Device extends Vue {
-  @Prop({ type: Boolean, default: false }) isActive!: boolean
-  deviceCols = deviceCols
+  @Component({ name: 'Device', components: { QueryForm, DeviceForm } })
+  export default class Device extends Vue {
+    @Prop({ type: Boolean, default: false }) isActive!: boolean
+    deviceCols = deviceCols
 
-  visible = false
+    visible = false
 
-  current: Partial<IDevice> = {}
+    current: Partial<IDevice> = {}
 
-  selected: IDevice[] = []
+    selected: IDevice[] = []
 
-  types: IDeviceType[] = []
+    types: IDeviceType[] = []
 
-  archives: IDevice[] = []
+    archives: IDevice[] = []
 
-  loading: ILoading = { query: false, add: false, update: false, del: false, export: false }
+    loading: ILoading = { query: false, add: false, update: false, del: false, export: false }
 
-  pagination: IPagination = getDefaultPagination()
+    pagination: IPagination = getDefaultPagination()
 
-  query: Partial<IDevice> = {}
+    query: Partial<IDevice> = {}
 
-  onQuery(query) {
-    this.query = { ...query }
-    this.doQuery({ current: 1 })
-  }
+    onQuery(query) {
+      this.query = { ...query }
+      this.doQuery({ current: 1 })
+    }
 
-  async doQuery(query = {}) {
-    this.loading.query = true
-    try {
-      const {
-        result: { records, size, total, current }
-      } = await devicePage({ ...this.pagination, ...this.query, ...query, ...this.$store.getters['project/id'] })
-      this.pagination = { current, size, total }
-      this.archives = records || []
-    } catch (error) {
-      console.log(error)
+    async doQuery(query = {}) {
+      this.loading.query = true
+      try {
+        const {
+          result: { records, size, total, current }
+        } = await devicePage({ ...this.pagination, ...this.query, ...query, ...this.$store.getters['project/id'] })
+        this.pagination = { current, size, total }
+        this.archives = records || []
+      } catch (error) {
+        console.log(error)
+      }
+      this.loading.query = false
     }
-    this.loading.query = false
-  }
 
-  onPageChange(pagination) {
-    this.pagination = { ...this.pagination, ...pagination }
-    this.doQuery()
-  }
+    onPageChange(pagination) {
+      this.pagination = { ...this.pagination, ...pagination }
+      this.doQuery()
+    }
 
-  async onSubmit(data: IDevice) {
-    this.loading[data.id ? 'update' : 'add'] = true
-    try {
-      const { result } = await (data.id
-        ? updateDevice({ ...data, fileTypeID: 803 })
-        : addDevice({ ...data, ...this.$store.getters['project/info'], fileTypeID: 803 }))
-      this.$message[result ? 'success' : 'error'](`${data.id ? '修改' : '新增'}设备档案${result ? '成功!' : '失败!'}`)
-      if (result) {
-        this.visible = false
-        this.doQuery()
+    async onSubmit(data: IDevice) {
+      this.loading[data.id ? 'update' : 'add'] = true
+      try {
+        const { result } = await (data.id
+          ? updateDevice({ ...data, fileTypeID: 803 })
+          : addDevice({ ...data, ...this.$store.getters['project/info'], fileTypeID: 803 }))
+        this.$message[result ? 'success' : 'error'](`${data.id ? '修改' : '新增'}设备档案${result ? '成功!' : '失败!'}`)
+        if (result) {
+          this.visible = false
+          this.doQuery()
+        }
+      } catch (error) {
+        console.log(error)
       }
-    } catch (error) {
-      console.log(error)
+      this.loading[data.id ? 'update' : 'add'] = false
     }
-    this.loading[data.id ? 'update' : 'add'] = false
-  }
 
-  onAdd() {
-    this.current = {}
-    this.visible = true
-  }
+    onAdd() {
+      this.current = {}
+      this.visible = true
+    }
 
-  onUpdate(row) {
-    this.current = { ...row }
-    this.visible = true
-  }
+    onUpdate(row) {
+      this.current = { ...row }
+      this.visible = true
+    }
 
-  async onDel(ids) {
-    await this.$confirm(`是否确认删除这${this.selected.length}项设备档案?`, '提示', {
-      confirmButtonText: '确定',
-      cancelButtonText: '取消',
-      type: 'warning'
-    })
-    this.loading.del = true
-    try {
-      const { result } = await deleteDeviceBatch(ids)
-      this.$message[result ? 'success' : 'error'](`删除设备档案${result ? '成功!' : '失败!'}`)
-      result && this.doQuery()
-    } catch (error) {
-      console.log(error)
+    async onDel(ids) {
+      await this.$confirm(`是否确认删除这${this.selected.length}项设备档案?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+      this.loading.del = true
+      try {
+        const { result } = await deleteDeviceBatch(ids)
+        this.$message[result ? 'success' : 'error'](`删除设备档案${result ? '成功!' : '失败!'}`)
+        result && this.doQuery()
+      } catch (error) {
+        console.log(error)
+      }
+      this.loading.del = false
     }
-    this.loading.del = false
-  }
 
-  onExport(ids) {
-    console.log(ids)
-  }
+    onExport(ids) {
+      console.log(ids)
+    }
 
-  onDblClick(row) {
-    this.current = { ...row }
-    this.visible = true
-  }
+    onDblClick(row) {
+      this.current = { ...row }
+      this.visible = true
+    }
 
-  onSelectionChange(selections) {
-    this.selected = [...selections]
-  }
+    onSelectionChange(selections) {
+      this.selected = [...selections]
+    }
 
-  async getAllTypes() {
-    try {
-      const {
-        result: { records }
-      } = await deviceTypePage({ current: 1, size: 9999 })
-      this.types = records || []
-    } catch (error) {
-      console.log(error)
+    async getAllTypes() {
+      try {
+        const {
+          result: { records }
+        } = await deviceTypePage({ current: 1, size: 9999 })
+        this.types = records || []
+      } catch (error) {
+        console.log(error)
+      }
     }
-  }
 
-  mounted() {
-    this.preparing()
-  }
+    mounted() {
+      this.preparing()
+    }
 
-  preparing() {
-    this.doQuery()
-    this.getAllTypes()
+    preparing() {
+      this.doQuery()
+      this.getAllTypes()
+    }
   }
-}
 </script>

+ 90 - 72
src/views/spectrum/configuration/point/PointForm/BasisForm.vue

@@ -2,6 +2,7 @@
   <el-form class="form" ref="form" v-bind="{ labelWidth, size: 'small' }" :model="formData" :rules="rules">
     <el-row :gutter="10">
       <el-col :span="12">
+      
         <el-form-item label="监测站点编号" prop="siteCode">
           <el-input v-model="formData.siteCode" placeholder="系统生成" disabled />
         </el-form-item>
@@ -14,28 +15,45 @@
         <el-form-item label="监测站点地址" prop="siteAddress">
           <el-input v-model="formData.siteAddress" :placeholder="message.siteAddress" />
         </el-form-item>
-        <el-form-item label="监测站点坐标" :show-messag="false" style="margin-bottom: 0">
+        <el-form-item label="监测站点坐标" :show-messag="false" style="margin-bottom: 0" required>
           <el-row type="flex" justify="space-between" :gutter="10">
             <el-col>
               <el-form-item prop="latitude">
-                <el-input-number v-model="formData.latitude" :placeholder="message.latitude" v-bind="getDefalutNumberProp()" :precision="7" :controls="false" />
+                <el-input-number
+                  v-model="formData.latitude"
+                  :placeholder="message.latitude"
+                  v-bind="getDefalutNumberProp()"
+                  :precision="7"
+                  :controls="false"
+                />
               </el-form-item>
             </el-col>
             <el-col style="flex: 0 0 1em; text-align: center"> ~ </el-col>
             <el-col>
               <el-form-item prop="longitude">
-                <el-input-number v-model="formData.longitude" :placeholder="message.longitude" v-bind="getDefalutNumberProp()" :precision="7" :controls="false" />
+                <el-input-number
+                  v-model="formData.longitude"
+                  :placeholder="message.longitude"
+                  v-bind="getDefalutNumberProp()"
+                  :precision="7"
+                  :controls="false"
+                />
               </el-form-item>
             </el-col>
             <el-col style="flex: 0 0 5em; text-align: center">
-              <el-button :type="enable.coordinate ? 'warning' : 'primary'" @click="enable.coordinate = !enable.coordinate" :disabled="enable.device" size="small">
+              <el-button
+                :type="enable.coordinate ? 'warning' : 'primary'"
+                @click="enable.coordinate = !enable.coordinate"
+                :disabled="enable.device"
+                size="small"
+              >
                 图上选点
               </el-button>
             </el-col>
           </el-row>
         </el-form-item>
       </el-col>
-      <el-col :span="12" style="height: 254px;">
+      <el-col :span="12" style="height: 254px">
         <MinMap ref="minMap"></MinMap>
       </el-col>
     </el-row>
@@ -43,80 +61,80 @@
 </template>
 
 <script lang="ts">
-import { Vue, Component, ModelSync, Prop } from 'vue-property-decorator'
-import { ElForm } from 'element-ui/types/form'
-import { getDefalutNumberProp } from '@/utils/constant'
+  import { Vue, Component, ModelSync, Prop } from 'vue-property-decorator'
+  import { ElForm } from 'element-ui/types/form'
+  import { getDefalutNumberProp } from '@/utils/constant'
 
-import MinMap from '@/views/widgets/miniMap/index.vue'
+  import MinMap from '@/views/widgets/miniMap/index.vue'
 
-export interface IBasis {
-  /** 站点编号 */
-  siteCode: string
-  /** 站点名称 */
-  siteName: string
-  /** 断面Id */
-  sectionId: string
-  /** 站点地址 */
-  siteAddress: string
-  /** 纬度 */
-  latitude: string
-  /** 经度 */
-  longitude: string
-}
-
-@Component({ name: 'BasisForm', components: { MinMap } })
-export default class BasisForm extends Vue {
-  @ModelSync('value', 'change', { type: Object }) readonly formData!: IBasis
-  @Prop({ type: String, default: '8em' }) labelWidth!: string
-  @Prop({ type: Object, default: () => ({ coordinate: false, device: false }) }) enable!: {
-    coordinate: boolean
-    device: boolean
-  }
-  getDefalutNumberProp = getDefalutNumberProp
-  $refs!: { form: ElForm; minMap: any }
-  message = {
-    siteName: '请输入监测站点名称',
-    sectionId: '请输入断面编码',
-    siteAddress: '请输入监测站点地址',
-    latitude: '请输入纬度',
-    longitude: '请输入经度'
-  }
-  rules = {
-    siteName: [{ required: true, message: this.message.siteName, trigger: 'blur' }],
-    sectionId: [{ required: true, message: this.message.sectionId, trigger: 'blur' }],
-    siteAddress: [{ required: true, message: this.message.siteAddress, trigger: 'blur' }],
-    latitude: [{ required: true, message: this.message.latitude, trigger: 'blur' }],
-    longitude: [{ required: true, message: this.message.longitude, trigger: 'blur' }]
+  export interface IBasis {
+    /** 站点编号 */
+    siteCode: string
+    /** 站点名称 */
+    siteName: string
+    /** 断面Id */
+    sectionId: string
+    /** 站点地址 */
+    siteAddress: string
+    /** 纬度 */
+    latitude: string
+    /** 经度 */
+    longitude: string
   }
 
-  get AppX() {
-    return this.$store.getters.AppX
-  }
+  @Component({ name: 'BasisForm', components: { MinMap } })
+  export default class BasisForm extends Vue {
+    @ModelSync('value', 'change', { type: Object }) readonly formData!: IBasis
+    @Prop({ type: String, default: '8em' }) labelWidth!: string
+    @Prop({ type: Object, default: () => ({ coordinate: false, device: false }) }) enable!: {
+      coordinate: boolean
+      device: boolean
+    }
+    getDefalutNumberProp = getDefalutNumberProp
+    $refs!: { form: ElForm; minMap: any }
+    message = {
+      siteName: '请输入监测站点名称',
+      sectionId: '请输入断面编码',
+      siteAddress: '请输入监测站点地址',
+      latitude: '请输入纬度',
+      longitude: '请输入经度'
+    }
+    rules = {
+      siteName: [{ required: true, message: this.message.siteName, trigger: 'blur' }],
+      sectionId: [{ required: true, message: this.message.sectionId, trigger: 'blur' }],
+      siteAddress: [{ required: true, message: this.message.siteAddress, trigger: 'blur' }],
+      latitude: [{ required: true, message: this.message.latitude, trigger: 'blur' }],
+      longitude: [{ required: true, message: this.message.longitude, trigger: 'blur' }]
+    }
 
-  initMapClick() {
-    const Cesium = (window as any).Cesium
-    let viewer = this.$refs.minMap._viewer
-    let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
-    let leafletClick = Cesium.ScreenSpaceEventType.LEFT_CLICK
-    handler.setInputAction((event) => {
-      this.$emit('mapClick', event)
-      handler.removeInputAction(leafletClick)
-    }, leafletClick)
-  }
+    get AppX() {
+      return this.$store.getters.AppX
+    }
 
-  clearValidate() {
-    this.$refs.form.clearValidate()
-  }
+    initMapClick() {
+      const Cesium = (window as any).Cesium
+      let viewer = this.$refs.minMap._viewer
+      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
+      let leafletClick = Cesium.ScreenSpaceEventType.LEFT_CLICK
+      handler.setInputAction((event) => {
+        this.$emit('mapClick', event)
+        handler.removeInputAction(leafletClick)
+      }, leafletClick)
+    }
 
-  resetFields() {
-    this.$refs.form.resetFields()
-  }
-  async validate() {
-    return new Promise<IBasis>((resolve, reject) => {
-      this.$refs.form.validate((valid) => {
-        valid ? resolve(this.formData) : reject()
+    clearValidate() {
+      this.$refs.form.clearValidate()
+    }
+
+    resetFields() {
+      this.$refs.form.resetFields()
+    }
+    async validate() {
+      return new Promise<IBasis>((resolve, reject) => {
+        this.$refs.form.validate((valid) => {
+          valid ? resolve(this.formData) : reject()
+        })
       })
-    })
+    }
   }
-}
 </script>

+ 7 - 1
src/views/spectrum/configuration/point/PointForm/DeviceForm.vue

@@ -21,6 +21,7 @@
             :placeholder="message.deviceId"
             clearable
             style="width: 100%"
+            :loading="loading"
           >
             <el-option v-for="item in devices" :key="item.id" :label="item.deviceName" :value="item.id">
               {{ `${item.deviceName}${item.deviceSn ? ' | ' + item.deviceSn : ''}` }}
@@ -49,7 +50,7 @@
 </template>
 
 <script lang="ts">
-  import { Vue, Component, ModelSync, Prop } from 'vue-property-decorator'
+  import { Vue, Component, ModelSync, Prop, Watch } from 'vue-property-decorator'
   import { ElForm } from 'element-ui/types/form'
   import { getDefalutNumberProp, telAndMobileReg } from '@/utils/constant'
   import { ElUploadInternalFileDetail } from 'element-ui/types/upload'
@@ -87,6 +88,7 @@
     getDefalutNumberProp = getDefalutNumberProp
     $refs!: { form: ElForm }
     devices: IDevice[] = []
+    loading: boolean = false
     message = {
       typeId: '请选择设备类型',
       deviceId: '请选择设备',
@@ -105,7 +107,10 @@
       'install.installTime': [{ required: true, message: this.message.installTime, trigger: 'blur' }]
     }
 
+    @Watch('formData.typeId', { immediate: true })
     async onTypeChange(deviceType) {
+      if (!deviceType) return
+      this.loading = true
       try {
         const {
           result: { records }
@@ -114,6 +119,7 @@
       } catch (error) {
         console.log(error)
       }
+      this.loading = false
     }
 
     clearValidate() {

+ 108 - 0
src/views/spectrum/configuration/point/PointForm/StandardSaveAs.vue

@@ -0,0 +1,108 @@
+<template>
+  <tf-dialog
+    class="standard-save-as"
+    v-bind="$attrs"
+    v-on="listeners"
+    @submit="onSubmit"
+    :loading="loading"
+    :disabled="loading"
+    title="另存为指标标准"
+  >
+    <el-form label-width="auto" size="small" class="form" ref="form" :model="formData" :rules="rules">
+      <el-form-item label="指标标准名称" prop="standardName">
+        <el-input v-model="formData.standardName" placeholder="请输入指标标准名称" />
+      </el-form-item>
+    </el-form>
+  </tf-dialog>
+</template>
+
+<script lang="ts">
+  import { ElForm } from 'element-ui/types/form'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+  import { IStandard, IStandardParam } from '../../api/common'
+  import { addStandard, addStandardParam, getStandard, standardPage } from '../../api/standard'
+  @Component({ name: 'StandardSaveAs' })
+  export default class StandardSaveAs extends Vue {
+    @Prop({ type: Object, default: () => ({}) }) standard!: IStandard
+    @Prop({ type: Array, default: () => [] }) params!: IStandardParam[]
+    @Prop({ type: Number }) typeId!: number
+    $refs!: { form: ElForm }
+    formData: Partial<IStandard> = { standardName: '' }
+    rules: ElForm['rules'] = { standardName: [{ required: true, message: '请输入指标标准名称', trigger: 'change' }] }
+    loading: boolean = false
+
+    get listeners() {
+      const { submit, ...rest } = this.$listeners
+      return rest
+    }
+
+    onSubmit() {
+      this.$refs.form.validate(async (valid) => {
+        if (valid) {
+          const { id: oldId, standardName: oldName, ...rest } = this.standard
+
+          const saveStandard = async () => {
+            try {
+              await addStandard({
+                standardName: this.formData.standardName,
+                typeId: this.typeId,
+                ...this.$store.getters['project/info'],
+                ...rest
+              })
+              return true
+            } catch (error) {
+              console.log(error)
+            }
+            return false
+          }
+
+          const getStandardId = async () => {
+            try {
+              const {
+                result: { records }
+              } = await standardPage({ current: 1, size: 1, standardName: this.formData.standardName })
+              const { id: standardId } = records[0] || {}
+              return standardId
+            } catch (error) {
+              console.log(error)
+            }
+            return null
+          }
+
+          const saveParams = async (standardId: number) => {
+            try {
+              const results = await Promise.all(
+                this.params.map(({ id, ...rest }) => {
+                  return addStandardParam({ standardId, ...rest })
+                })
+              )
+
+              !results.some((item) => !item) && this.$message.success('指标标准另存成功')
+            } catch (error) {
+              console.log(error)
+            }
+          }
+
+          this.loading = true
+
+          const standardSaved = await saveStandard()
+
+          const standardId = standardSaved && (await getStandardId())
+
+          if (standardId && this.params.length > 0) {
+            await saveParams(standardId)
+          }
+
+          this.loading = false
+        }
+      })
+    }
+    @Watch('standard', { immediate: true })
+    onStandardChange(standard: IStandard) {
+      const { standardName } = standard || {}
+      this.formData.standardName = standardName ? `${standardName} - 复制` : ''
+    }
+  }
+</script>
+
+<style lang="scss"></style>

+ 35 - 21
src/views/spectrum/configuration/point/PointForm/ThresholdForm.vue

@@ -17,7 +17,7 @@
         </el-form-item>
       </el-col>
       <el-col :span="12">
-        <el-button type="text" size="small">另存为指标标准</el-button>
+        <el-button type="text" size="small" @click="onSaveAs">另存为指标标准</el-button>
       </el-col>
     </el-row>
     <el-form-item label="指标参数" prop="standardNames">
@@ -103,7 +103,7 @@
             clearable
             @change="() => onLevelChange(row)"
             style="width: 100%"
-            :disabled="disabled"
+            :disabled="disabled && !row.id.startsWith(NEW_RECORD_PREFIX)"
           >
             <el-option v-for="level of levels" :label="level.notes" :value="level.id" :key="level.id" />
           </el-select>
@@ -127,6 +127,7 @@
         </el-form-item>
       </template>
     </tf-table>
+    <StandardSaveAs :visible.sync="visible" :type-id="typeId" :standard="currentStandard" :params="formData.items" />
   </el-form>
 </template>
 
@@ -140,7 +141,8 @@
   import { ElTable } from 'element-ui/types/table'
   import moment from 'moment'
   import { IOriginalDictionary } from '@/api/common'
-  import { uniqBy } from 'lodash'
+  import { uniq, uniqBy } from 'lodash'
+  import StandardSaveAs from './StandardSaveAs.vue'
 
   export interface IFormData {
     standardId: number
@@ -192,8 +194,8 @@
       }
     )
   }
-
-  @Component({ name: 'ThresholdForm', components: {} })
+  const NEW_RECORD_PREFIX = '__new__'
+  @Component({ name: 'ThresholdForm', components: { StandardSaveAs } })
   export default class ThresholdForm extends Vue {
     @ModelSync('value', 'change', { type: Object, default: () => ({ standardId: undefined, items: [] }) })
     formData!: IFormData
@@ -205,6 +207,8 @@
 
     getDefalutNumberProp = getDefalutNumberProp
     $refs!: { form: ElForm; table: ElTable }
+    NEW_RECORD_PREFIX = NEW_RECORD_PREFIX
+    visible = false
     message = {
       standardId: '请选择指标标准'
     }
@@ -235,27 +239,20 @@
     standardParams: IStandardParam[] = []
 
     get standardParamNames() {
-      return this.standardParams.map((item) => item.targetName).join(', ')
+      return uniq(this.standardParams.map((item) => item.targetName)).join(', ')
     }
 
     get params() {
       return uniqBy(this.standardParams, 'targetId')
     }
 
-    async onStandardChange(standardId) {
-      this.loading.standardParam = true
-      try {
-        const {
-          result: { records }
-        } = await standardParamPage({ standardId, current: 1, size: 9999 })
-        this.standardParams = records
-        this.formData.items = records.map(({ id, ...rest }, index) => getDefaultThreshold(`${id}-${index}`, rest))
-      } catch (error) {
-        console.log(error)
-      }
-      this.$nextTick(() => {
-        this.loading.standardParam = false
-      })
+    get currentStandard() {
+      const current = this.standards.find((item) => item.id === this.formData.standardId) || {}
+      return current
+    }
+
+    onSaveAs() {
+      this.visible = true
     }
 
     onLevelChange(row: IThreshold) {
@@ -275,7 +272,7 @@
 
     onAdd(row: IThreshold) {
       const {} = row
-      this.formData.items = [...this.formData.items, getDefaultThreshold(`__new__${+new Date()}`)]
+      this.formData.items = [...this.formData.items, getDefaultThreshold(`${NEW_RECORD_PREFIX}${+new Date()}`)]
     }
 
     onDel(row: IThreshold) {
@@ -305,6 +302,23 @@
         this.formData.items = []
       }
     }
+    @Watch('formData.standardId', { immediate: true })
+    async onStandardChange(standardId) {
+      if (!standardId) return
+      this.loading.standardParam = true
+      try {
+        const {
+          result: { records }
+        } = await standardParamPage({ standardId, current: 1, size: 9999 })
+        this.standardParams = records
+        this.formData.items = records.map(({ id, ...rest }, index) => getDefaultThreshold(`${id}-${index}`, rest))
+      } catch (error) {
+        console.log(error)
+      }
+      this.$nextTick(() => {
+        this.loading.standardParam = false
+      })
+    }
   }
 </script>
 <style lang="scss" scoped>

+ 360 - 343
src/views/spectrum/configuration/point/PointForm/index.vue

@@ -1,5 +1,13 @@
 <template>
-  <tf-dialog v-bind="$attrs" v-on="listeners" @submit="onSubmit" @closed="onClosed" @open="onOpen" :loading="loading" width="896px">
+  <tf-dialog
+    v-bind="$attrs"
+    v-on="listeners"
+    @submit="onSubmit"
+    @closed="onClosed"
+    @open="onOpen"
+    :loading="loading"
+    width="896px"
+  >
     <tf-title>监测站点基本信息</tf-title>
     <BasisForm ref="basis" v-model="formData.basis" :enable="enable" :labelWidth="labelWidth" @mapClick="mapClick" />
     <tf-title>关联排水设施信息</tf-title>
@@ -7,387 +15,396 @@
     <tf-title>设备安装信息</tf-title>
     <DeviceForm ref="device" v-model="formData.device" :types="types" :labelWidth="labelWidth" />
     <tf-title>设备监测指标</tf-title>
-    <ThresholdForm ref="threshold" v-model="formData.threshold" :standards="standards" :labelWidth="labelWidth" :typeId="typeId" :levels="levels" :disabled="data && !!data.id" />
+    <ThresholdForm
+      ref="threshold"
+      v-model="formData.threshold"
+      :standards="standards"
+      :labelWidth="labelWidth"
+      :typeId="typeId"
+      :levels="levels"
+      :disabled="data && !!data.id"
+    />
   </tf-dialog>
 </template>
 
 <script lang="ts">
-import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
-import BasisForm from './BasisForm.vue'
-import ConnectForm from './ConnectForm.vue'
-import DeviceForm from './DeviceForm.vue'
-import ThresholdForm from './ThresholdForm.vue'
-import { IDeviceType, IPointDetail, IStandard, IPoint, IPointDetailResult } from '../../api/common'
-import { standardPage } from '../../api/standard'
-import { getDetail } from '../../api/point'
-import { IOriginalDictionary } from '@/api/common'
-import moment from 'moment'
-import PipeQueryHelper from '@/utils/mapCommon/PipeQueryHelper'
-import { CesiumToSuperMap } from '@/utils/mapCommon/tools'
-import pipeConfig from '@/views/widgets/PipeUnitInfo/config.json'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+  import BasisForm from './BasisForm.vue'
+  import ConnectForm from './ConnectForm.vue'
+  import DeviceForm from './DeviceForm.vue'
+  import ThresholdForm from './ThresholdForm.vue'
+  import { IDeviceType, IPointDetail, IStandard, IPoint, IPointDetailResult } from '../../api/common'
+  import { standardPage } from '../../api/standard'
+  import { getDetail } from '../../api/point'
+  import { IOriginalDictionary } from '@/api/common'
+  import moment from 'moment'
+  import PipeQueryHelper from '@/utils/mapCommon/PipeQueryHelper'
+  import { CesiumToSuperMap } from '@/utils/mapCommon/tools'
+  import pipeConfig from '@/views/widgets/PipeUnitInfo/config.json'
 
-interface IFormData {
-  basis: {
-    siteCode: string
-    siteName: string
-    sectionId: number
-    siteAddress: string
-    latitude: string
-    longitude: string
-    [x: string]: any
-  }
-  connect: {
-    drainageId: number
-    drainageName: string
-    drainageRoadName: string
-    drainageType: string
-    longitude2: number
-    latitude2: number
-    layerName: string
-  }
-  device: {
-    typeId: number
-    install: Partial<IPointDetailResult['installVo']>
-  }
-  threshold: {
-    standardId: number
-    items: Partial<IPointDetailResult['targetVos']>
+  interface IFormData {
+    basis: {
+      siteCode: string
+      siteName: string
+      sectionId: number
+      siteAddress: string
+      latitude: string
+      longitude: string
+      [x: string]: any
+    }
+    connect: {
+      drainageId: number
+      drainageName: string
+      drainageRoadName: string
+      drainageType: string
+      longitude2: number
+      latitude2: number
+      layerName: string
+    }
+    device: {
+      typeId: number
+      install: Partial<IPointDetailResult['installVo']>
+    }
+    threshold: {
+      standardId: number
+      items: Partial<IPointDetailResult['targetVos']>
+    }
+    fileList: IPointDetail['fileList']
   }
-  fileList: IPointDetail['fileList']
-}
 
-const getDefaultFormData = () => ({
-  basis: {
-    /** 站点编号 */
-    siteCode: undefined,
-    /** 站点名称 */
-    siteName: undefined,
-    /** 断面Id */
-    sectionId: undefined,
-    /** 站点地址 */
-    siteAddress: undefined,
-    /** 纬度 */
-    latitude: undefined,
-    /** 经度 */
-    longitude: undefined
-  },
+  const getDefaultFormData = () => ({
+    basis: {
+      /** 站点编号 */
+      siteCode: undefined,
+      /** 站点名称 */
+      siteName: undefined,
+      /** 断面Id */
+      sectionId: undefined,
+      /** 站点地址 */
+      siteAddress: undefined,
+      /** 纬度 */
+      latitude: undefined,
+      /** 经度 */
+      longitude: undefined
+    },
 
-  connect: {
-    /** 排水设施ID */
-    drainageId: undefined,
-    /** 排水设施名称 */
-    drainageName: undefined,
-    /** 排水设施所在道路名称 */
-    drainageRoadName: undefined,
-    /** 排水类型 */
-    drainageType: undefined,
-    /** 排水设施经度 */
-    longitude2: undefined,
-    /** 排水设施纬度 */
-    latitude2: undefined,
-    /** 排水设施所在图层名称 */
-    layerName: undefined
-  },
+    connect: {
+      /** 排水设施ID */
+      drainageId: undefined,
+      /** 排水设施名称 */
+      drainageName: undefined,
+      /** 排水设施所在道路名称 */
+      drainageRoadName: undefined,
+      /** 排水类型 */
+      drainageType: undefined,
+      /** 排水设施经度 */
+      longitude2: undefined,
+      /** 排水设施纬度 */
+      latitude2: undefined,
+      /** 排水设施所在图层名称 */
+      layerName: undefined
+    },
 
-  // project: {
-  //   /** 项目编码 */
-  //   projectCode: undefined,
-  //   /** 项目ID */
-  //   projectId: undefined,
-  //   /** 项目名称 */
-  //   projectName: undefined
-  // },
+    // project: {
+    //   /** 项目编码 */
+    //   projectCode: undefined,
+    //   /** 项目ID */
+    //   projectId: undefined,
+    //   /** 项目名称 */
+    //   projectName: undefined
+    // },
 
-  device: {
-    /** 设备类型ID */
-    typeId: undefined,
-    /** 设备安装信息 */
-    install: {
-      /** 设备ID */
-      deviceId: undefined,
-      /** 文件所属项目类型 */
-      fileTypeID: 123,
-      /** 安装人 */
-      installPeople: undefined,
-      /** 安装时间 */
-      installTime: undefined,
-      /** 联系人电话 */
-      liaisonPhone: undefined,
-      /** 关联状态0未启用,1启用(启用后不允许修改) */
-      relevancyState: undefined,
-      /** 站点ID */
-      siteId: undefined
+    device: {
+      /** 设备类型ID */
+      typeId: undefined,
+      /** 设备安装信息 */
+      install: {
+        /** 设备ID */
+        deviceId: undefined,
+        /** 文件所属项目类型 */
+        fileTypeID: 123,
+        /** 安装人 */
+        installPeople: undefined,
+        /** 安装时间 */
+        installTime: undefined,
+        /** 联系人电话 */
+        liaisonPhone: undefined,
+        /** 关联状态0未启用,1启用(启用后不允许修改) */
+        relevancyState: undefined,
+        /** 站点ID */
+        siteId: undefined
+      },
+      fileList: []
     },
-    fileList: []
-  },
-  /** 指标阈值列表 */
-  threshold: {
-    standardId: undefined,
-    items: []
-  }
-})
-const getDefaultEnableValue = () => ({ coordinate: false, device: false })
+    /** 指标阈值列表 */
+    threshold: {
+      standardId: undefined,
+      items: []
+    }
+  })
+  const getDefaultEnableValue = () => ({ coordinate: false, device: false })
 
-@Component({
-  name: 'PointForm',
-  components: { BasisForm, ConnectForm, DeviceForm, ThresholdForm }
-})
-export default class PointForm extends Vue {
-  @Prop({ type: Object, default: () => ({}) }) data!: IPoint
-  @Prop({ type: Boolean, default: false }) loading!: boolean
-  @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
-  @Prop({ type: Array, default: () => ({}) }) levels!: IOriginalDictionary[]
+  @Component({
+    name: 'PointForm',
+    components: { BasisForm, ConnectForm, DeviceForm, ThresholdForm }
+  })
+  export default class PointForm extends Vue {
+    @Prop({ type: Object, default: () => ({}) }) data!: IPoint
+    @Prop({ type: Boolean, default: false }) loading!: boolean
+    @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
+    @Prop({ type: Array, default: () => ({}) }) levels!: IOriginalDictionary[]
 
-  $refs!: {
-    basis: BasisForm
-    connect: ConnectForm
-    device: DeviceForm
-    threshold: ThresholdForm
-  }
+    $refs!: {
+      basis: BasisForm
+      connect: ConnectForm
+      device: DeviceForm
+      threshold: ThresholdForm
+    }
 
-  formData: Partial<IFormData> = getDefaultFormData()
+    formData: Partial<IFormData> = getDefaultFormData()
 
-  enable = getDefaultEnableValue()
-  standards: IStandard[] = []
-  labelWidth = 'auto'
-  keys = ['basis', 'connect', 'device', 'threshold']
-  get listeners() {
-    const { submit, open, closed, ...rest } = this.$listeners
-    return rest
-  }
+    enable = getDefaultEnableValue()
+    standards: IStandard[] = []
+    labelWidth = 'auto'
+    keys = ['basis', 'connect', 'device', 'threshold']
+    get listeners() {
+      const { submit, open, closed, ...rest } = this.$listeners
+      return rest
+    }
 
-  get AppX() {
-    return this.$store.getters.AppX
-  }
+    get AppX() {
+      return this.$store.getters.AppX
+    }
 
-  get typeId() {
-    const { device: { typeId } = {} } = this.formData
-    return typeId
-  }
+    get typeId() {
+      const { device: { typeId } = {} } = this.formData
+      return typeId
+    }
 
-  async onSubmit() {
-    const valid = !(await Promise.all(this.keys.map((key) => this.$refs[key].validate()))).some((item) => !item)
-    if (valid) {
-      console.log(this.formData)
-      const { basis, connect, device, threshold } = this.formData
-      const data: IPointDetail = {
-        ...basis,
-        ...connect,
-        ...device,
-        ...this.$store.getters['project/info'],
-        targets: threshold.items as IPointDetail['targets']
+    async onSubmit() {
+      const valid = !(await Promise.all(this.keys.map((key) => this.$refs[key].validate()))).some((item) => !item)
+      if (valid) {
+        console.log(this.formData)
+        const { basis, connect, device, threshold } = this.formData
+        const data: IPointDetail = {
+          ...basis,
+          ...connect,
+          ...device,
+          ...this.$store.getters['project/info'],
+          targets: threshold.items as IPointDetail['targets']
+        }
+        this.$emit('submit', data)
       }
-      this.$emit('submit', data)
     }
-  }
-
-  onClosed() {
-    this.formData = getDefaultFormData()
-    this.keys.forEach((key) => this.$refs[key].resetFields())
-    this.$emit('closed')
-  }
 
-  onOpen() {
-    setTimeout(() => this.keys.forEach((key) => this.$refs[key].clearValidate()), 0)
-    this.$emit('open')
-    this.$nextTick(() => {
-      // 更打开弹窗更新地图
-      this.$refs.basis.$refs.minMap.initMap().then(() => {
-        console.log('打开弹窗::', this.data)
-        console.log('lplplplp', PipeQueryHelper)
+    onClosed() {
+      this.formData = getDefaultFormData()
+      this.keys.forEach((key) => this.$refs[key].resetFields())
+      this.$emit('closed')
+    }
 
-        const { longitude2: longitude, latitude2: latitude } = this.data
-        this.echoPoint(longitude, latitude, 0)
-      })
-    })
-  }
+    onOpen() {
+      setTimeout(() => this.keys.forEach((key) => this.$refs[key].clearValidate()), 0)
+      this.$emit('open')
+      this.$nextTick(() => {
+        // 更打开弹窗更新地图
+        this.$refs.basis.$refs.minMap.initMap().then(() => {
+          console.log('打开弹窗::', this.data)
+          console.log('lplplplp', PipeQueryHelper)
 
-  async getDetail(id: number) {
-    const { result } = await getDetail(id)
-    const {
-      drainageId,
-      drainageName,
-      drainageRoadName,
-      drainageType,
-      longitude2,
-      latitude2,
-      layerName,
-      targetVos,
-      installVo,
-      statuses,
-      ...rest
-    } = result || {}
-    const typeId = ((targetVos || [])[0] || {}).typeId
-    this.formData = {
-      connect: { drainageId, drainageName, drainageRoadName, drainageType, longitude2, latitude2, layerName },
-      device: { typeId, install: installVo || {} },
-      threshold: {
-        standardId: undefined,
-        items: (targetVos || []).map((item) => {
-          const { biginTime, endTime } = item
-          return Object.defineProperty(item, 'timeRange', {
-            writable: true,
-            value: [moment(biginTime || '00:00', 'HH:mm').toDate(), moment(endTime || '23:59', 'HH:mm').toDate()]
-          })
+          const { longitude2: longitude, latitude2: latitude } = this.data
+          this.echoPoint(longitude, latitude, 0)
         })
-      },
-      basis: rest as IFormData['basis']
+      })
     }
-  }
 
-  @Watch('typeId')
-  async getAllStandards(typeId) {
-    try {
+    async getDetail(id: number) {
+      const { result } = await getDetail(id)
       const {
-        result: { records }
-      } = await standardPage({ typeId, current: 1, size: 9999 })
-      this.standards = records || []
-    } catch (error) {
-      console.log(error)
+        drainageId,
+        drainageName,
+        drainageRoadName,
+        drainageType,
+        longitude2,
+        latitude2,
+        layerName,
+        targetVos,
+        installVo,
+        statuses,
+        ...rest
+      } = result || {}
+      const typeId = ((targetVos || [])[0] || {}).typeId
+      this.formData = {
+        connect: { drainageId, drainageName, drainageRoadName, drainageType, longitude2, latitude2, layerName },
+        device: { typeId, install: installVo || {} },
+        threshold: {
+          standardId: undefined,
+          items: (targetVos || []).map((item) => {
+            const { biginTime, endTime, sid } = item
+            return Object.defineProperty({ ...item, id: sid }, 'timeRange', {
+              writable: true,
+              value: [moment(biginTime || '00:00', 'HH:mm').toDate(), moment(endTime || '23:59', 'HH:mm').toDate()]
+            })
+          })
+        },
+        basis: rest as IFormData['basis']
+      }
     }
-  }
 
-  @Watch('data', { immediate: true })
-  setDefaultData(val: IPoint) {
-    if (val.id) {
-      this.getDetail(val.id)
-    } else {
-      this.formData = getDefaultFormData()
+    @Watch('typeId')
+    async getAllStandards(typeId) {
+      try {
+        const {
+          result: { records }
+        } = await standardPage({ typeId, current: 1, size: 9999 })
+        this.standards = records || []
+      } catch (error) {
+        console.log(error)
+      }
     }
-  }
-
-  mapSelect() {
-    this.$refs.basis.initMapClick()
-  }
 
-  mapClick(event) {
-    const viewer = this.$refs.basis.$refs.minMap._viewer
-    const Cesium = (window as any).Cesium
-    const radius = 2
-    const position = viewer.scene.pickPosition(event.position)
-    const ellpise = new Cesium.Entity({
-      position: position,
-      ellipse: {
-        semiMajorAxis: radius,
-        semiMinorAxis: radius,
-        material: Cesium.Color.ORANGERED,
-        classificationType: Cesium.ClassificationType.TERRAIN
+    @Watch('data', { immediate: true })
+    setDefaultData(val: IPoint) {
+      if (val.id) {
+        this.getDetail(val.id)
+      } else {
+        this.formData = getDefaultFormData()
       }
-    })
-    const positions = PipeQueryHelper.converCesiumToSuperMapEllipse(ellpise)
-    // 查询数据
-    this.queryFacilities(positions.positions)
-  }
+    }
+
+    mapSelect() {
+      this.$refs.basis.initMapClick()
+    }
 
-  /**
-   * 空间查询数据服务
-   * @param {Cesium.Cartesian3[]} positions 多边形顶点
-   */
-  queryFacilities(positions) {
-    const viewer = this.$refs.basis.$refs.minMap._viewer
-    const Cesium = (window as any).Cesium
-    const SuperMap = (window as any).SuperMap
-    const geometry = CesiumToSuperMap.convertPolygon(Cesium, SuperMap, { positions: positions })
-    // console.log('appX',this.AppX.appConfig.gisResource.theme.config.pcdtps.url);
-    
-    // 查询url
-    const URL = this.AppX.appConfig.gisResource.tiplayers.config.geoquery.url
-    // const URL = this.AppX.appConfig.gisResource.theme.config.pcdtps.url
-    // const layerList = pipeConfig.pipe
-    const layerList = PipeQueryHelper.pipe
-    let datasetNames = []
-    layerList.forEach((item) => {
-      if (item.geometryType == 'point'&&item.pipeType=='PC') datasetNames.push(`${item.origindataset}@${item.datasource}`)
-    })
-    // console.log('数据集sss',datasetNames);
-    
-    if (datasetNames.length == 0) return
-    PipeQueryHelper.queryMapByGeometry({
-      url: URL,
-      datasetNames: datasetNames,
-      geometry: geometry,
-      completed: (response) => {
-        if (response.result.currentCount == 0) {
-          this.$message.info('未查询到相关设施!')
-          return
+    mapClick(event) {
+      const viewer = this.$refs.basis.$refs.minMap._viewer
+      const Cesium = (window as any).Cesium
+      const radius = 2
+      const position = viewer.scene.pickPosition(event.position)
+      const ellpise = new Cesium.Entity({
+        position: position,
+        ellipse: {
+          semiMajorAxis: radius,
+          semiMinorAxis: radius,
+          material: Cesium.Color.ORANGERED,
+          classificationType: Cesium.ClassificationType.TERRAIN
         }
-        // console.log('查询结果', response)
+      })
+      const positions = PipeQueryHelper.converCesiumToSuperMapEllipse(ellpise)
+      // 查询数据
+      this.queryFacilities(positions.positions)
+    }
 
-        const facilities = response.result.recordsets.find((item) => {
-          return item.features.length > 0
-        })
-        // console.log('有数据的图层', facilities)
-        // 图层名称
-        const dataSetName = facilities.datasetName.split('@')[0]
-        // 设施点
-        const feature = facilities.features[0].data
-        const { SMX: longitude, SMY: latitude, SMZ: altitude } = feature
-        // console.log('关联的点', feature)
-        // 标记选择的设施点
-        viewer.entities.removeById('correlation_facility')
-        viewer.entities.add({
-          id: 'correlation_facility',
-          position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
-          point: {
-            pixelSize: 10, //点的大小
-            color: Cesium.Color.RED, //点的颜色
-            outlineColor: Cesium.Color.YELLOW, //外圈颜色
-            outlineWidth: 5, //外圈大小
-            disableDepthTestDistance: 9999999,
-            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
+    /**
+     * 空间查询数据服务
+     * @param {Cesium.Cartesian3[]} positions 多边形顶点
+     */
+    queryFacilities(positions) {
+      const viewer = this.$refs.basis.$refs.minMap._viewer
+      const Cesium = (window as any).Cesium
+      const SuperMap = (window as any).SuperMap
+      const geometry = CesiumToSuperMap.convertPolygon(Cesium, SuperMap, { positions: positions })
+      // console.log('appX',this.AppX.appConfig.gisResource.theme.config.pcdtps.url);
+
+      // 查询url
+      const URL = this.AppX.appConfig.gisResource.tiplayers.config.geoquery.url
+      // const URL = this.AppX.appConfig.gisResource.theme.config.pcdtps.url
+      // const layerList = pipeConfig.pipe
+      const layerList = PipeQueryHelper.pipe
+      let datasetNames = []
+      layerList.forEach((item) => {
+        if (item.geometryType == 'point' && item.pipeType == 'PC')
+          datasetNames.push(`${item.origindataset}@${item.datasource}`)
+      })
+      // console.log('数据集sss',datasetNames);
+
+      if (datasetNames.length == 0) return
+      PipeQueryHelper.queryMapByGeometry({
+        url: URL,
+        datasetNames: datasetNames,
+        geometry: geometry,
+        completed: (response) => {
+          if (response.result.currentCount == 0) {
+            this.$message.info('未查询到相关设施!')
+            return
           }
-        })
-        const {
-          SMID: drainageId,
-          MANHOLE_TYPE: drainageName,
-          ROAD_NAME: drainageRoadName,
-          PIPE_CATEGORY: drainageType
-        } = feature
-        this.formData.connect = {
-          drainageId: Number(drainageId),
-          drainageName: drainageName,
-          drainageRoadName: drainageRoadName,
-          drainageType: drainageType,
-          longitude2: longitude,
-          latitude2: latitude,
-          layerName: dataSetName
+          // console.log('查询结果', response)
+
+          const facilities = response.result.recordsets.find((item) => {
+            return item.features.length > 0
+          })
+          // console.log('有数据的图层', facilities)
+          // 图层名称
+          const dataSetName = facilities.datasetName.split('@')[0]
+          // 设施点
+          const feature = facilities.features[0].data
+          const { SMX: longitude, SMY: latitude, SMZ: altitude } = feature
+          // console.log('关联的点', feature)
+          // 标记选择的设施点
+          viewer.entities.removeById('correlation_facility')
+          viewer.entities.add({
+            id: 'correlation_facility',
+            position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
+            point: {
+              pixelSize: 10, //点的大小
+              color: Cesium.Color.RED, //点的颜色
+              outlineColor: Cesium.Color.YELLOW, //外圈颜色
+              outlineWidth: 5, //外圈大小
+              disableDepthTestDistance: 9999999,
+              heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
+            }
+          })
+          const {
+            SMID: drainageId,
+            MANHOLE_TYPE: drainageName,
+            ROAD_NAME: drainageRoadName,
+            PIPE_CATEGORY: drainageType
+          } = feature
+          this.formData.connect = {
+            drainageId: Number(drainageId),
+            drainageName: drainageName,
+            drainageRoadName: drainageRoadName,
+            drainageType: drainageType,
+            longitude2: longitude,
+            latitude2: latitude,
+            layerName: dataSetName
+          }
+          // console.log('jk', this.formData.connect)
+        },
+        failed: function (err) {
+          console.error(err)
+          // this.$message.error('部件设施获取失败')
         }
-        // console.log('jk', this.formData.connect)
-      },
-      failed: function (err) {
-        console.error(err)
-        // this.$message.error('部件设施获取失败')
-      }
-    })
-  }
+      })
+    }
 
-  /**
-   * 站点关联设施回显
-   */
-  echoPoint(longitude: number, latitude: number, altitude: number = undefined) {
-    const viewer = this.$refs.basis.$refs.minMap._viewer
-    const Cesium = (window as any).Cesium
-    // 标记选择的设施点
-    viewer.entities.removeById('correlation_facility')
-    const entity = {
-      id: 'correlation_facility',
-      position: Cesium.Cartesian3.fromDegrees(longitude, latitude, altitude),
-      point: {
-        pixelSize: 10, //点的大小
-        color: Cesium.Color.RED, //点的颜色
-        outlineColor: Cesium.Color.YELLOW, //外圈颜色
-        outlineWidth: 5, //外圈大小
-        // disableDepthTestDistance: 9999999,
-        disableDepthTestDistance: Number.POSITIVE_INFINITY,
-        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
+    /**
+     * 站点关联设施回显
+     */
+    echoPoint(longitude: number, latitude: number, altitude: number = undefined) {
+      const viewer = this.$refs.basis.$refs.minMap._viewer
+      const Cesium = (window as any).Cesium
+      // 标记选择的设施点
+      viewer.entities.removeById('correlation_facility')
+      const entity = {
+        id: 'correlation_facility',
+        position: Cesium.Cartesian3.fromDegrees(longitude, latitude, altitude),
+        point: {
+          pixelSize: 10, //点的大小
+          color: Cesium.Color.RED, //点的颜色
+          outlineColor: Cesium.Color.YELLOW, //外圈颜色
+          outlineWidth: 5, //外圈大小
+          // disableDepthTestDistance: 9999999,
+          disableDepthTestDistance: Number.POSITIVE_INFINITY,
+          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
+        }
       }
+      viewer.entities.add(entity)
+      console.log('添加回显', viewer.entities.getById('correlation_facility'))
+      // viewer.flyTo(entity)
+      viewer.flyTo({
+        destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 0)
+      })
     }
-    viewer.entities.add(entity)
-    console.log('添加回显', viewer.entities.getById('correlation_facility'))
-    // viewer.flyTo(entity)
-    viewer.flyTo({
-      destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 0)
-    })
   }
-}
 </script>

+ 33 - 33
src/views/spectrum/configuration/standard/StandardForm.vue

@@ -9,7 +9,7 @@
           size="small"
           :disabled="!!formData.id"
           clearable
-          style="width:100%"
+          style="width: 100%"
         >
           <el-option v-for="item in types" :key="item.id" :label="item.deviceTypeName" :value="item.id" />
         </el-select>
@@ -23,42 +23,42 @@
 </template>
 
 <script lang="ts">
-import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
-import { ElForm } from 'element-ui/types/form'
-import { IDeviceType, IStandard } from '../api/common'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+  import { ElForm } from 'element-ui/types/form'
+  import { IDeviceType, IStandard } from '../api/common'
 
-@Component({ name: 'StandardForm', components: {} })
-export default class StandardForm extends Vue {
-  @Prop({ type: Object, default: () => ({}) }) data!: object
-  @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
-  @Prop({ type: Boolean, default: false }) loading!: boolean
-  $refs!: { form: ElForm }
+  @Component({ name: 'StandardForm', components: {} })
+  export default class StandardForm extends Vue {
+    @Prop({ type: Object, default: () => ({}) }) data!: IStandard
+    @Prop({ type: Array, default: () => [] }) types!: IDeviceType[]
+    @Prop({ type: Boolean, default: false }) loading!: boolean
+    $refs!: { form: ElForm }
 
-  formData: Partial<IStandard> = {}
+    formData: Partial<IStandard> = {}
 
-  get listeners() {
-    const { submit, ...rest } = this.$listeners
-    return rest
-  }
+    get listeners() {
+      const { submit, ...rest } = this.$listeners
+      return rest
+    }
 
-  rules = {
-    typeId: [{ required: true, message: '请选择设备类型' }],
-    standardName: [
-      { required: true, message: '指标标准名称不能为空!' },
-      { max: 50, message: '指标标准名称不超过50个字符' }
-    ]
-  }
+    rules = {
+      typeId: [{ required: true, message: '请选择设备类型' }],
+      standardName: [
+        { required: true, message: '指标标准名称不能为空!' },
+        { max: 50, message: '指标标准名称不超过50个字符' }
+      ]
+    }
 
-  onSubmit() {
-    this.$refs.form.validate((valid) => {
-      if (valid) {
-        this.$emit('submit', this.formData)
-      }
-    })
-  }
-  @Watch('data', { immediate: true })
-  setDefaultData(val) {
-    this.formData = val.id ? { ...val } : {}
+    onSubmit() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          this.$emit('submit', this.formData)
+        }
+      })
+    }
+    @Watch('data', { immediate: true })
+    setDefaultData(val) {
+      this.formData = val.id ? { ...val } : {}
+    }
   }
-}
 </script>

+ 1 - 1
src/views/spectrum/configuration/standard/widget.vue

@@ -294,7 +294,7 @@
       try {
         const {
           result: { records }
-        } = await deviceTypePage({ current: 1, size: 9999 })
+        } = await deviceTypePage({ current: 1, size: 9999, ...this.$store.getters['project/id'] })
         this.types = records || []
       } catch (error) {
         console.log(error)

+ 47 - 34
src/views/spectrum/configuration/team/TeamForm.vue

@@ -15,8 +15,21 @@
         />
       </el-form-item>
       <el-form-item label="关联监测点" prop="siteIds">
-        <el-select v-model="formData.siteIds" filterable placeholder="关联监测点" clearable multiple style="width:100%">
-          <el-option v-for="item in points" :key="item.id" :label="item.siteName" :value="item.id">
+        <el-select
+          v-model="formData.siteIds"
+          filterable
+          placeholder="关联监测点"
+          clearable
+          multiple
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in points"
+            :key="item.id"
+            :label="item.siteName"
+            :value="item.id"
+            :disabled="!!item.groupByName"
+          >
             {{ `${item.siteName}${item.sectionId ? ' | ' + item.sectionId : ''}` }}
           </el-option>
         </el-select>
@@ -26,42 +39,42 @@
 </template>
 
 <script lang="ts">
-import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
-import { ElForm } from 'element-ui/types/form'
-import { IPoint, ITeam } from '../api/common'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+  import { ElForm } from 'element-ui/types/form'
+  import { IPoint, ITeam } from '../api/common'
 
-@Component({ name: 'TeamForm', components: {} })
-export default class TeamForm extends Vue {
-  @Prop({ type: Object, default: () => ({}) }) data!: object
-  @Prop({ type: Array, default: () => [] }) points!: IPoint[]
-  @Prop({ type: Boolean, default: false }) loading!: boolean
-  $refs!: { form: ElForm }
+  @Component({ name: 'TeamForm', components: {} })
+  export default class TeamForm extends Vue {
+    @Prop({ type: Object, default: () => ({}) }) data!: ITeam
+    @Prop({ type: Array, default: () => [] }) points!: IPoint[]
+    @Prop({ type: Boolean, default: false }) loading!: boolean
+    $refs!: { form: ElForm }
 
-  formData: Partial<ITeam> = {}
+    formData: Partial<ITeam> = {}
 
-  get listeners() {
-    const { submit, ...rest } = this.$listeners
-    return rest
-  }
+    get listeners() {
+      const { submit, ...rest } = this.$listeners
+      return rest
+    }
 
-  rules = {
-    groupByName: [
-      { required: true, message: '分组名称不能为空!', trigger: 'blur' },
-      { max: 50, message: '分组名称不超过50个字符', trigger: 'blur' }
-    ],
-    remarks: [{ required: false, message: '请输入备注', max: 255, trigger: 'blur' }]
-  }
+    rules = {
+      groupByName: [
+        { required: true, message: '分组名称不能为空!', trigger: 'blur' },
+        { max: 50, message: '分组名称不超过50个字符', trigger: 'blur' }
+      ],
+      remarks: [{ required: false, message: '请输入备注', max: 255, trigger: 'blur' }]
+    }
 
-  onSubmit() {
-    this.$refs.form.validate((valid) => {
-      if (valid) {
-        this.$emit('submit', this.formData)
-      }
-    })
-  }
-  @Watch('data', { immediate: true })
-  setDefaultData(val) {
-    this.formData = val.id ? { ...val } : {}
+    onSubmit() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          this.$emit('submit', this.formData)
+        }
+      })
+    }
+    @Watch('data', { immediate: true })
+    setDefaultData(val) {
+      this.formData = val.id ? { ...val } : {}
+    }
   }
-}
 </script>

+ 97 - 98
src/views/spectrum/configuration/type/TypeForm.vue

@@ -2,7 +2,7 @@
   <tf-dialog v-bind="$attrs" v-on="listeners" @submit="onSubmit" :loading="loading" @closed="onClosed">
     <el-form class="form" ref="form" v-bind="{ labelWidth: 'auto', size: 'small' }" :model="formData" :rules="rules">
       <el-form-item required label="设备类型" prop="dictionaryId">
-        <el-select v-model="formData.dictionaryId" @change="onNameChange" :disabled="data.id" style="width: 100%">
+        <el-select v-model="formData.dictionaryId" @change="onNameChange" :disabled="!!data.id" style="width: 100%">
           <el-option v-for="item of dictionary" :key="item.id" :value="item.id" :label="item.deviceTypeName" />
         </el-select>
       </el-form-item>
@@ -24,124 +24,123 @@
 </template>
 
 <script lang="ts">
-import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
-import { ElForm } from 'element-ui/types/form'
-import { IDeviceTypeDictionary, IDeviceType } from '../api/common'
-import { getRemoteImg } from '@/api/ftp'
-import { ElUploadInternalFileDetail } from 'element-ui/types/upload'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+  import { ElForm } from 'element-ui/types/form'
+  import { IDeviceTypeDictionary, IDeviceType } from '../api/common'
+  import { getRemoteImg } from '@/api/ftp'
+  import { ElUploadInternalFileDetail } from 'element-ui/types/upload'
 
-const getDefaultValue = () => ({ dictionaryId: undefined, file: undefined, fileTypeID: 803 })
+  const getDefaultValue = () => ({ dictionaryId: undefined, file: undefined, fileTypeID: 803 })
 
-@Component({ name: 'TypeForm', components: {} })
-export default class TypeForm extends Vue {
-  @Prop({ type: Object, default: () => ({}) }) data!: IDeviceType
-  @Prop({ type: Boolean, default: false }) loading!: boolean
-  @Prop({ type: Array, default: () => [] }) dictionary!: IDeviceTypeDictionary[]
-  $refs!: { form: ElForm }
-  formData: Partial<IDeviceType> & {
-    file?: ElUploadInternalFileDetail | string
-  } = getDefaultValue()
-  imageUrl: string = ''
-  get listeners() {
-    const { submit, closed, ...rest } = this.$listeners
-    return rest
-  }
+  @Component({ name: 'TypeForm', components: {} })
+  export default class TypeForm extends Vue {
+    @Prop({ type: Object, default: () => ({}) }) data!: IDeviceType
+    @Prop({ type: Boolean, default: false }) loading!: boolean
+    @Prop({ type: Array, default: () => [] }) dictionary!: IDeviceTypeDictionary[]
+    $refs!: { form: ElForm }
+    formData: Partial<IDeviceType> & {
+      file?: ElUploadInternalFileDetail | string
+    } = getDefaultValue()
+    imageUrl: string = ''
+    get listeners() {
+      const { submit, closed, ...rest } = this.$listeners
+      return rest
+    }
 
-  get projectInfo() {
-    return this.$store.getters['project/info']
-  }
+    get projectInfo() {
+      return this.$store.getters['project/info']
+    }
 
-  rules = {
-    dictionaryId: [{ type: 'number', required: true, message: '请选择设备类型' }],
-    file: [{ validator: (rule, value, callback) => (!value ? callback(new Error('请上传图标')) : callback()) }]
-  }
+    rules = {
+      dictionaryId: [{ type: 'number', required: true, message: '请选择设备类型' }],
+      file: [{ validator: (rule, value, callback) => (!value ? callback(new Error('请上传图标')) : callback()) }]
+    }
 
-  onSubmit() {
-    this.$refs.form.validate((valid) => valid && this.$emit('submit', { ...this.formData, ...this.projectInfo }))
-  }
+    onSubmit() {
+      this.$refs.form.validate((valid) => valid && this.$emit('submit', { ...this.formData, ...this.projectInfo }))
+    }
 
-  onNameChange(id) {
-    const { dataUploadTime, deviceTypeName } = this.dictionary.find((item) => item.id === id) || {}
-    this.formData.dataUploadTime = dataUploadTime
-    this.formData.deviceTypeName = deviceTypeName
-  }
+    onNameChange(id) {
+      const { dataUploadTime, deviceTypeName } = this.dictionary.find((item) => item.id === id) || {}
+      this.formData = { ...this.formData, dataUploadTime, deviceTypeName }
+    }
 
-  onFileChange(file) {
-    const allowedTypes = ['image/jpeg', 'image/png']
-    const isLt10M = file.size / 1024 / 1024 < 10
-    let pass = true
+    onFileChange(file) {
+      const allowedTypes = ['image/jpeg', 'image/png']
+      const isLt10M = file.size / 1024 / 1024 < 10
+      let pass = true
 
-    if (!allowedTypes.includes(file.raw.type)) {
-      this.$message.error('上传文件只能是 JPG/JPEG、png 格式!')
-      pass = false
-    }
+      if (!allowedTypes.includes(file.raw.type)) {
+        this.$message.error('上传文件只能是 JPG/JPEG、png 格式!')
+        pass = false
+      }
 
-    if (!isLt10M) {
-      this.$message.error('上传文件大小不能超过 10MB!')
-      pass = false
-    }
-    if (pass) {
-      const reader = new FileReader()
-      reader.onload = (e) => {
-        this.imageUrl = e.target.result.toString()
+      if (!isLt10M) {
+        this.$message.error('上传文件大小不能超过 10MB!')
+        pass = false
+      }
+      if (pass) {
+        const reader = new FileReader()
+        reader.onload = (e) => {
+          this.imageUrl = e.target.result.toString()
+        }
+        reader.readAsDataURL(file.raw)
+        this.formData.file = file.raw
       }
-      reader.readAsDataURL(file.raw)
-      this.formData.file = file.raw
     }
-  }
-
-  onClosed() {
-    this.imageUrl = ''
-    this.$emit('closed')
-  }
 
-  @Watch('data', { immediate: true })
-  setDefaultData(val: IDeviceType) {
-    const { iconFiles } = val || {}
-    const { filePath } = (iconFiles || [])[0] || {}
-    if (val.id) {
-      this.formData = { ...val }
-      const { iconFiles } = val || {}
-      const { filePath } = (iconFiles || [])[0]
-      this.imageUrl = getRemoteImg(filePath)
-    } else {
-      this.formData = getDefaultValue()
+    onClosed() {
       this.imageUrl = ''
+      this.$emit('closed')
     }
 
-    if (filePath) this.imageUrl = getRemoteImg(filePath)
+    @Watch('data', { immediate: true })
+    setDefaultData(val: IDeviceType) {
+      const { iconFiles } = val || {}
+      const { filePath } = (iconFiles || [])[0] || {}
+      if (val.id) {
+        this.formData = { ...val }
+        const { iconFiles } = val || {}
+        const { filePath } = (iconFiles || [])[0]
+        this.imageUrl = getRemoteImg(filePath)
+      } else {
+        this.formData = getDefaultValue()
+        this.imageUrl = ''
+      }
+
+      if (filePath) this.imageUrl = getRemoteImg(filePath)
+    }
   }
-}
 </script>
 <style lang="scss" scoped>
-.form {
-  >>> .icon {
-    $width: 128px;
-    $height: 128px;
-    width: $width;
-    height: $height;
-    display: block;
-    border-radius: $--border-radius-base;
-    overflow: hidden;
-    &-uploader .el-upload {
-      border: 1px dashed $--border-color-base;
+  .form {
+    >>> .icon {
+      $width: 128px;
+      $height: 128px;
+      width: $width;
+      height: $height;
+      display: block;
       border-radius: $--border-radius-base;
-      cursor: pointer;
-      position: relative;
       overflow: hidden;
-      background-color: rgba(#000, 0.1);
-      &:hover {
-        border-color: $--color-primary;
+      &-uploader .el-upload {
+        border: 1px dashed $--border-color-base;
+        border-radius: $--border-radius-base;
+        cursor: pointer;
+        position: relative;
+        overflow: hidden;
+        background-color: rgba(#000, 0.1);
+        &:hover {
+          border-color: $--color-primary;
+        }
+      }
+      &-uploader-icon {
+        font-size: 28px;
+        color: $--color-text-secondary;
+        width: $width;
+        height: $height;
+        line-height: $height;
+        text-align: center;
       }
-    }
-    &-uploader-icon {
-      font-size: 28px;
-      color: $--color-text-secondary;
-      width: $width;
-      height: $height;
-      line-height: $height;
-      text-align: center;
     }
   }
-}
 </style>

+ 12 - 7
src/views/spectrum/configuration/utils.ts

@@ -1,7 +1,7 @@
 import { ColItem } from '@/api/common'
 import { elTableAlignLeft, getIntervalValue } from '@/utils/constant'
 import moment from 'moment'
-import { IDeviceTypeParam, IPoint, IStandardParam, ITeam } from './api/common'
+import { IDeviceTypeParam, IPoint, IStandardParam, ITeam, IDevice } from './api/common'
 
 export const deviceTypeCols: ColItem[] = [
   { type: 'selection', width: '50px' },
@@ -71,8 +71,13 @@ export const deviceCols: ColItem[] = [
   { prop: 'firmLiaison', label: '厂商联系人', width: '100px', ...elTableAlignLeft() },
   { prop: 'liaisonPhone', label: '联系人电话', width: '120px', ...elTableAlignLeft() },
   { prop: 'buyTime', label: '采购时间', width: '110px', ...elTableAlignLeft() },
-  { prop: 'deviceState', label: '设备状态', width: '80px', _slot: true },
-  { prop: 'remark', label: '备注', width: '120px', ...elTableAlignLeft() }
+  {
+    prop: 'deviceState',
+    label: '设备状态',
+    width: '80px',
+    formatter: ({ deviceState }: IDevice) => (deviceState === 1 ? '在用' : '闲置')
+  },
+  { prop: 'remark', label: '备注', width: '130px', ...elTableAlignLeft() }
 ]
 
 export const teamCols: ColItem[] = [
@@ -103,9 +108,9 @@ export const pointCols: ColItem[] = [
   { prop: 'partitionName', label: '排水分区', minWidth: '100px', ...elTableAlignLeft() },
   { prop: 'groupByName', label: '监测分组', minWidth: '100px', ...elTableAlignLeft() },
   { prop: 'siteCode', label: '站点编码', minWidth: '130px', ...elTableAlignLeft() },
-  { prop: 'siteName', label: '站点名称', minWidth: '130px', ...elTableAlignLeft() },
-  { prop: 'deviceSn', label: '设备SN', minWidth: '100px', ...elTableAlignLeft() },
-  { prop: 'deviceTypeName', label: '设备类型', minWidth: '100px', ...elTableAlignLeft() },
+  { prop: 'siteName', label: '站点名称', minWidth: '140px', ...elTableAlignLeft() },
+  { prop: 'deviceSn', label: 'SN序列号', minWidth: '120px', ...elTableAlignLeft() },
+  { prop: 'deviceTypeName', label: '设备类型', minWidth: '120px', ...elTableAlignLeft() },
   { prop: 'deviceName', label: '设备名称', minWidth: '130px', ...elTableAlignLeft() },
   { prop: 'installPeople', label: '负责人', minWidth: '80px', ...elTableAlignLeft() },
   { prop: 'liaisonPhone', label: '联系方式', minWidth: '120px', ...elTableAlignLeft() },
@@ -113,7 +118,7 @@ export const pointCols: ColItem[] = [
   {
     prop: 'installTime',
     label: '安装时间',
-    minWidth: '120px',
+    width: '120px',
     ...elTableAlignLeft(),
     formatter: ({ installTime }: IPoint) => (installTime ? moment(installTime).format('YYYY-MM-DD') : '')
   },

+ 1 - 1
src/views/spectrum/health/utils.ts

@@ -13,7 +13,7 @@ export const flawCols: ColItem[] = [
 
 export const flawPointParamCols: ColItem[] = [
   { type: 'index', label: '序号', width: '60px' },
-  { prop: 'interfaceCode', label: '参数代码', minWidth: '80px' },
+  { prop: 'paramCode', label: '参数代码', minWidth: '80px' },
   { prop: 'paramValue', label: '参数值', minWidth: '120px', _slot: true },
   { prop: 'unit', label: '单位', minWidth: '80px' },
   { prop: 'paramNotes', label: '参数说明', minWidth: '150px', ...elTableAlignLeft() }

+ 15 - 17
src/views/spectrum/reform/statistics/ChartItem.vue

@@ -1,24 +1,19 @@
 <template>
   <div class="cart-item">
     <slot name="title" />
-    <v-chart
-      :option="option"
-      :init-options="{ height: 400 }"
-      autoresize
-      style="width: 100%; height: 100%"
-      v-show="option.dataset.some((item) => item.source.length > 0)"
-    />
-    <el-empty :image="emptyImg" v-show="!option.dataset.some((item) => item.source && item.source.length > 0)">
+    <v-chart :option="option" :init-options="{ height: 400 }" autoresize style="width: 100%; height: 100%" />
+    <!-- <el-empty :image="emptyImg" v-show="!option.dataset.some((item) => item.source && item.source.length > 0)">
       <template v-slot:description>&nbsp;</template>
-    </el-empty>
+    </el-empty> -->
   </div>
 </template>
 
 <script lang="ts">
-  import { Vue, Component, Prop } from 'vue-property-decorator'
+  import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
   import { IStatisticsData } from '../api/common'
   import emptyImg from '@/assets/icon/null.png'
   import { IPointTarget } from '../../configuration/api/common'
+  import moment from 'moment'
 
   @Component({ name: 'ChartItem' })
   export default class ChartItem extends Vue {
@@ -26,20 +21,23 @@
     @Prop({ type: String }) itemKey!: keyof IStatisticsData['siteAndIndicateVo']
     @Prop({ type: Array, default: () => [] }) data!: IStatisticsData[]
     @Prop({ type: Array, default: () => [] }) standards!: IPointTarget['showVos']
+    @Watch('data', { immediate: true })
+    log(val) {
+      this.count++
+      console.log(this.count, this.itemKey, val, moment().format('YYYY-MM-DD HH:mm:ss'))
+    }
     emptyImg = emptyImg
-
+    count = 0
     getCodeName(code) {
       const { targetName } = this.standards.find((item) => item.targetCode === code) || {}
       return targetName || code
     }
 
     get option() {
-      const dataset = this.data.map(
-        ({ checkCode, siteAndIndicateVo: { [this.itemKey]: items = [] } }: IStatisticsData) => ({
-          id: checkCode,
-          source: items
-        })
-      )
+      const dataset = this.data.map(({ checkCode, siteAndIndicateVo: { [this.itemKey]: items } }: IStatisticsData) => ({
+        id: checkCode,
+        source: items || []
+      }))
       const series = this.data
         .map(({ checkCode }, index) => {
           return [

+ 3 - 9
src/views/spectrum/reform/statistics/DayAndHourChart.vue

@@ -1,17 +1,11 @@
 <template>
   <div class="cart-item">
     <slot name="title" />
-    <v-chart
-      :option="option"
-      :init-options="{ height: 400 }"
-      autoresize
-      style="width: 100%; height: 100%"
-      v-show="option.dataset.some((item) => item.source.length > 0)"
-    />
+    <v-chart :option="option" :init-options="{ height: 400 }" autoresize style="width: 100%; height: 100%" />
 
-    <el-empty :image="emptyImg" v-show="!option.dataset.some((item) => item.source && item.source.length > 0)">
+    <!-- <el-empty :image="emptyImg" v-show="!option.dataset.some((item) => item.source && item.source.length > 0)">
       <template v-slot:description>&nbsp;</template>
-    </el-empty>
+    </el-empty> -->
   </div>
 </template>
 

+ 1 - 1
src/views/spectrum/reform/utils.ts

@@ -13,7 +13,7 @@ export const dataQueryCols: ColItem[] = [
   { prop: 'checkTargetName', label: '监测指标', minWidth: '140px', ...elTableAlignLeft() },
   { prop: 'checkValue', label: '监测值', minWidth: '110px', ...elTableAlignLeft() },
   { prop: 'unit', label: '单位', width: '80px' },
-  { prop: 'checkResult', label: '判定结果', minWidth: '100px' },
+  { prop: 'checkResult', label: '判定结果', minWidth: '120px' },
   { prop: 'thresholdScope', label: '监测阈值', minWidth: '130px', ...elTableAlignLeft() },
   {
     prop: 'iscancel',

+ 4 - 1
tsconfig.json

@@ -22,5 +22,8 @@
     "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
   },
   "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx"],
-  "exclude": ["node_modules"]
+  "exclude": ["node_modules"],
+  "vueCompilerOptions": {
+    "target": 2
+  }
 }