From 530297eda34d030e9b3c8bd168ad818fde1a6ded Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 29 九月 2025 17:24:51 +0800
Subject: [PATCH] 临期相关页面
---
src/views/qualityManagement/nearExpiryReturn/index.vue | 519 ++++++++++++++++++++++++
src/views/customerService/expiryAfterSales/index.vue | 330 +++++++++++++++
src/api/customerService/index.js | 36 +
bin/build.bat | 22
src/api/qualityManagement/nearExpiryReturn.js | 45 ++
src/views/customerService/expiryAfterSales/components/formDia.vue | 291 +++++++++++++
6 files changed, 1,232 insertions(+), 11 deletions(-)
diff --git a/bin/build.bat b/bin/build.bat
index 8868727..a4cc0df 100644
--- a/bin/build.bat
+++ b/bin/build.bat
@@ -1,12 +1,12 @@
-@echo off
-echo.
-echo [信息] 打包Web工程,生成dist文件。
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-yarn build:prod
-
+@echo off
+echo.
+echo [锟斤拷息] 锟斤拷锟絎eb锟斤拷锟教o拷锟斤拷锟斤拷dist锟侥硷拷锟斤拷
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+yarn build:prod
+
pause
\ No newline at end of file
diff --git a/src/api/customerService/index.js b/src/api/customerService/index.js
index e83cdfb..b92033b 100644
--- a/src/api/customerService/index.js
+++ b/src/api/customerService/index.js
@@ -40,4 +40,40 @@
method: 'post',
data: query,
})
+}
+
+// 涓存湡鍞悗绠$悊-鍒嗛〉鏌ヨ
+export function expiryAfterSalesListPage(query) {
+ return request({
+ url: '/expiryAfterSales/listPage',
+ method: 'get',
+ params: query,
+ })
+}
+
+// 涓存湡鍞悗绠$悊-鏂板
+export function expiryAfterSalesAdd(query) {
+ return request({
+ url: '/expiryAfterSales/add',
+ method: 'post',
+ data: query,
+ })
+}
+
+// 涓存湡鍞悗绠$悊-鏇存柊
+export function expiryAfterSalesUpdate(query) {
+ return request({
+ url: '/expiryAfterSales/update',
+ method: 'post',
+ data: query,
+ })
+}
+
+// 涓存湡鍞悗绠$悊-鍒犻櫎
+export function expiryAfterSalesDelete(query) {
+ return request({
+ url: '/expiryAfterSales/delete',
+ method: 'delete',
+ data: query,
+ })
}
\ No newline at end of file
diff --git a/src/api/qualityManagement/nearExpiryReturn.js b/src/api/qualityManagement/nearExpiryReturn.js
new file mode 100644
index 0000000..af1f55a
--- /dev/null
+++ b/src/api/qualityManagement/nearExpiryReturn.js
@@ -0,0 +1,45 @@
+import request from '@/utils/request'
+
+// 鏌ヨ涓存湡閫�鍥炲彴璐﹀垪琛�
+export function nearExpiryReturnListPage(query) {
+ return request({
+ url: '/quality/nearExpiryReturn/listPage',
+ method: 'get',
+ params: query,
+ })
+}
+
+// 鏂板涓存湡閫�鍥炲彴璐�
+export function nearExpiryReturnAdd(data) {
+ return request({
+ url: '/quality/nearExpiryReturn/add',
+ method: 'post',
+ data: data,
+ })
+}
+
+// 淇敼涓存湡閫�鍥炲彴璐�
+export function nearExpiryReturnUpdate(data) {
+ return request({
+ url: '/quality/nearExpiryReturn/update',
+ method: 'post',
+ data: data,
+ })
+}
+
+// 鍒犻櫎涓存湡閫�鍥炲彴璐�
+export function nearExpiryReturnDel(ids) {
+ return request({
+ url: '/quality/nearExpiryReturn/del',
+ method: 'delete',
+ data: ids,
+ })
+}
+
+// 鑾峰彇涓存湡閫�鍥炲彴璐﹁鎯�
+export function nearExpiryReturnDetail(id) {
+ return request({
+ url: '/quality/nearExpiryReturn/' + id,
+ method: 'get',
+ })
+}
diff --git a/src/views/customerService/expiryAfterSales/components/formDia.vue b/src/views/customerService/expiryAfterSales/components/formDia.vue
new file mode 100644
index 0000000..a6ae725
--- /dev/null
+++ b/src/views/customerService/expiryAfterSales/components/formDia.vue
@@ -0,0 +1,291 @@
+<template>
+ <div>
+ <el-dialog
+ v-model="dialogFormVisible"
+ :title="dialogTitle"
+ width="70%"
+ @close="closeDia"
+ >
+ <el-form
+ :model="form"
+ label-width="140px"
+ label-position="top"
+ :rules="rules"
+ ref="formRef"
+ >
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="涓存湡浜у搧鍚嶇О锛�" prop="productName">
+ <el-input
+ v-model="form.productName"
+ placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
+ clearable
+ :disabled="operationType === 'view'"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="浜у搧鎵瑰彿锛�" prop="batchNumber">
+ <el-input
+ v-model="form.batchNumber"
+ placeholder="璇疯緭鍏ヤ骇鍝佹壒鍙�"
+ clearable
+ :disabled="operationType === 'view'"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="涓存湡鏃ユ湡锛�" prop="expiryDate">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.expiryDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨涓存湡鏃ユ湡"
+ clearable
+ :disabled="operationType === 'view'"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="搴撳瓨鏁伴噺锛�" prop="stockQuantity">
+ <el-input-number
+ v-model="form.stockQuantity"
+ :min="0"
+ placeholder="璇疯緭鍏ュ簱瀛樻暟閲�"
+ style="width: 100%"
+ :disabled="operationType === 'view'"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerName">
+ <el-input
+ v-model="form.customerName"
+ placeholder="璇疯緭鍏ュ鎴峰悕绉�"
+ clearable
+ :disabled="operationType === 'view'"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鑱旂郴鐢佃瘽锛�" prop="contactPhone">
+ <el-input
+ v-model="form.contactPhone"
+ placeholder="璇疯緭鍏ヨ仈绯荤數璇�"
+ clearable
+ :disabled="operationType === 'view'"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="闂鎻忚堪锛�" prop="problemDesc">
+ <el-input
+ v-model="form.problemDesc"
+ placeholder="璇疯緭鍏ラ棶棰樻弿杩�"
+ clearable
+ :disabled="operationType === 'view'"
+ type="textarea"
+ :rows="3"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30" v-if="operationType !== 'add'">
+ <el-col :span="12">
+ <el-form-item label="澶勭悊浜猴細" prop="handlerId">
+ <el-select
+ v-model="form.handlerId"
+ placeholder="璇烽�夋嫨澶勭悊浜�"
+ clearable
+ :disabled="operationType === 'view'"
+ style="width: 100%"
+ >
+ <el-option
+ v-for="item in userList"
+ :key="item.userId"
+ :label="item.nickName"
+ :value="item.userId"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="澶勭悊鏃ユ湡锛�" prop="handleDate">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.handleDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨澶勭悊鏃ユ湡"
+ clearable
+ :disabled="operationType === 'view'"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30" v-if="operationType !== 'add'">
+ <el-col :span="24">
+ <el-form-item label="澶勭悊缁撴灉锛�" prop="handleResult">
+ <el-input
+ v-model="form.handleResult"
+ placeholder="璇疯緭鍏ュ鐞嗙粨鏋�"
+ clearable
+ :disabled="operationType === 'view'"
+ type="textarea"
+ :rows="3"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitForm" v-if="operationType !== 'view'">纭</el-button>
+ <el-button @click="closeDia">{{ operationType === 'view' ? '鍏抽棴' : '鍙栨秷' }}</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import {ref, computed} from "vue";
+import useUserStore from "@/store/modules/user.js";
+// import {userListNoPageByTenantId} from "@/api/system/user.js"; // 鏆傛椂娉ㄩ噴鎺夛紝浣跨敤鍋囨暟鎹�
+// import {expiryAfterSalesAdd, expiryAfterSalesUpdate} from "@/api/customerService/index.js"; // 鏆傛椂娉ㄩ噴鎺夛紝浣跨敤鍋囨暟鎹�
+const { proxy } = getCurrentInstance()
+const emit = defineEmits(['close'])
+const dialogFormVisible = ref(false);
+const operationType = ref('')
+const userStore = useUserStore();
+
+const dialogTitle = computed(() => {
+ switch (operationType.value) {
+ case 'add':
+ return '鏂板涓存湡鍞悗';
+ case 'edit':
+ return '缂栬緫涓存湡鍞悗';
+ case 'view':
+ return '鏌ョ湅涓存湡鍞悗';
+ default:
+ return '涓存湡鍞悗绠$悊';
+ }
+});
+
+const data = reactive({
+ form: {
+ id: "",
+ productName: "",
+ batchNumber: "",
+ expiryDate: "",
+ stockQuantity: 0,
+ customerName: "",
+ contactPhone: "",
+ problemDesc: "",
+ handlerId: "",
+ handleDate: "",
+ handleResult: "",
+ status: 1
+ },
+ rules: {
+ productName: [{required: true, message: "璇疯緭鍏ヤ骇鍝佸悕绉�", trigger: "blur"}],
+ batchNumber: [{required: true, message: "璇疯緭鍏ヤ骇鍝佹壒鍙�", trigger: "blur"}],
+ expiryDate: [{required: true, message: "璇烽�夋嫨涓存湡鏃ユ湡", trigger: "change"}],
+ stockQuantity: [{required: true, message: "璇疯緭鍏ュ簱瀛樻暟閲�", trigger: "blur"}],
+ customerName: [{required: true, message: "璇疯緭鍏ュ鎴峰悕绉�", trigger: "blur"}],
+ contactPhone: [
+ {required: true, message: "璇疯緭鍏ヨ仈绯荤數璇�", trigger: "blur"},
+ {pattern: /^1[3-9]\d{9}$/, message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜", trigger: "blur"}
+ ],
+ problemDesc: [{required: true, message: "璇疯緭鍏ラ棶棰樻弿杩�", trigger: "blur"}],
+ }
+})
+const { form, rules } = toRefs(data);
+const userList = ref([])
+
+// 鎵撳紑寮规
+const openDialog = (type, row) => {
+ operationType.value = type;
+ dialogFormVisible.value = true;
+
+ // 妯℃嫙鑾峰彇鐢ㄦ埛鍒楄〃
+ userList.value = [
+ { userId: 1, nickName: "寮犱笁" },
+ { userId: 2, nickName: "鏉庡洓" },
+ { userId: 3, nickName: "鐜嬩簲" },
+ { userId: 4, nickName: "璧靛叚" },
+ { userId: 5, nickName: "瀛欏叓" }
+ ];
+
+ if (type === 'add') {
+ // 鏂板鏃堕噸缃〃鍗�
+ form.value = {
+ id: "",
+ productName: "",
+ batchNumber: "",
+ expiryDate: "",
+ stockQuantity: 0,
+ customerName: "",
+ contactPhone: "",
+ problemDesc: "",
+ handlerId: "",
+ handleDate: "",
+ handleResult: "",
+ status: 1
+ };
+ } else {
+ // 缂栬緫鎴栨煡鐪嬫椂濉厖鏁版嵁
+ form.value = { ...row };
+ if (type === 'edit' && !form.value.handlerId) {
+ form.value.handlerId = userStore.id;
+ form.value.handleDate = getCurrentDate();
+ }
+ }
+}
+
+const submitForm = () => {
+ proxy.$refs["formRef"].validate(valid => {
+ if (valid) {
+ // 妯℃嫙鎻愪氦鎿嶄綔
+ setTimeout(() => {
+ console.log("妯℃嫙鎻愪氦鐨勬暟鎹�:", form.value);
+ proxy.$modal.msgSuccess(operationType.value === 'add' ? "鏂板鎴愬姛" : "鏇存柊鎴愬姛");
+ closeDia();
+ }, 300);
+ }
+ });
+}
+
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.resetForm("formRef");
+ dialogFormVisible.value = false;
+ emit('close')
+};
+
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+ const today = new Date();
+ const year = today.getFullYear();
+ const month = String(today.getMonth() + 1).padStart(2, "0");
+ const day = String(today.getDate()).padStart(2, "0");
+ return `${year}-${month}-${day}`;
+}
+
+defineExpose({
+ openDialog,
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/customerService/expiryAfterSales/index.vue b/src/views/customerService/expiryAfterSales/index.vue
new file mode 100644
index 0000000..b958acb
--- /dev/null
+++ b/src/views/customerService/expiryAfterSales/index.vue
@@ -0,0 +1,330 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <span class="search_title">涓存湡鏃ユ湡锛�</span>
+ <el-date-picker
+ v-model="searchForm.expiryDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="handleQuery"
+ />
+ <span class="search_title ml10">澶勭悊鏃ユ湡锛�</span>
+ <el-date-picker
+ v-model="searchForm.handleDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="handleQuery"
+ />
+ <span style = "margin-left: 10px;" class="search_title">澶勭悊鐘舵�侊細</span>
+ <el-select v-model="searchForm.status" placeholder="璇烽�夋嫨鐘舵��" @change="handleQuery" style="width: 140px" clearable>
+ <el-option label="寰呭鐞�" :value="1"></el-option>
+ <el-option label="宸插鐞�" :value="2"></el-option>
+ </el-select>
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+ >鎼滅储</el-button
+ >
+ <el-button @click="resetQuery" style="margin-left: 10px"
+ >閲嶇疆</el-button
+ >
+ </div>
+ </div>
+ <div class="table_actions" style="margin-bottom: 10px;">
+ <el-button type="primary" @click="openForm('add')">鏂板</el-button>
+ <el-button type="danger" @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"
+ >
+ <!-- 琛ㄦ牸鎻掓Ы -->
+ <template #status="{ row }">
+ <el-tag :type="row.status === 1 ? 'warning' : 'success'">
+ {{ row.status === 1 ? '寰呭鐞�' : '宸插鐞�' }}
+ </el-tag>
+ </template>
+
+ <template #operation="{ row }">
+ <el-button type="primary" link @click="openForm('view', row)">鏌ョ湅</el-button>
+ <el-button type="primary" link @click="openForm('edit', row)" v-if="row.status === 1">缂栬緫</el-button>
+ </template>
+ </PIMTable>
+ </div>
+ <form-dia ref="formDia" @close="handleQuery"></form-dia>
+ </div>
+</template>
+
+<script setup>
+import {Search} from "@element-plus/icons-vue";
+import {onMounted, ref} from "vue";
+import FormDia from "@/views/customerService/expiryAfterSales/components/formDia.vue";
+import {ElMessageBox} from "element-plus";
+// import {expiryAfterSalesDelete, expiryAfterSalesListPage} from "@/api/customerService/index.js"; // 鏆傛椂娉ㄩ噴鎺夛紝浣跨敤鍋囨暟鎹�
+import useUserStore from "@/store/modules/user.js";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore()
+
+const data = reactive({
+ searchForm: {
+ expiryDate: "",
+ handleDate: "",
+ status: ""
+ },
+ tableData: [],
+ page: {
+ current: 1,
+ size: 10,
+ total: 0,
+ },
+ selectedRows: [],
+ tableLoading: false,
+ formDia: null,
+ tableColumn: [
+ {
+ label: "涓存湡浜у搧鍚嶇О",
+ prop: "productName",
+ width: "",
+ },
+ {
+ label: "浜у搧鎵瑰彿",
+ prop: "batchNumber",
+ width: "",
+ },
+ {
+ label: "涓存湡鏃ユ湡",
+ prop: "expiryDate",
+ width: "",
+ },
+ {
+ label: "搴撳瓨鏁伴噺",
+ prop: "stockQuantity",
+ width: "",
+ },
+ {
+ label: "瀹㈡埛鍚嶇О",
+ prop: "customerName",
+ width: "",
+ },
+ {
+ label: "闂鎻忚堪",
+ prop: "problemDesc",
+ width: "",
+ },
+ {
+ label: "澶勭悊鐘舵��",
+ prop: "status",
+ width: "",
+ slot: true,
+ },
+ {
+ label: "澶勭悊浜�",
+ prop: "handlerName",
+ width: "",
+ },
+ {
+ label: "澶勭悊鏃ユ湡",
+ prop: "handleDate",
+ width: "",
+ },
+ {
+ label: "鎿嶄綔",
+ prop: "operation",
+ slot: true,
+ width: "200",
+ },
+ ],
+});
+
+const {
+ searchForm,
+ tableData,
+ page,
+ selectedRows,
+ tableLoading,
+ formDia,
+ tableColumn,
+} = toRefs(data);
+
+// 鏌ヨ
+const handleQuery = () => {
+ page.value.current = 1;
+ getList();
+};
+
+// 閫夋嫨
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 閲嶇疆
+const resetQuery = () => {
+ proxy.resetForm("queryRef");
+ searchForm.value = {
+ expiryDate: "",
+ handleDate: "",
+ status: ""
+ };
+ handleQuery();
+};
+
+// 鍒嗛〉
+const pagination = (obj) => {
+ page.value.current = obj.page;
+ page.value.size = obj.limit;
+ getList();
+};
+
+// 鑾峰彇鍒楄〃鏁版嵁
+const getList = () => {
+ tableLoading.value = true;
+
+ // 妯℃嫙寮傛璇锋眰
+ setTimeout(() => {
+ // 鍋囨暟鎹�
+ const mockData = [
+ {
+ id: 1,
+ productName: "缁寸敓绱燙鐗�",
+ batchNumber: "VC20240801",
+ expiryDate: "2024-12-15",
+ stockQuantity: 150,
+ customerName: "寮犱笁鑽簵",
+ problemDesc: "涓磋繎淇濊川鏈熼渶瑕佸鐞�",
+ status: 1,
+ handlerName: "",
+ handleDate: "",
+ },
+ {
+ id: 2,
+ productName: "闃胯帿瑗挎灄鑳跺泭",
+ batchNumber: "AM20240715",
+ expiryDate: "2024-11-20",
+ stockQuantity: 80,
+ customerName: "鏉庡洓鍖婚櫌",
+ problemDesc: "搴撳瓨绉帇锛屼复鏈熷鐞�",
+ status: 2,
+ handlerName: "鐜嬩簲",
+ handleDate: "2024-09-25",
+ },
+ {
+ id: 3,
+ productName: "鎰熷啋鐏甸绮�",
+ batchNumber: "GM20240620",
+ expiryDate: "2024-10-30",
+ stockQuantity: 200,
+ customerName: "璧靛叚璇婃墍",
+ problemDesc: "瀛h妭鎬ц嵂鍝侊紝闇�瑕佹竻鐞嗗簱瀛�",
+ status: 1,
+ handlerName: "",
+ handleDate: "",
+ },
+ {
+ id: 4,
+ productName: "澶嶅悎缁寸敓绱犵墖",
+ batchNumber: "FH20240510",
+ expiryDate: "2024-12-01",
+ stockQuantity: 300,
+ customerName: "閽变竷杩為攣",
+ problemDesc: "涓存湡浜у搧閫�鎹㈢敵璇�",
+ status: 2,
+ handlerName: "瀛欏叓",
+ handleDate: "2024-09-20",
+ },
+ {
+ id: 5,
+ productName: "鏉胯摑鏍归绮�",
+ batchNumber: "BL20240430",
+ expiryDate: "2024-11-10",
+ stockQuantity: 120,
+ customerName: "鍛ㄤ節鑽埧",
+ problemDesc: "鎵规闂锛岄渶瑕佸彫鍥�",
+ status: 1,
+ handlerName: "",
+ handleDate: "",
+ }
+ ];
+
+ // 绠�鍗曠殑鎼滅储杩囨护
+ let filteredData = mockData;
+
+ if (searchForm.value.status !== "" && searchForm.value.status !== null) {
+ filteredData = filteredData.filter(item => item.status === searchForm.value.status);
+ }
+
+ if (searchForm.value.expiryDate) {
+ filteredData = filteredData.filter(item => item.expiryDate === searchForm.value.expiryDate);
+ }
+
+ if (searchForm.value.handleDate) {
+ filteredData = filteredData.filter(item => item.handleDate === searchForm.value.handleDate);
+ }
+
+ // 鍒嗛〉澶勭悊
+ const start = (page.value.current - 1) * page.value.size;
+ const end = start + page.value.size;
+ const paginatedData = filteredData.slice(start, end);
+
+ tableLoading.value = false;
+ tableData.value = paginatedData;
+ page.value.total = filteredData.length;
+ }, 500); // 妯℃嫙缃戠粶寤惰繜
+};
+
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ nextTick(() => {
+ formDia.value?.openDialog(type, row)
+ })
+};
+
+// 鍒犻櫎
+const handleDelete = () => {
+ let ids = [];
+ if (selectedRows.value.length > 0) {
+ ids = selectedRows.value.map((item) => item.id);
+ } else {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ tableLoading.value = true;
+
+ // 妯℃嫙鍒犻櫎鎿嶄綔
+ setTimeout(() => {
+ tableLoading.value = false;
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ console.log("妯℃嫙鍒犻櫎鐨勬暟鎹甀D:", ids);
+ getList(); // 閲嶆柊鑾峰彇鏁版嵁
+ }, 300);
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+
+onMounted(() => {
+ getList();
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/qualityManagement/nearExpiryReturn/index.vue b/src/views/qualityManagement/nearExpiryReturn/index.vue
new file mode 100644
index 0000000..d2fe85b
--- /dev/null
+++ b/src/views/qualityManagement/nearExpiryReturn/index.vue
@@ -0,0 +1,519 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="浜у搧鍚嶇О" prop="productName">
+ <el-input
+ v-model="queryParams.productName"
+ placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="鎵规鍙�" prop="batchNumber">
+ <el-input
+ v-model="queryParams.batchNumber"
+ placeholder="璇疯緭鍏ユ壒娆″彿"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="閫�鍥炴棩鏈�" prop="returnDate">
+ <el-date-picker
+ clearable
+ v-model="queryParams.returnDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨閫�鍥炴棩鏈�">
+ </el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="Plus"
+ @click="handleAdd"
+ >鏂板</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="Edit"
+ :disabled="single"
+ @click="handleUpdate"
+ >淇敼</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="Delete"
+ :disabled="multiple"
+ @click="handleDelete"
+ >鍒犻櫎</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="Download"
+ @click="handleExport"
+ >瀵煎嚭</el-button>
+ </el-col>
+ <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="nearExpiryReturnList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="搴忓彿" type="index" width="50" align="center" />
+ <el-table-column label="浜у搧鍚嶇О" prop="productName" />
+ <el-table-column label="浜у搧瑙勬牸" prop="productSpec" />
+ <el-table-column label="鎵规鍙�" prop="batchNumber" />
+ <el-table-column label="鐢熶骇鏃ユ湡" prop="productionDate" align="center">
+ <template #default="scope">
+ <span>{{ parseTime(scope.row.productionDate, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍒版湡鏃ユ湡" prop="expiryDate" align="center">
+ <template #default="scope">
+ <span>{{ parseTime(scope.row.expiryDate, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="閫�鍥炴暟閲�" prop="returnQuantity" />
+ <el-table-column label="閫�鍥炲師鍥�" prop="returnReason" />
+ <el-table-column label="閫�鍥炴棩鏈�" prop="returnDate" align="center">
+ <template #default="scope">
+ <span>{{ parseTime(scope.row.returnDate, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="澶勭悊鐘舵��" prop="status" align="center">
+ <template #default="scope">
+ <dict-tag :options="statusOptions" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template #default="scope">
+ <el-button size="mini" type="text" icon="Edit" @click="handleUpdate(scope.row)">淇敼</el-button>
+ <el-button size="mini" type="text" icon="Delete" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ v-model:page="queryParams.pageNum"
+ v-model:limit="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 娣诲姞鎴栦慨鏀逛复鏈熼��鍥炲彴璐﹀璇濇 -->
+ <el-dialog :title="title" v-model="open" width="800px" append-to-body>
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="浜у搧鍚嶇О" prop="productName">
+ <el-input v-model="form.productName" placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="浜у搧瑙勬牸" prop="productSpec">
+ <el-input v-model="form.productSpec" placeholder="璇疯緭鍏ヤ骇鍝佽鏍�" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="鎵规鍙�" prop="batchNumber">
+ <el-input v-model="form.batchNumber" placeholder="璇疯緭鍏ユ壒娆″彿" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="閫�鍥炴暟閲�" prop="returnQuantity">
+ <el-input-number v-model="form.returnQuantity" controls-position="right" :min="1" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="鐢熶骇鏃ユ湡" prop="productionDate">
+ <el-date-picker
+ clearable
+ v-model="form.productionDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨鐢熶骇鏃ユ湡">
+ </el-date-picker>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍒版湡鏃ユ湡" prop="expiryDate">
+ <el-date-picker
+ clearable
+ v-model="form.expiryDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨鍒版湡鏃ユ湡">
+ </el-date-picker>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="閫�鍥炴棩鏈�" prop="returnDate">
+ <el-date-picker
+ clearable
+ v-model="form.returnDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨閫�鍥炴棩鏈�">
+ </el-date-picker>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="澶勭悊鐘舵��" prop="status">
+ <el-select v-model="form.status" placeholder="璇烽�夋嫨澶勭悊鐘舵��">
+ <el-option
+ v-for="dict in statusOptions"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="24">
+ <el-form-item label="閫�鍥炲師鍥�" prop="returnReason">
+ <el-input v-model="form.returnReason" type="textarea" placeholder="璇疯緭鍏ラ��鍥炲師鍥�" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="24">
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </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>
+ </div>
+</template>
+
+<script setup name="NearExpiryReturn">
+import { ref, reactive, onMounted } from "vue";
+import { ElMessageBox } from "element-plus";
+import {
+ nearExpiryReturnListPage,
+ nearExpiryReturnAdd,
+ nearExpiryReturnUpdate,
+ nearExpiryReturnDel,
+ nearExpiryReturnDetail
+} from "@/api/qualityManagement/nearExpiryReturn";
+
+const { proxy } = getCurrentInstance();
+const { parseTime } = proxy;
+
+const nearExpiryReturnList = ref([]);
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+
+// 鐘舵�佸瓧鍏�
+const statusOptions = ref([
+ { label: "寰呭鐞�", value: "0" },
+ { label: "澶勭悊涓�", value: "1" },
+ { label: "宸插畬鎴�", value: "2" }
+]);
+
+const data = reactive({
+ form: {},
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ productName: null,
+ batchNumber: null,
+ returnDate: null
+ },
+ rules: {
+ productName: [
+ { required: true, message: "浜у搧鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+ ],
+ productSpec: [
+ { required: true, message: "浜у搧瑙勬牸涓嶈兘涓虹┖", trigger: "blur" }
+ ],
+ batchNumber: [
+ { required: true, message: "鎵规鍙蜂笉鑳戒负绌�", trigger: "blur" }
+ ],
+ returnQuantity: [
+ { required: true, message: "閫�鍥炴暟閲忎笉鑳戒负绌�", trigger: "blur" }
+ ],
+ productionDate: [
+ { required: true, message: "鐢熶骇鏃ユ湡涓嶈兘涓虹┖", trigger: "blur" }
+ ],
+ expiryDate: [
+ { required: true, message: "鍒版湡鏃ユ湡涓嶈兘涓虹┖", trigger: "blur" }
+ ],
+ returnDate: [
+ { required: true, message: "閫�鍥炴棩鏈熶笉鑳戒负绌�", trigger: "blur" }
+ ],
+ returnReason: [
+ { required: true, message: "閫�鍥炲師鍥犱笉鑳戒负绌�", trigger: "blur" }
+ ],
+ status: [
+ { required: true, message: "澶勭悊鐘舵�佷笉鑳戒负绌�", trigger: "change" }
+ ]
+ }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ涓存湡閫�鍥炲彴璐﹀垪琛� */
+function getList() {
+ loading.value = true;
+ // 浣跨敤鍋囨暟鎹�
+ const mockData = {
+ records: [
+ {
+ id: 1,
+ productName: "缁寸敓绱燙鐗�",
+ productSpec: "100mg脳30鐗�",
+ batchNumber: "VC20240315001",
+ productionDate: "2024-03-15",
+ expiryDate: "2024-09-15",
+ returnQuantity: 50,
+ returnReason: "涓磋繎淇濊川鏈�",
+ returnDate: "2024-09-10",
+ status: "1",
+ remark: "閫�鍥炰粨搴撳鐞�"
+ },
+ {
+ id: 2,
+ productName: "闃胯帿瑗挎灄鑳跺泭",
+ productSpec: "250mg脳24绮�",
+ batchNumber: "AMX20240220002",
+ productionDate: "2024-02-20",
+ expiryDate: "2024-08-20",
+ returnQuantity: 30,
+ returnReason: "鍖呰鐮存崯涓斾复鏈�",
+ returnDate: "2024-08-18",
+ status: "2",
+ remark: "宸查攢姣佸鐞�"
+ },
+ {
+ id: 3,
+ productName: "鎰熷啋鐏甸绮�",
+ productSpec: "10g脳12琚�",
+ batchNumber: "GML20240110003",
+ productionDate: "2024-01-10",
+ expiryDate: "2024-07-10",
+ returnQuantity: 25,
+ returnReason: "涓磋繎淇濊川鏈�",
+ returnDate: "2024-07-08",
+ status: "0",
+ remark: "寰呴噸鏂板寘瑁�"
+ },
+ {
+ id: 4,
+ productName: "澶嶅悎缁寸敓绱犵墖",
+ productSpec: "60鐗�/鐡�",
+ batchNumber: "VB20240405004",
+ productionDate: "2024-04-05",
+ expiryDate: "2025-04-05",
+ returnQuantity: 80,
+ returnReason: "涓磋繎淇濊川鏈�",
+ returnDate: "2024-09-25",
+ status: "1",
+ remark: "姝e湪鑱旂郴閿�鍞笭閬�"
+ },
+ {
+ id: 5,
+ productName: "閽欑墖",
+ productSpec: "600mg脳100鐗�",
+ batchNumber: "CA20240301005",
+ productionDate: "2024-03-01",
+ expiryDate: "2024-09-01",
+ returnQuantity: 120,
+ returnReason: "鍖呰闂涓斾复鏈�",
+ returnDate: "2024-08-30",
+ status: "2",
+ remark: "宸插畬鎴愰��璐у鐞�"
+ }
+ ],
+ total: 5
+ };
+
+ // 妯℃嫙杩囨护閫昏緫
+ let filteredRecords = mockData.records;
+
+ if (queryParams.value.productName) {
+ filteredRecords = filteredRecords.filter(item =>
+ item.productName.includes(queryParams.value.productName)
+ );
+ }
+
+ if (queryParams.value.batchNumber) {
+ filteredRecords = filteredRecords.filter(item =>
+ item.batchNumber.includes(queryParams.value.batchNumber)
+ );
+ }
+
+ if (queryParams.value.returnDate) {
+ filteredRecords = filteredRecords.filter(item =>
+ item.returnDate === queryParams.value.returnDate
+ );
+ }
+
+ nearExpiryReturnList.value = filteredRecords;
+ total.value = filteredRecords.length;
+ loading.value = false;
+}
+
+// 鍙栨秷鎸夐挳
+function cancel() {
+ open.value = false;
+ reset();
+}
+
+// 琛ㄥ崟閲嶇疆
+function reset() {
+ form.value = {
+ id: null,
+ productName: null,
+ productSpec: null,
+ batchNumber: null,
+ productionDate: null,
+ expiryDate: null,
+ returnQuantity: null,
+ returnReason: null,
+ returnDate: null,
+ status: null,
+ remark: null
+ };
+ proxy.resetForm("formRef");
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+ queryParams.value.pageNum = 1;
+ getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function resetQuery() {
+ proxy.resetForm("queryForm");
+ handleQuery();
+}
+
+// 澶氶�夋閫変腑鏁版嵁
+function handleSelectionChange(selection) {
+ ids.value = selection.map(item => item.id);
+ single.value = selection.length !== 1;
+ multiple.value = !selection.length;
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+function handleAdd() {
+ reset();
+ open.value = true;
+ title.value = "娣诲姞涓存湡閫�鍥炲彴璐�";
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+function handleUpdate(row) {
+ reset();
+ const id = row.id || ids.value;
+
+ // 浣跨敤鍋囨暟鎹幏鍙栬鎯�
+ const mockDetail = nearExpiryReturnList.value.find(item => item.id === (Array.isArray(id) ? id[0] : id));
+ if (mockDetail) {
+ form.value = { ...mockDetail };
+ open.value = true;
+ title.value = "淇敼涓存湡閫�鍥炲彴璐�";
+ }
+}
+
+/** 鎻愪氦鎸夐挳 */
+function submitForm() {
+ proxy.$refs["formRef"].validate(valid => {
+ if (valid) {
+ if (form.value.id != null) {
+ // 妯℃嫙鏇存柊
+ const index = nearExpiryReturnList.value.findIndex(item => item.id === form.value.id);
+ if (index !== -1) {
+ nearExpiryReturnList.value[index] = { ...form.value };
+ }
+ proxy.$modal.msgSuccess("淇敼鎴愬姛");
+ open.value = false;
+ getList();
+ } else {
+ // 妯℃嫙鏂板
+ const newId = Math.max(...nearExpiryReturnList.value.map(item => item.id)) + 1;
+ nearExpiryReturnList.value.push({ ...form.value, id: newId });
+ total.value = nearExpiryReturnList.value.length;
+ proxy.$modal.msgSuccess("鏂板鎴愬姛");
+ open.value = false;
+ getList();
+ }
+ }
+ });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete(row) {
+ const deleteIds = row.id || ids.value;
+ ElMessageBox.confirm('鏄惁纭鍒犻櫎涓存湡閫�鍥炲彴璐︾紪鍙蜂负"' + deleteIds + '"鐨勬暟鎹」锛�', "璀﹀憡", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning"
+ }).then(function() {
+ // 妯℃嫙鍒犻櫎
+ if (Array.isArray(deleteIds)) {
+ deleteIds.forEach(id => {
+ const index = nearExpiryReturnList.value.findIndex(item => item.id === id);
+ if (index !== -1) {
+ nearExpiryReturnList.value.splice(index, 1);
+ }
+ });
+ } else {
+ const index = nearExpiryReturnList.value.findIndex(item => item.id === deleteIds);
+ if (index !== -1) {
+ nearExpiryReturnList.value.splice(index, 1);
+ }
+ }
+ getList();
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ }).catch(() => {});
+}
+
+/** 瀵煎嚭鎸夐挳鎿嶄綔 */
+function handleExport() {
+ proxy.download('quality/nearExpiryReturn/export', {
+ ...queryParams.value
+ }, `涓存湡閫�鍥炲彴璐${new Date().getTime()}.xlsx`);
+}
+
+onMounted(() => {
+ getList();
+});
+</script>
--
Gitblit v1.9.3