| | |
| | | } |
| | | const { pageCurr, pageSize, conditions, columns } = this; |
| | | let params = {}; |
| | | let col, index; |
| | | Object.keys(conditions).forEach((v) => { |
| | | switch (v) { |
| | | case "isNormal": |
| | | if (conditions[v]) { |
| | | params["customCode"] = ""; |
| | | columns.forEach((val) => { |
| | | columns.forEach((val, idx) => { |
| | | if (val.dataIndex == "customCode") { |
| | | val.search.value = ""; |
| | | col = { ...val, search: { value: "", backup: "" } }; |
| | | index = idx; |
| | | } |
| | | }); |
| | | this.$set(this.columns, index, col); |
| | | } |
| | | break; |
| | | case "customCode": |
New file |
| | |
| | | import axios from "@/assets/axios"; |
| | | |
| | | /** |
| | | * 列表 |
| | | * @returns |
| | | */ |
| | | export const getList = (pageNum, pageSize, data) => { |
| | | return axios({ |
| | | method: "POST", |
| | | url: "technicalSpecification/getInfo", |
| | | params: { pageNum, pageSize, ...data }, |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 解析规格书说明 |
| | | * multipartFile |
| | | * @returns |
| | | */ |
| | | export const excelParse = (data) => { |
| | | return axios({ |
| | | method: "POST", |
| | | url: "technicalSpecification/excelParse", |
| | | headers: { |
| | | "Content-Type": "multipart/form-data", |
| | | }, |
| | | data, |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 解析规格书说明 |
| | | * file1 file2 |
| | | * technicalSpecificationStr |
| | | * @returns |
| | | */ |
| | | export const upload = (data) => { |
| | | return axios({ |
| | | method: "POST", |
| | | url: "technicalSpecification/upload", |
| | | headers: { |
| | | "Content-Type": "multipart/form-data", |
| | | }, |
| | | data, |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 更新锁定状态 |
| | | * {id lockFlag reason} |
| | | * @returns |
| | | */ |
| | | export const updateLock = (params) => { |
| | | return axios({ |
| | | method: "POST", |
| | | url: "technicalSpecification/updateLock", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 查询指定id的说明书的锁定日志 |
| | | * {id} |
| | | * @returns |
| | | */ |
| | | export const getLogs = (id) => { |
| | | return axios({ |
| | | method: "GET", |
| | | url: "technicalSpecificationLog/getLockLogInfoById", |
| | | params: { id }, |
| | | }); |
| | | }; |
| | | |
| | | |
| | | /** |
| | | * 查询指定技术规格书的所有版本 |
| | | * {applyCustomCode, applyMaterialCode, applyModel} |
| | | * @returns |
| | | */ |
| | | export const getVersions = (params) => { |
| | | return axios({ |
| | | method: "POST", |
| | | url: "technicalSpecification/getVersionByInfo", |
| | | params, |
| | | }); |
| | | }; |
New file |
| | |
| | | <template> |
| | | <div class=""> |
| | | <table class="table"> |
| | | <tbody> |
| | | <tr> |
| | | <th class="title" colspan="6">文件基本信息</th> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">文件名称</th> |
| | | <td colspan="5">{{ info.fileName }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">软件类型</th> |
| | | <td colspan="5">{{ info.type }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">文件版本</th> |
| | | <td colspan="1">{{ info.version }}</td> |
| | | <th class="col-1">基于版本</th> |
| | | <td colspan="3">{{ info.basedVersion }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">负责人</th> |
| | | <td colspan="1">{{ info.owner }}</td> |
| | | <th class="col-1">归档日期</th> |
| | | <td colspan="3">{{ info.filingDate }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="title" colspan="6">规格书适用机型</th> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">物料编码</th> |
| | | <td colspan="1">{{ info.applyMaterialCode }}</td> |
| | | <th class="col-1">规格型号</th> |
| | | <td colspan="1">{{ info.applyModel }}</td> |
| | | <th class="col-1">定制单号</th> |
| | | <td colspan="1">{{ info.applyCustomCode }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">发布说明</th> |
| | | <td colspan="5">{{ info.releaseNotes }}</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | info: { |
| | | type: Object, |
| | | default() { |
| | | return {}; |
| | | }, |
| | | }, |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | computed: {}, |
| | | watch: {}, |
| | | methods: {}, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .table { |
| | | width: 100%; |
| | | // table-layout: fixed; |
| | | border-collapse: collapse; |
| | | th, |
| | | td { |
| | | border: 1px #333 solid; |
| | | padding: 4px; |
| | | } |
| | | td { |
| | | // color: #13c2c2; |
| | | color: #333; |
| | | } |
| | | .title { |
| | | font-weight: 900; |
| | | padding-left: 2em; |
| | | font-style: italic; |
| | | } |
| | | } |
| | | .col-1 { |
| | | // word-break:break-all; |
| | | width: 6.4em; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="main"> |
| | | <a-layout class="main"> |
| | | <a-layout-sider width="260"> |
| | | <list class="list" :list="versionList" @select="selectChanged"></list> |
| | | </a-layout-sider> |
| | | <a-layout> |
| | | <a-layout-header> |
| | | <a-card> |
| | | <a-descriptions title="详情" bordered> |
| | | <a-descriptions-item label="文件名称">{{ |
| | | currentVersion.fileName |
| | | }}</a-descriptions-item> |
| | | <a-descriptions-item label="版本号">{{ |
| | | currentVersion.version |
| | | }}</a-descriptions-item> |
| | | <a-descriptions-item label="上传时间">{{ |
| | | currentVersion.createTime |
| | | }}</a-descriptions-item> |
| | | <a-descriptions-item label="负责人">{{ |
| | | currentVersion.owner |
| | | }}</a-descriptions-item> |
| | | <a-descriptions-item label="文件类型">{{ |
| | | currentVersion.type |
| | | }}</a-descriptions-item> |
| | | <a-descriptions-item label="归档日期">{{ |
| | | currentVersion.filingDate |
| | | }}</a-descriptions-item> |
| | | <a-descriptions-item label="发布说明">{{ |
| | | currentVersion.releaseNotes |
| | | }}</a-descriptions-item> |
| | | </a-descriptions> |
| | | </a-card> |
| | | </a-layout-header> |
| | | <a-layout-content> |
| | | <div class="wraper" ref="wraper"> |
| | | <div class="inner"> |
| | | <div class="title">适用产品</div> |
| | | <a-table |
| | | v-if="currentVersion.fileName" |
| | | ref="aTable" |
| | | size="small" |
| | | bordered |
| | | :columns="columns" |
| | | :data-source="dataSource" |
| | | :pagination="false" |
| | | rowKey="id" |
| | | > |
| | | </a-table> |
| | | </div> |
| | | </div> |
| | | </a-layout-content> |
| | | <a-layout-footer> |
| | | <a-card> |
| | | <template> |
| | | <a-button |
| | | v-if="currentVersion.lockFlag == 0" |
| | | type="primary" |
| | | @click="view(currentVersion)" |
| | | >预览</a-button |
| | | > |
| | | <a-button |
| | | v-if="canLock()" |
| | | type="primary" |
| | | @click="lock" |
| | | >锁定</a-button |
| | | > |
| | | <a-button |
| | | v-if="canUnLock()" |
| | | type="primary" |
| | | @click="lock()" |
| | | >解锁</a-button |
| | | > |
| | | <a-button type="primary" @click="viewLog">锁定日志</a-button> |
| | | </template> |
| | | </a-card> |
| | | </a-layout-footer> |
| | | </a-layout> |
| | | </a-layout> |
| | | <!-- 操作原因 --> |
| | | <a-modal |
| | | :visible="reasonVisible" |
| | | :width="460" |
| | | title="操作原因" |
| | | :destroyOnClose="true" |
| | | :maskClosable="false" |
| | | @cancel="reasonCancel" |
| | | @ok="reasonOk" |
| | | > |
| | | <a-form-model-item ref="name" label="操作原因"> |
| | | <a-input |
| | | type="textarea" |
| | | v-model="reason" |
| | | placeHolder="请输入操作原因" |
| | | /> |
| | | </a-form-model-item> |
| | | </a-modal> |
| | | <!-- 日志 --> |
| | | <a-modal |
| | | :visible="logVisible" |
| | | :footer="null" |
| | | :width="800" |
| | | title="操作日志" |
| | | :destroyOnClose="true" |
| | | @cancel="logCancel" |
| | | > |
| | | <div class="log-content"> |
| | | <a-timeline v-if="logList.length"> |
| | | <a-timeline-item |
| | | v-for="(item, idx) in logList" |
| | | :key="'log_' + idx" |
| | | :color="item.status == 0 ? 'red' : 'green'" |
| | | > |
| | | <div> |
| | | <span class="user">{{ item.userName }}</span> 在 |
| | | <span class="time">{{ item.createTime }}</span> |
| | | {{ item.status == 0 ? "锁定" : "解锁" }}了版本 |
| | | <span class="version">{{ item.fileVersion }}</span> |
| | | </div> |
| | | <div>操作原因: {{ item.reason ? item.reason : "无" }}</div> |
| | | </a-timeline-item> |
| | | </a-timeline> |
| | | <a-empty v-else /> |
| | | </div> |
| | | </a-modal> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import List from "./versionList"; |
| | | import getWebUrl from "@/assets/js/tools/getWebUrl"; |
| | | import { updateLock, getVersions, getLogs } from "./apis"; |
| | | import checkPermit from "@/assets/js/tools/checkPermit"; |
| | | import PERMITS from "@/assets/js/const/const_permits"; |
| | | import { mapGetters } from "vuex"; |
| | | export default { |
| | | name: "", |
| | | |
| | | data() { |
| | | let { applyMaterialCode, applyModel, applyCustomCode } = this.$route.query; |
| | | return { |
| | | logList: [], |
| | | logVisible: false, |
| | | reasonVisible: false, |
| | | reason: "", |
| | | applyMaterialCode, |
| | | applyModel, |
| | | applyCustomCode, |
| | | versionList: [], |
| | | webUrl: getWebUrl(), |
| | | currentVersion: {}, |
| | | columns: [ |
| | | { |
| | | title: "物料编码", |
| | | dataIndex: "applyMaterialCode", |
| | | align: "center", |
| | | }, |
| | | { |
| | | title: "物料型号", |
| | | dataIndex: "applyModel", |
| | | align: "center", |
| | | }, |
| | | { |
| | | title: "定制单号", |
| | | dataIndex: "applyCustomCode", |
| | | align: "center", |
| | | }, |
| | | ], |
| | | dataSource: [], |
| | | }; |
| | | }, |
| | | components: { |
| | | List, |
| | | }, |
| | | computed: { |
| | | ...mapGetters("account", ["permits", 'user']), |
| | | canUpload() { |
| | | return checkPermit(PERMITS.uploadSoftware, this.permits); |
| | | }, |
| | | canDownload() { |
| | | return checkPermit(PERMITS.downloadSoftware, this.permits); |
| | | }, |
| | | }, |
| | | watch: {}, |
| | | methods: { |
| | | canLock() { |
| | | let row = this.currentVersion; |
| | | let uname = this.user.name; |
| | | return row.owner == uname && row.lockFlag == 0; |
| | | }, |
| | | canUnLock() { |
| | | let row = this.currentVersion; |
| | | let uname = this.user.name; |
| | | // flag 为1 是可操作的 |
| | | return row.owner == uname && row.lockFlag == 1 && row.flag == 1; |
| | | }, |
| | | view(obj) { |
| | | let { fileUrl } = obj; |
| | | window.open(this.webUrl + fileUrl); |
| | | }, |
| | | viewLog() { |
| | | // console.log(obj); |
| | | const { id } = this.currentVersion; |
| | | getLogs(id).then((res) => { |
| | | const { code, data, data2 } = res.data; |
| | | if (code) { |
| | | this.logList = data2; |
| | | this.logVisible = true; |
| | | } else { |
| | | this.$message.error("日志查询失败"); |
| | | } |
| | | }); |
| | | }, |
| | | logCancel() { |
| | | this.logVisible = false; |
| | | }, |
| | | downloadFile() { |
| | | // console.log(record); |
| | | let record = this.currentVersion; |
| | | let loading = this.$layer.loading(); |
| | | let link = document.createElement("a"); |
| | | link.style.display = "none"; |
| | | let url = this.webUrl + record.fileUrl; |
| | | let fileName = record.fileUrl.split("/").pop(); |
| | | link.href = url; |
| | | link.download = fileName; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | this.$layer.close(loading); |
| | | document.body.removeChild(link); |
| | | }, |
| | | getVersions() { |
| | | let { applyMaterialCode, applyModel, applyCustomCode } = this; |
| | | getVersions({ applyMaterialCode, applyModel, applyCustomCode }).then( |
| | | (res) => { |
| | | const { code, data, data2 } = res.data; |
| | | let list = []; |
| | | if (code && data) { |
| | | list = data2; |
| | | } |
| | | this.versionList = list; |
| | | } |
| | | ); |
| | | }, |
| | | selectChanged(obj) { |
| | | // console.log(obj, "--=="); |
| | | this.currentVersion = obj; |
| | | this.dataSource = [obj]; |
| | | }, |
| | | reasonCancel() { |
| | | this.reasonVisible = false; |
| | | }, |
| | | reasonOk() { |
| | | let { id, lockFlag } = this.currentVersion; |
| | | let reason = this.reason; |
| | | lockFlag = lockFlag == 0 ? 1 : 0; |
| | | updateLock({id, lockFlag, reason}).then((res) => { |
| | | const { code } = res.data; |
| | | if (code) { |
| | | this.$message.success("操作成功"); |
| | | this.reasonVisible = false; |
| | | this.currentVersion.lockFlag = lockFlag; |
| | | } else { |
| | | this.$message.error("操作失败"); |
| | | } |
| | | }); |
| | | }, |
| | | lock() { |
| | | this.reason = ""; |
| | | this.reasonVisible = true; |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.getVersions(); |
| | | }, |
| | | beforeDestroy() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .main { |
| | | height: 100%; |
| | | .ant-layout-header, |
| | | .ant-layout-sider { |
| | | background: transparent; |
| | | } |
| | | .ant-layout-header { |
| | | height: auto; |
| | | } |
| | | .list { |
| | | height: 100%; |
| | | } |
| | | .wraper { |
| | | height: 100%; |
| | | position: relative; |
| | | .inner { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | } |
| | | } |
| | | /deep/.ant-layout { |
| | | margin-left: 10px; |
| | | } |
| | | .ant-layout-header { |
| | | padding: 0; |
| | | line-height: inherit; |
| | | margin-bottom: 10px; |
| | | } |
| | | .ant-btn + .ant-btn { |
| | | margin-left: 1em; |
| | | } |
| | | .ant-layout-content { |
| | | -webkit-box-sizing: border-box; |
| | | box-sizing: border-box; |
| | | margin: 0; |
| | | padding: 0; |
| | | color: rgba(0, 0, 0, 0.65); |
| | | font-size: 14px; |
| | | font-variant: tabular-nums; |
| | | line-height: 1.5; |
| | | list-style: none; |
| | | -webkit-font-feature-settings: "tnum"; |
| | | font-feature-settings: "tnum"; |
| | | position: relative; |
| | | background: #fff; |
| | | border-radius: 2px; |
| | | -webkit-transition: all 0.3s; |
| | | transition: all 0.3s; |
| | | padding: 24px; |
| | | zoom: 1; |
| | | /deep/.ant-descriptions-item-label { |
| | | width: 12rem; |
| | | text-align: right; |
| | | } |
| | | } |
| | | .ant-layout-footer { |
| | | padding: 0; |
| | | } |
| | | .img-wraper { |
| | | width: 80px; |
| | | height: 50px; |
| | | display: inline-block; |
| | | .image-view { |
| | | width: 100%; |
| | | height: 100%; |
| | | /deep/img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | } |
| | | /deep/.is-replace > td { |
| | | background: #00eaff; |
| | | } |
| | | /deep/.is-replace.is-replace.ant-table-row-hover > td, |
| | | /deep/.is-replace.is-replace:hover > td { |
| | | background: #affaff; |
| | | } |
| | | /deep/.ant-table-row-level-1 > td { |
| | | background: #ff8ea2; |
| | | } |
| | | /deep/.ant-table-row-level-1.ant-table-row-level-1.ant-table-row-hover > td, |
| | | /deep/.ant-table-row-level-1.ant-table-row-level-1:hover > td { |
| | | background: #ffbcc9; |
| | | } |
| | | .title { |
| | | margin-bottom: 20px; |
| | | color: rgba(0, 0, 0, 0.85); |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | line-height: 1.5; |
| | | } |
| | | } |
| | | .diff-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: 400px; |
| | | .footer { |
| | | text-align: right; |
| | | .btn { |
| | | padding: 6px; |
| | | display: inline-block; |
| | | background: #00eaff; |
| | | border-radius: 4px; |
| | | color: #fff; |
| | | } |
| | | } |
| | | .img-wrap { |
| | | flex: 1; |
| | | } |
| | | &.full { |
| | | position: fixed; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | height: auto; |
| | | } |
| | | } |
| | | .img-wrap { |
| | | width: 100%; |
| | | position: relative; |
| | | .img-wrap-inner { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | } |
| | | .all { |
| | | padding: 10px 20px; |
| | | font-size: 22px; |
| | | } |
| | | </style> |
New file |
| | |
| | | import list from './list'; |
| | | export default list; |
New file |
| | |
| | | <template> |
| | | <div class="main"> |
| | | <div class="inner" ref="wraper"> |
| | | <a-spin class="" :spinning="spinning" tip="拼命加载中..."> |
| | | <a-card> |
| | | <advance-table |
| | | ref="table" |
| | | class="doc-center-table" |
| | | :data-source="dataSource" |
| | | :columns="columns" |
| | | title="" |
| | | :row-key="(record, index) => index" |
| | | @search="onSearch" |
| | | @refresh="onRefresh" |
| | | @reset="onReset" |
| | | :format-conditions="true" |
| | | :scroll="{ y }" |
| | | :pagination="{ |
| | | current: pageCurr, |
| | | pageSize: pageSize, |
| | | total: total, |
| | | showSizeChanger: true, |
| | | showLessItems: true, |
| | | showQuickJumper: true, |
| | | pageSizeOptions: ['10', '20', '50', '100'], |
| | | showTotal: (total, range) => |
| | | `第 ${range[0]}-${range[1]} 条,总计 ${total} 条`, |
| | | onChange: onPageChange, |
| | | onShowSizeChange: onSizeChange, |
| | | }" |
| | | > |
| | | <template slot="title"> |
| | | <a-space class="operator"> |
| | | <span class="title">技术规格书</span> |
| | | <a-button v-if="canUploadBom" type="primary" @click="showUpload" |
| | | >新增</a-button |
| | | > |
| | | </a-space> |
| | | </template> |
| | | <template slot="status" slot-scope="{ record }"> |
| | | <a-tag color="green" v-if="!record.lockFlag">可用</a-tag> |
| | | <a-tag color="red" v-else>不可用</a-tag> |
| | | </template> |
| | | <template slot="action" slot-scope="{ record }"> |
| | | <a-button type="primary" @click="viewLog(record)" |
| | | >锁定日志</a-button |
| | | > |
| | | <a-divider type="vertical"></a-divider> |
| | | <a-popover title="" trigger="hover"> |
| | | <a-space class="btn-grp" direction="vertical" slot="content"> |
| | | <!-- <a-button |
| | | v-if="canUpload" |
| | | type="primary" |
| | | @click="updateDesc(record)" |
| | | >更新说明</a-button |
| | | > --> |
| | | <a-button |
| | | v-if="record.lockFlag == 0" |
| | | type="primary" |
| | | @click="view(record)" |
| | | >预览</a-button |
| | | > |
| | | <a-button |
| | | v-if="canLock(record)" |
| | | type="primary" |
| | | @click="lock(record)" |
| | | >锁定</a-button |
| | | > |
| | | <a-button |
| | | v-if="canUnLock(record)" |
| | | type="primary" |
| | | @click="lock(record)" |
| | | >解锁</a-button |
| | | > |
| | | <!-- <a-button |
| | | v-if="canUpload" |
| | | type="primary" |
| | | @click="handleEmailShow(record)" |
| | | >邮件通知</a-button |
| | | > --> |
| | | <a-button type="primary" @click="goHistory(record)" |
| | | >历史版本</a-button |
| | | > |
| | | </a-space> |
| | | <a>更多</a> |
| | | </a-popover> |
| | | </template> |
| | | </advance-table> |
| | | </a-card> |
| | | </a-spin> |
| | | </div> |
| | | <pop |
| | | :visible.sync="popVisible" |
| | | :x="popPosition.x" |
| | | :y="popPosition.y" |
| | | :position="popPosition.dir" |
| | | :info="popInfo" |
| | | ></pop> |
| | | <a-modal |
| | | :visible="uploadShow" |
| | | :footer="null" |
| | | :width="800" |
| | | title="上传SOP" |
| | | :destroyOnClose="true" |
| | | :maskClosable="false" |
| | | @cancel="uploadCancel" |
| | | > |
| | | <div class=""> |
| | | <template v-if="!onlyXls"> |
| | | <a-row type="flex" class="row"> |
| | | <a-col flex="6em" class="label">规格书文件</a-col> |
| | | <a-col :flex="1"> |
| | | <a-upload |
| | | class="upload" |
| | | :before-upload="beforeUpload" |
| | | @change="uploadChange" |
| | | accept=".zip,.rar,.pdf" |
| | | > |
| | | <a-button type="primary">选文件</a-button> |
| | | </a-upload> |
| | | </a-col> |
| | | </a-row> |
| | | </template> |
| | | <a-row type="flex" class="row"> |
| | | <a-col flex="6em" class="label">规格书说明</a-col> |
| | | <a-col :flex="1"> |
| | | <a-upload |
| | | class="upload" |
| | | :before-upload="beforeUpload" |
| | | @change="uploadChange1" |
| | | accept=".xls,.xlsx" |
| | | > |
| | | <a-button type="primary">说明文件</a-button> |
| | | </a-upload> |
| | | </a-col> |
| | | </a-row> |
| | | <div class="sub-title">说明文件解析结果</div> |
| | | <div class="res-content"> |
| | | <desc-res :info="resObj"></desc-res> |
| | | </div> |
| | | <div class="modal-footer"> |
| | | <a-button type="danger" @click="uploadCancel"> 取消 </a-button> |
| | | <a-button v-if="!onlyXls" type="primary" @click="uploadSop"> |
| | | 提交 |
| | | </a-button> |
| | | <a-button v-else type="primary" @click="applyModel"> 提交 </a-button> |
| | | </div> |
| | | </div> |
| | | </a-modal> |
| | | <a-modal |
| | | :visible="emailShow" |
| | | :footer="null" |
| | | :width="760" |
| | | title="邮件发送" |
| | | :destroyOnClose="true" |
| | | :maskClosable="false" |
| | | @cancel="emailCancel" |
| | | > |
| | | <email-card |
| | | :visible.sync="emailShow" |
| | | :users="userList" |
| | | :title="emailInfo.title" |
| | | :content="emailInfo.content" |
| | | :type="2" |
| | | v-if="emailShow" |
| | | ></email-card> |
| | | </a-modal> |
| | | <!-- 操作原因 --> |
| | | <a-modal |
| | | :visible="reasonVisible" |
| | | :width="460" |
| | | title="操作原因" |
| | | :destroyOnClose="true" |
| | | :maskClosable="false" |
| | | @cancel="reasonCancel" |
| | | @ok="reasonOk" |
| | | > |
| | | <a-form-model-item ref="name" label="操作原因"> |
| | | <a-input |
| | | type="textarea" |
| | | v-model="reason" |
| | | placeHolder="请输入操作原因" |
| | | /> |
| | | </a-form-model-item> |
| | | </a-modal> |
| | | <!-- 日志 --> |
| | | <a-modal |
| | | :visible="logVisible" |
| | | :footer="null" |
| | | :width="800" |
| | | title="操作日志" |
| | | :destroyOnClose="true" |
| | | @cancel="logCancel" |
| | | > |
| | | <div class="log-content"> |
| | | <a-timeline v-if="logList.length"> |
| | | <a-timeline-item |
| | | v-for="(item, idx) in logList" |
| | | :key="'log_' + idx" |
| | | :color="item.status == 0 ? 'red' : 'green'" |
| | | > |
| | | <div> |
| | | <span class="user">{{ item.userName }}</span> 在 |
| | | <span class="time">{{ item.createTime }}</span> |
| | | {{ item.status == 0 ? "锁定" : "解锁" }}了版本 |
| | | <span class="version">{{ item.fileVersion }}</span> |
| | | </div> |
| | | <div>操作原因: {{ item.reason ? item.reason : "无" }}</div> |
| | | </a-timeline-item> |
| | | </a-timeline> |
| | | <a-empty v-else /> |
| | | </div> |
| | | </a-modal> |
| | | |
| | | <!-- 日志 --> |
| | | <a-modal |
| | | :visible="pdfInfo.visible" |
| | | :footer="null" |
| | | :width="960" |
| | | title="文件预览" |
| | | :destroyOnClose="true" |
| | | @cancel="pdfCancel" |
| | | > |
| | | <div style="height:600px; overflow-y: auto"> |
| | | <iframe :src="pdfInfo.src"></iframe> |
| | | </div> |
| | | </a-modal> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import AdvanceTable from "@/components/table/advance/AdvanceTable"; |
| | | import getWebUrl from "@/assets/js/tools/getWebUrl"; |
| | | import checkPermit from "@/assets/js/tools/checkPermit"; |
| | | import PERMITS from "@/assets/js/const/const_permits"; |
| | | import { mapGetters } from "vuex"; |
| | | import EmailCard from "../../components/emailCard"; |
| | | import { getUserList } from "../../permission/apis"; |
| | | import { |
| | | excelParse, |
| | | upload, |
| | | getList, |
| | | updateLock, |
| | | getLogs, |
| | | // updateSop, |
| | | } from "./apis"; |
| | | |
| | | import { sendMail } from "../../components/emailCard/apis"; |
| | | |
| | | import offset from "@/assets/js/tools/offset"; |
| | | import Pop from "./pop"; |
| | | import DescRes from "./descRes"; |
| | | import getFileTypeAndName from "@/assets/js/tools/getFileTypeAndName"; |
| | | import VuePdf from "vue-pdf"; |
| | | |
| | | export default { |
| | | components: { |
| | | AdvanceTable, |
| | | Pop, |
| | | DescRes, |
| | | EmailCard, |
| | | VuePdf, |
| | | }, |
| | | name: "list", |
| | | data() { |
| | | return { |
| | | pdfInfo: { |
| | | visible: false, |
| | | src: "", |
| | | loadedRatio: 0, |
| | | page: 1, |
| | | numPages: 0, |
| | | rotate: 0, |
| | | }, |
| | | rowFileName: "", |
| | | logList: [], |
| | | logVisible: false, |
| | | currentObj: null, |
| | | reasonVisible: false, |
| | | reason: "", |
| | | emailShow: false, |
| | | emailInfo: { |
| | | title: "", |
| | | content: "", |
| | | }, |
| | | userList: [], |
| | | onlyXls: false, |
| | | uploadShow: false, |
| | | webUrl: getWebUrl(), |
| | | prodsColumns: [ |
| | | { |
| | | title: "物料编码", |
| | | dataIndex: "code", |
| | | align: "center", |
| | | }, |
| | | { |
| | | title: "型/板号", |
| | | dataIndex: "model", |
| | | align: "center", |
| | | width: 180, |
| | | }, |
| | | // { |
| | | // title: "操作", |
| | | // dataIndex: "operation", |
| | | // align: "center", |
| | | // width: 180, |
| | | // scopedSlots: { customRender: "action" }, |
| | | // }, |
| | | ], |
| | | file: null, |
| | | file1: null, |
| | | resObj: {}, |
| | | popInfo: {}, |
| | | popVisible: false, |
| | | popPosition: { |
| | | x: 500, |
| | | y: 100, |
| | | dir: "bottom", |
| | | }, |
| | | spinning: false, |
| | | loading: false, |
| | | pageCurr: 1, |
| | | pageSize: 20, |
| | | total: 0, |
| | | y: 400, |
| | | update: -1, |
| | | conditions: {}, |
| | | columns: [ |
| | | { |
| | | title: "文件名称", |
| | | dataIndex: "fileName", |
| | | align: "center", |
| | | width: 140, |
| | | // searchAble: true, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "文件版本", |
| | | dataIndex: "version", |
| | | align: "center", |
| | | width: 80, |
| | | searchAble: false, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "基于版本", |
| | | dataIndex: "basedVersion", |
| | | align: "center", |
| | | width: 80, |
| | | searchAble: false, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "发布时间", |
| | | dataIndex: "createTime", |
| | | align: "center", |
| | | width: 160, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "负责人", |
| | | dataIndex: "owner", |
| | | align: "center", |
| | | searchAble: true, |
| | | width: 90, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "适用产品料号", |
| | | dataIndex: "applyMaterialCode", |
| | | searchAble: true, |
| | | align: "center", |
| | | width: 120, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "适用产品型号", |
| | | dataIndex: "applyModel", |
| | | searchAble: true, |
| | | align: "center", |
| | | width: 120, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "适用产品定制单号", |
| | | dataIndex: "applyCustomCode", |
| | | searchAble: true, |
| | | align: "center", |
| | | width: 140, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "标准机型", |
| | | dataIndex: "isNormal", |
| | | dataType: "boolean", |
| | | align: "center", |
| | | width: 40, |
| | | searchAble: true, |
| | | noSearch: true, |
| | | visible: false, |
| | | }, |
| | | { |
| | | title: "发布说明", |
| | | dataIndex: "releaseNotes", |
| | | align: "center", |
| | | width: 260, |
| | | customCell: this.customCell, |
| | | }, |
| | | { |
| | | title: "是否可用", |
| | | dataIndex: "lockFlag", |
| | | dataType: "boolean", |
| | | align: "center", |
| | | searchAble: true, |
| | | width: 100, |
| | | // search: { |
| | | // default: true, |
| | | // }, |
| | | scopedSlots: { customRender: "status" }, |
| | | }, |
| | | { |
| | | title: "操作", |
| | | dataIndex: "operation", |
| | | align: "center", |
| | | width: 200, |
| | | fixed: "right", |
| | | scopedSlots: { customRender: "action" }, |
| | | noSearch: true, |
| | | }, |
| | | ], |
| | | dataSource: [], |
| | | }; |
| | | }, |
| | | computed: { |
| | | ...mapGetters("account", ["permits", "user"]), |
| | | ...mapGetters("setting", ["affixed"]), |
| | | canUploadBom() { |
| | | return checkPermit(PERMITS.uploadBom, this.permits); |
| | | }, |
| | | canUpload() { |
| | | return checkPermit(PERMITS.uploadSoftware, this.permits); |
| | | }, |
| | | canDownload() { |
| | | return checkPermit(PERMITS.downloadSop, this.permits); |
| | | }, |
| | | }, |
| | | watch: { |
| | | update(n) { |
| | | if (-1 != n && !this._inactive) { |
| | | this.$nextTick(() => { |
| | | const table = this.$refs.table; |
| | | const header = document.querySelectorAll( |
| | | ".doc-center-table .ant-table-header" |
| | | )[0].clientHeight; |
| | | const bar = document.querySelectorAll(".header-bar")[0].clientHeight; |
| | | if (table.fullScreen) { |
| | | this.y = table.$el.clientHeight - bar - header - 64; |
| | | } else { |
| | | const wraper = this.$refs.wraper.clientHeight; |
| | | const card = document.querySelectorAll(".ant-card-body")[0]; |
| | | const { paddingBottom, paddingTop } = getComputedStyle(card, null); |
| | | const h = |
| | | wraper - |
| | | header - |
| | | 64 - |
| | | bar - |
| | | parseInt(paddingBottom) - |
| | | parseInt(paddingTop); |
| | | this.y = h; |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | affixed() { |
| | | setTimeout(() => { |
| | | this.update = Math.random(); |
| | | }, 200); |
| | | }, |
| | | }, |
| | | methods: { |
| | | view(obj) { |
| | | let { fileUrl } = obj; |
| | | window.open(this.webUrl + fileUrl); |
| | | }, |
| | | canLock(row) { |
| | | let uname = this.user.name; |
| | | return row.owner == uname && row.lockFlag == 0; |
| | | }, |
| | | canUnLock(row) { |
| | | let uname = this.user.name; |
| | | // flag 为1 是可操作的 |
| | | return row.owner == uname && row.lockFlag == 1 && row.flag == 1; |
| | | }, |
| | | searchAllUserList() { |
| | | getUserList() |
| | | .then((res) => { |
| | | let rs = res.data; |
| | | if (rs.code && rs.data) { |
| | | this.userList = rs.data2; |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.log(error); |
| | | }); |
| | | }, |
| | | showUpload() { |
| | | this.file = null; |
| | | this.file1 = null; |
| | | this.resObj = {}; |
| | | this.onlyXls = false; |
| | | this.uploadShow = true; |
| | | }, |
| | | updateDesc(row) { |
| | | this.file = null; |
| | | this.file1 = null; |
| | | this.resObj = { rowId: row.id }; |
| | | this.rowFileName = row.fileName; |
| | | this.onlyXls = true; |
| | | this.uploadShow = true; |
| | | }, |
| | | uploadCancel() { |
| | | this.uploadShow = false; |
| | | }, |
| | | sendEmail() { |
| | | let { title, content } = this.handleEmailShow(this.curObj, true); |
| | | let params = { mailList: this.mailList, title, content }; |
| | | sendMail(params); |
| | | }, |
| | | handleEmailShow(record, get) { |
| | | let title = |
| | | "[技术规格书发布记录]" + record.fileName + " 版本:" + record.version; |
| | | let content = []; |
| | | content.push("负责人: " + record.owner); |
| | | content.push("归档日期: " + record.filingDate); |
| | | content.push("物料编码: " + record.applyMaterialCode); |
| | | content.push("物料名称: " + record.applyModel); |
| | | content.push("规格型号: " + record.applyModel); |
| | | content.push("标准机型: " + (!record.applyCustomCode ? "是" : "否")); |
| | | content.push("定制单号: " + (record.applyCustomCode || "无")); |
| | | content.push("版本: " + record.version); |
| | | content.push("发布说明: " + record.releaseNotes); |
| | | if (get) { |
| | | return { |
| | | title, |
| | | content: content.join("\n"), |
| | | }; |
| | | } |
| | | }, |
| | | emailCancel() { |
| | | this.emailShow = false; |
| | | }, |
| | | uploadSop() { |
| | | if (!this.file) { |
| | | this.$message.error("请选择要上传的文件"); |
| | | return false; |
| | | } |
| | | if (!this.file1) { |
| | | this.$message.error("请选择说明文件"); |
| | | return false; |
| | | } |
| | | if (!this.resObj.fileName) { |
| | | this.$message.error("说明文件解析异常"); |
| | | return false; |
| | | } |
| | | // 如果文件名称 != 说明里的文件名称 + 文件版本 则报错拒绝 |
| | | let reg = /(.*)\..{1,5}$/; |
| | | let name1 = this.file.name.match(reg)[1]; |
| | | let { fileName, version, type } = this.resObj; |
| | | let name2 = fileName + version; |
| | | |
| | | if (type.toLowerCase() != "pdf") { |
| | | this.$message.error("规格书文件类型不正确"); |
| | | return false; |
| | | } |
| | | |
| | | if (name1.toLowerCase() != name2.toLowerCase()) { |
| | | console.log(name1.toLowerCase() + "&&&&&&" + name2.toLowerCase()); |
| | | this.$message.error("规格书与说明文件可能不匹配"); |
| | | return false; |
| | | } |
| | | |
| | | let loading = this.$layer.loading(); |
| | | |
| | | const formData = new FormData(); |
| | | formData.append("file1", this.file); |
| | | formData.append("file2", this.file1); |
| | | formData.append("technicalSpecificationStr", JSON.stringify(this.resObj)); |
| | | upload(formData) |
| | | .then((res) => { |
| | | let { code, data, msg } = res.data; |
| | | if (code && data) { |
| | | this.uploadShow = false; |
| | | this.$message.success("上传成功"); |
| | | this.searchData(); |
| | | } else { |
| | | this.$message.error(msg); |
| | | } |
| | | this.$layer.close(loading); |
| | | }) |
| | | .catch((error) => { |
| | | this.$layer.close(loading); |
| | | console.log(error); |
| | | }); |
| | | }, |
| | | applyModel() { |
| | | if (!this.file1) { |
| | | this.$message.error("请选择说明文件"); |
| | | return false; |
| | | } |
| | | if (!this.resObj.fileName) { |
| | | this.$message.error("说明文件解析异常"); |
| | | return false; |
| | | } |
| | | |
| | | if ( |
| | | this.rowFileName.toLowerCase() != this.resObj.fileName.toLowerCase() |
| | | ) { |
| | | this.$message.error("说明文件与该条记录可能不匹配"); |
| | | return false; |
| | | } |
| | | let loading = this.$layer.loading(); |
| | | // updateSop(this.resObj) |
| | | // .then((res) => { |
| | | // let { code, data, msg } = res.data; |
| | | // if (code) { |
| | | // this.uploadShow = false; |
| | | // this.$message.success("上传成功"); |
| | | // this.searchData(); |
| | | // } else { |
| | | // this.$message.error("解析失败"); |
| | | // } |
| | | // this.$layer.close(loading); |
| | | // }) |
| | | // .catch((error) => { |
| | | // this.$layer.close(loading); |
| | | // console.log(error); |
| | | // }); |
| | | }, |
| | | cellMouseenter(e, obj) { |
| | | // console.log("enter", e, obj); |
| | | const wraper = this.$refs.wraper; |
| | | const { clientHeight, clientWidth } = wraper; |
| | | const { target, clientX, clientY } = e; |
| | | let { left: x, top: y } = offset(wraper); |
| | | x = clientX - x; |
| | | y = clientY - y; |
| | | // 如果clientHeight 小于380 * 2 则左右布局 |
| | | let dir = "bottom"; |
| | | if (clientHeight < 380 * 2) { |
| | | if (x + 420 + 18 > clientWidth) { |
| | | dir = "left"; |
| | | } else { |
| | | dir = "right"; |
| | | } |
| | | if (y < 180) { |
| | | y = 180; |
| | | } else if (y > clientHeight - 378) { |
| | | y = clientHeight / 2; |
| | | } |
| | | } else { |
| | | if (y + 18 + 360 > clientHeight) { |
| | | // y = clientHeight - 378; |
| | | dir = "top"; |
| | | } else { |
| | | dir = "bottom"; |
| | | } |
| | | if (x < 400) { |
| | | x = 400; |
| | | } |
| | | if (x + 400 > clientWidth) { |
| | | x = clientWidth - 400; |
| | | } |
| | | } |
| | | this.popPosition.x = x; |
| | | this.popPosition.y = y; |
| | | this.popPosition.dir = dir; |
| | | this.popInfo = obj; |
| | | this.popVisible = true; |
| | | }, |
| | | cellMouseleave(e, obj) { |
| | | // console.log("leave", obj); |
| | | this.popVisible = false; |
| | | }, |
| | | customCell(record) { |
| | | return { |
| | | on: { |
| | | mouseenter: (e) => this.cellMouseenter(e, record), |
| | | mouseleave: (e) => this.cellMouseleave(e, record), |
| | | }, |
| | | }; |
| | | }, |
| | | beforeUpload() { |
| | | return false; |
| | | }, |
| | | uploadChange(data) { |
| | | const { file, fileList } = data; |
| | | if (fileList.length > 1) { |
| | | fileList.shift(); |
| | | } |
| | | if (fileList.length) { |
| | | this.file = fileList[0].originFileObj; |
| | | } else { |
| | | this.file = null; |
| | | } |
| | | }, |
| | | uploadChange1(data) { |
| | | const { file, fileList } = data; |
| | | if (fileList.length > 1) { |
| | | fileList.shift(); |
| | | } |
| | | if (fileList.length) { |
| | | this.file1 = fileList[0].originFileObj; |
| | | } else { |
| | | this.file1 = null; |
| | | this.resObj = []; |
| | | return false; |
| | | } |
| | | let loading = this.$layer.loading(); |
| | | const formData = new FormData(); |
| | | formData.append("multipartFile", this.file1); |
| | | excelParse(formData) |
| | | .then((res) => { |
| | | this.$layer.close(loading); |
| | | let { code, data, data2, msg } = res.data; |
| | | if (code && data) { |
| | | let rowId = this.resObj.rowId; |
| | | this.resObj = data2; |
| | | this.resObj.id = rowId; |
| | | this.$message.success("解析成功"); |
| | | } else { |
| | | this.$message.error(msg); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | this.$layer.close(loading); |
| | | console.log(error); |
| | | }); |
| | | }, |
| | | resize() { |
| | | setTimeout(() => { |
| | | this.update = Math.random(); |
| | | }, 200); |
| | | }, |
| | | activeFN() { |
| | | this.resize(); |
| | | }, |
| | | onSearch(conditions, searchOptions, col) { |
| | | // console.log(conditions); |
| | | // console.log(searchOptions, "00", col); |
| | | this.pageCurr = 1; |
| | | this.conditions = conditions; |
| | | this.searchData(); |
| | | }, |
| | | onPageChange(page, pageSize) { |
| | | this.pageCurr = page; |
| | | this.pageSize = pageSize; |
| | | this.searchData(); |
| | | }, |
| | | onSizeChange(current, size) { |
| | | this.pageCurr = 1; |
| | | this.pageSize = size; |
| | | this.searchData(); |
| | | }, |
| | | onRefresh(conditions) { |
| | | this.conditions = conditions; |
| | | this.searchData(); |
| | | }, |
| | | onReset(conditions) { |
| | | this.conditions = conditions; |
| | | this.searchData(); |
| | | }, |
| | | searchData() { |
| | | const { pageCurr, pageSize, conditions, columns } = this; |
| | | let params2 = {}; |
| | | // console.log(this.conditions["status"]); |
| | | let col, index; |
| | | Object.keys(conditions).forEach((v) => { |
| | | switch (v) { |
| | | case "isNormal": |
| | | if (conditions[v]) { |
| | | params2["applyCustomCode"] = ""; |
| | | columns.forEach((val, idx) => { |
| | | if (val.dataIndex == "applyCustomCode") { |
| | | col = { ...val, search: { value: "", backup: "" } }; |
| | | index = idx; |
| | | } |
| | | }); |
| | | this.$set(this.columns, index, col); |
| | | } |
| | | break; |
| | | default: |
| | | params2[v] = conditions[v]; |
| | | break; |
| | | } |
| | | }); |
| | | let list = []; |
| | | getList(pageCurr, pageSize, params2) |
| | | .then((res) => { |
| | | let { code, data, data2 } = res.data; |
| | | let total = 0; |
| | | if (code && data) { |
| | | // console.log(data2); |
| | | list = data2.list; |
| | | total = data2.total; |
| | | } |
| | | this.dataSource = list.map((item) => { |
| | | const fileInfo = getFileTypeAndName(item.fileUrl); |
| | | item.isCanPreview = fileInfo.type === "pdf"; |
| | | return item; |
| | | }); |
| | | this.total = total; |
| | | if (-1 == this.update) { |
| | | this.update = Math.random(); |
| | | } |
| | | }) |
| | | .catch((err) => { |
| | | console.log(err); |
| | | }); |
| | | }, |
| | | downloadFile(record) { |
| | | const fileInfo = getFileTypeAndName(record.fileUrl); |
| | | let url = this.webUrl + record.fileUrl; |
| | | if (fileInfo.type === "pdf") { |
| | | // 预览 |
| | | window.open(url); |
| | | } else { |
| | | // 下载 |
| | | let loading = this.$layer.loading(); |
| | | let link = document.createElement("a"); |
| | | link.style.display = "none"; |
| | | let fileName = record.fileUrl.split("/").pop(); |
| | | link.href = url; |
| | | link.download = fileName; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | this.$layer.close(loading); |
| | | document.body.removeChild(link); |
| | | } |
| | | }, |
| | | reasonCancel() { |
| | | this.reasonVisible = false; |
| | | }, |
| | | reasonOk() { |
| | | let { id, lockFlag } = this.currentObj; |
| | | let reason = this.reason; |
| | | lockFlag = lockFlag == 0 ? 1 : 0; |
| | | updateLock({ id, lockFlag, reason }).then((res) => { |
| | | const { code } = res.data; |
| | | if (code) { |
| | | this.$message.success("操作成功"); |
| | | this.reasonVisible = false; |
| | | this.searchData(); |
| | | } else { |
| | | this.$message.error("操作失败"); |
| | | } |
| | | }); |
| | | }, |
| | | lock(record) { |
| | | this.reason = ""; |
| | | this.currentObj = record; |
| | | this.reasonVisible = true; |
| | | }, |
| | | viewLog(obj) { |
| | | // console.log(obj); |
| | | const { id } = obj; |
| | | getLogs(id).then((res) => { |
| | | const { code, data, data2 } = res.data; |
| | | if (code) { |
| | | this.logList = data2; |
| | | this.logVisible = true; |
| | | } else { |
| | | this.$message.error("日志查询失败"); |
| | | } |
| | | }); |
| | | }, |
| | | logCancel() { |
| | | this.logVisible = false; |
| | | }, |
| | | pdfCancel() { |
| | | this.pdfInfo.visible = false; |
| | | }, |
| | | goHistory(record) { |
| | | let { applyMaterialCode, applyModel, applyCustomCode } = record; |
| | | this.$router.push({ |
| | | path: "/resource/specification-history", |
| | | query: { applyMaterialCode, applyModel, applyCustomCode }, |
| | | }); |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.searchData(); |
| | | this.searchAllUserList(); |
| | | window.addEventListener("resize", this.resize); |
| | | }, |
| | | destroyed() { |
| | | window.removeEventListener("resize", this.resize); |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .main { |
| | | height: 100%; |
| | | position: relative; |
| | | .inner { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | } |
| | | } |
| | | .img-wraper { |
| | | width: 80px; |
| | | height: 50px; |
| | | display: inline-block; |
| | | .image-view { |
| | | width: 100%; |
| | | height: 100%; |
| | | /deep/img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | } |
| | | /deep/table { |
| | | table-layout: fixed; |
| | | } |
| | | .modal-footer { |
| | | text-align: right; |
| | | button + button { |
| | | margin-left: 8px; |
| | | } |
| | | } |
| | | .label { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | align-items: center; |
| | | padding-right: 0.4em; |
| | | height: 32px; |
| | | &::after { |
| | | content: ":"; |
| | | } |
| | | } |
| | | .row ~ .row { |
| | | margin-top: 10px; |
| | | } |
| | | .sub-title { |
| | | font-size: 14px; |
| | | font-weight: 700; |
| | | margin-top: 10px; |
| | | } |
| | | .res-content { |
| | | max-height: 260px; |
| | | overflow-y: auto; |
| | | margin-bottom: 10px; |
| | | } |
| | | .btn-grp button { |
| | | width: 6.4em; |
| | | } |
| | | .tag-all { |
| | | margin: 0; |
| | | } |
| | | /deep/ .ant-table-fixed-right { |
| | | .ant-table-body-outer { |
| | | margin-bottom: 0 !important; |
| | | } |
| | | .ant-table-body-inner { |
| | | overflow-x: hidden; |
| | | } |
| | | } |
| | | .log-content { |
| | | max-height: 400px; |
| | | overflow-y: auto; |
| | | |
| | | .user { |
| | | color: #23aaf2; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .time { |
| | | color: #f9be13; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .version { |
| | | color: #0aedb2; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .ant-timeline-item:first-of-type { |
| | | padding-top: 6px; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div |
| | | ref="pop" |
| | | :class="['pop', position]" |
| | | :style="{ |
| | | left: x + 'px', |
| | | top: y + 'px', |
| | | display: visible ? 'block' : 'none', |
| | | }" |
| | | > |
| | | <div class="inner"> |
| | | <desc-res :info="info"></desc-res> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import DescRes from "./rowRes"; |
| | | export default { |
| | | name: "", |
| | | components: { |
| | | DescRes, |
| | | }, |
| | | props: { |
| | | info: { |
| | | type: Object, |
| | | default() { |
| | | return {}; |
| | | }, |
| | | }, |
| | | x: { |
| | | type: Number, |
| | | default: 0, |
| | | }, |
| | | y: { |
| | | type: Number, |
| | | default: 0, |
| | | }, |
| | | visible: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | position: { |
| | | type: String, |
| | | default: "bottom", |
| | | }, |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | methods: { |
| | | onMouseenter() { |
| | | this.$emit('update:visible', true); |
| | | }, |
| | | onMouseleave() { |
| | | this.$emit('update:visible', false); |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | this.$refs.pop.addEventListener('mouseenter', this.onMouseenter); |
| | | this.$refs.pop.addEventListener('mouseleave', this.onMouseleave); |
| | | }, |
| | | beforeDestroy() { |
| | | this.$refs.pop.removeEventListener('mouseenter', this.onMouseenter); |
| | | this.$refs.pop.removeEventListener('mouseleave', this.onMouseleave); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .pop { |
| | | position: absolute; |
| | | z-index: 1; |
| | | background: rgba(0, 0, 0, 0.6); |
| | | width: 800px; |
| | | padding: 10px; |
| | | border-radius: 6px; |
| | | /deep/ th, |
| | | /deep/ td { |
| | | border: 1px #fff solid; |
| | | color: #fff; |
| | | } |
| | | &.top { |
| | | transform: translate(-50%, -100%); |
| | | margin-top: -10px; |
| | | &::after { |
| | | content: ""; |
| | | position: absolute; |
| | | top: 100%; |
| | | left: 50%; |
| | | transform: translateX(-5px); |
| | | display: inline-block; |
| | | width: 0; |
| | | height: 0; |
| | | border-top: 10px solid rgba(0, 0, 0, 0.6); |
| | | border-left: 5px solid transparent; |
| | | border-right: 5px solid transparent; |
| | | } |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | top: 100%; |
| | | left: 0; |
| | | right: 0; |
| | | display: inline-block; |
| | | height: 10px; |
| | | background: transparent; |
| | | } |
| | | } |
| | | &.bottom { |
| | | margin-top: 10px; |
| | | transform: translate(-50%, 0%); |
| | | &::after { |
| | | content: ""; |
| | | position: absolute; |
| | | bottom: 100%; |
| | | left: 50%; |
| | | transform: translateX(-5px); |
| | | display: inline-block; |
| | | width: 0; |
| | | height: 0; |
| | | border-bottom: 10px solid rgba(0, 0, 0, 0.6); |
| | | border-left: 5px solid transparent; |
| | | border-right: 5px solid transparent; |
| | | } |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | bottom: 100%; |
| | | left: 0; |
| | | right: 0; |
| | | height: 10px; |
| | | background: transparent; |
| | | } |
| | | } |
| | | &.left { |
| | | margin-left: -10px; |
| | | transform: translate(-100%, -50%); |
| | | &::after { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 100%; |
| | | top: 50%; |
| | | transform: translateY(-5px); |
| | | display: inline-block; |
| | | width: 0; |
| | | height: 0; |
| | | border-left: 10px solid rgba(0, 0, 0, 0.6); |
| | | border-top: 5px solid transparent; |
| | | border-bottom: 5px solid transparent; |
| | | } |
| | | } |
| | | &.right { |
| | | margin-left: 10px; |
| | | transform: translate(0%, -50%); |
| | | &::after { |
| | | content: ""; |
| | | position: absolute; |
| | | right: 100%; |
| | | top: 50%; |
| | | transform: translateY(-5px); |
| | | display: inline-block; |
| | | width: 0; |
| | | height: 0; |
| | | border-right: 10px solid rgba(0, 0, 0, 0.6); |
| | | border-top: 5px solid transparent; |
| | | border-bottom: 5px solid transparent; |
| | | } |
| | | } |
| | | .inner { |
| | | max-height: 360px; |
| | | overflow-y: auto; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class=""> |
| | | <table class="table"> |
| | | <tbody> |
| | | <tr> |
| | | <th class="title" colspan="6">文件基本信息</th> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">文件名称</th> |
| | | <td colspan="5">{{ info.fileName }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">软件类型</th> |
| | | <td colspan="5">{{ info.type }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">文件版本</th> |
| | | <td colspan="1">{{ info.version }}</td> |
| | | <th class="col-1">基于版本</th> |
| | | <td colspan="3">{{ info.basedVersion }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">负责人</th> |
| | | <td colspan="1">{{ info.owner }}</td> |
| | | <th class="col-1">归档日期</th> |
| | | <td colspan="3">{{ info.filingDate }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="title" colspan="6">规格书适用机型</th> |
| | | </tr> |
| | | <tr > |
| | | <th class="col-1">物料编码</th> |
| | | <td colspan="1">{{ info.applyMaterialCode }}</td> |
| | | <th class="col-1">规格型号</th> |
| | | <td colspan="1">{{ info.applyModel }}</td> |
| | | <th class="col-1">定制单号</th> |
| | | <td colspan="1">{{ info.applyCustomCode }}</td> |
| | | </tr> |
| | | <tr> |
| | | <th class="col-1">发布说明</th> |
| | | <td colspan="5">{{ info.releaseNotes }}</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | info: { |
| | | type: Object, |
| | | default() { |
| | | return {}; |
| | | }, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | }; |
| | | }, |
| | | computed: { |
| | | }, |
| | | watch: { |
| | | }, |
| | | methods: { |
| | | }, |
| | | |
| | | mounted() { |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .table { |
| | | width: 100%; |
| | | // table-layout: fixed; |
| | | border-collapse: collapse; |
| | | th, |
| | | td { |
| | | border: 1px #fff solid; |
| | | padding: 4px; |
| | | } |
| | | td { |
| | | color: #fff; |
| | | } |
| | | .title { |
| | | font-weight: 900; |
| | | padding-left: 2em; |
| | | font-style: italic; |
| | | } |
| | | } |
| | | .col-1 { |
| | | // word-break:break-all; |
| | | width: 6.4em; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="posR"> |
| | | <div class="inner"> |
| | | <a-card class="main"> |
| | | <!-- 列表 --> |
| | | <div class="contain"> |
| | | <div |
| | | :class="['item', { selected: currentV == item.id }]" |
| | | v-for="(item, idx) in list" |
| | | :key="'item_' + idx" |
| | | @click="selectHandle(item)" |
| | | > |
| | | <span :class="['status', { actived: item.lockFlag == 0 }]"></span> |
| | | <div class="version">{{ item.version }}</div> |
| | | </div> |
| | | </div> |
| | | </a-card> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | list: { |
| | | type: Array, |
| | | default() { |
| | | return []; |
| | | }, |
| | | }, |
| | | }, |
| | | computed: { |
| | | // data() { |
| | | // return this.list.filter((v) => { |
| | | // const reg = new RegExp(this.keyword, "i"); |
| | | // return reg.test(v.subModel); |
| | | // }); |
| | | // }, |
| | | }, |
| | | watch: { |
| | | list(n) { |
| | | if (n.length) { |
| | | this.selectHandle(this.list[0]); |
| | | } |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | // keyword: '', |
| | | currentV: "-1", |
| | | }; |
| | | }, |
| | | components: {}, |
| | | methods: { |
| | | selectHandle(item) { |
| | | this.currentV = item.id; |
| | | this.$emit("select", item); |
| | | }, |
| | | }, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .posR { |
| | | position: relative; |
| | | } |
| | | .inner { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | } |
| | | .main { |
| | | height: 100%; |
| | | /deep/.ant-card-body { |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | } |
| | | .contain { |
| | | margin-top: 8px; |
| | | border: 1px solid #e8e8e8; |
| | | flex: 1; |
| | | overflow: auto; |
| | | padding: 0 4px; |
| | | } |
| | | .item { |
| | | cursor: pointer; |
| | | box-shadow: 0px 4px 5px -2px #000; |
| | | padding: 6px 0; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | flex-direction: row; |
| | | align-items: center; |
| | | & + .item { |
| | | margin-top: 4px; |
| | | } |
| | | &:hover { |
| | | transform: scale(0.98, 0.9); |
| | | box-shadow: 0px 2px 5px -2px #000; |
| | | background: #f0f0f0; |
| | | } |
| | | &.selected { |
| | | transform: scale(0.98, 0.9); |
| | | box-shadow: 0px 2px 5px -2px #000; |
| | | color: #13c2c2; |
| | | font-weight: bold; |
| | | } |
| | | .version { |
| | | flex: 1; |
| | | } |
| | | .status { |
| | | display: inline-block; |
| | | width: 10px; |
| | | height: 10px; |
| | | background: #aaa; |
| | | border-radius: 50%; |
| | | margin-left: 10px; |
| | | margin-right: 20px; |
| | | &.actived { |
| | | background: #00ff79; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | name: 'sop历史版本', |
| | | meta: { |
| | | invisible: true, |
| | | highlight: '/resource/sop-history' |
| | | highlight: '/resource/sop-file' |
| | | }, |
| | | component: () => import('@/pages/resourceManage/sopFile/sop-history'), |
| | | }, |
| | | { |
| | | path: 'specification', |
| | | name: '技术规格书', |
| | | component: () => import('@/pages/resourceManage/specification'), |
| | | }, |
| | | { |
| | | path: 'specification-history', |
| | | name: '技术规格书历史版本', |
| | | meta: { |
| | | invisible: true, |
| | | highlight: '/resource/specification' |
| | | }, |
| | | component: () => import('@/pages/resourceManage/specification/history'), |
| | | }, |
| | | ] |
| | | }, |
| | | { |