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