浏览代码

Merge remote-tracking branch 'origin/staging' into dev_review

fenghao 3 年之前
父节点
当前提交
b737532043
共有 40 个文件被更改,包括 937 次插入222 次删除
  1. 13 2
      src/api/asset.js
  2. 5 2
      src/api/calendar.js
  3. 100 0
      src/api/external.js
  4. 1 2
      src/api/platform.js
  5. 1 4
      src/components/Schedule/ScheduleSwiper/index.vue
  6. 29 1
      src/components/Schedule/index.vue
  7. 1 4
      src/components/Schedule/mixins/event.js
  8. 5 5
      src/components/Schedule/mixins/schedule.js
  9. 1 4
      src/components/dialog/EventTargetDialog/index.vue
  10. 2 1
      src/constant.js
  11. 28 0
      src/global-api.js
  12. 2 17
      src/main.js
  13. 28 12
      src/router/index.js
  14. 2 4
      src/views/bigscreen/Program.vue
  15. 1 4
      src/views/bigscreen/ProgramDesigner.vue
  16. 3 3
      src/views/bigscreen/ast/core/widget/CImage.vue
  17. 1 1
      src/views/bigscreen/ast/core/widget/CMedia.vue
  18. 15 3
      src/views/bigscreen/ast/index.vue
  19. 1 1
      src/views/bigscreen/ast/mixin.js
  20. 2 3
      src/views/device/detail/components/DeviceInfo.vue
  21. 56 42
      src/views/device/detail/components/DeviceInvoke/ScreenSwitch.vue
  22. 11 11
      src/views/device/detail/components/LinkState.vue
  23. 268 0
      src/views/device/detail/components/external/Gateway/index.vue
  24. 9 11
      src/views/device/detail/components/external/Transmitter/index.vue
  25. 7 4
      src/views/device/detail/index.vue
  26. 1 4
      src/views/device/timeline/index.vue
  27. 143 0
      src/views/external/gateway/PLC.vue
  28. 157 0
      src/views/external/gateway/index.vue
  29. 3 3
      src/views/external/transmitter/index.vue
  30. 1 1
      src/views/realm/device/Product.vue
  31. 1 4
      src/views/review/components/ReviewProgram.vue
  32. 2 5
      src/views/review/components/ReviewPublish.vue
  33. 1 13
      src/views/review/index.vue
  34. 0 0
      src/views/review/workflow/detail/components/ReviewDialog.vue
  35. 4 9
      src/views/review/workflow/detail/index.vue
  36. 17 9
      src/views/review/workflow/index.vue
  37. 12 25
      src/views/review/workflow/mine/index.vue
  38. 1 4
      src/views/schedule/deploy/index.vue
  39. 1 0
      src/views/schedule/designer/index.vue
  40. 1 4
      src/views/schedule/history/index.vue

+ 13 - 2
src/api/asset.js

@@ -61,7 +61,7 @@ export function getAssetUrl (keyName) {
 }
 
 const LIMIT_SIZE = 1024 * 1024
-export function getThumbnailUrl (item, ratio = 'x0.2,q30') {
+export function getThumbnailUrl (item, option) {
   let url
   if (item && typeof item === 'object') {
     const { size, keyName } = item
@@ -69,13 +69,24 @@ export function getThumbnailUrl (item, ratio = 'x0.2,q30') {
       return getAssetUrl(keyName)
     }
     url = getAssetUrl(keyName)
+    option = getImageProxyOption(option, size)
   } else {
     url = getAssetUrl(item)
+    option = getImageProxyOption(option)
   }
   if (url.charAt(0) === '/') {
     url = `${location.origin}${url}`
   }
-  return `${process.env.VUE_APP_THUMBNAIL}/${ratio}/${url}`
+  return `${process.env.VUE_APP_THUMBNAIL}/${option}/${url}`
+}
+
+function getImageProxyOption (option, size) {
+  switch (option) {
+    case 'size':
+      return size ? `q${Math.ceil(LIMIT_SIZE * 100 / size)}` : 'q60'
+    default:
+      return option || 'x0.2,q30'
+  }
 }
 
 export function submitAsset ({ keyName, originalName }) {

+ 5 - 2
src/api/calendar.js

@@ -37,8 +37,11 @@ export function getSchedule (id, options) {
     method: 'GET',
     ...options
   }).then(({ data }) => {
-    const { id, type, status, name, resolutionRatio, eventDetail } = data
-    return { id, type, status, name, resolutionRatio, events: JSON.parse(eventDetail) || [] }
+    if (data) {
+      const { eventDetail, ...schedule } = data
+      return { events: JSON.parse(eventDetail) || [], ...schedule }
+    }
+    return null
   })
 }
 

+ 100 - 0
src/api/external.js

@@ -198,3 +198,103 @@ export function getCameras (query) {
     params
   })
 }
+
+export function getGateways (query) {
+  const { pageNum: pageIndex, pageSize, ...params } = query
+  return request({
+    url: '/device/thirdPartyGateway/list',
+    method: 'GET',
+    params: {
+      pageIndex, pageSize,
+      ...params
+    }
+  })
+}
+
+export function addGateway (data) {
+  return add({
+    url: '/device/thirdPartyGateway',
+    method: 'POST',
+    data
+  })
+}
+
+export function updateGateway (data) {
+  return update({
+    url: '/device/thirdPartyGateway',
+    method: 'PUT',
+    data
+  })
+}
+
+export function deleteGateway ({ id, name }) {
+  return del({
+    url: `/device/thirdPartyGateway/${id}`,
+    method: 'DELETE'
+  }, name)
+}
+
+export function getGateway (deviceId) {
+  return request({
+    url: `/device/bind/thirdPartyGateway/${deviceId}`,
+    method: 'GET'
+  }).then(({ data }) => data?.[0])
+}
+
+export function bindGateway (deviceId, thirdPartyDeviceId) {
+  return bind(deviceId, ThirdPartyDevice.GATEWAY, thirdPartyDeviceId)
+}
+
+export function plcCommand (deviceId, status) {
+  return messageSend({
+    url: '/device/thirdplc/command',
+    method: 'POST',
+    data: { deviceId, status }
+  }, '触发')
+}
+
+export function getPLCs (query) {
+  const { pageNum: pageIndex, pageSize, ...params } = query
+  return request({
+    url: '/device/thirdplc/pagequery',
+    method: 'POST',
+    data: {
+      pageIndex, pageSize,
+      ...params
+    }
+  })
+}
+
+export function addPLC (data) {
+  return add({
+    url: '/device/thirdplc/add',
+    method: 'POST',
+    data
+  })
+}
+
+export function updatePLC (data) {
+  return update({
+    url: '/device/thirdplc/modify',
+    method: 'PUT',
+    data
+  })
+}
+
+export function deletePLC ({ id, name }) {
+  return del({
+    url: `/device/thirdplc/delete/${id}`,
+    method: 'DELETE'
+  }, name)
+}
+
+export function bindPLC (deviceId, thirdPartyDeviceId) {
+  return bind(deviceId, ThirdPartyDevice.PLC, thirdPartyDeviceId)
+}
+
+export function getBoundPLCs (deviceId) {
+  return request({
+    url: `/device/bind/thirdPartyPlc/${deviceId}`,
+    method: 'GET'
+  }).then(({ data }) => data)
+}

+ 1 - 2
src/api/platform.js

