产品结构树:
1、新增指定文档为当前版本功能与文档版本内容差异比对功能(新增插件vue-code-diff)
2、调整产品及部件属性tab栏标题为属性信息
3、删除产品及部件属性信息中对应层级名称
全局:
调整设置后端接口地址方式由vue.config.js改为env环境文件配置
已添加5个文件
已修改13个文件
676 ■■■■■ 文件已修改
.env.development 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.production 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/dnc.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Component/ComponentInfo.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Document/DocumentModalForm.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Document/DocumentVersionTableList.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Document/FileCompareModal.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Document/FilePreview.vue 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Document/SelectFileCompareModal.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/common/ImportFileModal.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/common/TableContextMenu.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
NODE_ENV=development
# VUE_APP_API_BASE_URL=http://192.168.124.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://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
.env.production
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
NODE_ENV=production
# VUE_APP_API_BASE_URL=http://195.0.1.10:8099
# VUE_APP_API_BASE_URL=http://195.0.1.10:6099
# VUE_APP_API_BASE_URL=http://192.168.124.123:9999
VUE_APP_API_BASE_URL=http://172.16.99.3:6099
VUE_APP_CAS_BASE_URL=http://localhost:8888/cas
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview1p
package-lock.json
@@ -569,6 +569,11 @@
        "@babel/types": "^7.10.4"
      }
    },
    "@babel/helper-string-parser": {
      "version": "7.25.9",
      "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
      "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="
    },
    "@babel/helper-validator-identifier": {
      "version": "7.10.4",
      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
@@ -3534,6 +3539,56 @@
        }
      }
    },
    "@vue/compiler-sfc": {
      "version": "2.7.16",
      "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
      "integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
      "requires": {
        "@babel/parser": "^7.23.5",
        "postcss": "^8.4.14",
        "prettier": "^1.18.2 || ^2.0.0",
        "source-map": "^0.6.1"
      },
      "dependencies": {
        "@babel/helper-validator-identifier": {
          "version": "7.25.9",
          "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
          "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="
        },
        "@babel/parser": {
          "version": "7.26.5",
          "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.5.tgz",
          "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==",
          "requires": {
            "@babel/types": "^7.26.5"
          }
        },
        "@babel/types": {
          "version": "7.26.5",
          "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.5.tgz",
          "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==",
          "requires": {
            "@babel/helper-string-parser": "^7.25.9",
            "@babel/helper-validator-identifier": "^7.25.9"
          }
        },
        "postcss": {
          "version": "8.5.1",
          "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.1.tgz",
          "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
          "requires": {
            "nanoid": "^3.3.8",
            "picocolors": "^1.1.1",
            "source-map-js": "^1.2.1"
          }
        },
        "source-map": {
          "version": "0.6.1",
          "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
        }
      }
    },
    "@vue/component-compiler-utils": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.1.2.tgz",
@@ -3768,6 +3823,11 @@
      "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
      "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
      "dev": true
    },
    "abbrev": {
      "version": "1.1.1",
      "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz",
      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
    },
    "abs-svg-path": {
      "version": "0.1.1",
@@ -7539,6 +7599,11 @@
        }
      }
    },
    "csstype": {
      "version": "3.1.3",
      "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
    },
    "current-script-polyfill": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/current-script-polyfill/-/current-script-polyfill-1.0.0.tgz",
@@ -8037,6 +8102,34 @@
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
      "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw=="
    },
    "diff": {
      "version": "3.5.0",
      "resolved": "https://registry.npmmirror.com/diff/-/diff-3.5.0.tgz",
      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
    },
    "diff2html": {
      "version": "3.4.51",
      "resolved": "https://registry.npmmirror.com/diff2html/-/diff2html-3.4.51.tgz",
      "integrity": "sha512-/rVCSDyokkzSCEGaGjkkElXtIRwyNDRzIa3S8VUhR6pjk25p6+AMnb1s2zGmhjl66D5m/HnV3IeZoxnWsvTy+w==",
      "requires": {
        "diff": "^7.0.0",
        "highlight.js": "11.9.0",
        "hogan.js": "3.0.2"
      },
      "dependencies": {
        "diff": {
          "version": "7.0.0",
          "resolved": "https://registry.npmmirror.com/diff/-/diff-7.0.0.tgz",
          "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="
        },
        "highlight.js": {
          "version": "11.9.0",
          "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.9.0.tgz",
          "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==",
          "optional": true
        }
      }
    },
    "diffie-hellman": {
      "version": "5.0.3",
@@ -10220,6 +10313,22 @@
        "minimalistic-crypto-utils": "^1.0.1"
      }
    },
    "hogan.js": {
      "version": "3.0.2",
      "resolved": "https://registry.npmmirror.com/hogan.js/-/hogan.js-3.0.2.tgz",
      "integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==",
      "requires": {
        "mkdirp": "0.3.0",
        "nopt": "1.0.10"
      },
      "dependencies": {
        "mkdirp": {
          "version": "0.3.0",
          "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.3.0.tgz",
          "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew=="
        }
      }
    },
    "home-or-tmp": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
