lyh
2025-03-14 9737ae6cbdf64098554dc99e743a52669adb8138
Revert "1、设备类管理页面完成增删改查功能"

This reverts commit bc55e59f49229ffa77d2b32dd9fd0a9b6049b9b8.
已添加9个文件
已修改19个文件
已删除1个文件
1753 ■■■■■ 文件已修改
src/api/dnc.js 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/DeviceCustomTypeManagement.vue 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/ProductStructure.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | 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 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Process/ProcessInfo.vue 18 ●●●● 补丁 | 查看 | 原始文档 | 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 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue 104 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/common/TableContextMenu.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/modules/UserModal.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/dnc.js
@@ -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,6 +11,9 @@
    <!--导入文件公共弹窗-->
    <ImportFileModal/>
    <!--新增或编辑设备类公共弹窗-->
    <DeviceCustomTypeModal/>
  </a-card>
</template>
@@ -18,10 +21,12 @@
  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: {
    DeviceCustomTypeModal,
      ProductStructureTree,
      ProductStructureMain,
      ImportFileModal
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
@@ -30,7 +30,6 @@
  import dncApi from '@/api/dnc'
  import DepartPermissionTransfer from './DepartPermissionTransfer'
  import UserPermissionTransfer from './UserPermissionTransfer'
  import { queryProductionTreeList } from '@/api/api'
  export default {
    name: 'AssignPermissionModal',
@@ -82,7 +81,7 @@
      // è°ƒç”¨æŽ¥å£èŽ·å–æ‰€æœ‰è½¦é—´åˆ—è¡¨
      getAllDepartmentsListByApi() {
        this.allTreeKeys = []
        queryProductionTreeList()
      dncApi.getAllDepartmentsListApi()
          .then(res => {
            if (res.success) {
              this.allDepartmentsList = res.result
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.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:
            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">
      <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="其他文档">
@@ -26,14 +34,25 @@
  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 },
  components: {
    DeviceCustomTypeTableList,
    DocumentBatchDeleteModal,
    TableContextMenu,
    OtherDocumentTableList,
    NcDocumentTableList
  },
    data() {
      return {
        activeTabKey: 2,
        tableContainerSize: 'small',
      isProcessHasDeviceTypeList: false,
      isProcessStepHasDeviceTypeList: false,
        currentRightClickedTableRowInfo: {},
        currentTreeNodeInfo: {},
        hasLoadedDataTabKeyArray: []
@@ -43,8 +62,48 @@
      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 å½“前表格行信息
@@ -57,29 +116,6 @@
        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)
      },
      /**
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)
      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', this.currentSelected)
            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,7 +1,13 @@
<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)"
@@ -71,6 +77,7 @@
          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 },
@@ -81,6 +88,7 @@
          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 },
@@ -91,7 +99,7 @@
    },
    computed: {
      getCurrentMenuLevel() {
        switch (this.treeParams.type) {
      switch (+this.treeParams.type) {
          case 1:
            return 'product'
          case 2:
@@ -107,7 +115,7 @@
        }
      },
      getCurrentDocClassCode() {
        switch (this.treeParams.type) {
      switch (+this.treeParams.type) {
          case 1:
            return 'OTHER'
          case 2:
@@ -139,6 +147,7 @@
        } 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 })
      }
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 }],