From 14079a56d94f176b27300043b737c764e9ada389 Mon Sep 17 00:00:00 2001
From: hsy <1029150275@qq.com>
Date: 星期五, 28 八月 2026 15:57:20 +0800
Subject: [PATCH] feat(quality): 新增质量管理-报告管理模块
---
src/views/reportAnalysis/inspectionReport/index.vue | 235 +++++++++++++++++++++++++++++
src/views/reportAnalysis/inspectionReport/components/formDia.vue | 183 ++++++++++++++++++++++
src/api/reportAnalysis/inspectionReport.js | 44 +++++
3 files changed, 462 insertions(+), 0 deletions(-)
diff --git a/src/api/reportAnalysis/inspectionReport.js b/src/api/reportAnalysis/inspectionReport.js
new file mode 100644
index 0000000..4c5cb90
--- /dev/null
+++ b/src/api/reportAnalysis/inspectionReport.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鎶ュ憡鍒楄〃
+export function listInspectionReport(query) {
+ return request({
+ url: '/quality/inspectionReport/listPage',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鏌ヨ鎶ュ憡璇︾粏
+export function getInspectionReport(id) {
+ return request({
+ url: '/quality/inspectionReport/' + id,
+ method: 'get'
+ })
+}
+
+// 鏂板鎶ュ憡
+export function addInspectionReport(data) {
+ return request({
+ url: '/quality/inspectionReport',
+ method: 'post',
+ data: data
+ })
+}
+
+// 淇敼鎶ュ憡
+export function updateInspectionReport(data) {
+ return request({
+ url: '/quality/inspectionReport',
+ method: 'put',
+ data: data
+ })
+}
+
+// 鍒犻櫎鎶ュ憡
+export function delInspectionReport(id) {
+ return request({
+ url: '/quality/inspectionReport/' + id,
+ method: 'delete'
+ })
+}
diff --git a/src/views/reportAnalysis/inspectionReport/components/formDia.vue b/src/views/reportAnalysis/inspectionReport/components/formDia.vue
new file mode 100644
index 0000000..723c487
--- /dev/null
+++ b/src/views/reportAnalysis/inspectionReport/components/formDia.vue
@@ -0,0 +1,183 @@
+<template>
+ <el-dialog
+ :title="title"
+ v-model="visible"
+ width="600px"
+ append-to-body
+ :close-on-click-modal="false"
+ >
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+ <el-form-item label="浜у搧鍚嶇О" prop="productName">
+ <el-input v-model="form.productName" placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" />
+ </el-form-item>
+
+ <el-form-item label="浜у搧鍨嬪彿" prop="productModel">
+ <el-input v-model="form.productModel" placeholder="璇疯緭鍏ヤ骇鍝佸瀷鍙�" />
+ </el-form-item>
+
+ <el-form-item label="鎶ュ憡缂栧彿" prop="reportNo">
+ <el-input v-model="form.reportNo" placeholder="璇疯緭鍏ユ姤鍛婄紪鍙�" />
+ </el-form-item>
+
+ <el-form-item label="鎶ュ憡绫诲瀷" prop="reportType">
+ <el-select v-model="form.reportType" placeholder="璇烽�夋嫨鎶ュ憡绫诲瀷" style="width: 100%">
+ <el-option label="鍨嬪紡璇曢獙鎶ュ憡" value="鍨嬪紡璇曢獙鎶ュ憡" />
+ <el-option label="鍑哄巶妫�楠屾姤鍛�" value="鍑哄巶妫�楠屾姤鍛�" />
+ <el-option label="濮旀墭妫�楠屾姤鍛�" value="濮旀墭妫�楠屾姤鍛�" />
+ </el-select>
+ </el-form-item>
+
+ <el-form-item label="妫�娴嬪崟浣�" prop="testingAgency">
+ <el-input v-model="form.testingAgency" placeholder="璇疯緭鍏ユ娴嬪崟浣�" />
+ </el-form-item>
+
+ <el-form-item label="鎶ュ憡鏃ユ湡" prop="reportDate">
+ <el-date-picker
+ v-model="form.reportDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="閫夋嫨鎶ュ憡鏃ユ湡"
+ style="width: 100%"
+ @change="calculateExpiration"
+ />
+ </el-form-item>
+
+ <el-form-item label="鏈夋晥鏈�(鏈�)" prop="validityPeriod">
+ <el-input-number
+ v-model="form.validityPeriod"
+ :min="1"
+ :max="120"
+ controls-position="right"
+ style="width: 100%"
+ placeholder="璇疯緭鍏ユ湁鏁堟湡(鏈�)"
+ @change="calculateExpiration"
+ />
+ </el-form-item>
+
+ <el-form-item label="鍒版湡鏃堕棿" prop="expirationTime">
+ <el-date-picker
+ v-model="form.expirationTime"
+ type="date"
+ value-format="YYYY-MM-DD"
+ disabled
+ placeholder="绯荤粺鑷姩璁$畻"
+ style="width: 100%"
+ />
+ </el-form-item>
+
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ娉ㄥ唴瀹�" />
+ </el-form-item>
+
+ <el-form-item label="闄勪欢" prop="attachmentUrls">
+ <!-- 杩欓噷浣跨敤鏅�氱殑el-upload鍗犱綅锛屽疄闄呴」鐩腑鍙浛鎹负灏佽鐨� FileUpload -->
+ <FileUpload v-model="form.attachmentUrls" :limit="5" :fileSize="50" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+ <el-button @click="cancel">鍙� 娑�</el-button>
+ </div>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs, getCurrentInstance } from "vue";
+import { addInspectionReport, updateInspectionReport, getInspectionReport } from "@/api/reportAnalysis/inspectionReport.js";
+import dayjs from "dayjs";
+
+const { proxy } = getCurrentInstance();
+const emits = defineEmits(["close"]);
+
+const visible = ref(false);
+const title = ref("");
+const formRef = ref(null);
+
+const data = reactive({
+ form: {},
+ rules: {
+ productName: [{ required: true, message: "浜у搧鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }],
+ reportNo: [{ required: true, message: "鎶ュ憡缂栧彿涓嶈兘涓虹┖", trigger: "blur" }],
+ reportDate: [{ required: true, message: "鎶ュ憡鏃ユ湡涓嶈兘涓虹┖", trigger: "change" }],
+ validityPeriod: [{ required: true, message: "鏈夋晥鏈熶笉鑳戒负绌�", trigger: "blur" }],
+ expirationTime: [{ required: true, message: "鍒版湡鏃堕棿涓嶈兘涓虹┖", trigger: "change" }],
+ }
+});
+
+const { form, rules } = toRefs(data);
+
+// 鑷姩璁$畻鍒版湡鏃堕棿
+const calculateExpiration = () => {
+ if (form.value.reportDate && form.value.validityPeriod) {
+ form.value.expirationTime = dayjs(form.value.reportDate)
+ .add(form.value.validityPeriod, 'month')
+ .format('YYYY-MM-DD');
+ } else {
+ form.value.expirationTime = null;
+ }
+};
+
+const openDialog = (type, row) => {
+ reset();
+ if (type === "add") {
+ title.value = "鏂板鎶ュ憡";
+ visible.value = true;
+ } else {
+ title.value = "淇敼鎶ュ憡";
+ getInspectionReport(row.id).then(response => {
+ form.value = response.data;
+ visible.value = true;
+ });
+ }
+};
+
+const reset = () => {
+ form.value = {
+ id: null,
+ productName: null,
+ productModel: null,
+ reportNo: null,
+ reportDate: null,
+ validityPeriod: 12, // 榛樿涓�骞�
+ expirationTime: null,
+ testingAgency: null,
+ reportType: null,
+ attachmentUrls: null,
+ remark: null
+ };
+ if (formRef.value) {
+ formRef.value.resetFields();
+ }
+};
+
+const submitForm = () => {
+ formRef.value.validate(valid => {
+ if (valid) {
+ if (form.value.id != null) {
+ updateInspectionReport(form.value).then(() => {
+ proxy.$modal.msgSuccess("淇敼鎴愬姛");
+ visible.value = false;
+ emits("close");
+ });
+ } else {
+ addInspectionReport(form.value).then(() => {
+ proxy.$modal.msgSuccess("鏂板鎴愬姛");
+ visible.value = false;
+ emits("close");
+ });
+ }
+ }
+ });
+};
+
+const cancel = () => {
+ visible.value = false;
+ reset();
+};
+
+defineExpose({
+ openDialog
+});
+</script>
diff --git a/src/views/reportAnalysis/inspectionReport/index.vue b/src/views/reportAnalysis/inspectionReport/index.vue
new file mode 100644
index 0000000..5ae2b13
--- /dev/null
+++ b/src/views/reportAnalysis/inspectionReport/index.vue
@@ -0,0 +1,235 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <el-form :model="searchForm" inline style="margin-bottom: 0;">
+ <el-form-item label="浜у搧鍚嶇О锛�">
+ <el-input
+ v-model="searchForm.productName"
+ style="width: 200px"
+ placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ </el-form-item>
+ <el-form-item label="鎶ュ憡缂栧彿锛�">
+ <el-input
+ v-model="searchForm.reportNo"
+ style="width: 200px"
+ placeholder="璇疯緭鍏ユ姤鍛婄紪鍙�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ </el-form-item>
+ <el-form-item label="鎶ュ憡绫诲瀷锛�">
+ <el-select v-model="searchForm.reportType" clearable style="width: 200px" @change="handleQuery" placeholder="璇烽�夋嫨">
+ <!-- 涓存椂瀛楀吀鏁版嵁锛屽悗缁彲鏀逛负浠庡瓧鍏告帴鍙h幏鍙� -->
+ <el-option label="鍨嬪紡璇曢獙鎶ュ憡" value="鍨嬪紡璇曢獙鎶ュ憡" />
+ <el-option label="鍑哄巶妫�楠屾姤鍛�" value="鍑哄巶妫�楠屾姤鍛�" />
+ <el-option label="濮旀墭妫�楠屾姤鍛�" value="濮旀墭妫�楠屾姤鍛�" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">鎼滅储</el-button>
+ <el-button @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <div class="mb20" style="text-align: right;">
+ <el-button type="primary" @click="openForm('add')">鏂板</el-button>
+ <el-button type="danger" plain @click="handleDelete">娉ㄩ攢浣滃簾</el-button>
+ </div>
+
+ <div class="table_list">
+ <PIMTable
+ rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :page="page"
+ :isSelection="true"
+ @selection-change="handleSelectionChange"
+ :tableLoading="tableLoading"
+ @pagination="pagination"
+ :total="page.total"
+ ></PIMTable>
+ </div>
+
+ <FormDia ref="formDia" @close="handleQuery"></FormDia>
+ </div>
+</template>
+
+<script setup>
+import { Search } from "@element-plus/icons-vue";
+import { onMounted, ref, reactive, toRefs, nextTick, getCurrentInstance } from "vue";
+import FormDia from "./components/formDia.vue";
+import { ElMessageBox } from "element-plus";
+import { listInspectionReport, delInspectionReport } from "@/api/reportAnalysis/inspectionReport.js";
+import dayjs from "dayjs";
+
+const { proxy } = getCurrentInstance();
+
+const data = reactive({
+ searchForm: {
+ productName: "",
+ reportNo: "",
+ reportType: "",
+ },
+});
+const { searchForm } = toRefs(data);
+
+const tableColumn = ref([
+ {
+ label: "浜у搧鍚嶇О",
+ prop: "productName",
+ },
+ {
+ label: "浜у搧鍨嬪彿",
+ prop: "productModel",
+ },
+ {
+ label: "鎶ュ憡缂栧彿",
+ prop: "reportNo",
+ },
+ {
+ label: "鎶ュ憡鏃ユ湡",
+ prop: "reportDate",
+ width: 120
+ },
+ {
+ label: "鎶ュ憡绫诲瀷",
+ prop: "reportType",
+ },
+ {
+ label: "妫�娴嬪崟浣�",
+ prop: "testingAgency",
+ },
+ {
+ label: "鍒版湡鏃堕棿",
+ prop: "expirationTime",
+ dataType: "tag",
+ width: 120,
+ formatData: (val) => val, // 鍘熸牱杩斿洖鏃堕棿
+ formatType: (val) => {
+ // 棰勮閫昏緫锛氬皬浜庣瓑浜�30澶╁埌鏈燂紝杩斿洖 danger 鏍囩孩
+ if (!val) return 'info';
+ const days = dayjs(val).diff(dayjs(), 'day');
+ if (days <= 30 && days >= 0) {
+ return "danger";
+ } else if (days < 0) {
+ return "danger"; // 宸茶繃鏈�
+ }
+ return "success";
+ }
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: "right",
+ width: 120,
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openForm("edit", row);
+ }
+ }
+ ]
+ }
+]);
+
+const tableData = ref([]);
+const selectedRows = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 10,
+ total: 0
+});
+const formDia = ref();
+
+// 鏌ヨ鍒楄〃
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+
+const resetQuery = () => {
+ searchForm.value = {
+ productName: "",
+ reportNo: "",
+ reportType: "",
+ };
+ handleQuery();
+};
+
+const pagination = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+
+const getList = () => {
+ tableLoading.value = true;
+ const params = { ...searchForm.value, current: page.current, size: page.size };
+
+ listInspectionReport(params).then(res => {
+ tableLoading.value = false;
+ // PIMTable expected formats usually res.data.records or similar, if it uses IPage
+ if(res.data && res.data.records) {
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ } else {
+ // Fallback standard structure
+ tableData.value = res.data;
+ page.total = res.total || 0;
+ }
+ }).catch(err => {
+ tableLoading.value = false;
+ });
+};
+
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ nextTick(() => {
+ formDia.value?.openDialog(type, row);
+ });
+};
+
+// 鍒犻櫎(娉ㄩ攢浣滃簾)
+const handleDelete = () => {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨瑕佹敞閿�鐨勬暟鎹�");
+ return;
+ }
+ let ids = selectedRows.value.map((item) => item.id);
+
+ ElMessageBox.confirm("閫変腑鐨勬姤鍛婂皢琚敞閿�浣滃簾锛屾槸鍚︾‘璁わ紵", "璀﹀憡", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ delInspectionReport(ids.join(',')).then(() => {
+ proxy.$modal.msgSuccess("娉ㄩ攢鎴愬姛");
+ getList();
+ });
+ })
+ .catch(() => {});
+};
+
+onMounted(() => {
+ getList();
+});
+</script>
+
+<style scoped>
+</style>
--
Gitblit v1.9.3