1、设备类管理页面完成增删改查功能
2、产品结构树工序及工步层级引入设备类概念由系统参数配置决定是否展示,若设备类存在时则NC文档挂载在设备类下不存在时则按照对应工序或工步层级下
3、产品结构树工序及工步层级的刀具列表实现增删改查功能
4、新增设备类管理页面并完成布局
5、产品结构树接口调整,产品结构树节点实体信息通过点击后调取接口获取
6、产品结构树搜素输入框增加防抖机制,避免每次输入都重新计算消耗性能使页面卡顿
7、新增工序及工步层级的刀具列表并添加系统权限
8、用户管理页面移除新增用户时的密码校验
9、产品结构树各层级属性信息展示由每行3列调整为每行4列
10、产品结构树页面在工序和工步层级实现对设备类的增删改查功能
已添加9个文件
已修改21个文件
已删除1个文件
3272 ■■■■ 文件已修改
.env.development 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/dnc.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/DeviceCustomTypeManagement.vue 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/ProductStructure.vue 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/DeviceCustomTypeManagement/DeviceCustomTypeManagementModal.vue 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/DeviceCustomTypeManagement/WorkshopDeviceListModal.vue 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainBottom.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Component/ComponentInfo.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Cutter/CutterInfo.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Cutter/CutterModal.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Cutter/CutterModalForm.vue 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Cutter/CutterTableList.vue 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModal.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModalForm.vue 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeTableList.vue 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Part/PartInfo.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue 207 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Process/ProcessInfo.vue 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Process/ProcessModalForm.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProcessStep/ProcessStepInfo.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureMain.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue 746 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue 106 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue 275 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/common/TableContextMenu.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/modules/UserModal.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yarn.lock 350 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -1,7 +1,8 @@
NODE_ENV=development
# VUE_APP_API_BASE_URL=http://192.168.124.118:3000
# VUE_APP_API_BASE_URL=http://192.168.1.118:3000
# VUE_APP_API_BASE_URL=http://195.0.1.10:6099
VUE_APP_API_BASE_URL=http://192.168.124.26:9999
VUE_APP_API_BASE_URL=http://192.168.1.12:9999
# VUE_APP_API_BASE_URL=http://127.0.0.1:9999
# VUE_APP_API_BASE_URL=http://195.0.1.10:8099
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
src/api/dnc.js
@@ -15,7 +15,7 @@
  // èŽ·å–äº§å“ç»“æž„æ ‘
  getProductStructureTreeApi: () => getAction('/nc/product/getTree'),
  // èŽ·å–äº§å“ç»“æž„æ ‘èŠ‚ç‚¹å®žä½“ä¿¡æ¯
  getProductStructureTreeNodeEntityApi:params=> getAction('/nc/product/getTreeById',params),
  getProductStructureTreeNodeEntityApi: params => getAction('/nc/product/getTreeById', params),
  // èŽ·å–æ‰€æœ‰è®¾å¤‡çš„åˆ—è¡¨
  getAllDeviceListApi: (type) => getAction('/nc/device/list/all'),
  // å¯¼å…¥NC程序/文档
@@ -51,30 +51,32 @@
  appointCurrentDocumentVersionApi: fileId => putAction(`/nc/file/assign/version/${fileId}`),
  // æ–‡æ¡£æ¯”对
  fileCompareApi: fileIdArray => getAction(`/nc/file/comparison/${fileIdArray[0]}/${fileIdArray[1]}`),
  // èŽ·å–æ‰€æœ‰éƒ¨é—¨åˆ—è¡¨
  getAllDepartmentsListApi: () => getAction('/ucenter/depart/list/all'),
  // èŽ·å–æ‰€æœ‰ç”¨æˆ·åˆ—è¡¨
  // æƒé™é…ç½®å¼¹çª—中获取所有车间列表
  getAllDepartmentsListApi: () => getAction('/mdc/mdcProduction/queryTreeListByConfig'),
  // æƒé™é…ç½®å¼¹çª—中获取所有用户列表
  getAllUsersListApi: () => getAction('/sys/user/list'),
  // èŽ·å–æœ‰æƒé™çš„éƒ¨é—¨åˆ—è¡¨
  // æƒé™é…ç½®å¼¹çª—中获取有权限的部门列表
  getHasPermissionDepartApi: ({ type, id }) => getAction(`/nc/product/get/perm/depart/${type}/${id}`),
  // èŽ·å–æœ‰æƒé™çš„ç”¨æˆ·åˆ—è¡¨
  // æƒé™é…ç½®å¼¹çª—中获取有权限的用户列表
  getHasPermissionUserApi: ({ type, id }) => getAction(`/nc/product/get/perm/user/${type}/${id}`),
  // åˆ†é…éƒ¨é—¨æƒé™
  // æƒé™é…ç½®å¼¹çª—中分配部门权限
  assignPermissionToDepart: ({ treeNodeType, treeNodeId, isAssignSonNode, departIdArray }) => {
    return postAction(`/nc/product/assign/add/department/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, departIdArray)
  },
  // ç§»é™¤éƒ¨é—¨æƒé™
  // æƒé™é…ç½®å¼¹çª—中移除部门权限
  removePermissionFromDepart: ({ treeNodeType, treeNodeId, isAssignSonNode, departIdArray }) => {
    return postAction(`/nc/product/assign/remove/department/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, departIdArray)
  },
  // åˆ†é…ç”¨æˆ¶æƒé™
  // æƒé™é…ç½®å¼¹çª—中分配用戶权限
  assignPermissionToUser: ({ treeNodeType, treeNodeId, isAssignSonNode, userIdArray }) => {
    return postAction(`/nc/product/assign/add/user/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, userIdArray)
  },
  // ç§»é™¤ç”¨æˆ·æƒé™
  // æƒé™é…ç½®å¼¹çª—中移除用户权限
  removePermissionFromUser: ({ treeNodeType, treeNodeId, isAssignSonNode, userIdArray }) => {
    return postAction(`/nc/product/assign/remove/user/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, userIdArray)
  },
  // é€šè¿‡è½¦é—´ID获取设备类列表
  getDeviceCustomTypeListByProductionIdApi: productionId => getAction('/nc/deviceManagement/getDeviceManagementListByProductionId', { productionId }),
  //-------------------------设备结构树------------------------------------------------
  // èŽ·å–è®¾å¤‡æ ‘
