From 66b41779cf4090ed86509d9ed4b3522ded8e9049 Mon Sep 17 00:00:00 2001 From: he wei <858544502@qq.com> Date: 星期四, 25 七月 2024 13:30:57 +0800 Subject: [PATCH] UA 不良品页面提交 --- src/pages/components/filesList.vue | 179 +++++ src/pages/resourceManage/defective/apis.js | 48 + src/pages/resourceManage/defective/list.vue | 932 +++++++++++++++++++++++++++ src/pages/resourceManage/defective/prodUpload.vue | 417 ++++++++++++ src/components/datetimeRange/datetimeRange.vue | 20 src/pages/resourceManage/defective/disposeUpload.vue | 389 +++++++++++ src/pages/resourceManage/defective/index.js | 2 src/router/config.js | 5 src/components/table/advance/SearchArea.vue | 7 9 files changed, 1,996 insertions(+), 3 deletions(-) diff --git a/src/components/datetimeRange/datetimeRange.vue b/src/components/datetimeRange/datetimeRange.vue index 76cc4a2..5acaab5 100644 --- a/src/components/datetimeRange/datetimeRange.vue +++ b/src/components/datetimeRange/datetimeRange.vue @@ -1,11 +1,11 @@ <template> <div> <a-date-picker :getCalendarContainer="getCalendarContainer" v-model="startValue" :disabled-date="disabledStartDate" - :disabled-time="disabledStartTime" show-time format="YYYY-MM-DD HH:mm:ss" placeholder="Start" :open="startOpen" + :disabled-time="disabledStartTime" :show-time="showTime" :format="formatStr" placeholder="Start" :open="startOpen" size="small" @openChange="handleStartOpenChange" @change="change(0)" /> - <a-date-picker :getCalendarContainer="getCalendarContainer" v-model="endValue" :disabled-date="disabledEndDate" - :disabled-time="disabledEndTime" show-time format="YYYY-MM-DD HH:mm:ss" placeholder="End" :open="endOpen" + :disabled-time="disabledEndTime" :show-time="showTime" :format="formatStr" placeholder="End" :open="endOpen" size="small" @change="change(1)" @openChange="handleEndOpenChange" /> </div> </template> @@ -20,7 +20,18 @@ endOpen: false, }; }, - props: ["value", "getCalendarContainer"], + props: { + value: { + required: true, + }, + getCalendarContainer: { + required: true + }, + showTime: { + type: Boolean, + default: true + }, + }, model: { prop: "value", event: "change", @@ -40,6 +51,9 @@ this.endValue = value[1]; }, }, + formatStr() { + return this.showTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD" + }, }, methods: { range(start, end) { diff --git a/src/components/table/advance/SearchArea.vue b/src/components/table/advance/SearchArea.vue index 8bc7772..25377bb 100644 --- a/src/components/table/advance/SearchArea.vue +++ b/src/components/table/advance/SearchArea.vue @@ -41,6 +41,13 @@ <slot v-else-if="col.slots && col.slots.title" :name="col.slots.title"></slot> <datetime-range v-model="col.search.value" :getCalendarContainer="() => $refs.root" @change="onDateRangeChange(col)"></datetime-range> </div> + <div v-else-if="col.dataType === 'dateRange'" :class="['title', {active: col.search.value && (col.search.value[0] || col.search.value[1])}]"> + <template v-if="col.title"> + {{col.title}}: + </template> + <slot v-else-if="col.slots && col.slots.title" :name="col.slots.title"></slot> + <datetime-range v-model="col.search.value" :showTime="false" :getCalendarContainer="() => $refs.root" @change="onDateRangeChange(col)"></datetime-range> + </div> <div v-else-if="col.dataType === 'select'" :class="['title', {active: col.search.value !== undefined}]"> <template v-if="col.title"> {{col.title}}: diff --git a/src/pages/components/filesList.vue b/src/pages/components/filesList.vue new file mode 100644 index 0000000..9e6e45a --- /dev/null +++ b/src/pages/components/filesList.vue @@ -0,0 +1,179 @@ +<template> + <div class=""> + <a-table + ref="aTable" + size="small" + :scroll="{ y }" + bordered + :columns="columns" + :data-source="dataSource" + :pagination="false" + :rowKey="(record, index) => index" + > + <template slot="action" slot-scope="text, record"> + <div v-if="record.url"> + <a v-if="canView(record)" @click="view(record)">棰勮</a> + <template> + <a-divider type="vertical"></a-divider> + <a @click="downloadOther(record.url)">涓嬭浇</a> + </template> + </div> + </template> + </a-table> + <a-modal + :width="600" + :visible="previewVisible" + :footer="null" + @cancel="handleCancel" + > + <img alt="example" style="width: 100%" :src="imgUrl" /> + </a-modal> + </div> +</template> + +<script> +import getWebUrl from "@/assets/js/tools/getWebUrl"; +import { dwgReview } from "@/pages/workplace/apis"; +import { mapGetters } from "vuex"; +export default { + name: "", + components: {}, + props: { + list: { + type: Array, + default() { + return []; + }, + }, + }, + data() { + const columns = [ + { + title: "鏂囦欢鍚嶇О", + dataIndex: "fileName", + align: "center", + width: 200, + }, + { + title: "鏂囦欢绫诲瀷", + dataIndex: "fileType", + align: "center", + width: 100, + }, + { + title: "鎿嶄綔", + dataIndex: "operation", + key: "operation", + align: "center", + width: 200, + scopedSlots: { customRender: "action" }, + }, + ]; + return { + y1: 400, + columns, + y: 500, + imgUrl: "", + previewVisible: false, + webUrl: getWebUrl(), + }; + }, + methods: { + handleClick() { + this.$emit("success", this.list); + }, + canView(obj) { + return [ + "bmp", + "jpg", + "jpeg", + "gif", + "png", + "pdf", + "doc", + "docx", + "dwg", + ].some((v) => v == obj.fileType); + }, + view(obj) { + switch (obj.fileType) { + // 鍥剧墖 + case "bmp": + case "jpg": + case "jpeg": + case "gif": + case "png": + this.imgUrl = this.webUrl + obj.url; + this.previewVisible = true; + break; + case "pdf": + window.open(this.webUrl + obj.url); + break; + case "doc": + case "docx": + case "dwg": + this.dwgReview(obj.url); + break; + default: + this.$message.warn("璇ョ被鍨嬫枃浠舵殏涓嶆敮鎸侀瑙�"); + break; + } + }, + handleCancel() { + this.previewVisible = false; + }, + dwgReview(url) { + let loading = this.$layer.loading(); + dwgReview(url) + .then((res) => { + let { code, data, msg } = res.data; + if (code && data) { + window.open(this.webUrl + data); + } else { + this.$message.error(msg); + } + this.$layer.close(loading); + }) + .catch((error) => { + console.log(error); + this.$layer.close(loading); + }); + }, + downloadOther(url) { + let reg = /(.*\\+)*(.*)$/; + let fileName = url.match(reg)[2]; + + let link = document.createElement("a"); + link.style.display = "none"; + link.href = this.webUrl + url; + link.download = fileName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }, + }, + computed: { + dataSource() { + let reg = /(.*\\+)*(.*)$/; + return this.list.map((item) => { + let fileName = item.match(reg)[2]; + let arr = fileName.split("."); + let fileType = arr.length ? arr[arr.length - 1].toLowerCase() : ""; + return { + fileName, + fileType, + url: item, + }; + }); + }, + ...mapGetters("account", ["permits"]), + }, + mounted() {}, +}; +</script> + +<style lang="less" scoped> +/deep/.is-lock td { + background: #ddd; +} +</style> diff --git a/src/pages/resourceManage/defective/apis.js b/src/pages/resourceManage/defective/apis.js new file mode 100644 index 0000000..d1ea008 --- /dev/null +++ b/src/pages/resourceManage/defective/apis.js @@ -0,0 +1,48 @@ +import axios from "@/assets/axios"; + +/** + * 褰曞叆涓嶈壇鍝佷俊鎭� + * @param {*} data {multipartFileList, defectiveJson} + * @returns + */ +export const addDefective = (data) => { + return axios({ + method: "POST", + url: "defective/addDefective", + headers: { + "Content-Type": "multipart/form-data" + }, + data + }) +} + +/** + * 澶勭悊涓嶈壇鍝佷俊鎭� + * @param {*} data {multipartFileList, defectiveHisJson} + * @returns + */ +export const updateDefective = (data) => { + return axios({ + method: "POST", + url: "defective/updateDefective", + headers: { + "Content-Type": "multipart/form-data" + }, + data + }) +} + +/** + * 褰掓。涓嶈壇鍝佷俊鎭� + * @param {*} data deftId + * @returns + */ +export const stopDefective = (deftId) => { + return axios({ + method: "POST", + url: "defective/stopDefective", + params: { + deftId + } + }) +} \ No newline at end of file diff --git a/src/pages/resourceManage/defective/disposeUpload.vue b/src/pages/resourceManage/defective/disposeUpload.vue new file mode 100644 index 0000000..dcd88ba --- /dev/null +++ b/src/pages/resourceManage/defective/disposeUpload.vue @@ -0,0 +1,389 @@ +<template> + <div class="dispose"> + <a-form-model + ref="formRef" + name="advanced_search" + class="ant-advanced-search-form" + :model="info" + :rules="rules" + > + <a-row> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="鍏ュ簱鏃堕棿" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="startTime" + > + <a-date-picker + format="YYYY-MM-DD" + disabled + valueFormat="YYYY-MM-DD" + :allowClear="false" + :disabled-date="disabledDate" + :show-time="{ defaultValue: moment('00:00:00', 'HH:mm:ss') }" + v-model="info.startTime" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="鍘傚晢鍚嶇О" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="provideName" + > + <a-input + disabled + placeholder="璇疯緭鍏ュ巶鍟嗗悕绉�" + v-model.trim="info.provideName" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="浜у搧鍚嶇О" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="productName" + > + <a-input + disabled + placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" + v-model.trim="info.productName" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="浜у搧鍨嬪彿" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="type" + > + <a-input + disabled + placeholder="璇疯緭鍏ヤ骇鍝佸瀷鍙�" + v-model.trim="info.type" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="鍓╀綑涓嶈壇鏁�" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="restProduct" + > + <a-input disabled v-model.number="info.restProduct" /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="澶勭悊鏁伴噺" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="delProduct" + > + <a-input-number + placeholder="璇疯緭鍏ュ鐞嗘暟閲�" + :min="1" + :max="info.restProduct" + v-model.number="info.delProduct" + /> + </a-form-model-item> + </a-col> + <a-col :span="24"> + <a-form-model-item + class="ant-row-flex" + label="澶勭悊鎻忚堪" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="note" + > + <a-textarea + placeholder="璇疯緭鍏ュ鐞嗘弿杩�" + v-model.trim="info.note" + :rows="2" + /> + </a-form-model-item> + </a-col> + </a-row> + <a-row type="flex" class="row"> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="閭欢閫氱煡" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="selectedItems" + > + <a-select + mode="multiple" + placeholder="" + :value="info.selectedItems" + style="width: 100%" + allow-clear + @change="handleChange" + > + <a-select-option + v-for="item in filteredOptions" + :key="item.name" + :value="item.name" + :disabled="!item.isHasMail" + > + {{ item.name }} + </a-select-option> + </a-select> + </a-form-model-item> + </a-col> + </a-row> + <a-row type="flex" class="row"> + <a-col flex="8em" class="label">闄勪欢</a-col> + <a-col :flex="1"> + <a-upload + class="upload" + :before-upload="beforeUpload" + @change="uploadChange" + multiple + > + <!-- accept=".zip,.rar" --> + <a-button type="primary">閫夋嫨闄勪欢</a-button> + </a-upload> + </a-col> + </a-row> + </a-form-model> + <div class="modal-footer"> + <a-button type="danger" @click="cancel"> 鍙栨秷 </a-button> + <a-button type="primary" @click="ok"> 鎻愪氦 </a-button> + </div> + </div> +</template> + +<script> +import moment from "moment"; +import { updateDefective } from "./apis"; + +import { searchDefaultMailUser } from "../../components/emailCard/apis"; +import { getUserList } from "../../permission/apis"; + +export default { + name: "", + props: { + record: { + type: Object, + required: true, + }, + }, + data() { + // console.log("record", this.record, "============="); + const { + restProduct, + id: deftId, + productName, + provideName, + type, + startTime, + } = this.record; + + return { + userList: [], + defaultMailUsers: [], + selectedItems: [], + userListAll: [], + info: { + deftId, + restProduct, + provideName, + productName, + note: "", + type, + sumProduct: "", + badProduct: "", + delProduct: "", + // startTime: moment().format("YYYY-MM-DD"), + startTime, + selectedItems: [], + }, + file: null, + receiverIds: "", + receiverNames: "", + rules: { + delProduct: [ + { + required: true, + message: "璇疯緭鍏ュ鐞嗘暟閲�", + trigger: "blur", + }, + ], + note: [ + { + required: true, + message: "璇疯緭鍏ュ鐞嗘弿杩�", + trigger: "blur", + }, + ], + selectedItems: [ + { + required: true, + message: "璇峰厛鎷╄閭欢閫氱煡鐨勪汉鍛�", + trigger: "blur", + }, + // { validator: validateSelectedItems, trigger: "change" }, + ], + }, + }; + }, + computed: { + filteredOptions() { + let users = this.userListAll; + return users + .filter((o) => !this.info.selectedItems.includes(o.name)) + .map((o) => { + o.isHasMail = o.mail ? true : false; + return o; + }); + }, + }, + methods: { + moment, + beforeUpload() { + return false; + }, + uploadChange(data) { + const { file, fileList } = data; + if (fileList.length) { + this.file = fileList.map((v) => v.originFileObj); + } else { + this.file = null; + } + }, + searchAllUserList() { + getUserList() + .then((res) => { + let rs = res.data; + if (rs.code && rs.data) { + this.userListAll = rs.data2; + this.searchDefaultMailUser(); + } + }) + .catch((error) => { + console.log(error); + }); + }, + searchDefaultMailUser() { + // type涓�4 + let type = 4; + searchDefaultMailUser(type).then((res) => { + let rs = res.data; + let data = []; + if (rs.code === 1) { + data = rs.data.map((item) => { + return item.user; + }); + } + this.info.selectedItems = this.userListAll + .filter((o) => data.includes(o.name) && o.mail) + .map((item) => { + return item.name; + }); + this.handleChange(this.info.selectedItems); + }); + }, + handleChange(selectedItems) { + this.info.selectedItems = selectedItems; + let users = this.userListAll; + let mailList = users.filter((o) => + this.info.selectedItems.includes(o.name) + ); + this.receiverNames = mailList.map((v) => v.name).join(","); + this.receiverIds = mailList.map((v) => v.id).join(","); + }, + cancel() { + this.$emit("cancel"); + }, + ok() { + this.$refs["formRef"].validate((valid) => { + if (valid) { + let loading = this.$layer.loading(); + const formData = new FormData(); + if (this.file) { + this.file.forEach((v) => { + formData.append("multipartFileList", v); + }); + } + let { deftId, note, delProduct } = this.info; + formData.append( + "defectiveHisJson", + JSON.stringify({ + deftId, + note, + delProduct, + receiverIds: this.receiverIds, + receiverNames: this.receiverNames, + }) + ); + + updateDefective(formData) + .then((res) => { + let { code, data } = res.data; + this.$layer.close(loading); + if (code && data) { + this.$message.success("鎿嶄綔鎴愬姛"); + this.$emit("ok"); + } else { + this.$message.error("鎿嶄綔澶辫触"); + } + }) + .catch((err) => { + console.log(err); + this.$layer.close(loading); + }); + } else { + this.$message.error("瀛樺湪鏈�氳繃妫�楠岀殑琛ㄥ崟椤�"); + return false; + } + }); + }, + disabledDate(current) { + // Can not select days before today and today + return current > moment().endOf("day"); + }, + }, + mounted() { + this.searchAllUserList(); + }, +}; +</script> + +<style lang="less" scoped> +.modal-footer { + text-align: right; + button + button { + margin-left: 8px; + } +} +.row { + color: rgba(0, 0, 0, 0.85); + line-height: 30px; + .label { + text-align: right; + } + .label::after { + content: ":"; + position: relative; + top: -0.5px; + margin: 0 8px 0 2px; + } +} + +/deep/ .ant-input-number { + width: 100%; +} +</style> diff --git a/src/pages/resourceManage/defective/index.js b/src/pages/resourceManage/defective/index.js new file mode 100644 index 0000000..5d44f9c --- /dev/null +++ b/src/pages/resourceManage/defective/index.js @@ -0,0 +1,2 @@ +import list from './list'; +export default list; diff --git a/src/pages/resourceManage/defective/list.vue b/src/pages/resourceManage/defective/list.vue new file mode 100644 index 0000000..cd7a070 --- /dev/null +++ b/src/pages/resourceManage/defective/list.vue @@ -0,0 +1,932 @@ +<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" + :loading="loading" + title="" + row-key="id" + @search="onSearch" + @refresh="onRefresh" + @reset="onReset" + :format-conditions="true" + :scroll="{ x: 400, 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, + }" + :rowClassName="rowClassFn" + > + <template slot="dataIndex" slot-scope="{ index }"> + {{ index + 1 }} + </template> + <template slot="title"> + <a-space class="operator"> + <span class="title">涓嶈壇鍝佷腑蹇�</span> + <a-button + v-if="canUploadBom" + type="primary" + @click="uploadDefective" + >鏂板</a-button + > + </a-space> + </template> + <template slot="action" slot-scope="{ record }"> + <a @click="viewLog(record)">澶勭悊璁板綍</a> + <template v-if="record.nameList && record.nameList.length"> + <a-divider type="vertical"></a-divider> + <a @click="showFileList(record)">闄勪欢</a> + </template> + <a-divider type="vertical"></a-divider> + <!-- TODO --> + <a v-if="record.confirmStatus < 2" @click="dispose(record)" + >澶勭悊</a + > + <a + v-else-if="record.confirmStatus == 2" + @click="stopDefective(record)" + >褰掓。</a + > + </template> + </advance-table> + </a-card> + </a-spin> + </div> + <!-- 涓婁紶 --> + <a-modal + :visible="bomUploadShow" + :width="760" + title="涓婁紶涓嶈壇鍝佷俊鎭�" + :destroyOnClose="true" + :maskClosable="false" + @cancel="bomUploadCancel" + @ok="bomUploadOk" + :footer="null" + > + <prod-upload @ok="bomUploadOk" @cancel="bomUploadCancel"></prod-upload> + </a-modal> + <!-- 澶勭悊 --> + <a-modal + :visible="disposeVisible" + :width="760" + title="澶勭悊涓嶈壇鍝�" + :destroyOnClose="true" + :maskClosable="false" + @cancel="disposeCancel" + @ok="disposeOk" + :footer="null" + > + <dispose-upload + :record="currentData" + @ok="disposeOk" + @cancel="disposeCancel" + ></dispose-upload> + </a-modal> + <!-- 鎿嶄綔璁板綍 --> + <a-modal + :visible="logVisible" + :width="760" + title="鎿嶄綔璁板綍" + :destroyOnClose="true" + :maskClosable="false" + @cancel="logVisible = false" + :footer="null" + > + <div class="log-content" v-if="logVisible"> + <a-timeline> + <a-timeline-item + v-for="(item, idx) in logList" + :key="'log_' + idx" + :color=" + 0 == item.confirmStatus || 3 == item.confirmStatus + ? 'red' + : 'green' + " + > + <div> + <span class="user">{{ item.delName }}</span> 鍦� + <span class="time">{{ item.recordTime }}</span> + <template v-if="0 == item.confirmStatus"> + 鍒涘缓浜嗕笉鑹搧璁板綍 + <span class="rest">浣�({{ item.restProduct }})</span> + </template> + <template v-else-if="3 == item.confirmStatus"> + 褰掓。浜嗕笉鑹搧璁板綍 + </template> + <template v-else> + {{ { "1": "澶勭悊", "2": "澶勭悊" }[item.confirmStatus] }}浜� + <span class="version">{{ item.delProduct }}</span + >涓笉鑹搧 <span class="rest">浣�({{ item.restProduct }})</span> + <div class="">鎻忚堪: {{ item.note }}</div> + <div + class="others" + v-if="item.hisNameList && item.hisNameList.length" + > + <div class="label">闄勪欢</div> + <div class="content"> + <div + class="item" + v-for="file in item.hisNameList" + :key="file" + > + <div class="file-name">{{ file }}</div> + <div class="btn-list"> + <a-button + class="btn" + v-if="canView(file)" + @click="view(file, item.delUrl)" + >棰勮</a-button + > + <a-button + class="btn" + type="primary" + @click="downloadOther(file, item.delUrl)" + >涓嬭浇</a-button + > + </div> + </div> + </div> + </div> + </template> + </div> + </a-timeline-item> + </a-timeline> + </div> + </a-modal> + + <!-- 闄勪欢 --> + <a-modal + :visible="otherFilesVisible" + :width="760" + title="闄勪欢" + :destroyOnClose="true" + :maskClosable="false" + @cancel="otherFilesVisible = false" + :footer="null" + > + <files-list v-if="otherFilesVisible" :list="fileList"></files-list> + </a-modal> + <a-modal + :width="600" + :visible="previewVisible" + :footer="null" + @cancel="handleCancel" + > + <img alt="example" style="width: 100%" :src="imgUrl" /> + </a-modal> + </div> +</template> + +<script> +import AdvanceTable from "@/components/table/advance/AdvanceTable"; +import ProdUpload from "./prodUpload"; +import DisposeUpload from "./disposeUpload"; +import DrawUpload from "@/pages/components/drawUpload"; +import DownloadReason from "@/pages/components/downloadReason"; +import DownloadLogs from "@/pages/components/downloadLogs"; + +import filesList from "@/pages/components/filesList"; + +import getWebUrl from "@/assets/js/tools/getWebUrl"; + +import { stopDefective } from "./apis"; +import { mapGetters } from "vuex"; +import checkPermit from "@/assets/js/tools/checkPermit"; +import PERMITS from "@/assets/js/const/const_permits"; + +import createWs from "@/assets/js/websocket"; +import DiffList from "@/pages/components/diffList"; +import FeedbackForm from "../components/feedbackForm.vue"; +import OwnerDownload from "../components/ownerDownload"; +import moment from "moment"; +const WSMixin = createWs("defective"); + +export default { + name: "", + mixins: [WSMixin], + data() { + return { + previewVisible: false, + imgUrl: "", + fileList: [], + otherFilesVisible: false, + currentData: {}, + logVisible: false, + disposeVisible: false, + logList: [], + + ownerLogVisible: false, + reason: "", + reasonVisible: false, + oprateInfo: "", + downloadlogVisible: false, + tester: [], + downloadReasonVisible: false, + curObj: null, + errorVisible: false, + feedbackShow: false, + lockListVisible: false, + currentObj: null, + bomLockList: [], + otherLockList: [], + ecrList: [], + ecrListVisible: false, + fromProd: undefined, + prodList: [], + diffData: {}, + bomUploadShow: false, + prodData: {}, + userListAll: [], + mailList: [], + file: null, + // title: "", + fileUrl: "", + resList: [], + uploadShow: false, + customShow: false, + customProd: null, + editShow: false, + editObj: undefined, + selectedRowKeys: [], + selectedRows: [], + spinning: false, + loading: false, + pageCurr: 1, + pageSize: 10, + total: 0, + y: 400, + update: -1, + webUrl: getWebUrl(), + conditions: {}, + columns: [ + { + fixed: "left", + title: "搴忓彿", + dataIndex: "dataIndex", + key: "dataIndex", + align: "center", + width: 60, + noSearch: true, + scopedSlots: { customRender: "dataIndex" }, + }, + { + title: "鐗╂枡鍚嶇О", + dataIndex: "productName", + key: "productName", + width: 130, + align: "center", + // searchAble: true, + noSearch: true, + }, + { + title: "鍨嬪彿", + dataIndex: "type", + key: "type", + align: "center", + width: 180, + noSearch: true, + }, + { + title: "鍘傚晢鍚嶇О", + dataIndex: "provideName", + key: "provideName", + align: "center", + width: 180, + // searchAble: true, + noSearch: true, + }, + { + title: "鍏ユ枡鏃堕棿", + dataIndex: "startTimeEx", + key: "startTimeEx", + align: "center", + width: 160, + searchAble: true, + dataType: "dateRange", + }, + { + title: "鍒涘缓浜�", + dataIndex: "recorder", + align: "center", + width: 160, + searchAble: true, + dataType: "select", + search: { + default: "", + selectOptions: [], + }, + }, + { + title: "鐘舵��", + dataIndex: "status", + align: "center", + searchAble: true, + dataType: "select", + search: { + default: "", + selectOptions: [ + { + title: "鍏ㄩ儴", + value: "", + }, + { + title: "鏈鐞�", + value: 0, + }, + { + title: "澶勭悊涓�", + value: 1, + }, + { + title: "宸插畬鎴�", + value: 2, + }, + { + title: "褰掓。", + value: 3, + }, + ], + }, + }, + { + title: "鎬绘暟閲�", + dataIndex: "sumProduct", + align: "center", + // searchAble: true, + noSearch: true, + // visible: false, + }, + { + title: "涓嶈壇鏁�", + dataIndex: "badProduct", + align: "center", + // searchAble: true, + noSearch: true, + // visible: false, + }, + { + title: "涓嶈壇鎻忚堪", + dataIndex: "content", + align: "center", + // searchAble: true, + noSearch: true, + // visible: false, + }, + { + title: "鎿嶄綔", + dataIndex: "operation", + key: "operation", + align: "center", + width: 228, + fixed: "right", + scopedSlots: { customRender: "action" }, + noSearch: true, + }, + ], + dataSource: [], + }; + }, + components: { + AdvanceTable, + // ChangeParts, + filesList, + ProdUpload, + DisposeUpload, + DrawUpload, + DiffList, + FeedbackForm, + DownloadReason, + DownloadLogs, + OwnerDownload, + }, + methods: { + rowClassFn(record) { + let classList = []; + classList.push("level-" + record.confirmStatus); + return classList; + }, + dispose(record) { + this.currentData = record; + this.disposeVisible = true; + }, + canView(fileName) { + let arr = fileName.split("."); + let fileType = arr.length ? arr[arr.length - 1].toLowerCase() : ""; + return [ + "bmp", + "jpg", + "jpeg", + "gif", + "png", + "pdf", + "doc", + "docx", + "dwg", + ].some((v) => v == fileType); + }, + view(fileName, url) { + let arr = fileName.split("."); + let fileType = arr.length ? arr[arr.length - 1].toLowerCase() : ""; + switch (fileType) { + // 鍥剧墖 + case "bmp": + case "jpg": + case "jpeg": + case "gif": + case "png": + this.imgUrl = this.webUrl + url + fileName; + this.previewVisible = true; + break; + case "pdf": + window.open(this.webUrl + url + fileName); + break; + case "doc": + case "docx": + case "dwg": + this.dwgReview(url + fileName); + break; + default: + this.$message.warn("璇ョ被鍨嬫枃浠舵殏涓嶆敮鎸侀瑙�"); + break; + } + }, + handleCancel() { + this.previewVisible = false; + }, + downloadOther(fileName, url) { + let link = document.createElement("a"); + link.style.display = "none"; + link.href = this.webUrl + url + fileName; + link.download = fileName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }, + stopDefective(record) { + // console.log("record", record, "============="); + const self = this; + this.$confirm({ + title: "璇风‘璁�", + content: "璇风‘璁ゆ槸鍚﹁繘琛屽綊妗f搷浣滐紵", + onOk() { + stopDefective(record.id) + .then((res) => { + let { code, data } = res.data; + if (code && data) { + self.$message.success("鎿嶄綔鎴愬姛"); + } else { + self.$message.error("鎿嶄綔澶辫触"); + } + }) + .catch((err) => { + console.log(err); + }); + }, + onCancel() {}, + }); + }, + onSearch(conditions, searchOptions) { + // console.log(conditions); + // console.log(searchOptions); + this.pageCurr = 1; + this.conditions = conditions; + this.sendMessage(); + }, + onPageChange(page, pageSize) { + this.pageCurr = page; + this.pageSize = pageSize; + this.sendMessage(); + }, + onSizeChange(current, size) { + this.pageCurr = 1; + this.pageSize = size; + this.sendMessage(); + }, + onRefresh(conditions) { + this.conditions = conditions; + this.sendMessage(); + }, + onReset(conditions) { + this.conditions = conditions; + this.sendMessage(); + }, + showFileList(record) { + let { nameList, fileUrl } = record; + // let baseUrl = this.webUrl; + this.fileList = nameList.map((v) => fileUrl + v); + this.otherFilesVisible = true; + }, + searchData(res) { + if (res) { + // res = res.data; + // console.log(res, "======"); + let data = []; + let total = 0; + if (res.code && res.data) { + data = res.data2.list.map((v) => { + v.status = ["鏈鐞�", "澶勭悊涓�", "宸插畬鎴�", "褰掓。"][v.confirmStatus]; + v.recorder = v.senderName; + return v; + }); + total = res.data2.total; + } + this.dataSource = data; + this.total = total; + if (-1 == this.update) { + this.update = Math.random(); + } + } + }, + resize() { + setTimeout(() => { + this.update = Math.random(); + }, 200); + }, + onWSOpen() { + this.$nextTick(() => { + this.sendMessage(); + }); + }, + sendMessage() { + if (!this.isWSOpen) { + return false; + } + const { pageCurr, pageSize, conditions, columns } = this; + let params = {}; + let col, index; + Object.keys(conditions).forEach((v) => { + switch (v) { + case "startTimeEx": + if (conditions[v]) { + if (conditions[v][0]) { + params["startTime"] = + moment(conditions[v][0]).format("YYYY-MM-DD") + " 00:00:00"; + } + if (conditions[v][1]) { + params["endTime"] = + moment(conditions[v][1]).format("YYYY-MM-DD") + " 23:59:59"; + } + } + break; + case "status": + if ("" !== conditions[v]) { + params["confirmStatus"] = conditions[v]; + } + break; + case "recorder": + if ("" !== conditions[v]) { + params["senderId"] = conditions[v]; + } + break; + default: + params[v] = conditions[v]; + break; + } + }); + let data = { + pageSize, + pageCurr, + ...params, + }; + // console.log("=====9=", data, JSON.stringify(data)); + this.SOCKET.send(JSON.stringify(data)); + }, + onWSMessage(res) { + res = JSON.parse(res.data); + // // console.log(res, "=====111data"); + this.searchData(res); + }, + activeFN() { + this.resize(); + }, + uploadDefective() { + this.bomUploadShow = true; + }, + disposeCancel() { + this.disposeVisible = false; + }, + disposeOk() { + this.disposeVisible = false; + }, + bomUploadCancel() { + this.bomUploadShow = false; + }, + bomUploadOk() { + this.bomUploadShow = false; + // 璋冪敤sendMessage 鏇存柊鍒楄〃 + this.pageCurr = 1; + this.sendMessage(); + }, + viewLog(obj) { + // console.log(obj); + this.logList = obj.hisList; + this.logVisible = true; + }, + logCancel() { + this.logVisible = false; + }, + }, + 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); + // console.log(h, "h",wraper, header, bar ); + this.y = h; + } + }); + } + }, + affixed() { + setTimeout(() => { + this.update = Math.random(); + }, 200); + }, + }, + computed: { + ...mapGetters("account", [ + "roles", + "projectManagerList", + "generalManagerList", + "permits", + "user", + ]), + ...mapGetters("setting", ["affixed"]), + canUploadBom() { + return checkPermit(PERMITS.uploadBom, this.permits); + }, + canDownloadBom() { + return checkPermit(PERMITS.downloadBom, this.permits); + }, + canFeedback() { + return checkPermit(PERMITS.feedback, this.permits); + }, + abLabel() { + let num = this.abTbl.dataSource.length; + num = num > 99 ? "99+" : num; + return "寮傚父(" + num + ")"; + }, + errorLabel() { + let num = this.errorTbl.dataSource.length; + num = num > 99 ? "99+" : num; + return "閿欒(" + num + ")"; + }, + abState() { + let result = false; + if (this.abTbl.dataSource.length != 0) { + if (this.abTbl.ignore) { + result = false; + } else { + result = true; + } + } else { + result = false; + } + + return result; + }, + submitState() { + let result = { + code: 0, + msg: "瀛樺湪寮傚父鎴栭敊璇殑鏁版嵁锛岃淇鍚庡啀鎻愪氦", + }; + if (this.abState) { + result.code = 1; + } else { + result.code = 0; + } + + if (this.errorTbl.dataSource.length != 0) { + result.code = 1; + } + + return result; + }, + isTester() { + return this.tester.some((v) => v == this.user.name); + }, + }, + mounted() { + this.sendMessage(); + 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; +} + +.text-right { + text-align: right; + + span::after { + content: ":"; + position: relative; + top: -0.5px; + margin: 0 8px 0 2px; + } +} + +.upload { + padding: 10px 0; +} + +.modal-footer { + text-align: right; + + button + button { + margin-left: 8px; + } +} + +.mt8 { + margin-top: 8px; +} + +.from { + width: 100%; +} + +.label { + display: flex; + justify-content: flex-end; + padding-right: 1em; + align-items: center; +} + +.bom-list /deep/ .ant-card-body { + padding: 8px 24px; +} + +.log-content { + max-height: 400px; + overflow-y: auto; + + .user { + color: #23aaf2; + font-weight: 700; + } + + .rest, + .time { + color: #f9be13; + font-weight: 700; + } + + .version { + color: #0aedb2; + font-weight: 700; + } + + .ant-timeline-item:first-of-type { + padding-top: 6px; + } +} + +.table-title { + font-weight: 700; + color: #13c2c2; +} + +.btn-grp .ant-btn { + min-width: 6.4em; +} +/deep/.level-1 > td { + background: #fec54b; +} +/deep/.level-1.level-1.level-1.ant-table-row-hover > td, +/deep/.level-1.level-1.level-1:hover > td { + background: #fcd583; +} +/deep/.level-0 > td { + background: #fca4b3; +} +/deep/.level-0.level-0.level-0.ant-table-row-hover > td, +/deep/.level-0.level-0.level-0:hover > td { + background: #f6c4cc; +} +/deep/.level-2 > td { + background: #7bfd7b; +} +/deep/.level-2.level-2.level-2.ant-table-row-hover > td, +/deep/.level-2.level-2.level-2:hover > td { + background: #b2fbbd; +} +.others { + display: flex; + align-items: flex-start; + .label { + margin-right: 0.4em; + &::after { + content: ":"; + } + } + .content { + flex: 1; + .item { + display: flex; + align-items: center; + margin-bottom: 0.4em; + .file-name { + flex: 1; + text-align: right; + padding-right: 0.6em; + } + .btn { + & + .btn { + margin-left: 0.4em; + } + } + } + } +} +</style> + +<style lang="less"> +.full-modal { + height: 100%; + .ant-modal { + max-width: 100%; + height: 100%; + top: 0; + padding-bottom: 0; + margin: 0; + } + .ant-modal-content { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + // height: calc(100vh); + } + .ant-modal-body { + flex: 1; + } +} +</style> diff --git a/src/pages/resourceManage/defective/prodUpload.vue b/src/pages/resourceManage/defective/prodUpload.vue new file mode 100644 index 0000000..c42fab9 --- /dev/null +++ b/src/pages/resourceManage/defective/prodUpload.vue @@ -0,0 +1,417 @@ +<template> + <div class=""> + <a-form-model + ref="formRef" + name="advanced_search" + class="ant-advanced-search-form" + :model="info" + :rules="rules" + > + <a-row> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="鍏ュ簱鏃堕棿" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="startTime" + > + <a-date-picker + format="YYYY-MM-DD" + valueFormat="YYYY-MM-DD" + :allowClear="false" + :disabled-date="disabledDate" + :show-time="{ defaultValue: moment('00:00:00', 'HH:mm:ss') }" + v-model="info.startTime" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="鍘傚晢鍚嶇О" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="provideName" + > + <a-input + placeholder="璇疯緭鍏ュ巶鍟嗗悕绉�" + v-model.trim="info.provideName" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="浜у搧鍚嶇О" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="productName" + > + <a-input + placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" + v-model.trim="info.productName" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="浜у搧鍨嬪彿" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="type" + > + <a-input placeholder="璇疯緭鍏ヤ骇鍝佸瀷鍙�" v-model.trim="info.type" /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="鎬绘暟" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="sumProduct" + > + <a-input-number + placeholder="璇疯緭鍏ユ潵鏂欐�绘暟" + :min="1" + v-model.number="info.sumProduct" + /> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="涓嶈壇浜у搧鏁�" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="badProduct" + > + <a-input-number + placeholder="璇疯緭鍏ヤ笉鑹骇鍝佹暟" + :min="1" + :max="info.sumProduct" + v-model.number="info.badProduct" + /> + </a-form-model-item> + </a-col> + <a-col :span="24"> + <a-form-model-item + class="ant-row-flex" + label="涓嶈壇鐜拌薄鎻忚堪" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="content" + > + <a-textarea + placeholder="璇疯緭鍏ヤ笉鑹幇璞℃弿杩�" + v-model.trim="info.content" + :rows="2" + /> + </a-form-model-item> + </a-col> + </a-row> + <a-row type="flex" class="row"> + <a-col :span="12"> + <a-form-model-item + class="ant-row-flex" + label="閭欢閫氱煡" + :labelCol="{ flex: '8em' }" + :wrapperCol="{ flex: 1 }" + prop="selectedItems" + > + <a-select + mode="multiple" + placeholder="" + :value="info.selectedItems" + style="width: 100%" + allow-clear + @change="handleChange" + > + <a-select-option + v-for="item in filteredOptions" + :key="item.name" + :value="item.name" + :disabled="!item.isHasMail" + > + {{ item.name }} + </a-select-option> + </a-select> + </a-form-model-item> + </a-col> + </a-row> + <a-row type="flex" class="row"> + <a-col flex="8em" class="label">闄勪欢</a-col> + <a-col :flex="1"> + <a-upload + class="upload" + :before-upload="beforeUpload" + @change="uploadChange" + multiple + > + <!-- accept=".zip,.rar" --> + <a-button type="primary">閫夋嫨闄勪欢</a-button> + </a-upload> + </a-col> + </a-row> + </a-form-model> + <div class="modal-footer"> + <a-button type="danger" @click="cancel"> 鍙栨秷 </a-button> + <a-button type="primary" @click="ok"> 鎻愪氦 </a-button> + </div> + </div> +</template> + +<script> +import moment from "moment"; +import { addDefective } from "./apis"; + +import { searchDefaultMailUser } from "../../components/emailCard/apis"; +import { getUserList } from "../../permission/apis"; + +export default { + name: "", + props: {}, + data() { + const validatebadProduct = (rule, value, callback) => { + if (this.info.sumProduct == "") { + callback(new Error('璇峰厛杈撳叆鎬绘暟')); + this.$refs.formRef.validateField("sumProduct"); + } + callback(); + }; + return { + userList: [], + defaultMailUsers: [], + selectedItems: [], + userListAll: [], + info: { + provideName: "", + productName: "", + content: "", + type: "", + sumProduct: "", + badProduct: "", + startTime: moment().format("YYYY-MM-DD"), + selectedItems: [], + }, + file: null, + receiverIds: "", + receiverNames: "", + rules: { + startTime: [ + { + required: true, + message: "璇烽�夋嫨鍏ュ簱鏃ユ湡", + trigger: ["blur", "change"], + }, + ], + provideName: [ + { + required: true, + message: "璇疯緭鍏ュ巶鍟嗗悕绉�", + trigger: "blur", + }, + ], + productName: [ + { + required: true, + message: "璇疯緭鍏ヤ骇鍝佸悕绉�", + trigger: "blur", + }, + ], + type: [ + { + required: true, + message: "璇疯緭鍏ュ瀷鍙�", + trigger: "blur", + }, + ], + sumProduct: [ + { + required: true, + message: "璇疯緭鍏ユ�绘暟", + trigger: "blur", + }, + ], + badProduct: [ + { + required: true, + message: "璇疯緭鍏ヤ笉鑹骇鍝佹暟", + trigger: "blur", + }, + { validator: validatebadProduct, trigger: "change" }, + ], + content: [ + { + required: true, + message: "璇疯緭鍏ヤ笉鑹幇璞℃弿杩�", + trigger: "blur", + }, + ], + selectedItems: [ + { + required: true, + message: "璇峰厛鎷╄閭欢閫氱煡鐨勪汉鍛�", + trigger: "blur", + }, + // { validator: validateSelectedItems, trigger: "change" }, + ], + }, + }; + }, + computed: { + filteredOptions() { + let users = this.userListAll; + return users + .filter((o) => !this.info.selectedItems.includes(o.name)) + .map((o) => { + o.isHasMail = o.mail ? true : false; + return o; + }); + }, + }, + methods: { + moment, + beforeUpload() { + return false; + }, + uploadChange(data) { + const { file, fileList } = data; + if (fileList.length) { + this.file = fileList.map((v) => v.originFileObj); + } else { + this.file = null; + } + }, + searchAllUserList() { + getUserList() + .then((res) => { + let rs = res.data; + if (rs.code && rs.data) { + this.userListAll = rs.data2; + this.searchDefaultMailUser(); + } + }) + .catch((error) => { + console.log(error); + }); + }, + searchDefaultMailUser() { + // type涓�4 + let type = 4; + searchDefaultMailUser(type).then((res) => { + let rs = res.data; + let data = []; + if (rs.code === 1) { + data = rs.data.map((item) => { + return item.user; + }); + } + this.info.selectedItems = this.userListAll + .filter((o) => data.includes(o.name) && o.mail) + .map((item) => { + return item.name; + }); + this.handleChange(this.info.selectedItems); + }); + }, + handleChange(selectedItems) { + this.info.selectedItems = selectedItems; + let users = this.userListAll; + let mailList = users.filter((o) => + this.info.selectedItems.includes(o.name) + ); + this.receiverNames = mailList.map((v) => v.name).join(","); + this.receiverIds = mailList.map((v) => v.id).join(","); + }, + cancel() { + this.$emit("cancel"); + }, + ok() { + this.$refs["formRef"].validate((valid) => { + if (valid) { + let loading = this.$layer.loading(); + const formData = new FormData(); + if (this.file) { + this.file.forEach((v) => { + formData.append("multipartFileList", v); + }); + } + let { + provideName, + content, + type, + sumProduct, + productName, + badProduct, + startTime, + } = this.info; + formData.append( + "defectiveJson", + JSON.stringify({ + provideName, + productName, + content, + type, + sumProduct, + badProduct, + startTime, + receiverIds: this.receiverIds, + receiverNames: this.receiverNames, + }) + ); + + addDefective(formData).then((res) => { + // console.log("res", res, "============="); + res = res.data; + this.$layer.close(loading); + if (res.code && res.data) { + this.$message.success("鎿嶄綔鎴愬姛"); + this.$emit("ok"); + } else { + this.$message.error("鎿嶄綔澶辫触"); + } + }); + } else { + this.$message.error("瀛樺湪鏈�氳繃妫�楠岀殑琛ㄥ崟椤�"); + return false; + } + }); + }, + disabledDate(current) { + // Can not select days before today and today + return current > moment().endOf("day"); + }, + }, + mounted() { + this.searchAllUserList(); + }, +}; +</script> + +<style lang="less" scoped> +.modal-footer { + text-align: right; + button + button { + margin-left: 8px; + } +} +.row { + color: rgba(0, 0, 0, 0.85); + line-height: 30px; + .label { + text-align: right; + } + .label::after { + content: ":"; + position: relative; + top: -0.5px; + margin: 0 8px 0 2px; + } +} +/deep/ .ant-input-number { + width: 100%; +} +</style> diff --git a/src/router/config.js b/src/router/config.js index 424bb41..a25e0d7 100644 --- a/src/router/config.js +++ b/src/router/config.js @@ -169,6 +169,11 @@ }, component: () => import('@/pages/resourceManage/specification/history'), }, + { + path: 'defective', + name: '涓嶈壇鍝佺鐞�', + component: () => import('@/pages/resourceManage/defective'), + }, ] }, { -- Gitblit v1.9.1