@@ -7,7 +7,6 @@ import {
   resolve,
   reject,
   addScope,
-  addStatusScope,
   addOrg
 } from './base'
 
@@ -29,7 +28,7 @@ export function getPublishes (query) {
   return tenantRequest({
     url: '/orchestration/calendarReleaseSchedu/page',
     method: 'GET',
-    params: addStatusScope({
+    params: addScope({
       pageIndex, pageSize,
       ...params
     })

+ 1 - 4
src/components/Schedule/ScheduleSwiper/index.vue

@@ -234,10 +234,7 @@ export default {
       })
     },
     onView ({ id }) {
-      window.open(this.$router.resolve({
-        name: 'program',
-        params: { id }
-      }).href, '_blank')
+      this.$viewProgram(id)
     },
     onDel (event, index) {
       this.events.splice(index, 1)

+ 29 - 1
src/components/Schedule/index.vue

@@ -1,4 +1,5 @@
 <script>
+import { mapGetters } from 'vuex'
 import { getSchedule } from '@/api/calendar'
 import ScheduleCalendar from './ScheduleCalendar'
 import ScheduleSwiper from './ScheduleSwiper'
@@ -12,7 +13,11 @@ export default {
   props: {
     schedule: {
       type: String,
-      default: null
+      required: true
+    },
+    editable: {
+      type: [Boolean, String],
+      default: false
     }
   },
   data () {
@@ -20,6 +25,9 @@ export default {
       options: null
     }
   },
+  computed: {
+    ...mapGetters(['isSuperAdmin', 'tenant', 'userId'])
+  },
   watch: {
     schedule: {
       handler () {
@@ -72,9 +80,29 @@ export default {
     }
 
     const { detail } = this.options
+
+    if (!detail) {
+      return h('el-result', {
+        props: {
+          icon: 'warning',
+          subTitle: '数据不存在'
+        }
+      })
+    }
+
+    if (!this.isSuperAdmin && detail.tenant !== this.tenant) {
+      return h('el-result', {
+        props: {
+          icon: 'warning',
+          subTitle: '无权限'
+        }
+      })
+    }
+
     return h([null, 'ScheduleSwiper', 'ScheduleCalendar'][detail.type - 1], {
       props: {
         detail,
+        editable: this.editable && (this.isSuperAdmin || detail.createBy === this.userId),
         ...this.$attrs
       },
       on: this.$listeners

+ 1 - 4
src/components/Schedule/mixins/event.js

@@ -62,10 +62,7 @@ export default {
             this.$refs.scheduleDialog.show(event.target.id)
             break
           default:
-            window.open(this.$router.resolve({
-              name: 'program',
-              params: { id: event.target.id }
-            }).href, '_blank')
+            this.$viewProgram(event.target.id)
             break
         }
       }

+ 5 - 5
src/components/Schedule/mixins/schedule.js

@@ -2,7 +2,6 @@ import {
   saveScheduleEvents,
   submitSchedule
 } from '@/api/calendar'
-import { State } from '@/constant'
 
 export default {
   props: {
@@ -13,12 +12,15 @@ export default {
     hideHeader: {
       type: [Boolean, String],
       default: false
+    },
+    editable: {
+      type: [Boolean, String],
+      default: false
     }
   },
   data () {
     return {
-      scheduleOptions: null,
-      editable: false
+      scheduleOptions: null
     }
   },
   computed: {
@@ -36,7 +38,6 @@ export default {
     }
   },
   created () {
-    this.editable = this.detail.status === State.READY
     this.scheduleOptions = {
       ...this.detail,
       events: this.transformEvents(this.detail.events)
@@ -54,7 +55,6 @@ export default {
     },
     submit () {
       submitSchedule(this.scheduleOptions, this.getEvents()).then(() => {
-        this.editable = false
         this.$emit('submit')
       })
     }

+ 1 - 4
src/components/dialog/EventTargetDialog/index.vue

@@ -74,10 +74,7 @@ export default {
     onView ({ id }) {
       switch (this.$refs.tableDialog.getTable().getCondition().type) {
         case EventTarget.PROGRAM:
-          window.open(this.$router.resolve({
-            name: 'program',
-            params: { id }
-          }).href, '_blank')
+          this.$viewProgram(id)
           break
         case EventTarget.RECUR:
           this.$refs.scheduleDialog.show(id)

+ 2 - 1
src/constant.js

@@ -64,7 +64,8 @@ export const ThirdPartyDevice = {
   SENDING_CARD: 2,
   SCREEN: 3,
   LED_CAMERA: 4,
-  TRAFFIC_CAMERA: 5
+  TRAFFIC_CAMERA: 5,
+  PLC: 6
 }
 
 export const Transmitter = {

+ 28 - 0
src/global-api.js

@@ -0,0 +1,28 @@
+import {
+  showLoading,
+  closeLoading
+} from './utils/pop'
+
+export function injectGlobalApi (Vue, store) {
+  Vue.config.productionTip = false
+  Vue.config.errorHandler = err => {
+    closeLoading()
+    throw err
+  }
+
+  Vue.prototype.__STAGING__ = __STAGING__
+  Vue.prototype.__PLACEHOLDER__ = __PLACEHOLDER__
+
+  Vue.prototype.roleSet = store.getters.roles
+  Vue.prototype.accessSet = store.getters.accesses
+
+  Vue.prototype.$showLoading = showLoading
+  Vue.prototype.$closeLoading = closeLoading
+
+  Vue.prototype.$viewProgram = function (id, type = 'view') {
+    window.open(this.$router.resolve({
+      name: 'program',
+      params: { type, id }
+    }).href, '_blank')
+  }
+}

+ 2 - 17
src/main.js

@@ -14,10 +14,7 @@ import './icons'
 import './components'
 import './permission'
 
-import {
-  showLoading,
-  closeLoading
-} from './utils/pop'
+import { injectGlobalApi } from './global-api'
 
 const initOptions = {
   url: process.env.VUE_APP_KEYCLOAK_OPTIONS_URL,
@@ -58,17 +55,6 @@ async function startApp () {
 
   Vue.use(Element)
   Vue.prototype.$keycloak = keycloak
-  Vue.prototype.$showLoading = showLoading
-  Vue.prototype.$closeLoading = closeLoading
-
-  Vue.prototype.__STAGING__ = __STAGING__
-  Vue.prototype.__PLACEHOLDER__ = __PLACEHOLDER__
-
-  Vue.config.productionTip = false
-  Vue.config.errorHandler = err => {
-    closeLoading()
-    throw err
-  }
 
   await store.dispatch('user/login', keycloak)
   store.dispatch('permission/generateRoutes', {
@@ -77,8 +63,7 @@ async function startApp () {
   })
   router.addRoutes(store.getters.permissionRoutes)
 
-  Vue.prototype.roleSet = store.getters.roles
-  Vue.prototype.accessSet = store.getters.accesses
+  injectGlobalApi(Vue, store, router)
 
   new Vue({
     router,

+ 28 - 12
src/router/index.js

@@ -126,10 +126,7 @@ export const asyncRoutes = [
             path: ':id',
             component: () => import('@/views/schedule/designer/index'),
             access: Access.MANAGE_CALENDAR,
-            meta: {
-              title: '编辑',
-              cache: 'ScheduleList'
-            },
+            meta: { title: '编辑', cache: 'ScheduleList' },
             props: {
               redirect: 'schedule-list'
             }
@@ -145,25 +142,37 @@ export const asyncRoutes = [
       },
       {
         path: 'review',
+        component: () => import('@/views/review/index'),
+        access: Access.MANAGE_GROUP,
+        meta: { title: '审核管理' }
+      },
+      {
+        path: 'workflow',
         component: Solo,
         access: Access.MANAGE_GROUP,
-        meta: { title: '审核管理' },
+        meta: { title: '流程审核' },
         children: [
           {
-            name: 'review-list',
+            name: 'workflow-list',
             path: '',
-            component: () => import('@/views/review/index'),
-            meta: { cache: 'Review' }
+            component: () => import('@/views/review/workflow/index'),
+            meta: { cache: 'WorkflowList' }
           },
           {
             hidden: true,
-            name: 'review-detail',
+            name: 'workflow-detail',
             path: ':id',
-            component: () => import('@/views/review/detail/index'),
-            meta: { title: '审核', cache: 'Review' }
+            component: () => import('@/views/review/workflow/detail/index'),
+            meta: { title: '审核', cache: 'WorkflowList' }
           }
         ]
       },
+      {
+        path: 'mine',
+        component: () => import('@/views/review/workflow/mine/index'),
+        access: Access.MANAGE_CALENDAR,
+        meta: { title: '我的流程' }
+      },
       {
         name: 'schedule-deploy-history',
         path: 'history',
@@ -231,6 +240,13 @@ export const asyncRoutes = [
         component: () => import('@/views/external/transmitter/index'),
         meta: { title: '发送控制设备' }
       },
+      {
+        path: 'gateway',
+        name: 'gateway',
+        access: Access.MANAGE_TENANTS,
+        component: () => import('@/views/external/gateway/index'),
+        meta: { title: '网关' }
+      },
       {
         path: 'camera',
         name: 'camera',
@@ -332,7 +348,7 @@ export const asyncRoutes = [
   {
     hidden: true,
     name: 'program',
-    path: '/cm/program/:id',
+    path: '/cm/program/:type/:id',
     component: () => import('@/views/bigscreen/ast/index'),
     props: true
   },

+ 2 - 4
src/views/bigscreen/Program.vue

@@ -59,10 +59,8 @@ export default {
   },
   methods: {
     onClick () {
-      window.open(this.$router.resolve({
-        name: 'program',
-        params: { id: this.program.id }
-      }).href, '_blank')
+      const { id, status } = this.program
+      this.$viewProgram(id, status !== State.SUBMITTED && status !== State.RESOLVED ? 'design' : 'view')
     },
     onEdit () {
       const name = this.name

+ 1 - 4
src/views/bigscreen/ProgramDesigner.vue

@@ -180,10 +180,7 @@ export default {
         this.active = `${State.READY}`
         this.$refs.table.resetCondition({ status: State.READY, name: this.program.name })
         setTimeout(() => {
-          window.open(this.$router.resolve({
-            name: 'program',
-            params: { id }
-          }).href, '_blank')
+          this.$viewProgram(id, 'design')
         }, 500)
       })
     },

+ 3 - 3
src/views/bigscreen/ast/core/widget/CImage.vue

@@ -114,17 +114,17 @@ export default {
     },
     slideStyles () {
       return {
-        'background-image': this.img ? `url(${getThumbnailUrl(this.img)})` : 'none'
+        'background-image': this.img ? `url(${getThumbnailUrl(this.img, 'size')})` : 'none'
       }
     },
     flipFrontStyles () {
       return {
-        'background-image': this.frontImage ? `url(${getThumbnailUrl(this.frontImage)})` : 'none'
+        'background-image': this.frontImage ? `url(${getThumbnailUrl(this.frontImage, 'size')})` : 'none'
       }
     },
     flipBackStyles () {
       return {
-        'background-image': this.backImage ? `url(${getThumbnailUrl(this.backImage)})` : 'none'
+        'background-image': this.backImage ? `url(${getThumbnailUrl(this.backImage, 'size')})` : 'none'
       }
     },
     isNormal () {

+ 1 - 1
src/views/bigscreen/ast/core/widget/CMedia.vue

@@ -75,7 +75,7 @@ export default {
       return this.source?.type === AssetType.IMAGE
     },
     imageStyles () {
-      return this.isImage ? { 'background-image': `url(${getThumbnailUrl(this.source.keyName)})` } : null
+      return this.isImage ? { 'background-image': `url(${getThumbnailUrl(this.source, 'size')})` } : null
     },
     isVideo () {
       return this.source?.type === AssetType.VIDEO

+ 15 - 3
src/views/bigscreen/ast/index.vue

@@ -1,6 +1,7 @@
 <script>
 import '@/scss/iconfont/iconfont.css'
 
+import { mapGetters } from 'vuex'
 import { getProgram } from '@/api/program'
 import {
   State,
@@ -19,6 +20,10 @@ export default {
     next(false)
   },
   props: {
+    type: {
+      type: String,
+      default: 'view'
+    },
     id: {
       type: String,
       default: null
@@ -32,6 +37,9 @@ export default {
       activeComponent: null
     }
   },
+  computed: {
+    ...mapGetters(['isSuperAdmin', 'tenant', 'userId'])
+  },
   watch: {
     id: {
       handler () {
@@ -47,16 +55,20 @@ export default {
       getProgram(this.id, { custom: true }).then(
         ({ data }) => {
           try {
-            const { id, status, name, resolutionRatio, itemJsonStr } = data
+            const { tenant, createBy, id, status, name, resolutionRatio, itemJsonStr } = data
+            if (!this.isSuperAdmin && tenant !== this.tenant) {
+              this.showMessage('warning', '无权限')
+              return
+            }
             const [width, height] = resolutionRatio.split('x')
             if (!width || !height) {
               this.showMessage('error', '布局分辨率异常,请联系管理员')
               return
             }
 
-            if (status === State.SUBMITTED || status === State.RESOLVED) {
+            if (this.type !== 'design' || status === State.SUBMITTED || status === State.RESOLVED) {
               this.activeComponent = 'Viewer'
-            } else if (this.accessSet.has(Access.MANAGE_CALENDAR)) {
+            } else if (this.accessSet.has(Access.MANAGE_CALENDAR) && (this.isSuperAdmin || createBy === this.userId)) {
               this.activeComponent = 'Designer'
             } else {
               this.showMessage('warning', '暂无编辑权限,请联系管理员')

+ 1 - 1
src/views/bigscreen/ast/mixin.js

@@ -61,7 +61,7 @@ export default {
         const { backgroundImage, backgroundColor } = this.node
         return {
           'background-color': backgroundColor,
-          'background-image': backgroundImage[0] ? `url("${getThumbnailUrl(backgroundImage[0])}")` : 'none'
+          'background-image': backgroundImage[0] ? `url("${getThumbnailUrl(backgroundImage[0], 'size')}")` : 'none'
         }
       }
       return null

+ 2 - 3
src/views/device/detail/components/DeviceInfo.vue

@@ -13,7 +13,7 @@
     </div>
     <div class="l-flex--row c-info__block">
       <div class="l-flex--row l-flex__fill c-info__item">
-        <div class="l-flex__none c-info__title">设备名称</div>
+        <div class="l-flex__none c-info__title">名称</div>
         <div class="l-flex__fill c-info__value">{{ device.name }}</div>
       </div>
       <div class="l-flex--row l-flex__fill c-info__item">
@@ -193,7 +193,6 @@ export default {
 
 <style lang="scss" scoped>
 .o-map {
-  min-height: 300px;
-  max-height: 600px;
+  min-height: 90px;
 }
 </style>

+ 56 - 42
src/views/device/detail/components/DeviceInvoke/ScreenSwitch.vue

@@ -2,65 +2,79 @@
   <div class="l-flex--col center has-border radius has-padding">
     <i
       class="o-icon has-bg u-pointer"
-      @click="invoke"
+      @click="onInvoke"
     />
     <div class="has-padding u-color--black u-bold">开关大屏</div>
     <el-dialog
       :visible.sync="show"
       custom-class="c-dialog"
       title="开关大屏"
-      :before-close="onCloseDialog"
     >
-      <!-- <tabs
-        :items="tabs"
-        :active.sync="active"
-      /> -->
-      <template v-if="show">
-        <template v-if="isImmediate">
-          <div class="l-flex__fill l-flex--col jcenter center has-bottom-padding">
-            <div>
-              <button
-                class="o-button c-sibling-item"
-                @click="onSwitch(true)"
-              >
-                即刻开机
-              </button>
-              <button
-                class="o-button c-sibling-item far"
-                @click="onSwitch(false)"
-              >
-                即刻关机
-              </button>
-            </div>
-            <div class="has-padding u-color--info">【实时控制】会立即触发</div>
-          </div>
-        </template>
-        <schema-table
-          v-else
-          ref="table"
-          :schema="schema"
-          :proxy.sync="currOptions"
-        />
-      </template>
+      <div
+        v-if="show"
+        class="l-flex__fill l-flex--col jcenter center has-bottom-padding"
+      >
+        <div>
+          <button
+            class="o-button c-sibling-item"
+            @click="onSwitch(true)"
+          >
+            即刻开机
+          </button>
+          <button
+            class="o-button c-sibling-item far"
+            @click="onSwitch(false)"
+          >
+            即刻关机
+          </button>
+        </div>
+      </div>
     </el-dialog>
-    <task-dialog
-      ref="editDialog"
-      :title="dialogTitle"
-      @confirm="onSave"
-    />
   </div>
 </template>
 
 <script>
-import switchTaskMixin from './mixins/switch-task'
+import {
+  getBoundPLCs,
+  plcCommand
+} from '@/api/external'
 
 export default {
   name: 'ScreenSwitch',
-  mixins: [switchTaskMixin],
+  props: {
+    device: {
+      type: Object,
+      required: true
+    }
+  },
   data () {
     return {
-      openFunctionKey: 'bootScreen',
-      closeFunctionKey: 'shutdownScreen'
+      show: false
+    }
+  },
+  methods: {
+    onInvoke () {
+      const loading = this.$showLoading()
+      getBoundPLCs(this.device.id).finally(() => {
+        this.$closeLoading(loading)
+      }).then(data => {
+        if (data.length) {
+          this.show = true
+        } else {
+          this.$message({
+            type: 'warning',
+            message: '暂未绑定PLC,请联系管理员'
+          })
+        }
+      })
+    },
+    onSwitch (open) {
+      this.$confirm(
+        `立即${open ? '开机' : '关机'}?`,
+        { type: 'warning' }
+      ).then(() => {
+        plcCommand(this.device.id, open ? 1 : 0)
+      })
     }
   }
 }

+ 11 - 11
src/views/device/detail/components/LinkState.vue

@@ -226,8 +226,8 @@ export default {
 
 .c-link-state {
   position: relative;
-  min-width: 1024px;
-  min-height: 490px;
+  min-width: 970px;
+  min-height: 410px;
   overflow-x: auto;
 }
 
@@ -264,23 +264,23 @@ export default {
   }
 
   &.l6 {
-    @include getPosition(234px, 209px, 258px, 1px);
+    @include getPosition(234px, 209px, 216px, 1px);
   }
 
   &.l7 {
-    @include getPosition(490px, 209px, 1px, 105px);
+    @include getPosition(448px, 209px, 1px, 95px);
   }
 
   &.l8 {
-    @include getPosition(490px, 314px, 52px, 1px);
+    @include getPosition(448px, 304px, 66px, 1px);
   }
 
   &.l9 {
-    @include getPosition(490px, 209px, 52px, 1px);
+    @include getPosition(448px, 209px, 66px, 1px);
   }
 
   &.l10 {
-    @include getPosition(402px, 369px, 268px, 1px);
+    @include getPosition(360px, 366px, 296px, 1px);
   }
 }
 
@@ -349,11 +349,11 @@ export default {
   }
 
   &.traffic_camera {
-    @include getPosition(528px, 162px, 79px, 79px);
+    @include getPosition(500px, 156px, 79px, 79px);
   }
 
   &.led_camera {
-    @include getPosition(528px, 262px, 79px, 79px);
+    @include getPosition(500px, 252px, 79px, 79px);
   }
 
   &.traffic_camera,
@@ -368,7 +368,7 @@ export default {
   }
 
   &.gateway {
-    @include getPosition(270px, 278px, 138px, 138px);
+    @include getPosition(270px, 250px, 138px, 138px);
 
     &.online {
       background-image: url("~@/assets/linkState/icon_gateway_online.svg");
@@ -380,7 +380,7 @@ export default {
   }
 
   &.led {
-    @include getPosition(670px, 209px, 352px, 198px);
+    @include getPosition(624px, 208px, 352px, 198px);
     background-color: rgba(#000, 0.8);
     background-position: center center;
     background-size: contain;

+ 268 - 0
src/views/device/detail/components/external/Gateway/index.vue

@@ -0,0 +1,268 @@
+<template>
+  <div
+    v-loading="loading"
+    class="l-flex--col"
+  >
+    <template v-if="!loading">
+      <warning
+        v-if="error"
+        @click="getGateway"
+      />
+      <template v-else>
+        <template v-if="gateway">
+          <div class="c-sibling-item--v c-info">
+            <div class="l-flex--row has-bottom-padding u-bold">
+              <span class="c-sibling-item">网关信息</span>
+              <span
+                v-if="isSuperAdmin"
+                class="c-sibling-item c-info__edit u-pointer"
+                @click="onUnbindGateway"
+              >
+                <i class="el-icon-edit" />
+                解绑
+              </span>
+            </div>
+            <div class="l-flex--row c-info__block">
+              <div class="l-flex--row l-flex__fill c-info__item">
+                <div class="l-flex__none c-info__title">名称</div>
+                <auto-text
+                  class="l-flex__fill c-info__value"
+                  :text="gateway.name"
+                />
+              </div>
+              <div class="l-flex--row l-flex__fill c-info__item">
+                <div class="l-flex__none c-info__title">地址</div>
+                <div class="l-flex__fill c-info__value">{{ gateway.ip }}</div>
+              </div>
+            </div>
+          </div>
+          <div class="c-sibling-item--v far c-info">
+            <div class="l-flex--row has-bottom-padding u-bold">
+              <span class="c-sibling-item">PLC信息</span>
+              <span
+                v-if="isSuperAdmin"
+                class="c-sibling-item c-info__edit u-pointer"
+                @click="onBindPLC"
+              >
+                <i class="el-icon-edit" />
+                绑定
+              </span>
+            </div>
+            <div
+              v-if="plcs.length === 0"
+              class="u-color--info"
+            >暂未绑定</div>
+            <div
+              v-for="plc in plcs"
+              :key="plc.id"
+              class="l-flex--row c-info__block"
+            >
+              <div class="l-flex--row l-flex__fill c-info__item">
+                <div class="l-flex__none c-info__title">
+                  <span
+                    class="c-info__edit u-pointer"
+                    @click="onUnbindPLC(plc)"
+                  >
+                    解绑
+                  </span>
+                  名称
+                </div>
+                <auto-text
+                  class="l-flex__fill c-info__value"
+                  :text="plc.thirdPartyDevice.name"
+                />
+              </div>
+              <div class="l-flex--row l-flex__fill c-info__item">
+                <div class="l-flex__none c-info__title">地址</div>
+                <div class="l-flex__fill c-info__value">{{ plc.thirdPartyDevice.identifier }}</div>
+              </div>
+            </div>
+          </div>
+        </template>
+        <template v-else>
+          <div class="l-flex__fill l-flex--row center u-color--info">
+            <div class="l-flex--col center">
+              <div class="has-padding">未绑定网关,请联系管理员</div>
+              <button
+                v-if="isSuperAdmin"
+                class="o-button"
+                @click="onBindGateway"
+              >
+                绑定网关
+              </button>
+            </div>
+          </div>
+        </template>
+      </template>
+    </template>
+    <table-dialog
+      ref="chooseDialog"
+      :title="dialogTitle"
+      :schema="schema"
+      @choosen="onChoose"
+    />
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import {
+  getGateway,
+  getGateways,
+  bindGateway,
+  getBoundPLCs,
+  getPLCs,
+  bindPLC,
+  unbind
+} from '@/api/external'
+
+export default {
+  name: 'Gateway',
+  props: {
+    device: {
+      type: Object,
+      required: true
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      error: false,
+      info: null,
+      deviceType: 'GATEWAY'
+    }
+  },
+  computed: {
+    ...mapGetters(['isSuperAdmin']),
+    dialogTitle () {
+      switch (this.deviceType) {
+        case 'PLC':
+          return 'PLC选择'
+        default:
+          return '网关选择'
+      }
+    },
+    schema () {
+      switch (this.deviceType) {
+        case 'PLC':
+          return {
+            list: this.getPLCs,
+            cols: [
+              { prop: 'name', label: '名称' },
+              { prop: 'identifier', label: '地址' },
+              { prop: 'remark', label: '备注' }
+            ]
+          }
+        default:
+          return {
+            list: getGateways,
+            cols: [
+              { prop: 'name', label: '名称' },
+              { prop: 'ip', label: '地址' }
+            ]
+          }
+      }
+    },
+    gateway () {
+      return this.info?.gateway?.thirdPartyDevice
+    },
+    plcs () {
+      return this.info?.plcs || []
+    }
+  },
+  activated () {
+    !this.info && this.getInfo()
+  },
+  methods: {
+    getInfo (type) {
+      if (this.loading) {
+        return
+      }
+      this.loading = true
+      this.error = false
+
+      let arr
+      if (this.info && type) {
+        switch (type) {
+          case 'PLC':
+            arr = [Promise.resolve(this.info.gateway), this.getBoundPLCs()]
+            break
+          default:
+            arr = [this.getGateway(), Promise.resolve(this.info.plcs)]
+            break
+        }
+      } else {
+        arr = [this.getGateway(), this.getBoundPLCs()]
+      }
+
+      this.info = null
+      Promise.all(arr).then(
+        data => {
+          this.info = {
+            gateway: data[0],
+            plcs: data[1]
+          }
+        },
+        () => {
+          this.error = false
+        }
+      ).finally(() => {
+        this.loading = false
+      })
+    },
+    getGateway () {
+      return getGateway(this.device.id)
+    },
+    getBoundPLCs () {
+      return getBoundPLCs(this.device.id)
+    },
+    onChoose ({ value, done }) {
+      (this.deviceType === 'PLC' ? bindPLC : bindGateway)(this.device.id, value.id).then(() => {
+        done()
+        this.getInfo(this.deviceType)
+      })
+    },
+    onBindGateway () {
+      this.deviceType = 'GATEWAY'
+      this.$refs.chooseDialog.show()
+    },
+    onUnbindGateway () {
+      if (this.plcs.length) {
+        this.$message({
+          type: 'warning',
+          message: '请先解绑所有PLC'
+        })
+        return
+      }
+      this.$confirm(
+        '解绑网关?',
+        { type: 'warning' }
+      ).then(() => {
+        unbind(this.info.gateway.id).then(() => {
+          this.info = null
+        })
+      })
+    },
+    getPLCs (params) {
+      return getPLCs({
+        gatewayId: this.gateway.id,
+        ...params
+      })
+    },
+    onBindPLC () {
+      this.deviceType = 'PLC'
+      this.$refs.chooseDialog.show()
+    },
+    onUnbindPLC (plc) {
+      this.$confirm(
+        `解绑PLC ${plc.thirdPartyDevice.name}?`,
+        { type: 'warning' }
+      ).then(() => {
+        unbind(plc.id).then(() => {
+          this.plcs.splice(this.plcs.indexOf(plc), 1)
+        })
+      })
+    }
+  }
+}
+</script>

+ 9 - 11
src/views/device/detail/components/external/Transmitter/index.vue

@@ -24,37 +24,37 @@
             </div>
             <div class="l-flex--row c-info__block">
               <div class="l-flex--row l-flex__fill c-info__item">
-                <div class="l-flex__none c-info__title">设备名称</div>
+                <div class="l-flex__none c-info__title">名称</div>
                 <auto-text
                   class="l-flex__fill c-info__value"
                   :text="transmitter.name"
                 />
               </div>
               <div class="l-flex--row l-flex__fill c-info__item">
-                <div class="l-flex__none c-info__title">厂家名称</div>
+                <div class="l-flex__none c-info__title">厂家</div>
                 <div class="l-flex__fill c-info__value">{{ transmitter.manufacturerName }}</div>
               </div>
             </div>
             <div class="l-flex--row c-info__block">
               <div class="l-flex--row l-flex__fill c-info__item">
-                <div class="l-flex__none c-info__title">设备型号</div>
+                <div class="l-flex__none c-info__title">型号</div>
                 <auto-text
                   class="l-flex__fill c-info__value"
                   :text="transmitter.type"
                 />
               </div>
               <div class="l-flex--row l-flex__fill c-info__item">
-                <div class="l-flex__none c-info__title">设备类型</div>
+                <div class="l-flex__none c-info__title">类型</div>
                 <div class="l-flex__fill c-info__value">{{ type }}</div>
               </div>
             </div>
             <div class="l-flex--row c-info__block">
               <div class="l-flex--row l-flex__fill c-info__item">
-                <div class="l-flex__none c-info__title">支持设备监测</div>
+                <div class="l-flex__none c-info__title">设备监测</div>
                 <div class="l-flex__fill c-info__value">{{ supportDetection }}</div>
               </div>
               <div class="l-flex--row l-flex__fill c-info__item">
-                <div class="l-flex__none c-info__title">支持内容保护</div>
+                <div class="l-flex__none c-info__title">内容保护</div>
                 <div class="l-flex__fill c-info__value">{{ supportContentProtection }}</div>
               </div>
             </div>
@@ -69,7 +69,7 @@
                 class="o-button"
                 @click="onBind"
               >
-                绑定设备
+                绑定发送控制设备
               </button>
             </div>
           </div>
@@ -95,7 +95,6 @@ import {
   unbind
 } from '@/api/external'
 import { Transmitter } from '@/constant'
-import { createListOptions } from '@/utils'
 
 export default {
   name: 'Transmitter',
@@ -110,7 +109,6 @@ export default {
       loading: false,
       error: false,
       info: null,
-      options: createListOptions({ manufacturerKey: void 0 }),
       schema: {
         condition: { manufacturerKey: void 0 },
         filters: [
@@ -134,10 +132,10 @@ export default {
       return this.transmitter && this.transmitter.flag & Transmitter.IS_ASYNC ? '异步盒' : '非异步盒'
     },
     supportDetection () {
-      return this.transmitter && this.transmitter.flag & Transmitter.SUPPORT_DETECTION ? '是' : '否'
+      return this.transmitter && this.transmitter.flag & Transmitter.SUPPORT_DETECTION ? '支持' : '不支持'
     },
     supportContentProtection () {
-      return this.transmitter && this.transmitter.flag & Transmitter.SUPPORT_CONTENT_PROTECTION ? '是' : '否'
+      return this.transmitter && this.transmitter.flag & Transmitter.SUPPORT_CONTENT_PROTECTION ? '支持' : '不支持'
     }
   },
   activated () {

+ 7 - 4
src/views/device/detail/index.vue

@@ -75,6 +75,7 @@ import Sensors from './components/external/Sensors'
 import Transmitter from './components/external/Transmitter'
 import ReceivingCard from './components/external/ReceivingCard'
 import Camera from './components/external/Camera'
+import Gateway from './components/external/Gateway'
 
 export default {
   name: 'DeviceDetail',
@@ -87,7 +88,8 @@ export default {
     Sensors,
     Transmitter,
     ReceivingCard,
-    Camera
+    Camera,
+    Gateway
   },
   data () {
     return {
@@ -103,11 +105,12 @@ export default {
         { key: 'DeviceAlarm', label: '设备告警' },
         this.accessSet.has(Access.MANAGE_DEVICE) ? { key: 'DeviceInvoke', label: '设备操控' } : null,
         __SENSOR__ ? { key: 'Sensors', label: '传感器' } : null,
+        __STAGING__ ? { key: 'LinkState', label: '全链路监测' } : null,
         __STAGING__ ? { key: 'Transmitter', label: '发送控制设备' } : null,
         __STAGING__ ? { key: 'ReceivingCard', label: '接收卡' } : null,
-        __STAGING__ ? { key: 'LinkState', label: '全链路监测状态' } : null,
-        __STAGING__ ? { key: 'Camera', label: '摄像头' } : null
-      ].filter(val => val)
+        __STAGING__ ? { key: 'Camera', label: '摄像头' } : null,
+        __STAGING__ ? { key: 'Gateway', label: '网关' } : null
+      ].filter(Boolean)
     }
   },
   computed: {

+ 1 - 4
src/views/device/timeline/index.vue

@@ -473,10 +473,7 @@ export default {
       if (this.programProxy) {
         switch (this.programProxy.event.target.type) {
           case EventTarget.PROGRAM:
-            window.open(this.$router.resolve({
-              name: 'program',
-              params: { id: this.programProxy.event.target.id }
-            }).href, '_blank')
+            this.$viewProgram(this.programProxy.event.target.id)
             break
           case EventTarget.RECUR:
             this.$refs.scheduleDialog.show(this.programProxy.event.target.id)

+ 143 - 0
src/views/external/gateway/PLC.vue

@@ -0,0 +1,143 @@
+<template>
+  <schema-table
+    ref="table"
+    :schema="schema"
+  >
+    <confirm-dialog
+      ref="editDialog"
+      :title="dialogTitle"
+      :append-to-body="true"
+      @confirm="onConfirm"
+    >
+      <div class="c-grid-form u-align-self--center">
+        <span class="c-grid-form__label required">名称:</span>
+        <el-input
+          v-model.trim="plc.name"
+          placeholder="最多50个字符"
+          maxlength="50"
+          clearable
+        />
+        <span class="c-grid-form__label required">地址:</span>
+        <el-input
+          v-model.trim="plc.identifier"
+          placeholder="最多50个字符"
+          maxlength="50"
+          clearable
+        />
+        <span class="c-grid-form__label">备注:</span>
+        <el-input
+          v-model.trim="plc.remark"
+          type="textarea"
+          maxlength="100"
+          :rows="3"
+          show-word-limit
+        />
+      </div>
+    </confirm-dialog>
+  </schema-table>
+</template>
+
+<script>
+import {
+  getPLCs,
+  addPLC,
+  updatePLC,
+  deletePLC
+} from '@/api/external'
+
+export default {
+  name: 'PLCList',
+  props: {
+    gateway: {
+      type: Object,
+      required: true
+    }
+  },
+  data () {
+    return {
+      plc: {},
+      schema: {
+        list: this.getPLCs,
+        buttons: [
+          { type: 'add', on: this.onAdd }
+        ],
+        cols: [
+          { prop: 'name', label: '名称' },
+          { prop: 'identifier', label: '地址' },
+          { prop: 'remark', label: '备注' },
+          { type: 'invoke', render: [
+            { label: '编辑', on: this.onEdit },
+            { label: '删除', on: this.onDel }
+          ] }
+        ]
+      }
+    }
+  },
+  computed: {
+    dialogTitle () {
+      return this.plc.id ? '编辑PLC' : '新增PLC'
+    }
+  },
+  methods: {
+    getPLCs (params) {
+      return getPLCs({
+        gatewayId: this.gateway.id,
+        ...params
+      })
+    },
+    onAdd () {
+      this.plc = {
+        name: '',
+        identifier: '',
+        remark: ''
+      }
+      this.$refs.editDialog.show()
+    },
+    onEdit ({ id, name, identifier, remark }) {
+      this.plc = { id, name, identifier, remark }
+      this.$refs.editDialog.show()
+    },
+    onConfirm (done) {
+      if (!this.plc.name) {
+        this.$message({
+          type: 'warning',
+          message: '请填写PLC名称'
+        })
+        return
+      }
+      if (!this.plc.identifier) {
+        this.$message({
+          type: 'warning',
+          message: '请填写PLC标识'
+        })
+        return
+      }
+      if (this.plc.id) {
+        this.onConfirmEdit(this.plc, done)
+      } else {
+        this.onConfirmAdd(this.plc, done)
+      }
+    },
+    onConfirmAdd (plc, done) {
+      addPLC({
+        gatewayId: this.gateway.id,
+        ...plc
+      }).then(() => {
+        done()
+        this.$refs.table.resetCondition()
+      })
+    },
+    onConfirmEdit (plc, done) {
+      updatePLC(plc).then(() => {
+        done()
+        this.$refs.table.pageTo()
+      })
+    },
+    onDel (plc) {
+      deletePLC(plc).then(() => {
+        this.$refs.table.decrease(1)
+      })
+    }
+  }
+}
+</script>

+ 157 - 0
src/views/external/gateway/index.vue

@@ -0,0 +1,157 @@
+<template>
+  <wrapper
+    fill
+    margin
+    padding
+    background
+  >
+    <schema-table
+      ref="table"
+      :schema="schema"
+    />
+    <confirm-dialog
+      ref="editDialog"
+      :title="dialogTitle"
+      @confirm="onConfirm"
+    >
+      <div class="c-grid-form u-align-self--center">
+        <span class="c-grid-form__label required">名称:</span>
+        <el-input
+          v-model.trim="gateway.name"
+          placeholder="最多50个字符"
+          maxlength="50"
+          clearable
+        />
+        <span class="c-grid-form__label required">地址:</span>
+        <el-input
+          v-model.trim="gateway.ip"
+          placeholder="最多50个字符"
+          maxlength="50"
+          clearable
+        />
+        <span class="c-grid-form__label">备注:</span>
+        <el-input
+          v-model.trim="gateway.remark"
+          type="textarea"
+          maxlength="100"
+          :rows="3"
+          show-word-limit
+        />
+      </div>
+    </confirm-dialog>
+    <el-dialog
+      :visible.sync="showPlc"
+      title="PLC"
+      custom-class="c-dialog"
+      :close-on-click-modal="false"
+    >
+      <plc
+        v-if="showPlc"
+        :gateway="gateway"
+      />
+    </el-dialog>
+  </wrapper>
+</template>
+
+<script>
+import {
+  getGateways,
+  addGateway,
+  updateGateway,
+  deleteGateway
+} from '@/api/external'
+import PLC from './PLC'
+
+export default {
+  name: 'GatewayList',
+  components: {
+    plc: PLC
+  },
+  data () {
+    return {
+      gateway: {},
+      schema: {
+        list: getGateways,
+        buttons: [
+          { type: 'add', on: this.onAdd }
+        ],
+        cols: [
+          { prop: 'name', label: '名称' },
+          { prop: 'ip', label: '地址' },
+          { prop: 'remark', label: '备注' },
+          { type: 'invoke', width: 160, render: [
+            { label: '编辑', on: this.onEdit },
+            { label: 'PLC', on: this.onEditPLC },
+            { label: '删除', on: this.onDel }
+          ] }
+        ]
+      },
+      showPlc: false
+    }
+  },
+  computed: {
+    dialogTitle () {
+      return this.gateway.id ? '编辑网关' : '新增网关'
+    }
+  },
+  methods: {
+    onAdd () {
+      this.gateway = {
+        name: '',
+        ip: '',
+        mac: '',
+        account: '',
+        password: '',
+        remark: ''
+      }
+      this.$refs.editDialog.show()
+    },
+    onEdit ({ id, name, ip, remark }) {
+      this.gateway = { id, name, ip, remark }
+      this.$refs.editDialog.show()
+    },
+    onConfirm (done) {
+      if (!this.gateway.name) {
+        this.$message({
+          type: 'warning',
+          message: '请填写网关名称'
+        })
+        return
+      }
+      if (!this.gateway.ip) {
+        this.$message({
+          type: 'warning',
+          message: '请填写网关地址'
+        })
+        return
+      }
+      if (this.gateway.id) {
+        this.onConfirmEdit(this.gateway, done)
+      } else {
+        this.onConfirmAdd(this.gateway, done)
+      }
+    },
+    onConfirmAdd (gateway, done) {
+      addGateway(gateway).then(() => {
+        done()
+        this.$refs.table.resetCondition()
+      })
+    },
+    onConfirmEdit (gateway, done) {
+      updateGateway(gateway).then(() => {
+        done()
+        this.$refs.table.pageTo()
+      })
+    },
+    onDel (gateway) {
+      deleteGateway(gateway).then(() => {
+        this.$refs.table.decrease(1)
+      })
+    },
+    onEditPLC (gateway) {
+      this.gateway = gateway
+      this.showPlc = true
+    }
+  }
+}
+</script>

+ 3 - 3
src/views/external/transmitter/index.vue

@@ -43,14 +43,14 @@
             active-color="#13ce66"
             inactive-color="#ff4949"
           />
-          <span class="c-sibling-item far">支持设备监测:</span>
+          <span class="c-sibling-item far">设备监测:</span>
           <el-switch
             v-model="flag.detection"
             class="c-sibling-item"
             active-color="#13ce66"
             inactive-color="#ff4949"
           />
-          <span class="c-sibling-item far">支持内容保护:</span>
+          <span class="c-sibling-item far">内容保护:</span>
           <el-switch
             v-model="flag.contentProtection"
             class="c-sibling-item"
@@ -133,7 +133,7 @@ export default {
   },
   computed: {
     dialogTitle () {
-      return this.transmitter.id ? '添加发送控制设备' : '修改发送控制设备'
+      return this.transmitter.id ? '编辑发送控制设备' : '新增发送控制设备'
     }
   },
   methods: {

+ 1 - 1
src/views/realm/device/Product.vue

@@ -194,7 +194,7 @@ export default {
         done()
         return Promise.reject()
       }
-      return (this.isAdd ? addProduct : this.updateProduct)(this.currObj).then(done)
+      return (this.isAdd ? addProduct : updateProduct)(this.currObj).then(done)
     },
     onDel (product) {
       return deleteProduct(product).then(() => {

+ 1 - 4
src/views/review/components/ReviewProgram.vue

@@ -43,10 +43,7 @@ export default {
       return program
     },
     onView ({ id }) {
-      window.open(this.$router.resolve({
-        name: 'program',
-        params: { id }
-      }).href, '_blank')
+      this.$viewProgram(id)
     }
   }
 }

+ 2 - 5
src/views/review/components/ReviewPublish.vue

@@ -28,7 +28,7 @@ export default {
   data () {
     return {
       schema: {
-        condition: { status: State.REVIEW },
+        condition: { status: State.SUBMITTED },
         list: getPublishes,
         transform: this.transform,
         cols: [
@@ -119,10 +119,7 @@ export default {
       this.$refs.scheduleDialog.show(id)
     },
     viewProgram (id) {
-      window.open(this.$router.resolve({
-        name: 'program',
-        params: { id }
-      }).href, '_blank')
+      this.$viewProgram(id)
     }
   }
 }

+ 1 - 13
src/views/review/index.vue

@@ -29,14 +29,6 @@
         label="发布审核"
         name="ReviewPublish"
       />
-      <el-tab-pane
-        label="流程审批"
-        name="ReviewWorkflow"
-      />
-      <el-tab-pane
-        label="我的流程"
-        name="MyWorkflow"
-      />
     </el-tabs>
     <component
       :is="active"
@@ -90,8 +82,6 @@ import ReviewProgram from './components/ReviewProgram'
 import ReviewProgramRecur from './components/ReviewProgramRecur'
 import ReviewSchedule from './components/ReviewSchedule'
 import ReviewPublish from './components/ReviewPublish'
-import ReviewWorkflow from './components/ReviewWorkflow'
-import MyWorkflow from './components/MyWorkflow'
 
 export default {
   name: 'Review',
@@ -100,9 +90,7 @@ export default {
     ReviewProgram,
     ReviewProgramRecur,
     ReviewSchedule,
-    ReviewPublish,
-    ReviewWorkflow,
-    MyWorkflow
+    ReviewPublish
   },
   data () {
     return {

+ 0 - 0
src/views/review/components/ReviewDialog.vue → src/views/review/workflow/detail/components/ReviewDialog.vue


+ 4 - 9
src/views/review/detail/index.vue → src/views/review/workflow/detail/index.vue

@@ -12,7 +12,7 @@
       @click="getPublishWorkflowDetail"
     />
     <div v-if="dataMap.length">
-      <div class="l-flex--row has-padding o-title">{{ title }}</div>
+      <div class="l-flex--row o-title has-bottom-padding u-color--black u-bold">{{ title }}</div>
       <div class="l-flex--row has-padding">
         <el-steps
           :active="active"
@@ -119,7 +119,7 @@
 </template>
 
 <script>
-import ReviewDialog from '../components/ReviewDialog'
+import ReviewDialog from './components/ReviewDialog'
 import {
   getPublishWorkflowDetail,
   calendarPublishReject
@@ -182,12 +182,12 @@ const allDataMap = [
   'programCalendar',
   'calendarReleaseScheduling'
 ]
+
 export default {
   name: 'ReviewDetail',
   components: {
     ReviewDialog
   },
-  props: {},
   data () {
     return {
       error: false,
@@ -249,7 +249,6 @@ export default {
               { prop: 'duration', label: '时长' },
               { prop: 'size', label: '文件大小' },
               { prop: 'createBy', label: '申请人' },
-              { prop: 'createTime', label: '提交时间', 'min-width': 100 },
               { prop: 'ai', label: 'AI审核', type: 'tag', width: 100 },
               {
                 label: '审核状态',
@@ -278,7 +277,6 @@ export default {
               { prop: 'name', label: '节目名称', 'min-width': 100 },
               { prop: 'resolutionRatio', label: '分辨率' },
               { prop: 'createBy', label: '申请人' },
-              { prop: 'createTime', label: '提交时间' },
               {
                 label: '审核状态',
                 type: 'tag',
@@ -325,7 +323,6 @@ export default {
               { prop: 'name', label: '排期名称', 'min-width': 100 },
               { prop: 'resolutionRatio', label: '分辨率' },
               { prop: 'createBy', label: '申请人' },
-              { prop: 'createTime', label: '提交时间' },
               {
                 label: '审核状态',
                 type: 'tag',
@@ -386,7 +383,6 @@ export default {
               { prop: 'name', label: '名称', 'min-width': 100 },
               { prop: 'resolutionRatio', label: '分辨率' },
               { prop: 'createBy', label: '申请人' },
-              { prop: 'createTime', label: '提交时间' },
               {
                 type: 'invoke',
                 width: 160,
@@ -778,6 +774,7 @@ export default {
   }
 }
 </script>
+
 <style lang="scss" scoped>
 .o-card {
   display: flex;
@@ -805,8 +802,6 @@ export default {
 }
 .o-title {
   font-size: 18px;
-  font-weight: bold;
-  color: #333333;
 }
 .fl-end {
   justify-content: flex-end;

+ 17 - 9
src/views/review/components/ReviewWorkflow.vue → src/views/review/workflow/index.vue

@@ -1,18 +1,28 @@
 <template>
-  <schema-table
-    ref="table"
-    :schema="schema"
-    @row-click="onToggle"
-  />
+  <wrapper
+    fill
+    margin
+    padding
+    background
+  >
+    <schema-table
+      ref="table"
+      :schema="schema"
+      @row-click="onToggle"
+    />
+  </wrapper>
 </template>
 
 <script>
 import { getPublishWorkflows } from '@/api/workflow'
 import {
-  PublishType, EventPriority
+  PublishType,
+  EventPriority
 } from '@/constant'
 import { getEventDescription } from '@/utils/event'
+
 export default {
+  name: 'WorkflowList',
   data () {
     return {
       schema: {
@@ -147,7 +157,7 @@ export default {
     },
     review (item) {
       this.$router.push({
-        name: 'review-detail',
+        name: 'workflow-detail',
         params: {
           id: item.workflowId,
           name: item.name
@@ -157,5 +167,3 @@ export default {
   }
 }
 </script>
-
-<style></style>

+ 12 - 25
src/views/review/components/MyWorkflow.vue → src/views/review/workflow/mine/index.vue

@@ -1,5 +1,10 @@
 <template>
-  <div>
+  <wrapper
+    fill
+    margin
+    padding
+    background
+  >
     <el-tabs
       :value="active"
       class="c-tabs has-bottom-padding"
@@ -24,17 +29,19 @@
       @row-click="onToggle"
     />
     <schedule-dialog ref="scheduleDialog" />
-  </div>
+  </wrapper>
 </template>
 
 <script>
 import {
-  getPublishWorkflows, calendarPublishRestart
+  getPublishWorkflows,
+  calendarPublishRestart
 } from '@/api/workflow'
 import {
   PublishType, EventPriority, State
 } from '@/constant'
 import { getEventDescription } from '@/utils/event'
+
 export default {
   name: 'MyWorkflow',
   data () {
@@ -42,9 +49,6 @@ export default {
       active: '1',
       schema: {
         condition: { self: true, status: 1, name: '' },
-        // filters: [
-        //   { key: 'name', type: 'search', placeholder: '名称' }
-        // ],
         list: getPublishWorkflows,
         transform: this.transform,
         cols: [
@@ -67,7 +71,6 @@ export default {
           { prop: 'type', label: '类型', width: 100 },
           { prop: 'name', label: '名称', 'min-width': 100 },
           { prop: 'resolutionRatio', label: '分辨率' },
-          { prop: 'createBy', label: '申请人' },
           { prop: 'createTime', label: '提交时间' },
           {
             label: '审核状态',
@@ -81,7 +84,7 @@ export default {
           },
           {
             type: 'invoke',
-            width: 160,
+            width: 120,
             render: [
               { label: '查看', on: this.onView },
               {
@@ -196,21 +199,7 @@ export default {
       this.$refs.scheduleDialog.show(id)
     },
     viewProgram (id) {
-      window.open(
-        this.$router.resolve({
-          name: 'program',
-          params: { id }
-        }).href,
-        '_blank'
-      )
-    },
-    review (item) {
-      this.$router.push({
-        name: 'review-detail',
-        params: {
-          id: item.workflowId
-        }
-      })
+      this.$viewProgram(id)
     },
     restart (item) {
       calendarPublishRestart(item.workflowId, item.name).then(() => {
@@ -220,5 +209,3 @@ export default {
   }
 }
 </script>
-
-<style></style>

+ 1 - 4
src/views/schedule/deploy/index.vue

@@ -254,10 +254,7 @@ export default {
       this.eventOptions.schedule = { id, name }
     },
     onViewProgram () {
-      window.open(this.$router.resolve({
-        name: 'program',
-        params: { id: this.programId }
-      }).href, '_blank')
+      this.$viewProgram(this.programId)
     },
     getPublishTarget () {
       if (this.eventOptions.type === PublishType.CALENDAR) {

+ 1 - 0
src/views/schedule/designer/index.vue

@@ -8,6 +8,7 @@
     <schedule
       class="l-flex__auto"
       :schedule="scheduleId"
+      editable
       @submit="onSubmit"
     />
   </wrapper>

+ 1 - 4
src/views/schedule/history/index.vue

@@ -115,10 +115,7 @@ export default {
       this.$refs.scheduleDialog.show(id)
     },
     viewProgram (id) {
-      window.open(this.$router.resolve({
-        name: 'program',
-        params: { id }
-      }).href, '_blank')
+      this.$viewProgram(id)
     }
   }
 }