@@ -90,5 +92,8 @@
  // ç§»é™¤ç”¨æˆ·æƒé™
  removeDeviceTreePermissionFromUser: ({ treeNodeType, treeNodeId, isAssignSonNode, userIdArray }) => {
    return postAction(`/nc/device/assign/remove/user/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, userIdArray)
  }
  },
  //-------------------------设备类管理------------------------------------------------
  // èŽ·å–æœ‰æƒé™çš„è½¦é—´æ ‘åˆ—è¡¨
  getHasPermissionWorkshopTreeApi: () => getAction('/nc/deviceManagement/getProductionIdsByUserId')
}
src/views/dnc/base/DeviceCustomTypeManagement.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,189 @@
<template>
  <a-card :bordered="false">
    <!-- æŸ¥è¯¢åŒºåŸŸ -->
    <div class="table-page-search-wrapper">
      <a-form layout="inline" @keyup.enter.native="searchQuery">
        <a-row :gutter="24">
          <a-col :md="4" :sm="4">
            <a-form-item label="车间">
              <a-select v-model="queryParam.productionId" placeholder="请选择车间">
                <a-select-option v-for="item in workshopTreeData" :key="item.id">
                  {{ item.productionName }}
                </a-select-option>
              </a-select>
            </a-form-item>
          </a-col>
          <a-col :md="4" :sm="4">
            <a-form-item label="设备类名称">
              <a-input placeholder="请输入设备类名称" v-model="queryParam.deviceManagementName"></a-input>
            </a-form-item>
          </a-col>
          <a-col :md="4" :sm="4">
            <a-space>
              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
              <a-button type="primary" @click="searchReset" icon="reload">重置</a-button>
            </a-space>
          </a-col>
        </a-row>
      </a-form>
    </div>
    <!-- æ“ä½œæŒ‰é’®åŒºåŸŸ -->
    <div class="table-operator" style="border-top: 5px">
      <a-button @click="handleAdd" type="primary" icon="plus">添加设备类</a-button>
      <!--      <a-button type="primary" icon="download" @click="handleExportXls('设备类信息')">导出</a-button>-->
      <a-dropdown v-if="selectedRowKeys.length > 0">
        <a-menu slot="overlay" @click="handleMenuClick">
          <a-menu-item key="1">
            <a-icon type="delete" @click="batchDel"/>
            åˆ é™¤
          </a-menu-item>
        </a-menu>
        <a-button style="margin-left: 8px">
          æ‰¹é‡æ“ä½œ
          <a-icon type="down"/>
        </a-button>
      </a-dropdown>
    </div>
    <!-- table区域-begin -->
    <div>
      <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
        <i class="anticon anticon-info-circle ant-alert-icon"></i>已选择&nbsp;<a style="font-weight: 600">{{
          selectedRowKeys.length
        }}</a>项&nbsp;&nbsp;
        <a style="margin-left: 24px" @click="onClearSelected">清空</a>
      </div>
      <a-table
        ref="table"
        bordered
        size="middle"
        rowKey="id"
        :scroll="{y:465}"
        :columns="columns"
        :dataSource="dataSource"
        :pagination="ipagination"
        :loading="loading"
        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
        @change="handleTableChange">
        <template slot="action" slot-scope="text, record">
          <a @click="handleEdit(record)">编辑</a>
          <a-divider type="vertical"/>
          <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
            <a>删除</a>
          </a-popconfirm>
        </template>
      </a-table>
    </div>
    <!-- table区域-end -->
    <DeviceCustomTypeManagementModal ref="modalForm" :workshopTreeData="workshopTreeData" @ok="loadData"/>
  </a-card>
</template>
<script>
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import dncApi from '@/api/dnc'
import DeviceCustomTypeManagementModal
  from '@views/dnc/base/modules/DeviceCustomTypeManagement/DeviceCustomTypeManagementModal.vue'
export default {
  name: 'DeviceCustomTypeManagement',
  mixins: [JeecgListMixin],
  components: {
    DeviceCustomTypeManagementModal
  },
  data() {
    return {
      columns: [
        {
          title: '#',
          dataIndex: '',
          key: 'rowIndex',
          width: 60,
          align: 'center',
          customRender: function(t, r, index) {
            return parseInt(index) + 1
          }
        },
        {
          title: '车间',
          align: 'center',
          width: 200,
          dataIndex: 'productionId_dictText'
        },
        {
          title: '设备类',
          align: 'center',
          width: 200,
          dataIndex: 'deviceManagementCode'
        },
        {
          title: '设备类名称',
          align: 'center',
          width: 200,
          dataIndex: 'deviceManagementName'
        },
        {
          title: '设备组编号',
          align: 'center',
          dataIndex: 'equipmentIds',
          width: 400,
          ellipsis: true
        },
        {
          title: '操作',
          dataIndex: 'action',
          scopedSlots: { customRender: 'action' },
          align: 'center',
          width: 80
        }
      ],
      url: {
        list: '/nc/deviceManagement/query',
        delete: '/nc/deviceManagement/delete',
        deleteBatch: '/nc/deviceManagement/deleteBatch'
      },
      workshopTreeData: []
    }
  },
  created() {
    this.getWorkshopListByApi()
  },
  methods: {
    // è°ƒç”¨æŽ¥å£èŽ·å–æŸ¥è¯¢åŒºåŸŸè½¦é—´æ ‘åˆ—è¡¨
    getWorkshopListByApi() {
      dncApi.getHasPermissionWorkshopTreeApi()
        .then(res => {
          if (res.success) {
            this.workshopTreeData = res.result
          }
        })
    },
    handleAdd: function() {
      this.$refs.modalForm.add()
      this.$refs.modalForm.title = '新增'
      this.$refs.modalForm.disabledEdit = false
    },
    handleEdit: function(record) {
      this.$refs.modalForm.edit(record)
      this.$refs.modalForm.title = '编辑'
      this.$refs.modalForm.disabledEdit = true
    },
    handleMenuClick(e) {
      if (e.key == 1) {
        this.batchDel()
      }
    }
  }
}
</script>
src/views/dnc/base/ProductStructure.vue
@@ -11,30 +11,35 @@
    <!--导入文件公共弹窗-->
    <ImportFileModal/>
    <!--新增或编辑设备类公共弹窗-->
    <DeviceCustomTypeModal/>
  </a-card>
</template>
<script>
  import ProductStructureTree from './modules/ProductStructure/ProductStructureTree'
  import ProductStructureMain from './modules/ProductStructure/ProductStructureMain'
  import ImportFileModal from '../common/ImportFileModal'
import ProductStructureTree from './modules/ProductStructure/ProductStructureTree'
import ProductStructureMain from './modules/ProductStructure/ProductStructureMain'
import ImportFileModal from '../common/ImportFileModal'
import DeviceCustomTypeModal from '@views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModal.vue'
  export default {
    name: 'ProductStructure',
    components: {
      ProductStructureTree,
      ProductStructureMain,
      ImportFileModal
    },
    data() {
      return {}
    },
    methods: {}
  }
export default {
  name: 'ProductStructure',
  components: {
    DeviceCustomTypeModal,
    ProductStructureTree,
    ProductStructureMain,
    ImportFileModal
  },
  data() {
    return {}
  },
  methods: {}
}
</script>
<style scoped lang="less">
  /deep/ .ant-card-body {
    padding: 8px;
  }
/deep/ .ant-card-body {
  padding: 8px;
}
</style>
src/views/dnc/base/modules/DeviceCustomTypeManagement/DeviceCustomTypeManagementModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,223 @@
<template>
  <a-modal
    :title="title"
    :width="700"
    @cancel="close"
    :visible="visible"
    :footer="null"
    style="height: 100%;overflow: auto;padding-bottom: 53px;">
    <a-spin :spinning="confirmLoading">
      <a-form-model ref="form" :form="form" :model="model" :rules="validatorRules" :labelCol="labelCol"
                    :wrapperCol="wrapperCol">
        <a-row :gutter="24">
          <a-col :span="12">
            <a-form-model-item label="车间分配" prop="productionId">
              <a-select v-model="model.productionId" placeholder="请选择车间" @change="handleSelectChange"
                        :disabled="disabledEdit">
                <a-select-option v-for="item in workshopTreeData" :key="item.id">
                  {{ item.productionName }}
                </a-select-option>
              </a-select>
            </a-form-model-item>
          </a-col>
          <a-col :span="12">
            <a-form-model-item label="设备类" prop="deviceManagementCode">
              <a-input allow-clear placeholder="请输入设备类" :readOnly="disabledEdit"
                       v-model="model.deviceManagementCode"/>
            </a-form-model-item>
          </a-col>
        </a-row>
        <a-row :gutter="24">
          <a-col :span="12">
            <a-form-model-item label="设备类名称" prop="deviceManagementName">
              <a-input allow-clear placeholder="请输入设备类名称" :readOnly="disabledEdit"
                       v-model="model.deviceManagementName"/>
            </a-form-model-item>
          </a-col>
        </a-row>
        <a-row :gutter="24">
          <a-col :span="24">
            <a-form-model-item label="设备组编号" :labelCol="labelColLong" :wrapperCol="wrapperColLong"
                               prop="equipmentIds">
              <a-input-search v-model="model.equipmentIds" :disabled="!model.productionId" @search="deviceSearch"
                              enter-button :placeholder='!model.productionId?"请选择车间":"请选择设备组编号"'/>
            </a-form-model-item>
          </a-col>
        </a-row>
      </a-form-model>
    </a-spin>
    <div class="drawer-bottom-button">
      <a-space>
        <a-button @click="close">取消</a-button>
        <a-button @click="handleSubmit" type="primary" :loading="confirmLoading">提交</a-button>
      </a-space>
    </div>
    <workshop-device-list-modal :productionId="model.productionId" ref="deviceListModel"
                                @sendSelectedRowKeys="getDeviceRowKeys"/>
  </a-modal>
</template>
<script>
import { httpAction } from '@/api/manage'
import WorkshopDeviceListModal from '@views/dnc/base/modules/DeviceCustomTypeManagement/WorkshopDeviceListModal.vue'
export default {
  name: 'DeviceCustomTypeManagementModal',
  components: { WorkshopDeviceListModal },
  props: {
    workshopTreeData: {
      type: Array
    }
  },
  data() {
    return {
      title: '',
      form: this.$form.createForm(this),
      validatorRules: {
        productionId: [
          {
            required: true, message: '请选择车间!'
          }
        ],
        deviceManagementCode: [
          {
            required: true, message: '请输入设备类!'
          }
        ],
        deviceManagementName: [
          {
            required: true, message: '请输入设备类名称!'
          }
        ],
        equipmentIds: [
          {
            required: true, message: '请选择设备编号!'
          }
        ]
      },
      visible: false,
      disabledEdit: false,
      model: {},
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 14 }
      },
      labelColLong: {
        xs: { span: 24 },
        sm: { span: 4 }
      },
      wrapperColLong: {
        xs: { span: 24 },
        sm: { span: 19 }
      },
      confirmLoading: false,
      url: {
        add: '/nc/deviceManagement/add',
        edit: '/nc/deviceManagement/edit'
      }
    }
  },
  methods: {
    // è½¦é—´é€‰æ‹©å™¨å€¼å‘生改变时触发清空已选择的设备编号组
    handleSelectChange() {
      if (this.model.equipmentIds) delete this.model.equipmentIds
    },
    /**
     * å½“设备选择完成后提交将已选择的设备编号列表以逗号隔开拆分到参数中
     * @param selectedRowKeys
     */
    getDeviceRowKeys(selectedRowKeys) {
      if (selectedRowKeys.length === 0) return
      this.$set(this.model, 'equipmentIds', selectedRowKeys.join(','))
      this.$refs.form.clearValidate()
    },
    deviceSearch() {
      this.$refs.deviceListModel.openPage()
      this.$refs.deviceListModel.title = '选择设备'
      this.$refs.deviceListModel.disableSubmit = false
    },
    add() {
      this.edit({})
    },
    edit(record) {
      this.visible = true
      this.model = Object.assign({}, record)
    },
    handleSubmit() {
      const that = this
      // è§¦å‘表单验证
      this.$refs.form.validate(valid => {
        if (valid) {
          that.confirmLoading = true
          let apiUrl, method
          if (!this.model.id) {
            apiUrl = this.url.add
            method = 'post'
          } else {
            apiUrl = this.url.edit
            method = 'put'
          }
          httpAction(apiUrl, this.model, method)
            .then((res) => {
              if (res.success) {
                that.$notification.success({
                  message: '消息',
                  description: res.message
                })
                that.$emit('ok')
                that.close()
              } else {
                that.$notification.warning({
                  message: '消息',
                  description: res.message
                })
              }
            })
            .finally(() => {
              that.confirmLoading = false
            })
        } else {
          return false
        }
      })
    },
    close() {
      this.$emit('close')
      this.visible = false
      this.$refs.form.clearValidate()
    }
  }
}
</script>
<style scoped>
.drawer-bottom-button {
  position: absolute;
  bottom: -40px;
  width: 100%;
  border-top: 1px solid #e8e8e8;
  padding: 10px 16px;
  text-align: right;
  left: 0;
  background: #fff;
  border-radius: 0 0 2px 2px;
}
</style>
src/views/dnc/base/modules/DeviceCustomTypeManagement/WorkshopDeviceListModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
<template>
  <a-modal :title="title" :width="1000" :visible="visible" :maskClosable="false" @ok="handleOk" @cancel="close"
           cancelText="关闭">
    <div class="table-page-search-wrapper">
      <a-form layout="inline" @keyup.enter.native="searchQuery">
        <a-row :gutter="24">
          <a-col :md="8" :sm="8">
            <a-form-item label="设备编号">
              <a-input placeholder="请输入设备编号" v-model="queryParam.equipmentId"/>
            </a-form-item>
          </a-col>
          <a-col :md="8" :sm="8">
            <a-form-item label="设备名称">
              <a-input placeholder="请输入设备名称" v-model="queryParam.equipmentName"/>
            </a-form-item>
          </a-col>
          <a-col :md="3" :sm="3">
            <a-space>
              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
              <a-button type="primary" @click="searchReset" icon="reload">重置</a-button>
            </a-space>
          </a-col>
        </a-row>
      </a-form>
    </div>
    <!-- table区域-begin -->
    <a-table ref="table" size="middle" bordered rowKey="equipmentId" :scroll="{y: 300}" :columns="columns"
             :dataSource="dataSource" :pagination="ipagination" :loading="loading"
             :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange, type:'checkbox'}"
             @change="handleTableChange">
    </a-table>
    <!-- table区域-end -->
  </a-modal>
</template>
<script>
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
export default {
  name: 'WorkshopDeviceListModal',
  mixins: [JeecgListMixin],
  components: {},
  props: {
    productionId: {
      type: String
    }
  },
  data() {
    return {
      title: '',
      visible: false,
      disableMixinCreated: true,
      columns: [
        {
          title: '设备编号',
          align: 'center',
          dataIndex: 'equipmentId'
        },
        {
          title: '设备名称',
          align: 'center',
          dataIndex: 'equipmentName'
        },
        {
          title: '设备型号',
          align: 'center',
          dataIndex: 'equipmentModel'
        },
        {
          title: '机床IP',
          align: 'center',
          dataIndex: 'equipmentIp'
        },
        {
          title: '驱动类型',
          align: 'center',
          dataIndex: 'driveType'
        },
        {
          title: '端口',
          align: 'center',
          dataIndex: 'dataPort'
        },
        {
          title: '数控系统',
          align: 'center',
          dataIndex: 'controlSystem'
        }
      ],
      url: {
        list: '/nc/deviceManagement/getEquipmentListByProductionId'
      }
    }
  },
  methods: {
    openPage() {
      this.visible = true
      this.onClearSelected()
      this.dataSource = []
      this.queryParam = Object.assign({}, { productionId: this.productionId })
      this.loadData()
    },
    searchQuery() {
      this.loadData()
      this.onClearSelected()
    },
    searchReset() {
      this.queryParam = Object.assign({}, { productionId: this.productionId })
      this.loadData()
      this.onClearSelected()
    },
    close() {
      this.$emit('close')
      this.visible = false
    },
    handleOk() {
      this.$emit('sendSelectedRowKeys', this.selectedRowKeys)
      this.close()
    }
  }
}
</script>
src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainBottom.vue
@@ -1,6 +1,6 @@
<template>
  <div>
    <a-tabs v-model="activeTabKey" @change="handleTabChange">
  <div style="height: 100%">
    <a-tabs style="height: 100%" v-model="activeTabKey" @change="handleTabChange">
      <a-tab-pane :key="1" tab="设备属性" v-if="currentTreeNodeInfo.type===2&&!currentDocumentInfo.docId">
        <DeviceInfo :currentLevelDetails="currentTreeNodeInfo.entity" :size="containerSize"/>
      </a-tab-pane>
src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
@@ -82,6 +82,7 @@
      getTreeDataByApi() {
        this.loading = true
        this.cardLoading = true
        this.treeDataSource = []
        dncApi.getDeviceTreeDataApi()
          .then(res => {
            if (res.success) {
src/views/dnc/base/modules/ProductStructure/Component/ComponentInfo.vue
@@ -1,6 +1,6 @@
<template>
  <a-descriptions bordered :size="size">
    <a-descriptions-item label="名称">{{currentLevelDetails.componentName}}</a-descriptions-item>
  <a-descriptions bordered :size="size" :column="4">
    <a-descriptions-item label="名称" :span="2">{{currentLevelDetails.componentName}}</a-descriptions-item>
    <a-descriptions-item label="代号">{{currentLevelDetails.componentCode}}</a-descriptions-item>
    <a-descriptions-item label="型号    ">{{currentLevelDetails.componentModel}}</a-descriptions-item>
    <a-descriptions-item label="物料编码">{{currentLevelDetails.materielCode}}</a-descriptions-item>
@@ -10,12 +10,12 @@
    <a-descriptions-item label="生产类型">{{currentLevelDetails.produceType}}</a-descriptions-item>
    <a-descriptions-item label="处理类型    ">{{currentLevelDetails.processType}}</a-descriptions-item>
    <a-descriptions-item label="结构类型    ">{{currentLevelDetails.structureType}}</a-descriptions-item>
    <a-descriptions-item label="重量" :span="2">{{currentLevelDetails.componentWeight}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createName}}</a-descriptions-item>
    <a-descriptions-item label="创建时间" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateName}}</a-descriptions-item>
    <a-descriptions-item label="修改时间" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="3">{{currentLevelDetails.description}}</a-descriptions-item>
    <a-descriptions-item label="重量" >{{currentLevelDetails.componentWeight}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="创建时间">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="修改时间">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="4">{{currentLevelDetails.description}}</a-descriptions-item>
  </a-descriptions>
</template>
src/views/dnc/base/modules/ProductStructure/Cutter/CutterInfo.vue
ÎļþÒÑɾ³ý
src/views/dnc/base/modules/ProductStructure/Cutter/CutterModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
<template>
  <j-modal
    :title="title"
    :width="width"
    :visible="visible"
    switchFullscreen
    :maskClosable="false"
    @ok="handleOk"
    @cancel="handleCancel"
    :okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
    cancelText="关闭">
    <CutterModalForm ref="realForm" @ok="submitCallback" :disableSubmit="disableSubmit"/>
  </j-modal>
</template>
<script>
import CutterModalForm from './CutterModalForm.vue'
export default {
  name: 'CutterModal',
  components: {
    CutterModalForm
  },
  props: {
    currentTreeNodeInfo: {
      type: Object
    }
  },
  data() {
    return {
      title: '',
      width: 700,
      visible: false,
      disableSubmit: false
    }
  },
  methods: {
    // æ·»åŠ æ‰€ç”¨åˆ€å…·
    handleCutterAdd() {
      const { id, type } = this.currentTreeNodeInfo
      this.visible = true
      this.$nextTick(() => {
        if (this.$refs.realForm) {
          this.$refs.realForm.add({
            attributionId: id,
            attributionType: type
          })
        }
      })
    },
    // ç¼–辑刀具信息
    handleCutterEdit(record) {
      this.visible = true
      this.$nextTick(() => {
        if (this.$refs.realForm) {
          this.$refs.realForm.edit({ ...record })
        }
      })
    },
    handleOk() {
      this.$refs.realForm.submitForm()
    },
    submitCallback() {
      this.$emit('submitSuccess')
      this.visible = false
    },
    handleCancel() {
      this.$emit('close')
      this.visible = false
    }
  }
}
</script>
src/views/dnc/base/modules/ProductStructure/Cutter/CutterModalForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,152 @@
<template>
  <a-spin :spinning="confirmLoading">
    <a-form-model ref="form" :model="model" :rules="validatorRules" :labelCol="labelCol" :wrapperCol="wrapperCol">
      <a-row>
        <a-col :span="12">
          <a-form-model-item label="刀具编号" prop="cutterCode">
            <a-input v-model="model.cutterCode" placeholder="请输入刀具编号" :readOnly="disableSubmit"/>
          </a-form-model-item>
        </a-col>
        <a-col :span="12">
          <a-form-model-item label="刀具名称" prop="cutterName">
            <a-input v-model="model.cutterName" placeholder="请输入刀具名称" :readOnly="disableSubmit"/>
          </a-form-model-item>
        </a-col>
      </a-row>
      <a-row>
        <a-col :span="12">
          <a-form-model-item label="刀具类型">
            <j-dict-select-tag v-model="model.cutterType" placeholder="请选择刀具类型" dictCode="cutter_type"
                               :disabled="disableSubmit"/>
          </a-form-model-item>
        </a-col>
        <a-col :span="12">
          <a-form-model-item label="额定寿命">
            <a-input-number v-model="model.lifetime" :min="0" placeholder="请输入额定寿命" style="width: 100%"
                            :disabled="disableSubmit"/>
          </a-form-model-item>
        </a-col>
      </a-row>
      <a-row>
        <a-col :span="12">
          <a-form-model-item label="刀位">
            <a-input v-model="model.cutterSpacing" placeholder="请输入刀位" :readOnly="disableSubmit"/>
          </a-form-model-item>
        </a-col>
        <a-col :span="12">
          <a-form-model-item label="刀具数量">
            <a-input-number v-model="model.quantity" placeholder="请输入刀具数量" :min="1" style="width: 100%"
                            :disabled="disableSubmit"/>
          </a-form-model-item>
        </a-col>
      </a-row>
      <a-row>
        <a-col :span="24">
          <a-form-model-item label="描述" :labelCol="labelColLong" :wrapperCol="wrapperColLong">
            <a-textarea v-model="model.description" placeholder="请输入描述" :readOnly="disableSubmit"/>
          </a-form-model-item>
        </a-col>
      </a-row>
    </a-form-model>
  </a-spin>
</template>
<script>
import { httpAction } from '@/api/manage'
export default {
  name: 'CutterModalForm',
  components: {},
  props: {
    disableSubmit: {
      type: Boolean
    }
  },
  data() {
    return {
      model: {
        quantity: 1
      },
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 14 }
      },
      labelColLong: {
        xs: { span: 24 },
        sm: { span: 4 }
      },
      wrapperColLong: {
        xs: { span: 24 },
        sm: { span: 19 }
      },
      confirmLoading: false,
      validatorRules: {
        cutterCode: [
          { required: true, message: '请输入刀具编号!' }
        ],
        cutterName: [
          { required: true, message: '请输入刀具名称!' }
        ]
      },
      url: {
        add: '/nc/cutter/add',
        edit: '/nc/cutter/edit'
      }
    }
  },
  created() {
    //备份model原始值
    this.modelDefault = JSON.parse(JSON.stringify(this.model))
  },
  methods: {
    add(params) {
      this.edit({ ...this.modelDefault, ...params })
    },
    edit(record) {
      this.model = Object.assign({}, record)
      console.log('model', this.model)
    },
    submitForm() {
      const that = this
      // è§¦å‘表单验证
      this.$refs.form.validate(valid => {
        if (valid) {
          that.confirmLoading = true
          let httpUrl, method
          if (!this.model.id) {
            httpUrl = this.url.add
            method = 'post'
          } else {
            httpUrl = this.url.edit
            method = 'put'
          }
          httpAction(httpUrl, this.model, method).then((res) => {
            if (res.success) {
              that.$notification.success({
                message: '消息',
                description: res.message
              })
              that.$emit('ok')
            } else {
              that.$notification.warning({
                message: '消息',
                description: res.message
              })
            }
          }).finally(() => {
            that.confirmLoading = false
          })
        }
      })
    }
  }
}
</script>
src/views/dnc/base/modules/ProductStructure/Cutter/CutterTableList.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,153 @@
<template>
  <div>
    <!-- æŸ¥è¯¢åŒºåŸŸ -->
    <div class="table-page-search-wrapper">
      <a-form layout="inline" @keyup.enter.native="searchQuery">
        <a-row :gutter="24">
          <a-col :md="5" :sm="5">
            <a-form-item label="刀具编号">
              <a-input placeholder="请输入刀具编号" v-model="queryParam.cutterCode" allow-clear/>
            </a-form-item>
          </a-col>
          <a-col :md="5" :sm="5">
            <a-form-item label="刀具名称">
              <a-input placeholder="请输入刀具名称" v-model="queryParam.cutterName" allow-clear/>
            </a-form-item>
          </a-col>
          <a-col :md="4" :sm="4">
            <a-space>
              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
              <a-button type="primary" @click="handleAdd" icon="plus" v-has="'cutter_add'">新增</a-button>
              <a-button type="primary" @click="handleExportXls('刀具列表')" icon="export">导出</a-button>
              <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader"
                        :action="importExcelUrl" @change="handleImportExcel">
                <a-button type="primary" icon="import">导入</a-button>
              </a-upload>
            </a-space>
          </a-col>
        </a-row>
      </a-form>
    </div>
    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination" :size="size" rowKey="id"
             @change="handleTableChange" :scroll="{y:189}">
      <template slot="action" slot-scope="text, record">
        <a @click="handleEdit(record)">编辑</a>
        <a-divider type="vertical"/>
        <a-dropdown>
          <a class="ant-dropdown-link">
            æ›´å¤š
            <a-icon type="down"/>
          </a>
          <a-menu slot="overlay">
            <a-menu-item>
              <a href="javascript:;" @click="handleDetail(record)">详情</a>
            </a-menu-item>
            <a-menu-item>
              <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
                <a>删除</a>
              </a-popconfirm>
            </a-menu-item>
          </a-menu>
        </a-dropdown>
      </template>
    </a-table>
    <CutterModal ref="cutterModalRef" :currentTreeNodeInfo="currentLevelInfo" @submitSuccess="loadData"/>
  </div>
</template>
<script>
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import CutterModal from '@views/dnc/base/modules/ProductStructure/Cutter/CutterModal.vue'
export default {
  name: 'CutterTableList',
  components: { CutterModal },
  mixins: [JeecgListMixin],
  props: {
    currentLevelInfo: {
      type: Object
    },
    size: {
      type: String
    }
  },
  data() {
    return {
      disableMixinCreated: true,
      columns: [
        {
          title: '序号',
          dataIndex: 'rowIndex',
          key: 'rowIndex',
          width: 65,
          align: 'center',
          customRender: function(t, r, index) {
            return parseInt(index) + 1
          }
        },
        { title: '刀具编号', dataIndex: 'cutterCode', align: 'center' },
        { title: '刀具名称', dataIndex: 'cutterName', align: 'center' },
        { title: '刀具类型', dataIndex: 'cutterType_dictText', align: 'center' },
        { title: '额定寿命', dataIndex: 'lifetime', width: 150, align: 'center' },
        { title: '刀位', dataIndex: 'cutterSpacing', width: 150, align: 'center' },
        { title: '刀具数量', dataIndex: 'quantity', width: 150, align: 'center' },
        { title: '操作', dataIndex: 'action', scopedSlots: { customRender: 'action' }, align: 'center', width: 150 }
      ],
      url: {
        list: '/nc/cutter/getByBusinessId',
        delete: '/nc/cutter/delete',
        exportXlsUrl: '/nc/cutter/exportXls',
        importExcelUrl: '/nc/cutter/importExcel'
      }
    }
  },
  computed: {
    importExcelUrl: function() {
      return `${window._CONFIG['domianURL']}${this.url.importExcelUrl}`
    }
  },
  methods: {
    setQueryParamAndLoadData(pageNo = 1) {
      const { id, type } = this.currentLevelInfo
      this.queryParam = Object.assign({}, { attributionId: id, attributionType: type })
      this.loadData(pageNo)
    },
    handleAdd() {
      if (!this.$refs.cutterModalRef) return
      this.$refs.cutterModalRef.title = '添加刀具'
      this.$refs.cutterModalRef.disableSubmit = false
      this.$refs.cutterModalRef.handleCutterAdd()
    },
    /**
     * ç¼–辑表格行信息
     * @param record è¡¨æ ¼è¡Œä¿¡æ¯
     */
    handleEdit(record) {
      if (!this.$refs.cutterModalRef) return
      this.$refs.cutterModalRef.title = '编辑刀具信息'
      this.$refs.cutterModalRef.disableSubmit = false
      this.$refs.cutterModalRef.handleCutterEdit(record)
    },
    /**
     * æŸ¥çœ‹è¡¨æ ¼å®Œæ•´è¡Œä¿¡æ¯
     * @param record è¡¨æ ¼è¡Œä¿¡æ¯
     */
    handleDetail: function(record) {
      if (!this.$refs.cutterModalRef) return
      this.$refs.cutterModalRef.title = '刀具详情'
      this.$refs.cutterModalRef.disableSubmit = true
      this.$refs.cutterModalRef.handleCutterEdit(record)
    }
  }
}
</script>
src/views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
<template>
  <j-modal
    :title="title"
    :width="width"
    :visible="visible"
    switchFullscreen
    :maskClosable="false"
    @ok="handleOk"
    @cancel="handleCancel"
    cancelText="关闭">
    <DeviceCustomTypeModalForm ref="realForm" @ok="handleCancel"/>
  </j-modal>
</template>
<script>
import DeviceCustomTypeModalForm from './DeviceCustomTypeModalForm'
export default {
  name: 'DeviceCustomTypeModal',
  components: {
    DeviceCustomTypeModalForm
  },
  data() {
    return {
      title: '',
      width: 700,
      visible: false
    }
  },
  created() {
    this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
  },
  methods: {
    // ç‚¹å‡»æ·»åŠ è®¾å¤‡ç±»æ–°å¢žå·¥åºæˆ–å·¥æ­¥ä¸‹è®¾å¤‡ç±»
    handleAddType(treeNodeInfo) {
      this.visible = true
      const { treeKey, type } = treeNodeInfo
      console.log('treeNodeInfo', treeNodeInfo)
      this.$nextTick(() => {
        if (this.$refs.realForm) {
          this.$refs.realForm.add({
            attributionId: treeKey,
            attributionType: type
          })
          this.$refs.realForm.getWorkshopListByApi()
        }
      })
    },
    // ç¼–辑设备类信息
    handleTypeEdit(_, tableRowInfo) {
      this.visible = true
      this.$nextTick(() => {
        if (this.$refs.realForm) {
          this.$refs.realForm.getWorkshopListByApi()
          this.$refs.realForm.handleProductionChange()
          this.$refs.realForm.edit({ ...tableRowInfo })
        }
      })
    },
    handleCancel() {
      this.visible = false
    },
    handleOk() {
      this.$refs.realForm.submitForm()
    },
    triggerCorrespondingMethod({ methodName, modalTitle, treeNodeInfo, tableRowInfo }) {
      console.log('触发右键菜单')
      if (this[methodName]) {
        this.title = modalTitle
        this[methodName](treeNodeInfo, tableRowInfo)
      }
    }
  }
}
</script>
src/views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModalForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,150 @@
<template>
  <a-spin :spinning="confirmLoading">
    <a-form-model ref="form" :model="model" :rules="validatorRules" :labelCol="labelCol" :wrapperCol="wrapperCol">
      <a-row>
        <a-col :span="12">
          <a-form-model-item label="车间" prop="productionId">
            <a-select v-model="model.productionId" placeholder="请选择车间" @change="handleProductionChange">
              <a-select-option v-for="item in workshopTreeData" :key="item.id">
                {{ item.productionName }}
              </a-select-option>
            </a-select>
          </a-form-model-item>
        </a-col>
        <a-col :span="12">
          <a-form-model-item label="设备类" prop="deviceManagementId">
            <a-select v-model="model.deviceManagementId" placeholder="请选择设备类" :disabled="!model.productionId"
                      @change="handleCodeSelectChange">
              <a-select-option v-for="item in deviceCustomTypeList" :key="item.id">
                {{ item.deviceManagementCode }}
              </a-select-option>
            </a-select>
          </a-form-model-item>
        </a-col>
      </a-row>
      <a-row>
        <a-col :span="12">
          <a-form-model-item label="设备类名称">
            <a-input v-model="model.deviceManagementId_dictText" placeholder="请选择设备类" readOnly/>
          </a-form-model-item>
        </a-col>
      </a-row>
    </a-form-model>
  </a-spin>
</template>
<script>
import { httpAction } from '@/api/manage'
import dncApi from '@/api/dnc'
export default {
  name: 'DeviceCustomTypeModalForm',
  components: {},
  data() {
    return {
      model: {},
      workshopTreeData: [],
      deviceCustomTypeList: [],
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 17 }
      },
      confirmLoading: false,
      validatorRules: {
        productionId: [
          { required: true, message: '请选择车间!' }
        ],
        deviceManagementId: [
          { required: true, message: '请选择设备类!' }
        ]
      },
      url: {
        add: '/nc/deviceType/add',
        edit: '/nc/deviceType/edit'
      }
    }
  },
  created() {
    //备份model原始值
    this.modelDefault = JSON.parse(JSON.stringify(this.model))
  },
  methods: {
    // è°ƒç”¨æŽ¥å£èŽ·å–æŸ¥è¯¢åŒºåŸŸè½¦é—´æ ‘åˆ—è¡¨
    getWorkshopListByApi() {
      dncApi.getHasPermissionWorkshopTreeApi()
        .then(res => {
          if (res.success) this.workshopTreeData = res.result
        })
    },
    // è½¦é—´é€‰æ‹©æ”¹å˜åŽæ¸…空设备类选择并重新获取设备类列表
    handleProductionChange() {
      if (this.model.deviceManagementId) delete this.model.deviceManagementId
      if (this.model.deviceManagementId_dictText) delete this.model.deviceManagementId_dictText
      dncApi.getDeviceCustomTypeListByProductionIdApi(this.model.productionId)
        .then(res => {
          if (res.success) this.deviceCustomTypeList = res.result
        })
    },
    /**
     * è®¾å¤‡ç±»é€‰æ‹©æ”¹å˜åŽè§¦å‘填充设备类对应设备类名称
     * @param value
     */
    handleCodeSelectChange(value) {
      this.$set(this.model, 'deviceManagementId_dictText', this.deviceCustomTypeList.find(item => item.id === value).deviceManagementName)
    },
    add(params) {
      this.edit({ ...this.modelDefault, ...params })
    },
    edit(record) {
      this.model = Object.assign({}, record)
    },
    submitForm() {
      const that = this
      // è§¦å‘表单验证
      this.$refs.form.validate(valid => {
        if (valid) {
          that.confirmLoading = true
          let httpUrl, method
          if (!this.model.id) {
            httpUrl = that.url.add
            method = 'post'
          } else {
            httpUrl = that.url.edit
            method = 'put'
          }
          httpAction(httpUrl, that.model, method)
            .then((res) => {
              if (res.success) {
                that.$notification.success({
                  message: '消息',
                  description: res.message
                })
                that.$bus.$emit('deviceCustomTypeAddSubmitSuccess')
                that.$emit('ok')
              } else {
                that.$notification.warning({
                  message: '消息',
                  description: res.message
                })
              }
            })
            .finally(() => {
              that.confirmLoading = false
            })
        }
      })
    }
  }
}
</script>
src/views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeTableList.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,167 @@
<template>
  <div style="flex: 0.25;margin-right: 10px">
    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false"
             :scroll="{y:189}" :customRow="customRow" :size="size" rowKey="id" @change="handleTableChange">
    </a-table>
  </div>
</template>
<script>
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import DeviceCustomTypeModal from '@views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModal.vue'
import { deleteAction } from '@api/manage'
export default {
  name: 'DeviceCustomTypeTableList',
  components: { DeviceCustomTypeModal },
  mixins: [JeecgListMixin],
  props: {
    currentTreeNodeInfo: {
      type: Object
    },
    size: {
      type: String
    }
  },
  data() {
    return {
      disableMixinCreated: true,
      columns: [
        // {
        //   title: '车间',
        //   dataIndex: 'productionId_dictText',
        //   align: 'center'
        // },
        {
          title: '设备类',
          dataIndex: 'deviceManagementCode_dictText',
          align: 'center'
        },
        {
          title: '设备类名称',
          dataIndex: 'deviceManagementId_dictText',
          align: 'center'
        }
      ],
      dataSource: [],
      currentRightClickedTypeInfo: {},
      currentClickedTypeInfo: {},
      url: {
        list: '/nc/deviceType/getByBusinessId',
        delete: '/nc/deviceType/delete'
      }
    }
  },
  watch: {
    currentTreeNodeInfo: {
      handler(value) {
        this.currentClickedTypeInfo = {}
      },
      immediate: true
    }
  },
  created() {
    this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    this.$bus.$on('deviceCustomTypeAddSubmitSuccess', this.loadData)
  },
  methods: {
    setQueryParamAndLoadData() {
      console.log('currentLevelInfo', this.currentTreeNodeInfo)
      const { id, type } = this.currentTreeNodeInfo
      this.queryParam = Object.assign({}, { attributionId: id, attributionType: type })
      this.loadData()
    },
    customRow(record) {
      return {
        on: {
          contextmenu: event => {
            event.preventDefault()
            this.currentRightClickedTypeInfo = Object.assign({ param: 'deviceCustomType' }, record)
            this.$emit('handleTableContextMenuOpen', this.currentRightClickedTypeInfo)
          },
          click: () => {
            if (this.currentClickedTypeInfo.docId === record.docId) return
            this.currentClickedTypeInfo = Object.assign({}, record)
            // this.$bus.$emit('sendCurrentClickedDocumentInfo', record)
          }
        }
      }
    },
    /**
     * è¡¨æ ¼åˆ†é¡µã€æŽ’序改变、筛选时触发
     * @param pagination åˆ†é¡µå™¨é€‰é¡¹
     * @param filters ç­›é€‰é€‰é¡¹
     * @param sorter æŽ’序选项
     */
    handleTableChange(pagination, filters, sorter) {
      if (sorter.order) {
        this.isorter.column = sorter.field
        this.isorter.order = sorter.order === 'ascend' ? 'asc' : 'desc'
      } else {
        this.isorter.column = 'createTime'
        this.isorter.order = 'desc'
      }
      for (let key in filters) {
        this.filters[key] = filters[key].join(',')
      }
      this.ipagination = pagination
      this.loadData()
    },
    /**
     * åˆ é™¤å·¥åºæˆ–工步层级添加的设备类
     * @param tableRowInfo
     */
    handleTypeDelete(tableRowInfo) {
      const { id } = tableRowInfo
      const { $confirm, url, loadData, $notification, $destroyAll } = this
      $confirm({
        title: '提示',
        content: '确认删除此条记录吗?',
        okText: '确认',
        okType: 'danger',
        cancelText: '取消',
        onOk: () => {
          if (!url.delete) {
            this.$message.error('请设置url.delete属性!')
            return
          }
          deleteAction(url.delete, { id: id })
            .then((res) => {
              if (res.success) {
                $notification.success({
                  message: '消息',
                  description: res.message
                })
                loadData()
              } else {
                $notification.warning({
                  message: '消息',
                  description: res.message
                })
              }
            })
            .finally(() => {
              $destroyAll()
            })
        },
        onCancel: () => {
          $destroyAll()
        }
      })
    },
    triggerCorrespondingMethod({ methodName, modalTitle, tableRowInfo }) {
      if (this[methodName] && tableRowInfo.param === 'deviceCustomType') this[methodName](tableRowInfo, modalTitle)
    }
  }
}
</script>
<style scoped>
</style>
src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
@@ -1,5 +1,5 @@
<template>
  <div>
  <div style="flex: 1">
    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
             :scroll="{y:189}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
src/views/dnc/base/modules/ProductStructure/Part/PartInfo.vue
@@ -1,6 +1,6 @@
<template>
  <a-descriptions bordered :size="size">
    <a-descriptions-item label="零件名称">{{currentLevelDetails.partsName}}</a-descriptions-item>
  <a-descriptions bordered :size="size" :column="4">
    <a-descriptions-item label="零件名称" :span="2">{{currentLevelDetails.partsName}}</a-descriptions-item>
    <a-descriptions-item label="零件代号">{{currentLevelDetails.partsCode}}</a-descriptions-item>
    <a-descriptions-item label="零件型号    ">{{currentLevelDetails.partsModel}}</a-descriptions-item>
    <a-descriptions-item label="物料编码">{{currentLevelDetails.materielCode}}</a-descriptions-item>
@@ -10,12 +10,12 @@
    <a-descriptions-item label="生产类型">{{currentLevelDetails.produceType}}</a-descriptions-item>
    <a-descriptions-item label="处理类型    ">{{currentLevelDetails.processType}}</a-descriptions-item>
    <a-descriptions-item label="结构类型    ">{{currentLevelDetails.structureType}}</a-descriptions-item>
    <a-descriptions-item label="重量" :span="2">{{currentLevelDetails.partsWeight}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createName}}</a-descriptions-item>
    <a-descriptions-item label="创建时间" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateName}}</a-descriptions-item>
    <a-descriptions-item label="修改时间" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="3">{{currentLevelDetails.description}}</a-descriptions-item>
    <a-descriptions-item label="重量">{{currentLevelDetails.partsWeight}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="创建时间">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="修改时间">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="4">{{currentLevelDetails.description}}</a-descriptions-item>
  </a-descriptions>
</template>
src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue
@@ -27,124 +27,123 @@
</template>
<script>
  import dncApi from '@/api/dnc'
  import DepartPermissionTransfer from './DepartPermissionTransfer'
  import UserPermissionTransfer from './UserPermissionTransfer'
  import { queryProductionTreeList } from '@/api/api'
import dncApi from '@/api/dnc'
import DepartPermissionTransfer from './DepartPermissionTransfer'
import UserPermissionTransfer from './UserPermissionTransfer'
  export default {
    name: 'AssignPermissionModal',
    components: { UserPermissionTransfer, DepartPermissionTransfer },
    props: {
      currentTreeNodeInfo: {
        type: Object
      }
    },
    data() {
      return {
        visible: false,
        title: '',
        isAssignSonNode: true,
        activeTabKey: 1,
        allDepartmentsList: [],
        allUsersList: [],
        allTreeKeys: [],
        hasLoadedDataTabKeyArray: []
      }
    },
    watch: {
      visible: {
        handler(value) {
          if (value) {
            this.activeTabKey = 1
            this.isAssignSonNode = true
            this.getAllDepartmentsListByApi()
          }
        }
      },
      activeTabKey: {
        handler(value) {
          if (this.hasLoadedDataTabKeyArray.includes(value)) return
          if (value === 2) this.getAllUsersListByApi()
          this.hasLoadedDataTabKeyArray.push(value)
export default {
  name: 'AssignPermissionModal',
  components: { UserPermissionTransfer, DepartPermissionTransfer },
  props: {
    currentTreeNodeInfo: {
      type: Object
    }
  },
  data() {
    return {
      visible: false,
      title: '',
      isAssignSonNode: true,
      activeTabKey: 1,
      allDepartmentsList: [],
      allUsersList: [],
      allTreeKeys: [],
      hasLoadedDataTabKeyArray: []
    }
  },
  watch: {
    visible: {
      handler(value) {
        if (value) {
          this.activeTabKey = 1
          this.isAssignSonNode = true
          this.getAllDepartmentsListByApi()
        }
      }
    },
    created() {
      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    activeTabKey: {
      handler(value) {
        if (this.hasLoadedDataTabKeyArray.includes(value)) return
        if (value === 2) this.getAllUsersListByApi()
        this.hasLoadedDataTabKeyArray.push(value)
      }
    }
  },
  created() {
    this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
  },
  methods: {
    // ç‚¹å‡»æ ‘节点右键菜单权限配置按钮后触发
    handleAssignPermission() {
      this.visible = true
    },
    methods: {
      // ç‚¹å‡»æ ‘节点右键菜单权限配置按钮后触发
      handleAssignPermission() {
        this.visible = true
      },
      // è°ƒç”¨æŽ¥å£èŽ·å–æ‰€æœ‰è½¦é—´åˆ—è¡¨
      getAllDepartmentsListByApi() {
        this.allTreeKeys = []
        queryProductionTreeList()
          .then(res => {
            if (res.success) {
              this.allDepartmentsList = res.result
              this.generateList(this.allDepartmentsList)
              this.$nextTick(() => {
                this.$refs.departPermissionTransferRef.getHasPermissionDepartByApi()
                this.$refs.departPermissionTransferRef.expandedKeys = this.allTreeKeys
                this.$refs.departPermissionTransferRef.flatten(JSON.parse(JSON.stringify(this.allDepartmentsList)))
              })
              // åªæœ‰ä¸Šæ¬¡é€€å‡ºæ—¶åœ¨è½¦é—´åˆ†é…tab界面才会进入此判断
              // è‹¥ä¸Šæ¬¡é€€å‡ºæ—¶åœ¨ç”¨æˆ·åˆ†é…tab界面则再次进入时key由2变为1时会触发watch监测activeTabKey变化则会将key:1加入hasLoadedDataTabKeyArray,因此无需再次加入key:1
              if (!this.hasLoadedDataTabKeyArray.includes(this.activeTabKey)) this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
            }
          })
      },
      /**
       * é€’归获得所有树节点key
       * @param data
       */
      generateList(data) {
        for (let i = 0; i < data.length; i++) {
          const node = data[i]
          const key = node.key
          this.allTreeKeys.push(key)
          if (node.children) this.generateList(node.children)
        }
      },
      // è°ƒç”¨æŽ¥å£èŽ·å–æ‰€æœ‰ç”¨æˆ·åˆ—è¡¨
      getAllUsersListByApi() {
        dncApi.getAllUsersListApi()
          .then(res => {
            if (res.success) {
              this.allUsersList = res.result.records
              this.$nextTick(() => this.$refs.userPermissionTransferRef.getHasPermissionUserByApi())
            }
          })
      },
      setAdminDisabled() {
        this.allUsersList = this.allUsersList.map(item => {
          return {
            ...item,
            disabled: item.username === 'admin'
    // è°ƒç”¨æŽ¥å£èŽ·å–æ‰€æœ‰è½¦é—´åˆ—è¡¨
    getAllDepartmentsListByApi() {
      this.allTreeKeys = []
      dncApi.getAllDepartmentsListApi()
        .then(res => {
          if (res.success) {
            this.allDepartmentsList = res.result
            this.generateList(this.allDepartmentsList)
            this.$nextTick(() => {
              this.$refs.departPermissionTransferRef.getHasPermissionDepartByApi()
              this.$refs.departPermissionTransferRef.expandedKeys = this.allTreeKeys
              this.$refs.departPermissionTransferRef.flatten(JSON.parse(JSON.stringify(this.allDepartmentsList)))
            })
            // åªæœ‰ä¸Šæ¬¡é€€å‡ºæ—¶åœ¨è½¦é—´åˆ†é…tab界面才会进入此判断
            // è‹¥ä¸Šæ¬¡é€€å‡ºæ—¶åœ¨ç”¨æˆ·åˆ†é…tab界面则再次进入时key由2变为1时会触发watch监测activeTabKey变化则会将key:1加入hasLoadedDataTabKeyArray,因此无需再次加入key:1
            if (!this.hasLoadedDataTabKeyArray.includes(this.activeTabKey)) this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
          }
        })
      },
    },
      handleModalClose() {
        this.visible = false
        this.hasLoadedDataTabKeyArray = []
      },
    /**
     * é€’归获得所有树节点key
     * @param data
     */
    generateList(data) {
      for (let i = 0; i < data.length; i++) {
        const node = data[i]
        const key = node.key
        this.allTreeKeys.push(key)
        if (node.children) this.generateList(node.children)
      }
    },
      triggerCorrespondingMethod({ methodName, modalTitle }) {
        if (this[methodName]) {
          this[methodName]()
          this.title = modalTitle
    // è°ƒç”¨æŽ¥å£èŽ·å–æ‰€æœ‰ç”¨æˆ·åˆ—è¡¨
    getAllUsersListByApi() {
      dncApi.getAllUsersListApi()
        .then(res => {
          if (res.success) {
            this.allUsersList = res.result.records
            this.$nextTick(() => this.$refs.userPermissionTransferRef.getHasPermissionUserByApi())
          }
        })
    },
    setAdminDisabled() {
      this.allUsersList = this.allUsersList.map(item => {
        return {
          ...item,
          disabled: item.username === 'admin'
        }
      })
    },
    handleModalClose() {
      this.visible = false
      this.hasLoadedDataTabKeyArray = []
    },
    triggerCorrespondingMethod({ methodName, modalTitle }) {
      if (this[methodName]) {
        this[methodName]()
        this.title = modalTitle
      }
    }
  }
}
</script>
<style scoped>
src/views/dnc/base/modules/ProductStructure/Process/ProcessInfo.vue
@@ -1,19 +1,19 @@
<template>
  <a-descriptions bordered :size="size">
    <a-descriptions-item label="工序名称">{{currentLevelDetails.processName}}</a-descriptions-item>
    <a-descriptions-item label="工序号">{{currentLevelDetails.processCode}}</a-descriptions-item>
    <a-descriptions-item label="工艺编号    ">{{currentLevelDetails.craftNo}}</a-descriptions-item>
  <a-descriptions bordered :size="size" :column="4">
    <a-descriptions-item label="工序名称" :span="2">{{currentLevelDetails.processName}}</a-descriptions-item>
    <a-descriptions-item label="工序号" :span="2">{{currentLevelDetails.processCode}}</a-descriptions-item>
    <a-descriptions-item label="工艺编号" :span="2">{{currentLevelDetails.craftNo}}</a-descriptions-item>
    <a-descriptions-item label="工序类型">{{currentLevelDetails.processType}}</a-descriptions-item>
    <a-descriptions-item label="加工设备型号">{{currentLevelDetails.processingEquipmentModel}}</a-descriptions-item>
    <a-descriptions-item label="加工设备类型">{{currentLevelDetails.processingEquipmentOs}}</a-descriptions-item>
    <a-descriptions-item label="加工设备编号">{{currentLevelDetails.processingEquipmentCode}}</a-descriptions-item>
    <a-descriptions-item label="工装编号">{{currentLevelDetails.assembleStep}}</a-descriptions-item>
    <a-descriptions-item label="工装名称    ">{{currentLevelDetails.assembleName}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createName}}</a-descriptions-item>
    <a-descriptions-item label="创建时间" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateName}}</a-descriptions-item>
    <a-descriptions-item label="修改时间" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="3">{{currentLevelDetails.description}}</a-descriptions-item>
    <a-descriptions-item label="工装名称">{{currentLevelDetails.assembleName}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="创建时间">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="修改时间">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="4">{{currentLevelDetails.description}}</a-descriptions-item>
  </a-descriptions>
</template>
src/views/dnc/base/modules/ProductStructure/Process/ProcessModalForm.vue
@@ -122,7 +122,6 @@
    created() {
      //备份model原始值
      this.modelDefault = JSON.parse(JSON.stringify(this.model))
      this.$bus.$on('sendAllDeviceList', deviceList => this.deviceList = deviceList)
    },
    methods: {
      add(params) {
src/views/dnc/base/modules/ProductStructure/ProcessStep/ProcessStepInfo.vue
@@ -1,5 +1,5 @@
<template>
  <a-descriptions bordered :size="size">
  <a-descriptions bordered :size="size" :column="4">
    <a-descriptions-item label="工步名称">{{currentLevelDetails.stepName}}</a-descriptions-item>
    <a-descriptions-item label="工步号">{{currentLevelDetails.stepCode}}</a-descriptions-item>
    <a-descriptions-item label="工步类型">{{currentLevelDetails.stepType}}</a-descriptions-item>
@@ -7,12 +7,12 @@
    <a-descriptions-item label="加工设备类型">{{currentLevelDetails.processingEquipmentOs}}</a-descriptions-item>
    <a-descriptions-item label="加工设备编号">{{currentLevelDetails.deviceNo}}</a-descriptions-item>
    <a-descriptions-item label="工装编号">{{currentLevelDetails.assembleStep}}</a-descriptions-item>
    <a-descriptions-item label="工装名称    " :span="2">{{currentLevelDetails.assembleName}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createName}}</a-descriptions-item>
    <a-descriptions-item label="创建时间" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateName}}</a-descriptions-item>
    <a-descriptions-item label="修改时间" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="3">{{currentLevelDetails.description}}</a-descriptions-item>
    <a-descriptions-item label="工装名称">{{currentLevelDetails.assembleName}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="创建时间">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="修改时间">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="描述" :span="4">{{currentLevelDetails.description}}</a-descriptions-item>
  </a-descriptions>
</template>
src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue
@@ -1,12 +1,12 @@
<template>
  <a-descriptions bordered :size="size">
    <a-descriptions-item label="名称">{{currentLevelDetails.productName}}</a-descriptions-item>
  <a-descriptions bordered :size="size" :column="4">
    <a-descriptions-item label="名称" :span="2">{{currentLevelDetails.productName}}</a-descriptions-item>
    <a-descriptions-item label="型号">{{currentLevelDetails.productModel}}</a-descriptions-item>
    <a-descriptions-item label="代码    ">{{currentLevelDetails.productNo}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createName}}</a-descriptions-item>
    <a-descriptions-item label="创建时间" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateName}}</a-descriptions-item>
    <a-descriptions-item label="修改时间" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
    <a-descriptions-item label="创建人">{{currentLevelDetails.createBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="创建时间">{{currentLevelDetails.createTime}}</a-descriptions-item>
    <a-descriptions-item label="修改人">{{currentLevelDetails.updateBy_dictText}}</a-descriptions-item>
    <a-descriptions-item label="修改时间">{{currentLevelDetails.updateTime}}</a-descriptions-item>
  </a-descriptions>
</template>
src/views/dnc/base/modules/ProductStructure/ProductStructureMain.vue
@@ -1,12 +1,12 @@
<template>
  <div style="height: 100%;max-height: 748px">
    <!--产品结构树右侧顶部区域-->
    <div style="height: 45%;overflow: hidden">
    <div style="height: 55%;overflow: hidden">
      <ProductStructureMainTop :size="tabContainerSize"/>
    </div>
    <!--产品结构树右侧底部区域-->
    <div style="height: 55%;overflow: hidden">
    <div style="height: 45%;overflow: hidden">
      <ProductStructureMainBottom :size="tabContainerSize"/>
    </div>
  </div>
src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue
@@ -1,6 +1,7 @@
<template>
  <div v-if="currentLevelInfo.type!==4">
    <a-tabs v-model="activeTabKey" v-if="Object.keys(currentLevelInfo).length>0" @change="handleTabChange">
  <div v-if="+currentLevelInfo.type!==4" style="height: 100%">
    <a-tabs style="height: 100%" v-model="activeTabKey" v-if="Object.keys(currentLevelInfo).length>0"
            @change="handleTabChange">
      <a-tab-pane :key="1" tab="属性信息" v-if="+currentLevelInfo.type===1">
        <ProductInfo :currentLevelDetails="currentLevelInfo.entity" :size="containerSize"/>
      </a-tab-pane>
@@ -21,8 +22,10 @@
        <ProcessStepInfo :currentLevelDetails="currentLevelInfo.entity" :size="containerSize"/>
      </a-tab-pane>
      <a-tab-pane :key="2" tab="刀具信息" v-if="+currentLevelInfo.type===5||+currentLevelInfo.type===6">
        <CutterInfo :currentLevelDetails="currentLevelInfo.entity" :size="containerSize"/>
      <!--系统参数配置中若参数为1时才展示对应层级的刀具列表-->
      <a-tab-pane :key="2" tab="刀具列表"
                  v-if="+currentLevelInfo.type===5&&isProcessHasCutterList||+currentLevelInfo.type===6&&isProcessStepHasCutterList">
        <CutterTableList ref="cutterTableListRef" :currentLevelInfo="currentLevelInfo" :size="containerSize"/>
      </a-tab-pane>
      <template v-if="currentLevelInfo.hasOwnProperty('attributionType')">
@@ -57,19 +60,19 @@
import ComponentInfo from './Component/ComponentInfo'
import PartInfo from './Part/PartInfo'
import ProcessInfo from './Process/ProcessInfo'
import ProcessStepInfo from './ProcessStep/ProcessStepInfo'
import CutterTableList from './Cutter/CutterTableList'
import DocumentInfo from '../../../common/DocumentInfo'
import DocumentVersionTableList from '../../../common/DocumentVersionTableList'
import UseDocumentEquipmentTableList from './Document/UseNcDocumentEquipmentTableList'
import ProcessStepInfo from './ProcessStep/ProcessStepInfo'
import FilePreview from '../../../common/FilePreview'
import TableContextMenu from '../../../common/TableContextMenu'
import CutterInfo from '@views/dnc/base/modules/ProductStructure/Cutter/CutterInfo.vue'
import dncApi from '@/api/dnc'
import { getAction } from '@/api/manage'
export default {
  name: 'ProductStructureMainBottom',
  components: {
    CutterInfo,
    CutterTableList,
    TableContextMenu,
    FilePreview,
    ProcessStepInfo,
@@ -85,6 +88,8 @@
    return {
      activeTabKey: 1,
      containerSize: 'small',
      isProcessHasCutterList: false,
      isProcessStepHasCutterList: false,
      currentLevelInfo: {},
      currentRightClickedTableRowInfo: {},
      hasLoadedDataTabKeyArray: []
@@ -94,30 +99,47 @@
    this.$bus.$on('sendCurrentClickedDocumentInfo', this.receiveCurrentLevelInfo)
    this.$bus.$on('sendCurrentTreeNodeInfo', this.receiveCurrentLevelInfo)
    this.$bus.$on('reloadMainBottomTableData', this.reloadMainBottomTableData)
    this.getCutterListDisplayPermission('dnc_cutter_process', 'isProcessHasCutterList')
    this.getCutterListDisplayPermission('dnc_cutter_step', 'isProcessStepHasCutterList')
  },
  methods: {
    /**
     * èŽ·å–åˆ€å…·åˆ—è¡¨åœ¨å·¥åºå’Œå·¥æ­¥å±‚çº§çš„å±•ç¤ºæƒé™
     * @param settingKey å„层级展示权限key
     * @param dataProperty ç»„ä»¶data中的属性值用来控制是否展示
     */
    getCutterListDisplayPermission(settingKey, dataProperty) {
      getAction(`/system/sysParams/query/by/settingKey?settingKey=${settingKey}`).then(res => {
        if (res.success) {
          this[dataProperty] = res.result.settingValue === '1'
        }
      })
    },
    /**
     * æŽ¥æ”¶æ ‘组件以及表格传来的当前选中或点击的项信息
     * @param levelInfo å½“前层级信息
     */
    receiveCurrentLevelInfo(levelInfo) {
      const { id, type } = levelInfo
      dncApi.getProductStructureTreeNodeEntityApi({ id, type })
        .then(res => {
          if (res.success) {
            console.log('res-------------', res)
            this.currentLevelInfo = Object.assign(levelInfo, { entity: res.result[0] })
          }
        })
      this.currentLevelInfo = levelInfo
      this.activeTabKey = 1
      this.hasLoadedDataTabKeyArray = []
    },
    /**
     * tab栏切换时触发
     * @param activeTabKey å½“前激活的tabKey
     */
    handleTabChange(activeTabKey) {
      if (!this.hasLoadedDataTabKeyArray.includes(activeTabKey)) {
        switch (activeTabKey) {
          case 2:
            this.$nextTick(() => this.$refs.filePreviewRef.getFilePreviewByApi())
            if (this.currentLevelInfo.hasOwnProperty('attributionType')) {
              console.log('ref', this.$refs.filePreviewRef)
              this.$nextTick(() => this.$refs.filePreviewRef.getFilePreviewByApi())
            } else {
              this.$nextTick(() => this.$refs.cutterTableListRef.setQueryParamAndLoadData(1))
            }
            break
          case 3:
            this.$nextTick(() => this.$refs.documentVersionTableRef.loadData())
@@ -172,6 +194,6 @@
}
/deep/ .ant-tabs-tabpane {
  overflow: auto;
  overflow: hidden auto;
}
</style>
src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
@@ -1,10 +1,18 @@
<template>
  <div v-if="currentTreeNodeInfo.type!==4">
  <div v-if="+currentTreeNodeInfo.type!==4">
    <a-tabs v-model="activeTabKey" @contextmenu.native="e=>e.preventDefault()" @change="handleTabChange"
            v-if="Object.keys(currentTreeNodeInfo).length!==0">
      <a-tab-pane :key="1" tab="NC文档" v-if="currentTreeNodeInfo.type===5||currentTreeNodeInfo.type===6">
        <NcDocumentTableList ref="ncDocumentTableListRef" :currentTreeNodeInfo="currentTreeNodeInfo"
                             @handleTableContextMenuOpen="handleTableContextMenuOpen" :size="tableContainerSize"/>
      <a-tab-pane :key="1" tab="NC管理" v-if="+currentTreeNodeInfo.type===5||+currentTreeNodeInfo.type===6">
        <div style="display: flex;">
          <!--系统参数配置中若参数为1时才展示对应层级的设备类列表-->
          <DeviceCustomTypeTableList
            v-if="+currentTreeNodeInfo.type===5&&isProcessHasDeviceTypeList||+currentTreeNodeInfo.type===6&&isProcessStepHasDeviceTypeList"
            ref="deviceCustomTypeTableList" :currentTreeNodeInfo="currentTreeNodeInfo"
            @handleTableContextMenuOpen="handleTableContextMenuOpen" :size="tableContainerSize"/>
          <NcDocumentTableList ref="ncDocumentTableListRef" :currentTreeNodeInfo="currentTreeNodeInfo"
                               @handleTableContextMenuOpen="handleTableContextMenuOpen" :size="tableContainerSize"/>
        </div>
      </a-tab-pane>
      <a-tab-pane :key="2" tab="其他文档">
@@ -21,398 +29,426 @@
</template>
<script>
  import dncApi from '@/api/dnc'
  import NcDocumentTableList from './Document/NcDocumentTableList'
  import OtherDocumentTableList from './Document/OtherDocumentTableList'
  import TableContextMenu from '../../../common/TableContextMenu'
  import DocumentBatchDeleteModal from '../../../common/DocumentBatchDeleteModal'
import dncApi from '@/api/dnc'
import NcDocumentTableList from './Document/NcDocumentTableList'
import OtherDocumentTableList from './Document/OtherDocumentTableList'
import TableContextMenu from '../../../common/TableContextMenu'
import DocumentBatchDeleteModal from '../../../common/DocumentBatchDeleteModal'
import DeviceCustomTypeTableList
  from '@views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeTableList.vue'
import { getAction } from '@api/manage'
  export default {
    name: 'ProductStructureMainTop',
    components: { DocumentBatchDeleteModal, TableContextMenu, OtherDocumentTableList, NcDocumentTableList },
    data() {
      return {
        activeTabKey: 2,
        tableContainerSize: 'small',
        currentRightClickedTableRowInfo: {},
        currentTreeNodeInfo: {},
        hasLoadedDataTabKeyArray: []
export default {
  name: 'ProductStructureMainTop',
  components: {
    DeviceCustomTypeTableList,
    DocumentBatchDeleteModal,
    TableContextMenu,
    OtherDocumentTableList,
    NcDocumentTableList
  },
  data() {
    return {
      activeTabKey: 2,
      tableContainerSize: 'small',
      isProcessHasDeviceTypeList: false,
      isProcessStepHasDeviceTypeList: false,
      currentRightClickedTableRowInfo: {},
      currentTreeNodeInfo: {},
      hasLoadedDataTabKeyArray: []
    }
  },
  created() {
    this.$bus.$on('sendCurrentTreeNodeInfo', this.receiveCurrentTreeNodeInfo)
    this.$bus.$on('reloadDocumentListData', this.reloadDocumentListData)
    this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    this.getDeviceTypeListDisplayPermission('dnc_device_type_process', 'isProcessHasDeviceTypeList')
    this.getDeviceTypeListDisplayPermission('dnc_device_type_step', 'isProcessStepHasDeviceTypeList')
  },
  methods: {
    /**
     * èŽ·å–è®¾å¤‡ç±»åž‹åˆ—è¡¨åœ¨å·¥åºå’Œå·¥æ­¥å±‚çº§çš„å±•ç¤ºæƒé™
     * @param settingKey å„层级展示权限key
     * @param dataProperty ç»„ä»¶data中的属性值用来控制是否展示
     */
    getDeviceTypeListDisplayPermission(settingKey, dataProperty) {
      getAction(`/system/sysParams/query/by/settingKey?settingKey=${settingKey}`).then(res => {
        if (res.success) {
          this[dataProperty] = res.result.settingValue === '1'
        }
      })
    },
    /**
     * æŽ¥æ”¶æ ‘组件传来的当前选中的树节点信息
     * @param treeNodeInfo æ ‘节点信息
     */
    receiveCurrentTreeNodeInfo(treeNodeInfo) {
      console.log('treeNodeInfo', treeNodeInfo)
      // ä»Žæ ‘组件接受树节点信息后从父组件流入子组件
      this.currentTreeNodeInfo = treeNodeInfo
      // æ¸…空上一节点已经加载过得文档列表tabKey
      this.hasLoadedDataTabKeyArray = []
      if (+treeNodeInfo.type === 5 || +treeNodeInfo.type === 6) {
        this.activeTabKey = 1
        this.$nextTick(() => {
          if (this.$refs.deviceCustomTypeTableList) this.$refs.deviceCustomTypeTableList.setQueryParamAndLoadData()
          else if (this.$refs.ncDocumentTableListRef) this.$refs.ncDocumentTableListRef.loadData(1)
        })
      } else {
        this.activeTabKey = 2
        this.$nextTick(() => {
          if (this.$refs.otherDocumentTableListRef) this.$refs.otherDocumentTableListRef.loadData(1)
        })
      }
      this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
    },
    /**
     * æŽ§åˆ¶å³é”®èœå•开启
     * @param record å½“前表格行信息
     */
    handleTableContextMenuOpen(record) {
      this.currentRightClickedTableRowInfo = Object.assign({}, record)
      console.log('currentRightClickedTableRowInfo', this.currentRightClickedTableRowInfo)
      this.$refs.tableContextMenuRef.currentMenuLevel = record.param
      this.$refs.tableContextMenuRef.menuStyle.top = event.clientY + 'px'
      this.$refs.tableContextMenuRef.menuStyle.left = event.clientX + 'px'
      this.$refs.tableContextMenuRef.menuVisible = true
      document.body.addEventListener('click', this.handleMenuClose)
    },
    /**
     * tab栏切换时触发
     * @param activeTabKey åˆ‡æ¢åŽçš„tabKey
     */
    handleTabChange(activeTabKey) {
      if (!this.hasLoadedDataTabKeyArray.includes(activeTabKey)) {
        this.$nextTick(() => {
          if (this.$refs.otherDocumentTableListRef) this.$refs.otherDocumentTableListRef.loadData(1)
        })
        // é˜»æ­¢æŽ¥å£åœ¨åŒä¸€æ–‡æ¡£ä¸€æ¬¡ç‚¹å‡»å†…多次触发
        this.hasLoadedDataTabKeyArray.push(activeTabKey)
      }
    },
    created() {
      this.$bus.$on('sendCurrentTreeNodeInfo', this.receiveCurrentTreeNodeInfo)
      this.$bus.$on('reloadDocumentListData', this.reloadDocumentListData)
      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    /**
     * æ–‡æ¡£ä»¥åŠNC程序导入/出库/入库成功后触发重新加载文档列表
     * @param docClassCode æ–‡æ¡£ç±»åˆ«
     * @param attributionId èŠ‚ç‚¹Id
     */
    reloadDocumentListData({ docClassCode, attributionId }) {
      // å¦‚果上传的文档不是所属于当前所展示节点的文档则不重新获取文档列表
      if (this.currentTreeNodeInfo.id !== attributionId) return
      if (docClassCode === 'NC') {
        if (this.$refs.ncDocumentTableListRef) this.$refs.ncDocumentTableListRef.loadData(1)
      } else {
        if (this.$refs.otherDocumentTableListRef) this.$refs.otherDocumentTableListRef.loadData(1)
      }
    },
    methods: {
      /**
       * æŽ§åˆ¶å³é”®èœå•开启
       * @param record å½“前表格行信息
       */
      handleTableContextMenuOpen(record) {
        this.currentRightClickedTableRowInfo = Object.assign({}, record)
        console.log('currentRightClickedTableRowInfo', this.currentRightClickedTableRowInfo)
        this.$refs.tableContextMenuRef.currentMenuLevel = record.param
        this.$refs.tableContextMenuRef.menuStyle.top = event.clientY + 'px'
        this.$refs.tableContextMenuRef.menuStyle.left = event.clientX + 'px'
        this.$refs.tableContextMenuRef.menuVisible = true
        document.body.addEventListener('click', this.handleMenuClose)
      },
      /**
       * æŽ¥æ”¶æ ‘组件传来的当前选中的树节点信息
       * @param treeNodeInfo æ ‘节点信息
       */
      receiveCurrentTreeNodeInfo(treeNodeInfo) {
        // ä»Žæ ‘组件接受树节点信息后从父组件流入子组件
        this.currentTreeNodeInfo = treeNodeInfo
        // æ¸…空上一节点已经加载过得文档列表tabKey
        this.hasLoadedDataTabKeyArray = []
        if (treeNodeInfo.type === 5 || treeNodeInfo.type === 6) {
          this.activeTabKey = 1
          this.$nextTick(() => {
            if (this.$refs.ncDocumentTableListRef) this.$refs.ncDocumentTableListRef.loadData(1)
          })
        } else {
          this.activeTabKey = 2
          this.$nextTick(() => {
            if (this.$refs.otherDocumentTableListRef) this.$refs.otherDocumentTableListRef.loadData(1)
          })
        }
        this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
      },
      /**
       * tab栏切换时触发
       * @param activeTabKey åˆ‡æ¢åŽçš„tabKey
       */
      handleTabChange(activeTabKey) {
        if (!this.hasLoadedDataTabKeyArray.includes(activeTabKey)) {
          this.$nextTick(() => {
            if (this.$refs.otherDocumentTableListRef) this.$refs.otherDocumentTableListRef.loadData(1)
          })
          // é˜»æ­¢æŽ¥å£åœ¨åŒä¸€æ–‡æ¡£ä¸€æ¬¡ç‚¹å‡»å†…多次触发
          this.hasLoadedDataTabKeyArray.push(activeTabKey)
        }
      },
      /**
       * æ–‡æ¡£ä»¥åŠNC程序导入/出库/入库成功后触发重新加载文档列表
       * @param docClassCode æ–‡æ¡£ç±»åˆ«
       * @param attributionId èŠ‚ç‚¹Id
       */
      reloadDocumentListData({ docClassCode, attributionId }) {
        // å¦‚果上传的文档不是所属于当前所展示节点的文档则不重新获取文档列表
        if (this.currentTreeNodeInfo.id !== attributionId) return
        if (docClassCode === 'NC') {
          if (this.$refs.ncDocumentTableListRef) this.$refs.ncDocumentTableListRef.loadData(1)
        } else {
          if (this.$refs.otherDocumentTableListRef) this.$refs.otherDocumentTableListRef.loadData(1)
        }
      },
      // ä¸‹è½½å½“前右键选中文档
      handleDownload() {
        const that = this
        const { docId, docName } = this.currentRightClickedTableRowInfo
        dncApi.downloadDocumentApi({ docId, docName })
          .then(res => {
            if (res && !res.success) {
              that.$notification.error({
                message: '消息',
                description: res.message
              })
            }
          })
          .catch(err => {
    // ä¸‹è½½å½“前右键选中文档
    handleDownload() {
      const that = this
      const { docId, docName } = this.currentRightClickedTableRowInfo
      dncApi.downloadDocumentApi({ docId, docName })
        .then(res => {
          if (res && !res.success) {
            that.$notification.error({
              message: '消息',
              description: err.message
              description: res.message
            })
          }
        })
        .catch(err => {
          that.$notification.error({
            message: '消息',
            description: err.message
          })
      },
      // åˆ é™¤å½“前右键选中文档
      handleDelete() {
        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
        const that = this
        that.$confirm({
          title: '提示',
          content: `删除后不可取消,确认删除吗?`,
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            dncApi.deleteDocumentApi(docId)
              .then((res) => {
                if (res.success) {
                  that.$notification.success({
                    message: '消息',
                    description: res.message
                  })
                  that.reloadDocumentListData({ docClassCode: param, attributionId })
                } else {
                  that.$notification.warning({
                    message: '消息',
                    description: res.message
                  })
                }
              })
              .finally(() => {
                that.$destroyAll()
              })
          },
          onCancel: () => {
            that.$destroyAll()
          }
        })
      },
    },
      /**
       * ç‚¹å‡»æ‰¹é‡åˆ é™¤åŽå‡ºçŽ°å¼¹çª—
       * @param modalTitle å¼¹çª—标题
       */
      handleBatchRemove(modalTitle) {
        if (!this.$refs.documentBatchDeleteModalRef) return
        this.$refs.documentBatchDeleteModalRef.title = modalTitle
        this.$refs.documentBatchDeleteModalRef.visible = true
      },
    // åˆ é™¤å½“前右键选中文档
    handleDelete() {
      const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
      const that = this
      that.$confirm({
        title: '提示',
        content: `删除后不可取消,确认删除吗?`,
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          dncApi.deleteDocumentApi(docId)
            .then((res) => {
              if (res.success) {
                that.$notification.success({
                  message: '消息',
                  description: res.message
                })
                that.reloadDocumentListData({ docClassCode: param, attributionId })
              } else {
                that.$notification.warning({
                  message: '消息',
                  description: res.message
                })
              }
            })
            .finally(() => {
              that.$destroyAll()
            })
        },
        onCancel: () => {
          that.$destroyAll()
        }
      })
    },
      /**
       * å‡ºåº“当前右键选中文档
       * @param menuLabel
       */
      handlePull(menuLabel) {
        const that = this
        const { docId, docName, param, attributionId } = this.currentRightClickedTableRowInfo
        that.$confirm({
          title: '提示',
          content: `确认${menuLabel}吗?`,
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            dncApi.documentOutboundApi({ docId, docName })
              .then(res => {
                console.log('res------------------', res)
                if (res.success) {
                  that.reloadDocumentListData({ docClassCode: param, attributionId })
                  that.$notification.success({
                    message: '消息',
                    description: `${menuLabel}成功`
                  })
                } else {
                  that.$notification.error({
                    message: '消息',
                    description: res.message
                  })
                }
              })
              .catch(err => {
    /**
     * ç‚¹å‡»æ‰¹é‡åˆ é™¤åŽå‡ºçŽ°å¼¹çª—
     * @param modalTitle å¼¹çª—标题
     */
    handleBatchRemove(modalTitle) {
      if (!this.$refs.documentBatchDeleteModalRef) return
      this.$refs.documentBatchDeleteModalRef.title = modalTitle
      this.$refs.documentBatchDeleteModalRef.visible = true
    },
    /**
     * å‡ºåº“当前右键选中文档
     * @param menuLabel
     */
    handlePull(menuLabel) {
      const that = this
      const { docId, docName, param, attributionId } = this.currentRightClickedTableRowInfo
      that.$confirm({
        title: '提示',
        content: `确认${menuLabel}吗?`,
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          dncApi.documentOutboundApi({ docId, docName })
            .then(res => {
              console.log('res------------------', res)
              if (res.success) {
                that.reloadDocumentListData({ docClassCode: param, attributionId })
                that.$notification.success({
                  message: '消息',
                  description: `${menuLabel}成功`
                })
              } else {
                that.$notification.error({
                  message: '消息',
                  description: err.message
                  description: res.message
                })
              }
            })
            .catch(err => {
              that.$notification.error({
                message: '消息',
                description: err.message
              })
              .finally(() => {
                that.$destroyAll()
              })
          },
          onCancel: () => {
            that.$destroyAll()
          }
        })
      },
            })
            .finally(() => {
              that.$destroyAll()
            })
        },
        onCancel: () => {
          that.$destroyAll()
        }
      })
    },
      /**
       * å–消出库当前右键选中文档
       * @param menuLabel
       */
      handleCancelPull(menuLabel) {
        const that = this
        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
        that.$confirm({
          title: '提示',
          content: `确认${menuLabel}吗?`,
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            dncApi.documentCancelOutboundApi(docId)
              .then(res => {
                if (res.success) {
                  this.reloadDocumentListData({ docClassCode: param, attributionId })
                  that.$notification.success({
                    message: '消息',
                    description: res.message
                  })
                } else {
                  that.$notification.error({
                    message: '消息',
                    description: res.message
                  })
                }
              })
              .catch(err => {
    /**
     * å–消出库当前右键选中文档
     * @param menuLabel
     */
    handleCancelPull(menuLabel) {
      const that = this
      const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
      that.$confirm({
        title: '提示',
        content: `确认${menuLabel}吗?`,
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          dncApi.documentCancelOutboundApi(docId)
            .then(res => {
              if (res.success) {
                this.reloadDocumentListData({ docClassCode: param, attributionId })
                that.$notification.success({
                  message: '消息',
                  description: res.message
                })
              } else {
                that.$notification.error({
                  message: '消息',
                  description: err.message
                  description: res.message
                })
              }
            })
            .catch(err => {
              that.$notification.error({
                message: '消息',
                description: err.message
              })
              .finally(() => {
                that.$destroyAll()
              })
          },
          onCancel() {
            that.$destroyAll()
          }
        })
      },
            })
            .finally(() => {
              that.$destroyAll()
            })
        },
        onCancel() {
          that.$destroyAll()
        }
      })
    },
      /**
       * å‘布当前右键选中文档
       * @param menuLabel
       */
      handlePublish(menuLabel) {
        const that = this
        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
        that.$confirm({
          title: '提示',
          content: `确认${menuLabel}吗?`,
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            dncApi.documentPublishApi(docId)
              .then(res => {
                if (res.success) {
                  this.reloadDocumentListData({ docClassCode: param, attributionId })
                  this.$bus.$emit('reloadMainBottomTableData', 'documentVersion')
                  that.$notification.success({
                    message: '消息',
                    description: res.message
                  })
                } else {
                  that.$notification.error({
                    message: '消息',
                    description: res.message
                  })
                }
              })
              .catch(err => {
    /**
     * å‘布当前右键选中文档
     * @param menuLabel
     */
    handlePublish(menuLabel) {
      const that = this
      const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
      that.$confirm({
        title: '提示',
        content: `确认${menuLabel}吗?`,
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          dncApi.documentPublishApi(docId)
            .then(res => {
              if (res.success) {
                this.reloadDocumentListData({ docClassCode: param, attributionId })
                this.$bus.$emit('reloadMainBottomTableData', 'documentVersion')
                that.$notification.success({
                  message: '消息',
                  description: res.message
                })
              } else {
                that.$notification.error({
                  message: '消息',
                  description: err.message
                  description: res.message
                })
              }
            })
            .catch(err => {
              that.$notification.error({
                message: '消息',
                description: err.message
              })
              .finally(() => {
                that.$destroyAll()
              })
          },
          onCancel() {
            that.$destroyAll()
          }
        })
      },
            })
            .finally(() => {
              that.$destroyAll()
            })
        },
        onCancel() {
          that.$destroyAll()
        }
      })
    },
      /**
       * é‡æ–°å‘布当前右键选中文档并重新发布退回上一文档版本
       * @param menuLabel
       */
      handleRepublish(menuLabel) {
        const that = this
        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
        that.$confirm({
          title: '提示',
          content: `确认${menuLabel}吗?`,
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            dncApi.documentRepublishApi(docId)
              .then(res => {
                if (res.success) {
                  this.reloadDocumentListData({ docClassCode: param, attributionId })
                  that.$notification.success({
                    message: '消息',
                    description: res.message
                  })
                } else {
                  that.$notification.error({
                    message: '消息',
                    description: res.message
                  })
                }
              })
              .catch(err => {
    /**
     * é‡æ–°å‘布当前右键选中文档并重新发布退回上一文档版本
     * @param menuLabel
     */
    handleRepublish(menuLabel) {
      const that = this
      const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
      that.$confirm({
        title: '提示',
        content: `确认${menuLabel}吗?`,
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          dncApi.documentRepublishApi(docId)
            .then(res => {
              if (res.success) {
                this.reloadDocumentListData({ docClassCode: param, attributionId })
                that.$notification.success({
                  message: '消息',
                  description: res.message
                })
              } else {
                that.$notification.error({
                  message: '消息',
                  description: err.message
                  description: res.message
                })
              }
            })
            .catch(err => {
              that.$notification.error({
                message: '消息',
                description: err.message
              })
              .finally(() => {
                that.$destroyAll()
              })
          },
          onCancel() {
            that.$destroyAll()
          }
        })
      },
            })
            .finally(() => {
              that.$destroyAll()
            })
        },
        onCancel() {
          that.$destroyAll()
        }
      })
    },
      /**
       * é‡å½’档当前右键选中文档且后续无法继续发布或归档
       * @param menuLabel
       */
      handlePigeonhole(menuLabel) {
        const that = this
        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
        that.$confirm({
          title: '提示',
          content: `${menuLabel}后不可取消,确认${menuLabel}吗?`,
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            dncApi.documentPigeonholeApi(docId)
              .then(res => {
                if (res.success) {
                  this.reloadDocumentListData({ docClassCode: param, attributionId })
                  that.$notification.success({
                    message: '消息',
                    description: res.message
                  })
                } else {
                  that.$notification.error({
                    message: '消息',
                    description: res.message
                  })
                }
              })
              .catch(err => {
    /**
     * é‡å½’档当前右键选中文档且后续无法继续发布或归档
     * @param menuLabel
     */
    handlePigeonhole(menuLabel) {
      const that = this
      const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
      that.$confirm({
        title: '提示',
        content: `${menuLabel}后不可取消,确认${menuLabel}吗?`,
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          dncApi.documentPigeonholeApi(docId)
            .then(res => {
              if (res.success) {
                this.reloadDocumentListData({ docClassCode: param, attributionId })
                that.$notification.success({
                  message: '消息',
                  description: res.message
                })
              } else {
                that.$notification.error({
                  message: '消息',
                  description: err.message
                  description: res.message
                })
              }
            })
            .catch(err => {
              that.$notification.error({
                message: '消息',
                description: err.message
              })
              .finally(() => {
                that.$destroyAll()
              })
          },
          onCancel() {
            that.$destroyAll()
          }
        })
      },
            })
            .finally(() => {
              that.$destroyAll()
            })
        },
        onCancel() {
          that.$destroyAll()
        }
      })
    },
      // æŽ§åˆ¶å³é”®èœå•关闭
      handleMenuClose() {
        this.$refs.tableContextMenuRef.menuVisible = false
        document.body.removeEventListener('click', this.handleMenuClose)
      },
    // æŽ§åˆ¶å³é”®èœå•关闭
    handleMenuClose() {
      this.$refs.tableContextMenuRef.menuVisible = false
      document.body.removeEventListener('click', this.handleMenuClose)
    },
      triggerCorrespondingMethod({ methodName, modalTitle }) {
        if (this[methodName]) this[methodName](modalTitle)
      }
    triggerCorrespondingMethod({ methodName, modalTitle }) {
      if (this[methodName]) this[methodName](modalTitle)
    }
  }
}
</script>
<style scoped>
  /deep/ .ant-table-tbody .ant-table-row {
    cursor: pointer;
  }
/deep/ .ant-table-tbody .ant-table-row {
  cursor: pointer;
}
</style>
src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
@@ -2,24 +2,26 @@
  <a-card class="tree_con" :loading="cardLoading" :bordered="false" @contextmenu.native="e=>e.preventDefault()">
    <a-spin :spinning="loading">
      <div style="display: flex;flex-direction: column;height: 100%">
        <div style="display: flex">
        <div style="display: flex;justify-content: space-between">
          <a-input placeholder="输入关键字进行搜索" allowClear v-model="searchInput"
                   @change="handleSearchInputChange"/>
          <a-dropdown :trigger="['click']" placement="bottomCenter" style="margin: 0 8px">
            <a-menu slot="overlay">
              <a-menu-item key="1" @click="expandedKeys = allTreeKeys">展开所有</a-menu-item>
              <a-menu-item key="2" @click="expandedKeys = ['-1']">合并所有</a-menu-item>
              <a-menu-item key="3" @click="getTreeDataByApi">刷新</a-menu-item>
            </a-menu>
            <a-button>
              <a-icon type="bars"/>
            </a-button>
          </a-dropdown>
          <a-button type="primary" v-has="'product_add'"
          <a-tooltip title="刷新">
            <a-button icon="reload" @click="getTreeDataByApi" style="width: 18%;margin-left: 8px"></a-button>
          </a-tooltip>
          <a-button type="primary" v-has="'product_add'" icon="plus" style="margin-left: 8px"
                    @click="$refs.productModalFormRef.triggerCorrespondingMethod({modalTitle:'添加产品',methodName:'handleProductAdd'})">
            <a-icon type="plus"></a-icon>
            äº§å“
            æ·»åŠ äº§å“
          </a-button>
          <!--          <a-dropdown :trigger="['click']" placement="bottomCenter" style="margin: 0 8px">-->
          <!--            <a-menu slot="overlay">-->
          <!--              <a-menu-item key="1" @click="expandedKeys = allTreeKeys">展开所有</a-menu-item>-->
          <!--              <a-menu-item key="2" @click="expandedKeys = ['-1']">合并所有</a-menu-item>-->
          <!--              <a-menu-item key="3" @click="getTreeDataByApi">刷新</a-menu-item>-->
          <!--            </a-menu>-->
          <!--            <a-button>-->
          <!--              <a-icon type="bars"/>-->
          <!--            </a-button>-->
          <!--          </a-dropdown>-->
        </div>
        <!--产品结构树-->
@@ -27,9 +29,9 @@
          <a-tree blockNode show-icon :expandedKeys.sync="expandedKeys"
                  :selectedKeys="selectedKeys" :treeData="treeDataSource" :autoExpandParent="autoExpandParent"
                  @select="handleTreeSelect" @expand="handleTreeExpand" @rightClick="handleTreeRightClick">
            <template slot="title" slot-scope="{ label, parentId, entity, key:treeKey,type}">
            <template slot="title" slot-scope="{ label, parentId, key:treeKey,type}">
              <ProductStructureTreeContextMenu ref="contextMenuRef"
                                               :treeParams="{label,treeKey,searchValue,type,entity}"/>
                                               :treeParams="{label,treeKey,searchValue,type}"/>
            </template>
            <a-icon slot="switcherIcon" type="down"/>
@@ -73,10 +75,12 @@
import ProcessModal from './Process/ProcessModal'
import ProcessStepModal from './ProcessStep/ProcessStepModal'
import AssignPermissionModal from './Permission/AssignPermissionModal'
import DeviceCustomTypeModal from '@views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModal.vue'
export default {
  name: 'ProductStructureTree',
  components: {
    DeviceCustomTypeModal,
    AssignPermissionModal,
    ProcessStepModal,
    ProcessModal,
@@ -100,7 +104,6 @@
      autoExpandParent: true,
      checkStrictly: true,
      allTreeKeys: [],
      currentSelected: {},
      rightClickSelected: {},
      url: {
        delete: '/nc/product/delete'
@@ -115,10 +118,10 @@
    getTreeDataByApi() {
      this.loading = true
      this.cardLoading = true
      this.treeDataSource = []
      dncApi.getProductStructureTreeApi()
        .then(res => {
          if (res.success) {
            console.log('res=================', res)
            this.dataList = []
            this.allTreeKeys = []
            this.treeDataSource = res.result
@@ -140,22 +143,62 @@
     * @param {node} node èŠ‚ç‚¹å¯¹è±¡
     */
    handleTreeSelect(selectedKeys, { node }) {
      const that = this
      let record = node.dataRef
      this.currentSelected = Object.assign({}, record)
      // å‘右侧父级组件发送当前选中树节点信息
      this.$bus.$emit('sendCurrentTreeNodeInfo', this.currentSelected)
      const { id, type } = record
      dncApi.getProductStructureTreeNodeEntityApi({ id, type })
        .then(res => {
          if (res.success) {
            let currentSelectedNodeInfo
            if (res.result.length > 0) {
              currentSelectedNodeInfo = Object.assign({}, record, { entity: res.result[0] })
            } else {
              currentSelectedNodeInfo = {}
              that.$notification.warning({
                message: '消息',
                description: '暂无该节点详细信息'
              })
            }
            // å‘右侧父级组件发送当前选中树节点信息
            this.$bus.$emit('sendCurrentTreeNodeInfo', currentSelectedNodeInfo)
          } else {
            that.$notification.error({
              message: '消息',
              description: res.message
            })
          }
        })
      if (selectedKeys.length === 0) return
      this.selectedKeys = selectedKeys
    },
    /**
     * æ ‘节点右键单击节点时触发
     * @param event äº‹ä»¶å¯¹è±¡
     * @param node èŠ‚ç‚¹å¯¹è±¡
     */
    handleTreeRightClick({ event, node }) {
    handleTreeRightClick({ node }) {
      const that = this
      const record = node.dataRef
      this.rightClickSelected = Object.assign({}, record)
      const { id, type } = record
      dncApi.getProductStructureTreeNodeEntityApi({ id, type })
        .then(res => {
          if (res.success) {
            if (res.result.length > 0) {
              that.rightClickSelected = Object.assign({}, record, { entity: res.result[0] })
            } else {
              that.rightClickSelected = {}
              that.$notification.warning({
                message: '消息',
                description: '暂无该节点详细信息'
              })
            }
          } else {
            that.$notification.error({
              message: '消息',
              description: res.message
            })
          }
        })
    },
    // æ ‘节点右键单击菜单中删除按钮时触发
@@ -216,8 +259,18 @@
      this.autoExpandParent = false
    },
    /* è¾“入查询内容变化时触发 */
    // è¾“入查询内容变化时触发(增加防抖机制)
    handleSearchInputChange() {
      const that = this
      let timer
      if (timer) clearTimeout(timer)
      timer = setTimeout(function() {
        that.searchAndExpandTreeNode() // åŠ å°æ‹¬å·è°ƒç”¨å‡½æ•°
      }, 1000)
    },
    // é˜²æŠ–函数中触发搜索并展开树节点
    searchAndExpandTreeNode() {
      let search = this.searchInput
      let expandedKeys
      let autoExpandParent
@@ -237,7 +290,6 @@
        expandedKeys = this.beforeSearchExpandedKeys
        autoExpandParent = false
      }
      Object.assign(this, {
        expandedKeys,
        searchValue: search,
@@ -292,7 +344,7 @@
     * @param treeNode
     */
    setTreeNodeIcon(treeNode) {
      switch (treeNode.type) {
      switch (+treeNode.type) {
        case 1:
          treeNode.slots = { icon: 'product' }
          break
src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue
@@ -1,14 +1,20 @@
<template>
  <a-dropdown :trigger="['contextmenu']">
    <span v-if="treeParams.label.indexOf(treeParams.searchValue) > -1">{{ treeParams.label.substr(0, treeParams.label.indexOf(treeParams.searchValue)) }}<span
      class="replaceSearch">{{ treeParams.searchValue }}</span>{{ treeParams.label.substr(treeParams.label.indexOf(treeParams.searchValue) + treeParams.searchValue.length) }}</span>
    <span v-if="treeParams.label.indexOf(treeParams.searchValue) > -1">{{
        treeParams.label.substr(0, treeParams.label.indexOf(treeParams.searchValue))
      }}<span
        class="replaceSearch">{{
          treeParams.searchValue
        }}</span>{{
        treeParams.label.substr(treeParams.label.indexOf(treeParams.searchValue) + treeParams.searchValue.length)
      }}</span>
    <span v-else>{{ treeParams.label }}</span>
    <template #overlay>
      <a-menu @click="({ key: menuKey }) => onContextMenuClick(treeParams.treeKey, menuKey)"
              @contextmenu="event=>event.preventDefault()">
        <a-menu-item v-for="item in defaultContextMenuList[getCurrentMenuLevel]" :key="item.code" v-has="item.code">
          <a-icon :type="item.icon"/>
          {{item.label}}
          {{ item.label }}
        </a-menu-item>
      </a-menu>
    </template>
@@ -16,141 +22,144 @@
</template>
<script>
  export default {
    name: 'ProductStructureTreeContextMenu',
    components: {},
    props: {
      treeParams: {
        type: Object
      }
    },
    data() {
      return {
        defaultContextMenuList: {
          //产品
          product: [
            { label: '添加产品', code: 'product_add', icon: 'plus', isCommonMethod: false },
            { label: '添加部件', code: 'product_add_child', icon: 'plus', isCommonMethod: false },
            { label: '编辑产品信息', code: 'product_edit', icon: 'edit', isCommonMethod: false },
            // {  label: '导出文档', code: 'product_export', icon: 'export', isCommonMethod: true },
            { label: '导入其他文档', code: 'product_import', icon: 'import', isCommonMethod: true },
            { label: '删除', code: 'product_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //部件
          component: [
            { label: '添加子部件', code: 'component_add', icon: 'plus', isCommonMethod: false },
            { label: '添加零件', code: 'component_add_child', icon: 'plus', isCommonMethod: false },
            { label: '创建工序', code: 'component_add_relative', icon: 'plus', isCommonMethod: false },
            { label: '编辑部件信息', code: 'component_edit', icon: 'edit', isCommonMethod: false },
            // {  label: '导出文档', code: 'component_export', icon: 'export', isCommonMethod: true },
            { label: '导入其他文档', code: 'component_import', icon: 'import', isCommonMethod: true },
            { label: '删除', code: 'component_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //零件
          part: [
            { label: '添加零件', code: 'parts_add', icon: 'plus', isCommonMethod: false },
            { label: '创建工艺规程版本', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
            // { label: '创建工序', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
            { label: '编辑零件信息', code: 'parts_edit', icon: 'edit', isCommonMethod: false },
            // {  label: '导出文档', code: 'parts_export', icon: 'export', isCommonMethod: true },
            { label: '导入其他文档', code: 'parts_import', icon: 'import', isCommonMethod: true },
            { label: '删除', code: 'parts_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //工艺规程版本
          processSpecVersion: [
            { label: '创建工艺规程版本', code: 'version_add', icon: 'plus', isCommonMethod: false },
            { label: '创建工序', code: 'version_add_child', icon: 'plus', isCommonMethod: false },
            { label: '编辑工艺规程版本信息', code: 'version_edit', icon: 'edit', isCommonMethod: false },
            { label: '删除', code: 'version_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //工序
          process: [
            { label: '创建工序', code: 'process_add', icon: 'plus', isCommonMethod: false },
            { label: '创建工步', code: 'process_add_child', icon: 'plus', isCommonMethod: false },
            { label: '编辑工序信息', code: 'process_edit', icon: 'edit', isCommonMethod: false },
            { label: '删除', code: 'process_delete', icon: 'delete', isCommonMethod: true },
            // {  label: '导出NC程序', code: 'process_export', icon: 'export', isCommonMethod: true },
            { label: '导入NC程序', code: 'process_import', icon: 'import', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //工步
          processStep: [
            { label: '创建工步', code: 'processStep_add', icon: 'plus', isCommonMethod: false },
            { label: '编辑工步信息', code: 'processStep_edit', icon: 'edit', isCommonMethod: false },
            { label: '删除', code: 'processStep_delete', icon: 'delete', isCommonMethod: true },
            // {  label: '导出NC程序', code: 'processStep_export', icon: 'import', isCommonMethod: true },
            { label: '导入NC程序', code: 'processStep_import', icon: 'import', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ]
        }
      }
    },
    computed: {
      getCurrentMenuLevel() {
        switch (this.treeParams.type) {
          case 1:
            return 'product'
          case 2:
            return 'component'
          case 3:
            return 'part'
          case 4:
            return 'processSpecVersion'
          case 5:
            return 'process'
          case 6:
            return 'processStep'
        }
      },
      getCurrentDocClassCode() {
        switch (this.treeParams.type) {
          case 1:
            return 'OTHER'
          case 2:
            return 'OTHER'
          case 3:
            return 'OTHER'
          case 5:
            return 'NC'
          case 6:
            return 'NC'
        }
      }
    },
    methods: {
      onContextMenuClick(treeKey, menuKey) {
        const level = this.getCurrentMenuLevel
        const param = this.getCurrentDocClassCode
        console.log('level---------------------', level)
        console.log('param---------------------', param)
        const treeNodeInfo = Object.assign({}, this.treeParams, { param })
        console.log('treeNodeInfo******************', treeNodeInfo)
        const menuKeyArray = menuKey.split('_')
        const isCommonMethod = this.defaultContextMenuList[level].find(item => item.code === menuKey).isCommonMethod
        // product_add => handleAdd è§¦å‘对应组件事件
        let methodName
        // åˆ¤æ–­æ˜¯å¦ä¸ºå…¬å…±æ–¹æ³•,如果为公共方法则截取专有属性product/component/part/process等字段
        if (isCommonMethod) {
          methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).slice(1).join('')
        } else {
          methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).join('')
        }
        const modalTitle = this.defaultContextMenuList[level].find(item => item.code === menuKey).label
        this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle, treeNodeInfo })
export default {
  name: 'ProductStructureTreeContextMenu',
  components: {},
  props: {
    treeParams: {
      type: Object
    }
  },
  data() {
    return {
      defaultContextMenuList: {
        //产品
        product: [
          { label: '添加产品', code: 'product_add', icon: 'plus', isCommonMethod: false },
          { label: '添加部件', code: 'product_add_child', icon: 'plus', isCommonMethod: false },
          { label: '编辑产品信息', code: 'product_edit', icon: 'edit', isCommonMethod: false },
          // {  label: '导出文档', code: 'product_export', icon: 'export', isCommonMethod: true },
          { label: '导入其他文档', code: 'product_import', icon: 'import', isCommonMethod: true },
          { label: '删除', code: 'product_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //部件
        component: [
          { label: '添加子部件', code: 'component_add', icon: 'plus', isCommonMethod: false },
          { label: '添加零件', code: 'component_add_child', icon: 'plus', isCommonMethod: false },
          { label: '创建工序', code: 'component_add_relative', icon: 'plus', isCommonMethod: false },
          { label: '编辑部件信息', code: 'component_edit', icon: 'edit', isCommonMethod: false },
          // {  label: '导出文档', code: 'component_export', icon: 'export', isCommonMethod: true },
          { label: '导入其他文档', code: 'component_import', icon: 'import', isCommonMethod: true },
          { label: '删除', code: 'component_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //零件
        part: [
          { label: '添加零件', code: 'parts_add', icon: 'plus', isCommonMethod: false },
          { label: '创建工艺规程版本', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
          // { label: '创建工序', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
          { label: '编辑零件信息', code: 'parts_edit', icon: 'edit', isCommonMethod: false },
          // {  label: '导出文档', code: 'parts_export', icon: 'export', isCommonMethod: true },
          { label: '导入其他文档', code: 'parts_import', icon: 'import', isCommonMethod: true },
          { label: '删除', code: 'parts_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //工艺规程版本
        processSpecVersion: [
          { label: '创建工艺规程版本', code: 'version_add', icon: 'plus', isCommonMethod: false },
          { label: '创建工序', code: 'version_add_child', icon: 'plus', isCommonMethod: false },
          { label: '编辑工艺规程版本信息', code: 'version_edit', icon: 'edit', isCommonMethod: false },
          { label: '删除', code: 'version_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //工序
        process: [
          { label: '创建工序', code: 'process_add', icon: 'plus', isCommonMethod: false },
          { label: '创建工步', code: 'process_add_child', icon: 'plus', isCommonMethod: false },
          { label: '添加设备类', code: 'process_add_type', icon: 'plus', isCommonMethod: true },
          { label: '编辑工序信息', code: 'process_edit', icon: 'edit', isCommonMethod: false },
          { label: '删除', code: 'process_delete', icon: 'delete', isCommonMethod: true },
          // {  label: '导出NC程序', code: 'process_export', icon: 'export', isCommonMethod: true },
          { label: '导入NC程序', code: 'process_import', icon: 'import', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //工步
        processStep: [
          { label: '创建工步', code: 'processStep_add', icon: 'plus', isCommonMethod: false },
          { label: '编辑工步信息', code: 'processStep_edit', icon: 'edit', isCommonMethod: false },
          { label: '添加设备类', code: 'processStep_add_type', icon: 'plus', isCommonMethod: true },
          { label: '删除', code: 'processStep_delete', icon: 'delete', isCommonMethod: true },
          // {  label: '导出NC程序', code: 'processStep_export', icon: 'import', isCommonMethod: true },
          { label: '导入NC程序', code: 'processStep_import', icon: 'import', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ]
      }
    }
  },
  computed: {
    getCurrentMenuLevel() {
      switch (+this.treeParams.type) {
        case 1:
          return 'product'
        case 2:
          return 'component'
        case 3:
          return 'part'
        case 4:
          return 'processSpecVersion'
        case 5:
          return 'process'
        case 6:
          return 'processStep'
      }
    },
    getCurrentDocClassCode() {
      switch (+this.treeParams.type) {
        case 1:
          return 'OTHER'
        case 2:
          return 'OTHER'
        case 3:
          return 'OTHER'
        case 5:
          return 'NC'
        case 6:
          return 'NC'
      }
    }
  },
  methods: {
    onContextMenuClick(treeKey, menuKey) {
      const level = this.getCurrentMenuLevel
      const param = this.getCurrentDocClassCode
      console.log('level---------------------', level)
      console.log('param---------------------', param)
      const treeNodeInfo = Object.assign({}, this.treeParams, { param })
      console.log('treeNodeInfo******************', treeNodeInfo)
      const menuKeyArray = menuKey.split('_')
      const isCommonMethod = this.defaultContextMenuList[level].find(item => item.code === menuKey).isCommonMethod
      // product_add => handleAdd è§¦å‘对应组件事件
      let methodName
      // åˆ¤æ–­æ˜¯å¦ä¸ºå…¬å…±æ–¹æ³•,如果为公共方法则截取专有属性product/component/part/process等字段
      if (isCommonMethod) {
        methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).slice(1).join('')
      } else {
        methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).join('')
      }
      console.log('methodName', methodName)
      const modalTitle = this.defaultContextMenuList[level].find(item => item.code === menuKey).label
      this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle, treeNodeInfo })
    }
  }
}
</script>
<style scoped>
  .replaceSearch {
    color: #40a9ff;
    font-weight: bold;
    background-color: rgb(204, 204, 204);
  }
.replaceSearch {
  color: #40a9ff;
  font-weight: bold;
  background-color: rgb(204, 204, 204);
}
</style>
src/views/dnc/common/TableContextMenu.vue
@@ -41,6 +41,12 @@
        },
        currentMenuLevel: '',
        defaultContextMenuList: {
          //设备类
          deviceCustomType:[
            { label: '编辑设备类信息', code: 'type_edit', subMenu: [], icon: 'edit', isCommonMethod: false },
            { label: '删除', code: 'type_delete', subMenu: [], icon: 'delete', isCommonMethod: false },
            { label: '导入NC程序', code: 'type_document_import', subMenu: [], icon: 'import', isCommonMethod: true },
          ],
          //NC文档
          NC: [
            { label: '编辑文档信息', code: 'document_edit', subMenu: [], icon: 'edit', isCommonMethod: false },
src/views/system/modules/UserModal.vue
@@ -376,11 +376,12 @@
        validatorRules: {
          username: [{ required: true, message: '请输入用户账号!' },
            { validator: this.validateUsername }],
          password: [{
            required: true,
            pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
            message: '密码由8位数字、大小写字母和特殊符号组成!'
          },
          password: [
          //   {
          //   required: true,
          //   pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
          //   message: '密码由8位数字、大小写字母和特殊符号组成!'
          // },
            { validator: this.validateToNextPassword, trigger: 'change' }],
          confirmpassword: [{ required: true, message: '请重新输入登录密码!' },
            { validator: this.compareToFirstPassword }],
yarn.lock
@@ -355,10 +355,20 @@
  dependencies:
    "@babel/types" "^7.10.4"
"@babel/helper-string-parser@^7.25.9":
  version "7.25.9"
  resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
  integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
"@babel/helper-validator-identifier@^7.10.4":
  version "7.10.4"
  resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
  integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
"@babel/helper-validator-identifier@^7.25.9":
  version "7.25.9"
  resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
  integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
"@babel/helper-wrap-function@^7.10.4":
  version "7.10.4"
@@ -392,6 +402,13 @@
  version "7.10.4"
  resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64"
  integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==
"@babel/parser@^7.23.5":
  version "7.26.9"
  resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5"
  integrity sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==
  dependencies:
    "@babel/types" "^7.26.9"
"@babel/plugin-proposal-async-generator-functions@^7.2.0":
  version "7.10.4"
@@ -861,6 +878,14 @@
    lodash "^4.17.13"
    to-fast-properties "^2.0.0"
"@babel/types@^7.26.9":
  version "7.26.9"
  resolved "https://registry.npmmirror.com/@babel/types/-/types-7.26.9.tgz#08b43dec79ee8e682c2ac631c010bdcac54a21ce"
  integrity sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==
  dependencies:
    "@babel/helper-string-parser" "^7.25.9"
    "@babel/helper-validator-identifier" "^7.25.9"
"@hapi/address@2.x.x":
  version "2.1.4"
  resolved "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
@@ -1316,6 +1341,17 @@
    semver "^6.0.0"
    string.prototype.padstart "^3.0.0"
"@vue/compiler-sfc@2.7.16":
  version "2.7.16"
  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz#ff81711a0fac9c68683d8bb00b63f857de77dc83"
  integrity sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==
  dependencies:
    "@babel/parser" "^7.23.5"
    postcss "^8.4.14"
    source-map "^0.6.1"
  optionalDependencies:
    prettier "^1.18.2 || ^2.0.0"
"@vue/component-compiler-utils@^3.0.0", "@vue/component-compiler-utils@^3.1.0":
  version "3.1.2"
  resolved "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.2.tgz#8213a5ff3202f9f2137fe55370f9e8b9656081c3"
@@ -1507,6 +1543,11 @@
  version "4.2.2"
  resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
  integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
abbrev@1:
  version "1.1.1"
  resolved "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
  integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
abs-svg-path@~0.1.1:
  version "0.1.1"
@@ -1919,6 +1960,13 @@
  resolved "https://registry.npmjs.org/async-validator/-/async-validator-3.3.0.tgz#1d92193bbe60d6d6c8b246692c7005e9ed14a8ee"
  integrity sha512-cAHGD9EL8aCqWXjnb44q94MWiDFzUo1tMhvLb2WzcpWqGiKugsjWG9cvl+jPgkPca7asNbsBU3fa0cwkI/P+Xg==
async-validator@~1.8.1:
  version "1.8.5"
  resolved "https://registry.npmmirror.com/async-validator/-/async-validator-1.8.5.tgz#dc3e08ec1fd0dddb67e60842f02c0cd1cec6d7f0"
  integrity sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==
  dependencies:
    babel-runtime "6.x"
async@^2.1.2, async@^2.4.1, async@^2.6.2:
  version "2.6.3"
  resolved "https://registry.npmjs.org/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
@@ -2164,7 +2212,7 @@
    babel-traverse "^6.24.1"
    babel-types "^6.24.1"
babel-helper-vue-jsx-merge-props@^2.0.3:
babel-helper-vue-jsx-merge-props@^2.0.0, babel-helper-vue-jsx-merge-props@^2.0.3:
  version "2.0.3"
  resolved "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6"
  integrity sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==
@@ -2696,6 +2744,31 @@
  version "1.0.0"
  resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
  integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
bpmn-js@^7.2.1:
  version "7.5.0"
  resolved "https://registry.npmmirror.com/bpmn-js/-/bpmn-js-7.5.0.tgz#0e4675acdbdff676db859f8cb7ec395d20e7bbd8"
  integrity sha512-0ANaE6Bikg1GmkcvO7RK0MQPX+EKYKBc+q7OWk39/16NcCdNZ/4UiRcCr9n0u1VUCIDsSU/jJ79TIZFnV5CNjw==
  dependencies:
    bpmn-moddle "^7.0.4"
    css.escape "^1.5.1"
    diagram-js "^6.8.2"
    diagram-js-direct-editing "^1.6.1"
    ids "^1.0.0"
    inherits "^2.0.4"
    min-dash "^3.5.2"
    min-dom "^3.1.3"
    object-refs "^0.3.0"
    tiny-svg "^2.2.2"
bpmn-moddle@^7.0.4:
  version "7.1.3"
  resolved "https://registry.npmmirror.com/bpmn-moddle/-/bpmn-moddle-7.1.3.tgz#5b4592001e8f23dbdb18c557531e06489462bf42"
  integrity sha512-ZcBfw0NSOdYTSXFKEn7MOXHItz7VfLZTrFYKO8cK6V8ZzGjCcdiLIOiw7Lctw1PJsihhLiZQS8Htj2xKf+NwCg==
  dependencies:
    min-dash "^3.5.2"
    moddle "^5.0.2"
    moddle-xml "^9.0.6"
brace-expansion@^1.1.7:
  version "1.1.11"
@@ -3497,6 +3570,11 @@
  resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
  integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
component-event@^0.1.4:
  version "0.1.4"
  resolved "https://registry.npmmirror.com/component-event/-/component-event-0.1.4.tgz#3de78fc28782381787e24bf2a7c536bf0142c9b4"
  integrity sha512-GMwOG8MnUHP1l8DZx1ztFO0SJTFnIzZnBDkXAj8RM2ntV2A6ALlDxgbMY1Fvxlg6WPQ+5IM/a6vg4PEYbjg/Rw==
component-indexof@0.0.3:
  version "0.0.3"
  resolved "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24"
@@ -3904,6 +3982,11 @@
  resolved "https://registry.npmjs.org/css-what/-/css-what-3.3.0.tgz#10fec696a9ece2e591ac772d759aacabac38cd39"
  integrity sha512-pv9JPyatiPaQ6pf4OvD/dbfm0o5LviWmwxNWzblYf/1u9QZd0ihV+PMwy5jdQWQ3349kZmKEx9WXuSka2dM4cg==
css.escape@^1.5.1:
  version "1.5.1"
  resolved "https://registry.npmmirror.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
  integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
css@^2.0.0:
  version "2.2.4"
  resolved "https://registry.npmjs.org/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
@@ -4044,6 +4127,11 @@
  dependencies:
    clap "^1.0.9"
    source-map "^0.5.3"
csstype@^3.1.0:
  version "3.1.3"
  resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
  integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
current-script-polyfill@^1.0.0:
  version "1.0.0"
@@ -4301,9 +4389,9 @@
  resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
  integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
deepmerge@^1.5.2:
deepmerge@^1.2.0, deepmerge@^1.5.2:
  version "1.5.2"
  resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753"
  resolved "https://registry.npmmirror.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753"
  integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==
default-gateway@^4.2.0:
@@ -4432,6 +4520,54 @@
  resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
  integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
diagram-js-direct-editing@^1.6.1:
  version "1.8.0"
  resolved "https://registry.npmmirror.com/diagram-js-direct-editing/-/diagram-js-direct-editing-1.8.0.tgz#7a178cd9203f262842a3e0023f9644e04a157858"
  integrity sha512-B4Xj+PJfgBjbPEzT3uZQEkZI5xHFB0Izc+7BhDFuHidzrEMzQKZrFGdA3PqfWhReHf3dp+iB6Tt11G9eGNjKMw==
  dependencies:
    min-dash "^3.5.2"
    min-dom "^3.1.3"
diagram-js@^6.8.2:
  version "6.8.2"
  resolved "https://registry.npmmirror.com/diagram-js/-/diagram-js-6.8.2.tgz#d3c37915c62c0cc5d95bc533098c8a35b38e67be"
  integrity sha512-5EKYHjW2mmGsn9/jSenSkm8cScK5sO9eETBRQNIIzgZjxBDJn6eX964L2d7/vrAW9SeuijGUsztL9+NUinSsNg==
  dependencies:
    css.escape "^1.5.1"
    didi "^4.0.0"
    hammerjs "^2.0.1"
    inherits "^2.0.1"
    min-dash "^3.5.0"
    min-dom "^3.1.2"
    object-refs "^0.3.0"
    path-intersection "^2.2.0"
    tiny-svg "^2.2.1"
didi@^4.0.0:
  version "4.0.0"
  resolved "https://registry.npmmirror.com/didi/-/didi-4.0.0.tgz#2b89d892a67fd3777f7642d3bf06697b69e9b622"
  integrity sha512-AzMElh8mCHOPWPCWfGjoJRla31fMXUT6+287W5ef3IPmtuBcyG9+MkFS7uPP6v3t2Cl086KwWfRB9mESa0OsHQ==
diff2html@^3.3.1:
  version "3.4.51"
  resolved "https://registry.npmmirror.com/diff2html/-/diff2html-3.4.51.tgz#6355170d09d8625525f0846be2c73bc2838ab797"
  integrity sha512-/rVCSDyokkzSCEGaGjkkElXtIRwyNDRzIa3S8VUhR6pjk25p6+AMnb1s2zGmhjl66D5m/HnV3IeZoxnWsvTy+w==
  dependencies:
    diff "^7.0.0"
    hogan.js "3.0.2"
  optionalDependencies:
    highlight.js "11.9.0"
diff@^3.5.0:
  version "3.5.0"
  resolved "https://registry.npmmirror.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
diff@^7.0.0:
  version "7.0.0"
  resolved "https://registry.npmmirror.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a"
  integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==
diffie-hellman@^5.0.0:
  version "5.0.3"
  resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -4549,6 +4685,11 @@
  dependencies:
    domelementtype "1"
domify@^1.3.1:
  version "1.4.2"
  resolved "https://registry.npmmirror.com/domify/-/domify-1.4.2.tgz#2d3e8ac49cae41206cc84be31ca401050ae780a6"
  integrity sha512-m4yreHcUWHBncGVV7U+yQzc12vIlq0jMrtHZ5mW6dQMiL/7skSYNVX9wqKwOtyO9SGCgevrAFEgOCAHmamHTUA==
domutils@1.5.1:
  version "1.5.1"
  resolved "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
@@ -4647,6 +4788,18 @@
  version "1.3.496"
  resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.496.tgz#3f43d32930481d82ad3663d79658e7c59a58af0b"
  integrity sha512-TXY4mwoyowwi4Lsrq9vcTUYBThyc1b2hXaTZI13p8/FRhY2CTaq5lK+DVjhYkKiTLsKt569Xes+0J5JsVXFurQ==
element-ui@^2.12.0, element-ui@^2.13.2, element-ui@^2.15.14:
  version "2.15.14"
  resolved "https://registry.npmmirror.com/element-ui/-/element-ui-2.15.14.tgz#3c34df79467636592812d720d2e6784e7a6ec2ea"
  integrity sha512-2v9fHL0ZGINotOlRIAJD5YuVB8V7WKxrE9Qy7dXhRipa035+kF7WuU/z+tEmLVPBcJ0zt8mOu1DKpWcVzBK8IA==
  dependencies:
    async-validator "~1.8.1"
    babel-helper-vue-jsx-merge-props "^2.0.0"
    deepmerge "^1.2.0"
    normalize-wheel "^1.0.1"
    resize-observer-polyfill "^1.5.0"
    throttle-debounce "^1.0.1"
elliptic@^6.0.0, elliptic@^6.5.2:
  version "6.5.3"
@@ -5917,6 +6070,11 @@
    duplexer "^0.1.1"
    pify "^4.0.1"
hammerjs@^2.0.1:
  version "2.0.8"
  resolved "https://registry.npmmirror.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1"
  integrity sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==
handle-thing@^2.0.0:
  version "2.0.1"
  resolved "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e"
@@ -6042,6 +6200,16 @@
  resolved "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
  integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
highlight.js@11.9.0:
  version "11.9.0"
  resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
  integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
highlight.js@^9.18.5:
  version "9.18.5"
  resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825"
  integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==
highlight.js@^9.6.0:
  version "9.18.1"
  resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz#ed21aa001fe6252bb10a3d76d47573c6539fe13c"
@@ -6055,6 +6223,14 @@
    hash.js "^1.0.3"
    minimalistic-assert "^1.0.0"
    minimalistic-crypto-utils "^1.0.1"
hogan.js@3.0.2:
  version "3.0.2"
  resolved "https://registry.npmmirror.com/hogan.js/-/hogan.js-3.0.2.tgz#4cd9e1abd4294146e7679e41d7898732b02c7bfd"
  integrity sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==
  dependencies:
    mkdirp "0.3.0"
    nopt "1.0.10"
home-or-tmp@^2.0.0:
  version "2.0.0"
@@ -6284,6 +6460,11 @@
  dependencies:
    postcss "^6.0.1"
ids@^1.0.0:
  version "1.0.5"
  resolved "https://registry.npmmirror.com/ids/-/ids-1.0.5.tgz#0aeb4777e77e0017a983c9f7b0ca0cccf352afe4"
  integrity sha512-XQ0yom/4KWTL29sLG+tyuycy7UmeaM/79GRtSJq6IG9cJGIPeBz5kwDCguie3TwxaMNIc3WtPi0cTa1XYHicpw==
ieee754@^1.1.4:
  version "1.1.13"
  resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
@@ -6388,6 +6569,11 @@
  version "1.0.1"
  resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
  integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
indexof@0.0.1:
  version "0.0.1"
  resolved "https://registry.npmmirror.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
  integrity sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==
infer-owner@^1.0.3, infer-owner@^1.0.4:
  version "1.0.4"
@@ -7299,6 +7485,11 @@
  resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
  integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
lodash.clonedeep@^4.5.0:
  version "4.5.0"
  resolved "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
  integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
lodash.defaults@^3.1.2:
  version "3.1.2"
  resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c"
@@ -7360,6 +7551,11 @@
  version "4.1.2"
  resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
  integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.merge@^4.6.2:
  version "4.6.2"
  resolved "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
  integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.pick@^4.4.0:
  version "4.4.0"
@@ -7488,6 +7684,11 @@
  integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
  dependencies:
    object-visit "^1.0.0"
matches-selector@^1.2.0:
  version "1.2.0"
  resolved "https://registry.npmmirror.com/matches-selector/-/matches-selector-1.2.0.tgz#d1814e7e8f43e69d22ac33c9af727dc884ecf12a"
  integrity sha512-c4vLwYWyl+Ji+U43eU/G5FwxWd4ZH0ePUsFs5y0uwD9HUEFBXUQ1zUUan+78IpRD+y4pUfG0nAzNM292K7ItvA==
math-expression-evaluator@^1.2.14:
  version "1.2.22"
@@ -7652,6 +7853,22 @@
  resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
min-dash@^3.0.0, min-dash@^3.5.0, min-dash@^3.5.2, min-dash@^3.8.1:
  version "3.8.1"
  resolved "https://registry.npmmirror.com/min-dash/-/min-dash-3.8.1.tgz#09a8bd8a041d65eec4732042cde9cb24a6e84b0d"
  integrity sha512-evumdlmIlg9mbRVPbC4F5FuRhNmcMS5pvuBUbqb1G9v09Ro0ImPEgz5n3khir83lFok1inKqVDjnKEg3GpDxQg==
min-dom@^3.1.2, min-dom@^3.1.3:
  version "3.2.1"
  resolved "https://registry.npmmirror.com/min-dom/-/min-dom-3.2.1.tgz#c272a814397d8bfe97edd12670e7ac34123c043f"
  integrity sha512-v6YCmnDzxk4rRJntWTUiwggLupPw/8ZSRqUq0PDaBwVZEO/wYzCH4SKVBV+KkEvf3u0XaWHly5JEosPtqRATZA==
  dependencies:
    component-event "^0.1.4"
    domify "^1.3.1"
    indexof "0.0.1"
    matches-selector "^1.2.0"
    min-dash "^3.8.1"
mini-css-extract-plugin@^0.8.0:
  version "0.8.2"
  resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.2.tgz#a875e169beb27c88af77dd962771c9eedc3da161"
@@ -7752,12 +7969,33 @@
    for-in "^1.0.2"
    is-extendable "^1.0.1"
mkdirp@0.3.0:
  version "0.3.0"
  resolved "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
  integrity sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==
mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.0, mkdirp@~0.5.1:
  version "0.5.5"
  resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
  integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
  dependencies:
    minimist "^1.2.5"
moddle-xml@^9.0.6:
  version "9.0.6"
  resolved "https://registry.npmmirror.com/moddle-xml/-/moddle-xml-9.0.6.tgz#282b2a2232065a82556ba3fbbe3010b374f95cbf"
  integrity sha512-tl0reHpsY/aKlLGhXeFlQWlYAQHFxTkFqC8tq8jXRYpQSnLVw13T6swMaourLd7EXqHdWsc+5ggsB+fEep6xZQ==
  dependencies:
    min-dash "^3.5.2"
    moddle "^5.0.2"
    saxen "^8.1.2"
moddle@^5.0.2:
  version "5.0.4"
  resolved "https://registry.npmmirror.com/moddle/-/moddle-5.0.4.tgz#1108c9ff210df552ef4589513e620d171e4468e6"
  integrity sha512-Kjb+hjuzO+YlojNGxEUXvdhLYTHTtAABDlDcJTtTcn5MbJF9Zkv4I1Fyvp3Ypmfgg1EfHDZ3PsCQTuML9JD6wg==
  dependencies:
    min-dash "^3.0.0"
moment-timezone@^0.5.31:
  version "0.5.34"
@@ -7839,6 +8077,11 @@
  version "2.14.1"
  resolved "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
  integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
nanoid@^3.3.8:
  version "3.3.8"
  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
  integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
nanomatch@^1.2.9:
  version "1.2.13"
@@ -7957,6 +8200,13 @@
  resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.59.tgz#4d648330641cec704bff10f8e4fe28e453ab8e8e"
  integrity sha512-H3JrdUczbdiwxN5FuJPyCHnGHIFqQ0wWxo+9j1kAXAzqNMAHlo+4I/sYYxpyK0irQ73HgdiyzD32oqQDcU2Osw==
nopt@1.0.10:
  version "1.0.10"
  resolved "https://registry.npmmirror.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
  integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
  dependencies:
    abbrev "1"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
  version "2.5.0"
  resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@@ -8003,6 +8253,11 @@
  version "3.3.0"
  resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
  integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
normalize-wheel@^1.0.1:
  version "1.0.1"
  resolved "https://registry.npmmirror.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"
  integrity sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==
npm-run-path@^2.0.0:
  version "2.0.2"
@@ -8091,6 +8346,11 @@
  version "0.9.2"
  resolved "https://registry.npmjs.org/object-path/-/object-path-0.9.2.tgz#0fd9a74fc5fad1ae3968b586bda5c632bd6c05a5"
  integrity sha1-D9mnT8X60a45aLWGvaXGMr1sBaU=
object-refs@^0.3.0:
  version "0.3.0"
  resolved "https://registry.npmmirror.com/object-refs/-/object-refs-0.3.0.tgz#934f4f0fb6b409e78be15fa60f616108aed63786"
  integrity sha512-eP0ywuoWOaDoiake/6kTJlPJhs+k0qNm4nYRzXLNHj6vh+5M3i9R1epJTdxIPGlhWc4fNRQ7a6XJNCX+/L4FOQ==
object-visit@^1.0.0:
  version "1.0.1"
@@ -8474,6 +8734,11 @@
  resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-intersection@^2.2.0:
  version "2.2.1"
  resolved "https://registry.npmmirror.com/path-intersection/-/path-intersection-2.2.1.tgz#8476b75fefb7ac402f810d304e0eb0c080c11fe7"
  integrity sha512-9u8xvMcSfuOiStv9bPdnRJQhGQXLKurew94n4GPQCdH1nj9QKC9ObbNoIpiRq8skiOBxKkt277PgOoFgAt3/rA==
path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
  version "1.0.1"
  resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@@ -8547,6 +8812,11 @@
  version "4.1.3"
  resolved "https://registry.npmjs.org/photoswipe/-/photoswipe-4.1.3.tgz#59f49494eeb9ddab5888d03392926a19bc197550"
  integrity sha512-89Z43IRUyw7ycTolo+AaiDn3W1EEIfox54hERmm9bI12IB9cvRfHSHez3XhAyU8XW2EAFrC+2sKMhh7SJwn0bA==
picocolors@^1.1.1:
  version "1.1.1"
  resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
  integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
picomatch@^2.0.4, picomatch@^2.2.1:
  version "2.2.2"
@@ -9252,6 +9522,15 @@
    source-map "^0.6.1"
    supports-color "^6.1.0"
postcss@^8.4.14:
  version "8.5.3"
  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb"
  integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==
  dependencies:
    nanoid "^3.3.8"
    picocolors "^1.1.1"
    source-map-js "^1.2.1"
prelude-ls@~1.1.2:
  version "1.1.2"
  resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -9266,6 +9545,11 @@
  version "1.19.1"
  resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
  integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
"prettier@^1.18.2 || ^2.0.0":
  version "2.8.8"
  resolved "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
  integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
pretty-error@^2.0.2, pretty-error@^2.1.1:
  version "2.1.1"
@@ -9816,7 +10100,7 @@
  resolved "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147"
  integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=
resize-observer-polyfill@^1.5.1:
resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1:
  version "1.5.1"
  resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
  integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
@@ -10018,6 +10302,11 @@
  version "1.2.4"
  resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
  integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
saxen@^8.1.2:
  version "8.1.2"
  resolved "https://registry.npmmirror.com/saxen/-/saxen-8.1.2.tgz#e677b32afe93667c9d939d3f3de02e09df108e54"
  integrity sha512-xUOiiFbc3Ow7p8KMxwsGICPx46ZQvy3+qfNVhrkwfz3Vvq45eGt98Ft5IQaA1R/7Tb5B5MKh9fUR9x3c3nDTxw==
schema-utils@^0.3.0:
  version "0.3.0"
@@ -10350,6 +10639,11 @@
  version "2.0.1"
  resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
  integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
source-map-js@^1.2.1:
  version "1.2.1"
  resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
  integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
  version "0.5.3"
@@ -10935,6 +11229,11 @@
    loader-utils "^1.1.0"
    neo-async "^2.6.0"
throttle-debounce@^1.0.1:
  version "1.1.0"
  resolved "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-1.1.0.tgz#51853da37be68a155cb6e827b3514a3c422e89cd"
  integrity sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==
through2@^2.0.0:
  version "2.0.5"
  resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
@@ -10974,6 +11273,11 @@
  version "2.1.0"
  resolved "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
  integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
tiny-svg@^2.2.1, tiny-svg@^2.2.2:
  version "2.2.4"
  resolved "https://registry.npmmirror.com/tiny-svg/-/tiny-svg-2.2.4.tgz#8d4a16bd2c4644c8444fd3c2ece91db7631cfb35"
  integrity sha512-NOi39lBknf4UdDEahNkbEAJnzhu1ZcN2j75IS2vLRmIhsfxdZpTChfLKBcN1ShplVmPIXJAIafk6YY5/Aa80lQ==
tinycolor2@^1.4.1:
  version "1.4.1"
@@ -11443,6 +11747,16 @@
  resolved "https://registry.npmmirror.com/vue-calendar-component/-/vue-calendar-component-2.8.2.tgz#8f60c05a72c8aacbdd224016f4e1a96664abd8aa"
  integrity sha512-BJh7xOBzM7QVcapcN4EbPQ1eZ8Pii1/oy+dzqjZTilRSIDD7SRPdFpnUJwZvs8lCrhtBAyJbYFsdm2SogXWHVQ==
vue-code-diff@^1.2.0:
  version "1.2.0"
  resolved "https://registry.npmmirror.com/vue-code-diff/-/vue-code-diff-1.2.0.tgz#e38013307bab9296cc3512b2e7c9afed7890ae4a"
  integrity sha512-kgSCl1Cr3I0u0z5DyJFbqQ1Hk7s9uBl7bfGwIn1X8f1xGmWdu4eRqfeOLTS0ut06VfGslaprXdaSvgn7YGDh0Q==
  dependencies:
    diff "^3.5.0"
    diff2html "^3.3.1"
    highlight.js "^9.18.5"
    vue "^2.6.12"
vue-cropper@^0.5.4:
  version "0.5.4"
  resolved "https://registry.npmjs.org/vue-cropper/-/vue-cropper-0.5.4.tgz#0db3776894eea8673a3203a1513882a0eb4558ad"
@@ -11601,6 +11915,14 @@
  version "2.6.11"
  resolved "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
  integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
vue@^2.6.11, vue@^2.6.12:
  version "2.7.16"
  resolved "https://registry.npmmirror.com/vue/-/vue-2.7.16.tgz#98c60de9def99c0e3da8dae59b304ead43b967c9"
  integrity sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==
  dependencies:
    "@vue/compiler-sfc" "2.7.16"
    csstype "^3.1.0"
vuedraggable@^2.20.0:
  version "2.24.0"
@@ -11946,6 +12268,16 @@
  dependencies:
    errno "~0.1.7"
workflow-bpmn-modeler@^0.2.8:
  version "0.2.8"
  resolved "https://registry.npmmirror.com/workflow-bpmn-modeler/-/workflow-bpmn-modeler-0.2.8.tgz#632facb1f63bcce6b85378fa7bf3a7e0da07a675"
  integrity sha512-7Y2+YMx5mFDrpDAMoEK2EMVp5Z4585tYBLuqOxcbB5cdY6Vt1VjE1OBhzcwlFU6MWfpeisMGKbYtlPSHAOzsGg==
  dependencies:
    bpmn-js "^7.2.1"
    element-ui "^2.12.0"
    vue "^2.6.10"
    xcrud "0.4.1"
wrap-ansi@^2.0.0:
  version "2.1.0"
  resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -11998,6 +12330,16 @@
  dependencies:
    async-limiter "~1.0.0"
xcrud@0.4.1:
  version "0.4.1"
  resolved "https://registry.npmmirror.com/xcrud/-/xcrud-0.4.1.tgz#0b644bb20a307c769b8878b0d81b2791dfe1fce1"
  integrity sha512-aUbZZDARyNhbdBqT5nrHsXkYMM3Bo0i8EFvVgEyq444cxvYkqz4I71XWN2bPVhK/axfX4RawmIHjOQTz2v/apw==
  dependencies:
    element-ui "^2.13.2"
    lodash.clonedeep "^4.5.0"
    lodash.merge "^4.6.2"
    vue "^2.6.11"
xe-utils@2.4.8:
  version "2.4.8"
  resolved "https://registry.yarnpkg.com/xe-utils/-/xe-utils-2.4.8.tgz#0efda3ca81f6b55f68a8a31e276fb17da59c98b3"