@@ -12294,6 +12403,11 @@
        "thenify-all": "^1.0.0"
      }
    },
    "nanoid": {
      "version": "3.3.8",
      "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz",
      "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="
    },
    "nanomatch": {
      "version": "1.2.13",
      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -12445,6 +12559,14 @@
      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.59.tgz",
      "integrity": "sha512-H3JrdUczbdiwxN5FuJPyCHnGHIFqQ0wWxo+9j1kAXAzqNMAHlo+4I/sYYxpyK0irQ73HgdiyzD32oqQDcU2Osw==",
      "dev": true
    },
    "nopt": {
      "version": "1.0.10",
      "resolved": "https://registry.npmmirror.com/nopt/-/nopt-1.0.10.tgz",
      "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
      "requires": {
        "abbrev": "1"
      }
    },
    "normalize-package-data": {
      "version": "2.5.0",
@@ -13033,6 +13155,11 @@
      "version": "4.1.3",
      "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-4.1.3.tgz",
      "integrity": "sha512-89Z43IRUyw7ycTolo+AaiDn3W1EEIfox54hERmm9bI12IB9cvRfHSHez3XhAyU8XW2EAFrC+2sKMhh7SJwn0bA=="
    },
    "picocolors": {
      "version": "1.1.1",
      "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
    },
    "picomatch": {
      "version": "2.2.2",
@@ -15976,6 +16103,11 @@
        "amdefine": ">=0.0.4"
      }
    },
    "source-map-js": {
      "version": "1.2.1",
      "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
    },
    "source-map-resolve": {
      "version": "0.5.3",
      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -17310,6 +17442,33 @@
      "resolved": "https://registry.npmmirror.com/vue-calendar-component/-/vue-calendar-component-2.8.2.tgz",
      "integrity": "sha512-BJh7xOBzM7QVcapcN4EbPQ1eZ8Pii1/oy+dzqjZTilRSIDD7SRPdFpnUJwZvs8lCrhtBAyJbYFsdm2SogXWHVQ=="
    },
    "vue-code-diff": {
      "version": "1.2.0",
      "resolved": "https://registry.npmmirror.com/vue-code-diff/-/vue-code-diff-1.2.0.tgz",
      "integrity": "sha512-kgSCl1Cr3I0u0z5DyJFbqQ1Hk7s9uBl7bfGwIn1X8f1xGmWdu4eRqfeOLTS0ut06VfGslaprXdaSvgn7YGDh0Q==",
      "requires": {
        "diff": "^3.5.0",
        "diff2html": "^3.3.1",
        "highlight.js": "^9.18.5",
        "vue": "^2.6.12"
      },
      "dependencies": {
        "highlight.js": {
          "version": "9.18.5",
          "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-9.18.5.tgz",
          "integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA=="
        },
        "vue": {
          "version": "2.7.16",
          "resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.16.tgz",
          "integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
          "requires": {
            "@vue/compiler-sfc": "2.7.16",
            "csstype": "^3.1.0"
          }
        }
      }
    },
    "vue-cropper": {
      "version": "0.5.4",
      "resolved": "https://registry.npmjs.org/vue-cropper/-/vue-cropper-0.5.4.tgz",
package.json
@@ -37,6 +37,7 @@
    "vue": "^2.6.10",
    "vue-area-linkage": "^5.1.0",
    "vue-calendar-component": "^2.8.2",
    "vue-code-diff": "^1.2.0",
    "vue-cropper": "^0.5.4",
    "vue-drag-resize": "^1.5.4",
    "vue-i18n": "^8.7.0",
src/api/dnc.js
@@ -26,17 +26,25 @@
  // æŒ‡æ´¾æ–‡æ¡£åˆ°è®¾å¤‡
  assignDocumentToDeviceApi: params => postAction('/nc/activit/assign/file/apply', params),
  // ä¸‹è½½æ–‡æ¡£
  downloadDocumentApi: ({ id, docName }) => downloadFile(`/nc/doc/download/${id}`, docName),
  downloadDocumentApi: ({ docId, docName }) => downloadFile(`/nc/doc/download/${docId}`, docName),
  // æ–‡æ¡£å‡ºåº“
  documentOutboundApi: ({ id, docName }) => requestGetDownLoad(`/nc/doc/pull/${id}`, docName),
  documentOutboundApi: ({ docId, docName }) => requestGetDownLoad(`/nc/doc/pull/${docId}`, docName),
  // æ–‡æ¡£å–消出库
  documentCancelOutboundApi: id => putAction(`/nc/doc/cancel/pull/${id}`),
  documentCancelOutboundApi: docId => putAction(`/nc/doc/cancel/pull/${docId}`),
  // æ–‡æ¡£å…¥åº“
  documentVersionUpdateApi: ({ id, formData }) => uploadAction(`/nc/doc/push/${id}`, formData),
  documentVersionUpdateApi: ({ docId, formData }) => uploadAction(`/nc/doc/push/${docId}`, formData),
  // æ–‡æ¡£å‘布
  documentPublishApi: id => putAction(`/nc/doc/publish/${id}`),
  documentPublishApi: docId => putAction(`/nc/doc/publish/${docId}`),
  // æ–‡æ¡£é‡æ–°å‘布
  documentRepublishApi: id => putAction(`/nc/doc/republish/${id}`),
  documentRepublishApi: docId => putAction(`/nc/doc/republish/${docId}`),
  // æ–‡æ¡£å½’æ¡£
  documentPigeonholeApi: id => putAction(`/nc/doc/pigeonhole/${id}`)
  documentPigeonholeApi: docId => putAction(`/nc/doc/pigeonhole/${docId}`),
  // èŽ·å–æ–‡ä»¶é¢„è§ˆ
  getFilePreviewApi: docId => getAction(`/nc/doc/preview/${docId}`),
  // èŽ·å–PDF文件预览
  getPdfFilePreviewApi: docId => getAction(`/nc/doc/preview/pdf/${docId}`),
  // æŒ‡å®šå½“前文档版本
  appointCurrentDocumentVersionApi: fileId => putAction(`/nc/file/assign/version/${fileId}`),
  // æ–‡æ¡£æ¯”对
  fileCompareApi: fileIdArray => getAction(`/nc/file/comparison/${fileIdArray[0]}/${fileIdArray[1]}`)
}
src/utils/request.js
@@ -15,8 +15,7 @@
//console.log("apiBaseUrl= ",apiBaseUrl)
// åˆ›å»º axios å®žä¾‹
const service = axios.create({
  baseURL: '/api',
  // baseURL: apiBaseUrl, // api base_url
  baseURL: apiBaseUrl, // api base_url
  timeout: 500000 // è¯·æ±‚è¶…æ—¶æ—¶é—´
})
src/views/dnc/base/modules/ProductStructure/Component/ComponentInfo.vue
@@ -1,8 +1,8 @@
<template>
  <a-descriptions bordered :size="size">
    <a-descriptions-item label="部件名称">{{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.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>
    <a-descriptions-item label="材料">{{currentLevelDetails.materielDesp}}</a-descriptions-item>
    <a-descriptions-item label="规格    ">{{currentLevelDetails.componentScale}}</a-descriptions-item>
src/views/dnc/base/modules/ProductStructure/Document/DocumentModalForm.vue
@@ -101,7 +101,7 @@
                })
                that.$emit('ok')
              } else {
                that.$notification.warning({
                that.$notification.error({
                  message: '消息',
                  description: res.message
                })
src/views/dnc/base/modules/ProductStructure/Document/DocumentVersionTableList.vue
@@ -1,5 +1,7 @@
<template>
  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false" :size="size" rowKey="fileId">
  <div>
    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false" :size="size" rowKey="fileId"
             :customRow="customRow">
    <template slot="rowIndex" slot-scope="text,record,index">
      <span :style="{color:setCurrentVersionColor(record.publishFlag)}">{{parseInt(index) + 1}}</span>
    </template>
@@ -16,16 +18,21 @@
      <span :style="{color:setCurrentVersionColor(record.publishFlag)}">{{(text/1024).toFixed(2)}}KB</span>
    </template>
  </a-table>
    <SelectFileCompareModal :dataSource="dataSource" :setCurrentVersionColor="setCurrentVersionColor"
                            ref="selectFileCompareModalRef"/>
  </div>
</template>
<script>
  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
  import { getAction } from '@/api/manage'
  import dncApi from '@/api/dnc'
  import SelectFileCompareModal from './SelectFileCompareModal'
  export default {
    name: 'DocumentVersionTableList',
    mixins: [JeecgListMixin],
    components: {},
    components: { SelectFileCompareModal },
    props: {
      currentDocumentInfo: {
        type: Object
@@ -38,6 +45,7 @@
      return {
        disableMixinCreated: true,
        queryParams: {},
        currentDocumentVersion: '',
        columns: [
          { title: '序号', dataIndex: 'rowIndex', width: 65, align: 'center', scopedSlots: { customRender: 'rowIndex' } },
          { title: '文件名称', dataIndex: 'fileName', align: 'center', scopedSlots: { customRender: 'fileName' } },
@@ -48,6 +56,9 @@
          list: '/nc/file/find/list'
        }
      }
    },
    created() {
      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    },
    methods: {
      loadData() {
@@ -65,6 +76,8 @@
        getAction(this.url.list, params).then((res) => {
          if (res.success) {
            this.dataSource = res.list
            this.currentDocumentVersion = res.list.find(item => item.publishFlag).docVersion
            console.log('currentDocumentVersion', this.currentDocumentVersion)
          } else {
            this.$message.warning(res.message)
          }
@@ -74,6 +87,60 @@
      },
      /**
       * æŒ‡å®šå½“前文档为当前版本
       * @param fileId æ–‡ä»¶Id
       */
      handleFileAssign({ fileId }) {
        const that = this
        dncApi.appointCurrentDocumentVersionApi(fileId)
          .then(res => {
            if (res.success) {
              that.$notification.success({
                message: '消息',
                description: res.message
              })
              const currentAssignDocumentVersion = that.dataSource.find(item => item.fileId === fileId).docVersion
              // å¦‚果当前指定版本的版本号与当前版本的版本号一致则不重新加载列表并且不重新释放预览接口调取
              if (that.currentDocumentVersion === currentAssignDocumentVersion) return
              that.loadData()
              that.$emit('releaseFilePreviewApi')
            } else {
              that.$notification.error({
                message: '消息',
                description: res.message
              })
            }
          })
          .catch(err => {
            that.$notification.error({
              message: '消息',
              description: err.message
            })
          })
      },
      handleFileAddRelative(_, modalTitle) {
        if (!this.$refs.selectFileCompareModalRef) return
        this.$refs.selectFileCompareModalRef.visible = true
        this.$refs.selectFileCompareModalRef.title = modalTitle
      },
      customRow(record) {
        return {
          on: {
            contextmenu: event => {
              event.preventDefault()
              this.$emit('handleTableContextMenuOpen', Object.assign({ param: 'file' }, record))
            }
          }
        }
      },
      triggerCorrespondingMethod({ methodName, level, modalTitle, tableRowInfo }) {
        if (this[methodName]) this[methodName](tableRowInfo, modalTitle)
      },
      /**
       * è®¾ç½®è¡¨æ ¼ä¸­ä¸ºå½“前版本的文件表格行颜色标识
       * @param publishFlag æ˜¯å¦ä¸ºå½“前版本
       * @returns {string} é¢œè‰²æ ‡è¯†
src/views/dnc/base/modules/ProductStructure/Document/FileCompareModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
<template>
  <a-modal width="100%" :visible="visible" :title="title" @cancel="visible=false" :footer="null" :maskClosable="false">
    <a-row>
      <a-col :span="12"><span class="file-version-text">版本号:{{fileVersionArray[0]}}</span></a-col>
      <a-col :span="12"><span class="file-version-text">版本号:{{fileVersionArray[1]}}</span></a-col>
    </a-row>
    <div class="code-diff-container">
      <CodeDiff :old-string="oldVersionContent" :new-string="newVersionContent" outputFormat="side-by-side"/>
    </div>
  </a-modal>
</template>
<script>
  import CodeDiff from 'vue-code-diff'
  export default {
    name: 'FileCompareModal',
    components: { CodeDiff },
    props: {
      fileDiffObject: {
        type: Object
      },
      fileVersionArray: {
        type: Array
      }
    },
    watch: {
      visible: {
        handler(value) {
          if (value) {
            const { fileDiffObject } = this
            let fileContent = ''
            for (let key in fileDiffObject) {
              if (fileDiffObject.hasOwnProperty(key)) {
                fileDiffObject[key].forEach((content, index) => {
                  fileContent += content
                  if (index !== fileDiffObject[key].length - 1) {
                    fileContent += '\n'
                  }
                })
                if (key === 'first') {
                  this.oldVersionContent = fileContent
                  fileContent = ''
                }
                else this.newVersionContent = fileContent
              }
            }
          }
          else this.newVersionContent = this.oldVersionContent = ''
        }
      }
    },
    data() {
      return {
        visible: false,
        title: '',
        oldVersionContent: '',
        newVersionContent: ''
      }
    },
    methods: {}
  }
</script>
<style scoped>
  .file-version-text {
    font-weight: bold;
    font-size: 16px;
    margin-left: 5%;
  }
  .code-diff-container {
    height: 500px;
    overflow: auto;
    margin-top: 20px
  }
</style>
src/views/dnc/base/modules/ProductStructure/Document/FilePreview.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
<template>
  <a-spin :spinning="spinning" style="height: 100%">
    <!--<template v-if="currentDocumentInfo.docSuffix==='pdf'">-->
    <!--<iframe :src="pdfUrl" frameborder="0"-->
    <!--style="width: 100%;height: calc(100% - 5px)"></iframe>-->
    <!--</template>-->
    <template>
      <textarea id="ncFileInfo" style="resize:none;width:100%;height: 100%"></textarea>
    </template>
  </a-spin>
</template>
<script>
  import dncApi from '@/api/dnc'
  export default {
    name: 'FilePreview',
    components: {},
    props: {
      currentDocumentInfo: {
        type: Object
      }
    },
    data() {
      return {
        spinning: false,
        pdfUrl: ''
      }
    },
    methods: {
      getFilePreviewByApi() {
        const { docId, docSuffix } = this.currentDocumentInfo
        console.log('currentDocumentInfo', this.currentDocumentInfo)
        // if (docSuffix !== 'pdf') {
        //   document.getElementById('ncFileInfo').innerHTML = ''
        //   dncApi.getFilePreviewApi(docId)
        //     .then(res => {
        //       console.log('res----------------------------', res)
        //       if (res.success && res.list) {
        //         let str = ''
        //         res.list.forEach((val, k) => {
        //           str += val
        //           if (k != res.list.length - 1) {
        //             str += '\n'
        //           }
        //         })
        //         document.getElementById('ncFileInfo').innerHTML = str
        //       } else {
        //         this.$notification.error({
        //           message: '消息',
        //           description: res.message
        //         })
        //       }
        //     })
        // } else {
        //   dncApi.getPdfFilePreviewApi(docId)
        //     .then(res => {
        //       let url = window.URL.createObjectURL(new Blob([res], { type: 'application/zip' }))
        //       this.pdfUrl = './static/pdf/web/viewer.html?file=' + encodeURIComponent(url)
        //       console.log('url===========================', url)
        //       console.log('pdfUrl===========================', this.pdfUrl)
        //     })
        // }
        this.spinning = true
        document.getElementById('ncFileInfo').innerHTML = ''
        dncApi.getFilePreviewApi(docId)
          .then(res => {
            console.log('res----------------------------', res)
            if (res.success && res.list) {
              let str = ''
              res.list.forEach((val, k) => {
                str += val
                if (k != res.list.length - 1) {
                  str += '\n'
                }
              })
              document.getElementById('ncFileInfo').innerHTML = str
            } else {
              this.$notification.error({
                message: '消息',
                description: res.message
              })
            }
          })
          .finally(() => {
            this.spinning = false
          })
      },
    }
  }
</script>
<style scoped>
  /deep/ .ant-spin-container {
    height: 100%;
  }
</style>
src/views/dnc/base/modules/ProductStructure/Document/SelectFileCompareModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,134 @@
<template>
  <a-modal :title="title" :visible="visible" :width="700" @cancel="handleCloseModal" @ok="handleOpenCompareModal"
           :maskClosable="false">
    <a-table :dataSource="dataSource" :columns="columns" :pagination="false" bordered :scroll="{y:364}"
             :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}" rowKey="fileId">
      <template slot="rowIndex" slot-scope="text,record,index">
        <span :style="{color:setCurrentVersionColor(record.publishFlag)}">{{parseInt(index) + 1}}</span>
      </template>
      <template slot="fileName" slot-scope="text,record,index">
      <span :style="{color:setCurrentVersionColor(record.publishFlag)}">
        {{text}}.{{record.fileSuffix}}
        <span v-if="record.publishFlag">[当前版本]</span>
      </span>
      </template>
      <template slot="docVersion" slot-scope="text,record">
        <span :style="{color:setCurrentVersionColor(record.publishFlag)}">{{text}}</span>
      </template>
    </a-table>
    <FileCompareModal ref="fileCompareModalRef" :fileDiffObject="fileDiffObject" :fileVersionArray="fileVersionArray"/>
  </a-modal>
</template>
<script>
  import dncApi from '@/api/dnc'
  import FileCompareModal from './FileCompareModal'
  export default {
    name: 'SelectFileCompareModal',
    components: { FileCompareModal },
    props: {
      dataSource: {
        type: Array
      },
      setCurrentVersionColor: {
        type: Function
      }
    },
    data() {
      return {
        visible: false,
        title: '',
        selectedRowKeys: [],
        fileDiffObject: {},
        fileVersionArray: [],
        selectedFileInfo: {},
        columns: [
          { title: '序号', dataIndex: 'rowIndex', width: 65, align: 'center', scopedSlots: { customRender: 'rowIndex' } },
          { title: '文件名称', dataIndex: 'fileName', align: 'center', scopedSlots: { customRender: 'fileName' } },
          { title: '版本号', dataIndex: 'docVersion', align: 'center', scopedSlots: { customRender: 'docVersion' } }
        ]
      }
    },
    watch: {
      visible: {
        handler(value) {
          this.$nextTick(() => {
            const selectAllCheckboxNode = document.querySelector('.ant-table-selection-column .ant-table-selection')
            if (value) {
              if (this.dataSource.length > 2) selectAllCheckboxNode.style.display = 'none'
              else selectAllCheckboxNode.style.display = 'block'
            }
          })
        }
      }
    },
    methods: {
      onSelectChange(selectedRowKeys) {
        if (selectedRowKeys.length < 3) this.selectedRowKeys = selectedRowKeys
        else this.selectedRowKeys = selectedRowKeys.slice(-2)
      },
      handleOpenCompareModal() {
        const { $confirm, $notification, selectedRowKeys, title, dataSource } = this
        if (selectedRowKeys.length < 2) {
          $notification.warning({
            message: '消息',
            description: '请勾选两个版本比对'
          })
          return
        }
        const that = this
        $confirm({
          title: '提示',
          content: '确认提交吗?',
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            that.fileVersionArray = []
            dncApi.fileCompareApi(selectedRowKeys)
              .then(res => {
                if (res.success) {
                  $notification.success({
                    message: '消息',
                    description: res.message
                  })
                  that.fileDiffObject = res.data
                  // ä¼ é€’给子组件当前选中的文件版本号
                  selectedRowKeys.forEach(fileId => {
                    const selectedFileVersion = dataSource.find(item => item.fileId === fileId).docVersion
                    that.fileVersionArray.push(selectedFileVersion)
                  })
                  that.handleCloseModal()
                  if (!that.$refs.fileCompareModalRef) return
                  that.$refs.fileCompareModalRef.visible = true
                  that.$refs.fileCompareModalRef.title = title
                } else {
                  $notification.error({
                    message: '消息',
                    description: res.message
                  })
                }
              })
              .catch(err => {
                $notification.error({
                  message: '消息',
                  description: err.message
                })
              })
          }
        })
      },
      handleCloseModal() {
        this.visible = false
        this.selectedRowKeys = []
      }
    }
  }
</script>
<style scoped>
</style>
src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue
@@ -1,8 +1,8 @@
<template>
  <a-descriptions bordered :size="size">
    <a-descriptions-item label="产品名称">{{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.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>
src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue
@@ -1,11 +1,11 @@
<template>
  <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">
    <a-tab-pane :key="1" tab="属性信息" v-if="currentLevelInfo.type===1">
      <ProductInfo :currentLevelDetails="currentLevelInfo.entity" :size="containerSize"/>
    </a-tab-pane>
    <a-tab-pane :key="1" tab="部件属性" v-if="currentLevelInfo.type===2">
    <a-tab-pane :key="1" tab="属性信息" v-if="currentLevelInfo.type===2">
      <ComponentInfo :currentLevelDetails="currentLevelInfo.entity" :size="containerSize"/>
    </a-tab-pane>
@@ -27,11 +27,13 @@
      </a-tab-pane>
      <a-tab-pane :key="2" tab="预览">
        <FilePreview ref="filePreviewRef" :currentDocumentInfo="currentLevelInfo"/>
      </a-tab-pane>
      <a-tab-pane :key="3" tab="文档版本">
        <DocumentVersionTableList ref="documentVersionTableRef" :currentDocumentInfo="currentLevelInfo"
                                  @handleTableContextMenuOpen="handleTableContextMenuOpen"
                                  @releaseFilePreviewApi="releaseFilePreviewApi"
                                  :size="containerSize"/>
      </a-tab-pane>
@@ -40,6 +42,8 @@
                                       :size="containerSize"/>
      </a-tab-pane>
    </template>
    <TableContextMenu :tableRowInfo="currentRightClickedTableRowInfo" ref="tableContextMenuRef"/>
  </a-tabs>
</template>
@@ -52,10 +56,14 @@
  import DocumentVersionTableList from './Document/DocumentVersionTableList'
  import UseDocumentEquipmentTableList from './Document/UseNcDocumentEquipmentTableList'
  import ProcessStepInfo from './ProcessStep/ProcessStepInfo'
  import FilePreview from './Document/FilePreview'
  import TableContextMenu from '../../../common/TableContextMenu'
  export default {
    name: 'ProductStructureMainBottom',
    components: {
      TableContextMenu,
      FilePreview,
      ProcessStepInfo,
      UseDocumentEquipmentTableList,
      DocumentVersionTableList,
@@ -70,6 +78,7 @@
        activeTabKey: 1,
        containerSize: 'small',
        currentLevelInfo: {},
        currentRightClickedTableRowInfo: {},
        hasLoadedDataTabKeyArray: []
      }
    },
@@ -81,7 +90,7 @@
    methods: {
      /**
       * æŽ¥æ”¶æ ‘组件以及表格传来的当前选中或点击的项信息
       * @param levelInfo
       * @param levelInfo å½“前层级信息
       */
      receiveCurrentLevelInfo(levelInfo) {
        this.currentLevelInfo = levelInfo
@@ -91,15 +100,50 @@
      handleTabChange(activeTabKey) {
        if (!this.hasLoadedDataTabKeyArray.includes(activeTabKey)) {
          if (activeTabKey === 3) {
          switch (activeTabKey) {
            case 2:
              this.$nextTick(() => this.$refs.filePreviewRef.getFilePreviewByApi())
              break
            case 3:
            this.$nextTick(() => this.$refs.documentVersionTableRef.loadData())
          } else if (activeTabKey === 4) {
              break
            case 4:
            this.$nextTick(() => this.$refs.useDocumentEquipmentTableRef.loadData())
              break
            default:
          }
          // é˜»æ­¢æŽ¥å£åœ¨åŒä¸€æ–‡æ¡£ä¸€æ¬¡ç‚¹å‡»å†…多次触发
          this.hasLoadedDataTabKeyArray.push(activeTabKey)
        }
      },
      // é‡Šæ”¾æ–‡ä»¶é¢„览接口
      releaseFilePreviewApi() {
        // å¦‚果已经预览过此文档,可在此文档当前版本发生改变后再次预览新版本内容
        if (this.hasLoadedDataTabKeyArray.includes(2)) this.hasLoadedDataTabKeyArray = this.hasLoadedDataTabKeyArray.filter(item => item !== 2)
      },
      /**
       * æŽ§åˆ¶å³é”®èœå•开启
       * @param record å½“前表格行信息
       */
      handleTableContextMenuOpen(record) {
        this.currentRightClickedTableRowInfo = Object.assign({}, record)
        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)
      },
      /**
       * æŽ§åˆ¶å³é”®èœå•点击关闭
       */
      handleMenuClose() {
        this.$refs.tableContextMenuRef.menuVisible = false
        document.body.removeEventListener('click', this.handleMenuClose)
      },
      reloadMainBottomTableData(tableName) {
        if (this.$refs[tableName + 'TableRef']) this.$refs[tableName + 'TableRef'].loadData()
      }
src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
@@ -92,7 +92,7 @@
      handleDownload() {
        const that = this
        const { docId, docName } = this.currentRightClickedTableRowInfo
        dncApi.downloadDocumentApi({ id: docId, docName })
        dncApi.downloadDocumentApi({ docId, docName })
          .then(res => {
            if (res && !res.success) {
              that.$notification.error({
@@ -122,7 +122,7 @@
          okText: '确认',
          cancelText: '取消',
          onOk: () => {
            dncApi.documentOutboundApi({ id: docId, docName })
            dncApi.documentOutboundApi({ docId, docName })
              .then(res => {
                console.log('res------------------', res)
                if (res.success) {
src/views/dnc/common/ImportFileModal.vue
@@ -78,7 +78,7 @@
        this.isUploadMultiple = false
        console.log('tableRowInfo', tableRowInfo)
        this.uploadParams = Object.assign({}, {
          id: tableRowInfo.docId,
          docId: tableRowInfo.docId,
          attributionId: tableRowInfo.attributionId,
          docClassCode: tableRowInfo.param
        })
@@ -101,7 +101,7 @@
       * ç‚¹å‡»ä¸Šä¼ è‡³æœåŠ¡å™¨æŒ‰é’®æ—¶è§¦å‘
       */
      handleUpload() {
        const { fileList, $notification, isUploadMultiple, uploadParams, $bus } = this
        const { fileList, $notification, isUploadMultiple, uploadParams, $bus, handleModalClose } = this
        this.uploading = true
        let uploadedFileCount = 0
        let uploadSuccessFileCount = 0
@@ -118,7 +118,7 @@
            params = Object.assign({}, { params: uploadParams, formData })
          } else {
            apiMethod = dncApi.documentVersionUpdateApi
            params = Object.assign({}, { id: uploadParams.id, formData })
            params = Object.assign({}, { docId: uploadParams.docId, formData })
          }
          apiMethod(params)
            .then(res => {
@@ -151,7 +151,7 @@
                  $bus.$emit('reloadDocumentListData', uploadParams)
                  if (!isUploadMultiple) {
                    $bus.$emit('reloadMainBottomTableData', 'documentVersion')
                    this.visible = false //无法连续入库多个版本因此入库成功后即可退出窗口
                    handleModalClose() //无法连续入库多个版本因此入库成功后即可退出窗口
                  }
                }
                this.uploading = false
src/views/dnc/common/TableContextMenu.vue
@@ -83,8 +83,8 @@
          ],
          //文件
          file: [
            { label: '指定当前版本', code: 'file_assign', isCommonMethod: false },//文件-指定当前版本
            { label: '比对', code: 'file_add_relative', isCommonMethod: false }//比对
            { label: '指定当前版本', code: 'file_assign', subMenu: [], icon: 'export', isCommonMethod: false },//文件-指定当前版本
            { label: '比对', code: 'file_add_relative', subMenu: [], icon: 'export', isCommonMethod: false }//比对
          ]
        }
      }
@@ -93,12 +93,12 @@
      menuItemClick({ item, key }) {
        const menuKeyArray = key.split('_')
        const menuArrayItem = this.defaultContextMenuList[this.tableRowInfo.param].find(item => item.code === key)
        const subMenuArrayItem = this.defaultContextMenuList[this.tableRowInfo.param].find(item => item.subMenu.length > 0).subMenu.find(item => item.code === key)
        let isCommonMethod, modalTitle
        if (menuArrayItem) {
          isCommonMethod = menuArrayItem.isCommonMethod
          modalTitle = menuArrayItem.label
        } else {
          const subMenuArrayItem = this.defaultContextMenuList[this.tableRowInfo.param].find(item => item.subMenu.length > 0).subMenu.find(item => item.code === key)
          isCommonMethod = subMenuArrayItem.isCommonMethod
          modalTitle = subMenuArrayItem.label
        }
vue.config.js
@@ -108,13 +108,10 @@
       },*/
      /* æ³¨æ„ï¼šjeecgboot前端做了改造,此处不需要配置跨域和后台接口(只需要改.env相关配置文件即可)
          issues/3462 å¾ˆå¤šäººæ­¤å¤„做了配置,导致刷新前端404问题,请一定注意*/
      '/api': {
        target: 'http://127.0.0.1:9999',
      '/jeecg-boot': {
        target: 'http://localhost:8080', // è¯·æ±‚本地 éœ€è¦jeecg-boot后台项目
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
        changeOrigin: true
      }
    }
  },