From fb45193819e90f59c5f22a5f1e5a3f6a38c98c00 Mon Sep 17 00:00:00 2001 From: spring <2396852758@qq.com> Date: 星期二, 25 二月 2025 17:48:27 +0800 Subject: [PATCH] 搬迁投诉列表 --- src/views/CNAS/process/complaint/index.vue | 629 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/api/cnas/process/complaint.js | 57 ++++ 2 files changed, 686 insertions(+), 0 deletions(-) diff --git a/src/api/cnas/process/complaint.js b/src/api/cnas/process/complaint.js new file mode 100644 index 0000000..cd93e8d --- /dev/null +++ b/src/api/cnas/process/complaint.js @@ -0,0 +1,57 @@ +// 鎶曡瘔姹囨�昏〃鐩稿叧鎺ュ彛 +import request from "@/utils/request"; + +// 鎶曡瘔澶勭悊鏂板 +export function addProcessComplain(data) { + return request({ + url: "/processComplain/addProcessComplain", + method: "post", + data: data, + }); +} + +//鎶曡瘔澶勭悊璇︽儏 +export function getProcessComplain(query) { + return request({ + url: "/processComplain/getProcessComplain", + method: "get", + params: query, + }); +} + +// 鎶曡瘔澶勭悊淇敼 +export function doProcessComplain(data) { + return request({ + url: "/processComplain/doProcessComplain", + method: "post", + data: data, + }); +} + +//鎶曡瘔澶勭悊瀵煎嚭 +export function exportProcessComplain(query) { + return request({ + url: "/processComplain/exportProcessComplain", + method: "get", + responseType: "blob", + params: query, + }); +} + +//鎶曡瘔澶勭悊鍒嗛〉 +export function pageProcessComplain(query) { + return request({ + url: "/processComplain/pageProcessComplain", + method: "get", + params: query, + }); +} + +//鎶曡瘔澶勭悊鍒犻櫎 +export function delProcessComplain(query) { + return request({ + url: "/processComplain/delProcessComplain", + method: "delete", + params: query, + }); +} diff --git a/src/views/CNAS/process/complaint/index.vue b/src/views/CNAS/process/complaint/index.vue new file mode 100644 index 0000000..db76ec4 --- /dev/null +++ b/src/views/CNAS/process/complaint/index.vue @@ -0,0 +1,629 @@ +<template> + <div class="Complaint"> + <div class="search"> + <div class="search_thing"> + <div class="search_label">鏍峰搧缂栧彿锛�</div> + <div class="search_input"><el-input v-model="queryParams.sampleCode" clearable placeholder="璇疯緭鍏�" size="small" + @keyup.enter.native="refreshTable()"></el-input></div> + </div> + <div class="search_thing"> + <div class="search_label">鎶曡瘔鍚嶇О锛�</div> + <div class="search_input"> + <el-input v-model="queryParams.complainName" clearable placeholder="璇疯緭鍏�" size="small" + @keyup.enter.native="refreshTable()"></el-input> + </div> + </div> + <div class="search_thing" style="padding-left: 30px;"> + <el-button size="small" @click="refresh()">閲� 缃�</el-button> + <el-button size="small" type="primary" @click="refreshTable()">鏌� 璇�</el-button> + </div> + <div class="btn"> + <el-button :loading="outLoading" size="small" type="primary" @click="handleDown">瀵煎嚭</el-button> + <el-button size="small" type="primary" @click="openAdd">鏂板</el-button> + </div> + </div> + <div class="table"> + <lims-table :tableData="tableData" :column="column" :tableLoading="tableLoading" :height="'calc(100vh - 290px)'" + :page="page" @pagination="pagination"></lims-table> + </div> + <el-dialog :visible.sync="addDialogVisible" title="鏂板" width="400px"> + <el-row> + <el-col :span="24" style="margin-bottom: 16px;"> + <div class="search_thing"> + <div class="search_label">鎶曡瘔鏂瑰悕绉帮細</div> + <div class="search_input"><el-input v-model="addInfo.complainName" clearable placeholder="璇疯緭鍏�" + size="small"></el-input></div> + </div> + </el-col> + <el-col :span="24" style="margin-bottom: 16px;"> + <div class="search_thing"> + <div class="search_label">妫�楠屾姤鍛婄紪鍙凤細</div> + <div class="search_input"> + <el-input v-model="addInfo.code" clearable placeholder="璇疯緭鍏�" size="small"></el-input> + </div> + </div> + </el-col> + <el-col :span="24" style="margin-bottom: 16px;"> + <div class="search_thing"> + <div class="search_label">鏍峰搧缂栧彿锛�</div> + <div class="search_input"><el-input v-model="addInfo.sampleCode" clearable placeholder="璇疯緭鍏�" + size="small"></el-input></div> + </div> + </el-col> + <el-col :span="24"> + <div class="search_thing"> + <div class="search_label">鎶曡瘔鏂瑰紡锛�</div> + <div class="search_input"><el-input v-model="addInfo.complainMethod" clearable placeholder="璇疯緭鍏�" + size="small"></el-input></div> + </div> + </el-col> + </el-row> + <span slot="footer" class="dialog-footer"> + <el-button @click="addDialogVisible = false">鍙� 娑�</el-button> + <el-button :loading="addLoading" type="primary" @click="handleAdd">纭� 瀹�</el-button> + </span> + </el-dialog> + <el-dialog :class="{ downPdf: title == '瀵煎嚭' }" :modal="title != '瀵煎嚭'" :title="title" + :visible.sync="handleDialogVisible" width="800px"> + <div class="dialog-body"> + <div id="dialogBody"> + <h4 style="display: flex;align-items: center;flex-direction: column;justify-content: center;"> + <span style="font-size: 20px;">瀹㈡埛鎶曡瘔鍙楃悊鍗�</span> + <span>Customer complaint receipts</span> + </h4> + <p style="display: flex;justify-content: space-between;margin-top: 16px;"> + <span>{{ currentInfo0.complainNo }}</span> + <span>NO:</span> + </p> + <table border="1" cellpadding="10" class="tables"> + <tr> + <td colspan="3"> + <p>鎶曡瘔鏂瑰悕绉�</p> + <p class="en">Name of the complaining party</p> + </td> + <td colspan="3">{{ currentInfo0.complainName }}</td> + </tr> + <tr> + <td> + <p>妫�娴嬫姤鍛婄紪鍙�</p> + <p class="en">Test report number</p> + </td> + <td colspan="3">{{ currentInfo0.code }}</td> + <td> + <p>鏍峰搧缂栧彿</p> + <p class="en">Sample number</p> + </td> + <td>{{ currentInfo0.sampleCode }}</td> + </tr> + <tr> + <td> + <p>鎶曡瘔浜�</p> + <p class="en">Complainant</p> + </td> + <td>{{ currentInfo0.createUser }}</td> + <td> + <p>鐢佃瘽</p> + <p class="en">Phone</p> + </td> + <td>{{ currentInfo0.phone }}</td> + <td> + <p>E-Mail</p> + <p class="en">E-mail</p> + </td> + <td>{{ currentInfo0.email }}</td> + </tr> + <tr> + <td> + <p>鎶曡瘔鏂瑰紡</p> + <p class="en">Complaint method</p> + </td> + <td colspan="3">{{ currentInfo0.complainMethod }}</td> + <td> + <p>鎶曡瘔鏃ユ湡</p> + <p class="en">Date of complaint</p> + </td> + <td>{{ currentInfo0.createTime ? currentInfo0.createTime.split(' ')[0] : '' }}</td> + </tr> + <tr> + <td> + <p>闂璁板綍</p> + <p class="en">Problem logging</p> + </td> + <td colspan="5"> + <div class="user-content"> + <el-input v-if="title == '澶勭悊鎶曡瘔'" v-model="currentInfo0.problemRecords" :rows="3" placeholder="璇疯緭鍏ュ唴瀹�" + type="textarea"> + </el-input> + <p v-else style="text-align: left;line-height: 26px;">{{ currentInfo0.problemRecords }}</p> + </div> + <div v-if="title != '澶勭悊鎶曡瘔'" class="user-info"> + <div style="width: 200px;margin-right: 10px;"> + <p style="text-align: end;">璐ㄩ噺璐熻矗浜�:</p> + <p class="en" style="text-align: end;">Quality Manager:</p> + </div> + <span>{{ currentInfo0.problemRecordsUserName }}</span> + <div style="width: 70px;"> + <p>鏃ユ湡:</p> + <p class="en">Date:</p> + </div> + <span style="margin-right: 16px;">{{ currentInfo0.problemRecordsTime }}</span> + </div> + </td> + </tr> + <tr> + <td> + <p>璐d换褰掑睘鍙婃姇璇夋槸鍚︽垚绔�</p> + <p class="en">Attribution of responsibility and whether the complaint is established</p> + </td> + <td colspan="5"> + <div class="user-content"> + <el-input v-if="title == '澶勭悊鎶曡瘔'" v-model="currentInfo0.dutyOwnership" :rows="3" placeholder="璇疯緭鍏ュ唴瀹�" + type="textarea"> + </el-input> + <p v-else style="text-align: left;line-height: 26px;">{{ currentInfo0.dutyOwnership }}</p> + </div> + <div v-if="title != '澶勭悊鎶曡瘔'" class="user-info"> + <div style="width: 200px;margin-right: 10px;"> + <p style="text-align: end;">璐ㄩ噺璐熻矗浜�:</p> + <p class="en" style="text-align: end;">Quality Manager:</p> + </div> + <span>{{ currentInfo0.dutyOwnershipUserName }}</span> + <div style="width: 70px;"> + <p>鏃ユ湡:</p> + <p class="en">Date:</p> + </div> + <span style="margin-right: 16px;">{{ currentInfo0.dutyOwnershipTime }}</span> + </div> + </td> + </tr> + <tr> + <td> + <p>鍘熷洜鍒嗘瀽</p> + <p class="en">Cause analysis</p> + </td> + <td colspan="5"> + <div class="user-content"> + <el-input v-if="title == '澶勭悊鎶曡瘔'" v-model="currentInfo0.causeAnalysis" :rows="3" placeholder="璇疯緭鍏ュ唴瀹�" + type="textarea"> + </el-input> + <p v-else style="text-align: left;line-height: 26px;">{{ currentInfo0.causeAnalysis }}</p> + </div> + <div v-if="title != '澶勭悊鎶曡瘔'" class="user-info"> + <div style="width: 200px;margin-right: 10px;"> + <p style="text-align: end;">璐d换閮ㄩ棬璐熻矗浜�:</p> + <p class="en" style="text-align: end;">Head of Responsible Department:</p> + </div> + <span>{{ currentInfo0.causeAnalysisUserName }}</span> + <div style="width: 70px;"> + <p>鏃ユ湡:</p> + <p class="en">Date:</p> + </div> + <span style="margin-right: 16px;">{{ currentInfo0.causeAnalysisTime }}</span> + </div> + </td> + </tr> + <tr> + <td> + <p>绾犳鎺柦</p> + <p class="en">Corrective actions</p> + </td> + <td colspan="5"> + <div class="user-content"> + <el-input v-if="title == '澶勭悊鎶曡瘔'" v-model="currentInfo0.correctiveAction" :rows="3" placeholder="璇疯緭鍏ュ唴瀹�" + type="textarea"> + </el-input> + <p v-else style="text-align: left;line-height: 26px;">{{ currentInfo0.correctiveAction }}</p> + </div> + <div v-if="title != '澶勭悊鎶曡瘔'" class="user-info"> + <div style="width: 200px;margin-right: 10px;"> + <p style="text-align: end;">璐d换閮ㄩ棬璐熻矗浜�:</p> + <p class="en" style="text-align: end;">Head of Responsible Department:</p> + </div> + <span>{{ currentInfo0.correctiveActionUserName }}</span> + <div style="width: 70px;"> + <p>鏃ユ湡:</p> + <p class="en">Date:</p> + </div> + <span style="margin-right: 16px;">{{ currentInfo0.correctiveActionTime }}</span> + </div> + </td> + </tr> + <tr> + <td> + <p>绾犳鎺柦纭</p> + <p class="en">Corrective actions confirmation</p> + </td> + <td colspan="5"> + <div class="user-content"> + <el-input v-if="title == '澶勭悊鎶曡瘔'" v-model="currentInfo0.correctiveActionConfirmation" :rows="3" + placeholder="璇疯緭鍏ュ唴瀹�" type="textarea"> + </el-input> + <p v-else style="text-align: left;line-height: 26px;">{{ currentInfo0.correctiveActionConfirmation }} + </p> + </div> + <div v-if="title != '澶勭悊鎶曡瘔'" class="user-info"> + <div style="width: 200px;margin-right: 10px;"> + <p style="text-align: end;">璐ㄩ噺璐熻矗浜�:</p> + <p class="en" style="text-align: end;">Quality Manager:</p> + </div> + <span>{{ currentInfo0.correctiveActionConfirmationUserName }}</span> + <div style="width: 70px;"> + <p>鏃ユ湡:</p> + <p class="en">Date:</p> + </div> + <span style="margin-right: 16px;">{{ currentInfo0.correctiveActionConfirmationTime }}</span> + </div> + </td> + </tr> + </table> + </div> + </div> + <span v-if="title == '澶勭悊鎶曡瘔'" slot="footer" class="dialog-footer"> + <el-button @click="handleDialogVisible = false">鍙� 娑�</el-button> + <el-button :loading="addLoading" type="primary" @click="submit">鎻� 浜�</el-button> + </span> + </el-dialog> + </div> +</template> + +<script> +import limsTable from "@/components/Table/lims-table.vue"; +import { getYearAndMonthAndDays } from '@/utils/date' +import { exportHtmlToPDF } from '@/utils/downHtmlToPDF' +import { + addProcessComplain, + getProcessComplain, + doProcessComplain, + exportProcessComplain, + pageProcessComplain, + delProcessComplain +} from '@/api/cnas/process/complaint.js' +import { mapGetters } from "vuex"; +export default { + components: { + limsTable + }, + data() { + return { + addPower: false, + outLoading: false, + addDialogVisible: false, + addLoading: false, + handleDialogVisible: false, + title: '澶勭悊鎶曡瘔', + addInfo: {},//鏂板淇℃伅 + currentInfo: null,//鎺ュ彛璇锋眰鍥炴潵鐨勪俊鎭� + currentInfo0: {},//鐢ㄦ埛缂栬緫杩囧悗鐨勪俊鎭� + outPower: false, + queryParams: {}, + tableData: [], + column: [ + { label: "鎶曡瘔鍚嶇О", prop: "complainName" }, + { label: "鎶曡瘔浜�", prop: "complainant" }, + { label: "鎶曡瘔鏃ユ湡", prop: "createTime" }, + { + dataType: "action", + fixed: "right", + label: "鎿嶄綔", + operation: [ + { + name: "鏌ョ湅", + type: "text", + clickFun: (row) => { + this.handleLook(row); + }, + }, + { + name: "澶勭悊", + type: "text", + clickFun: (row) => { + this.handleWork(row); + }, + }, + { + name: "瀵煎嚭", + type: "text", + clickFun: (row) => { + this.handleOut(row); + }, + }, + { + name: "鍒犻櫎", + type: "text", + clickFun: (row) => { + this.handleDelete(row); + }, + }, + ], + }, + ], + page: { + total: 0, + size: 10, + current: 0, + }, + }; + }, + computed: { + ...mapGetters(["userId"]), + }, + mounted() { + // this.entityCopy = this.HaveJson(this.componentData.entity); + this.getList() + }, + methods: { + // 鏉冮檺鍒嗛厤 + getPower() { + let power = JSON.parse(sessionStorage.getItem('power')) + let up = false + let del = false + let add = false + let out = false + for (var i = 0; i < power.length; i++) { + if (power[i].menuMethod == 'doProcessComplain') { + up = true + } + if (power[i].menuMethod == 'addProcessComplain') { + add = true + } + if (power[i].menuMethod == 'delProcessComplain') { + del = true + } + if (power[i].menuMethod == 'exportProcessComplain') { + out = true + } + } + if (!up) { + this.componentData.do.splice(2, 1) + } + if (!del) { + this.componentData.do.splice(1, 1) + } + this.outPower = out + this.addPower = add + }, + openAdd() { + this.addInfo = {} + this.addDialogVisible = true + }, + handleAdd() { + this.addLoading = true + addProcessComplain(this.addInfo).then((res) => { + this.addLoading = false + if (res.code == 201) { + this.$message({ + type: 'error', + message: '鏂板澶辫触' + }) + return + } + this.$message({ + type: 'success', + message: '鏂板鎴愬姛' + }) + this.addDialogVisible = false + this.refresh() + }) + }, + // 澶勭悊鎶曡瘔 + handleWork(row) { + getProcessComplain({ id: row.id }).then((res) => { + this.currentInfo = res.data + this.currentInfo0 = this.HaveJson(res.data) + this.title = '澶勭悊鎶曡瘔' + this.handleDialogVisible = true + }) + }, + submit() { + this.handleParam('problemRecords') + this.handleParam('dutyOwnership') + this.handleParam('causeAnalysis') + this.handleParam('correctiveAction') + this.handleParam('correctiveActionConfirmation') + this.addLoading = true + for (let i in this.currentInfo0) { + if (!this.currentInfo0[i]) { + delete this.currentInfo0[i] + } + } + doProcessComplain(this.currentInfo0).then((res) => { + this.addLoading = false + if (res.code == 201) { + this.$message({ + type: 'error', + message: '鎻愪氦澶辫触' + }) + return + } + this.$message({ + type: 'success', + message: '鎻愪氦鎴愬姛' + }) + this.handleDialogVisible = false + this.refresh() + }) + }, + /** + * 澶勭悊鍙傛暟 + * + * @param {string} type - 闇�瑕佸鐞嗙殑鍙傛暟绫诲瀷 + */ + handleParam(type) { + if (this.currentInfo0[type] != this.currentInfo[type]) { + this.currentInfo0[type + 'User'] = this.userId + this.currentInfo0[type + 'Time'] = getYearAndMonthAndDays() + } + }, + // 鏌ョ湅鎶曡瘔 + handleLook(row) { + addProcessComplain({ id: row.id }).then((res) => { + this.currentInfo = res.data + this.currentInfo0 = this.HaveJson(res.data) + this.title = '鏌ョ湅鎶曡瘔' + this.handleDialogVisible = true + }) + }, + getList() { + this.tableLoading = true; + let param = { ...this.queryParams, ...this.page }; + delete param.total; + pageProcessComplain({ ...param }) + .then((res) => { + this.tableLoading = false; + if (res.code === 200) { + this.tableData = res.data.records; + this.page.total = res.data.total; + } + }) + .catch((err) => { + this.tableLoading = false; + }); + }, + pagination({ page, limit }) { + this.page.current = page; + this.page.size = limit; + this.getList(); + }, + refresh() { + this.queryParams = {}; + this.page.current = 1; + this.getList(); + }, + refreshTable() { + this.page.current = 1; + this.getList(); + }, + handleDown() { + this.outLoading = true + exportProcessComplain(this.queryParams).then(res => { + this.outLoading = false + if (res.code == 201) { + return + } + const blob = new Blob([res], { type: 'application/octet-stream' }); + this.$download.saveAs(blob, '鎶曡瘔鎯呭喌姹囨�昏〃.xlsx'); + }) + }, + handleOut(row) { + getProcessComplain({ id: row.id }).then((res) => { + if (res.code == 201) { + return + } + this.currentInfo = res.data + this.currentInfo0 = this.HaveJson(res.data) + this.title = '瀵煎嚭' + this.handleDialogVisible = true + setTimeout(() => { + this.$nextTick(() => { + const element = document.getElementById("dialogBody"); + exportHtmlToPDF(element, '鎶曡瘔璇︽儏').then(res => { + this.handleDialogVisible = false + }) + }) + }, 500); + }) + }, + handleDelete(row) { + this.$confirm("鏄惁鍒犻櫎璇ユ潯鏁版嵁?", "鎻愮ず", { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + delProcessComplain({ id: row.id }).then((res) => { + if (res.code == 201) return; + this.$message.success("鍒犻櫎鎴愬姛"); + this.refresh(); + }); + }) + .catch(() => { }); + }, + }, +} +</script> + +<style scoped> +.title { + height: 60px; + line-height: 60px; +} + +.search { + background-color: #fff; + height: 80px; + display: flex; + align-items: center; + position: relative; +} + +.search_thing { + width: 350px; + display: flex; + align-items: center; +} + +.search_label { + width: 110px; + font-size: 14px; + text-align: right; +} + +.search_input { + width: calc(100% - 110px); +} + +.table { + background-color: #fff; + height: calc(100% - 60px - 80px - 10px - 40px); + padding: 20px; +} + +.dialog-body { + max-height: 75vh; + overflow-y: auto; +} + +.tables { + table-layout: fixed; + width: 100%; +} + +.tables td { + height: 40px; + width: 100px; + text-align: center; + font-size: 14px; + word-wrap: break-word; + white-space: normal; +} + +.en { + font-size: 12px; + word-break: break-word; + /* 鑷姩鏂 */ + overflow-wrap: break-word; + /* 闃叉婧㈠嚭 */ + white-space: normal; + /* 榛樿鎹㈣ */ +} + +.user-info { + display: flex; + align-items: center; + justify-content: end; +} + +.user-content { + min-height: 60px; +} + +.downPdf { + opacity: 0 !important; +} + +.btn { + position: absolute; + top: 16px; + right: 20px; +} +</style> -- Gitblit v1.9.3