From 2307a3125c23ad79ee92306603a418085cee194d Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期四, 05 三月 2026 15:50:02 +0800
Subject: [PATCH] feat: 更新售后管理模块,新增产品选择弹窗和统计卡片

---
 src/views/customerService/feedbackRegistration/index.vue |  640 ++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 462 insertions(+), 178 deletions(-)

diff --git a/src/views/customerService/feedbackRegistration/index.vue b/src/views/customerService/feedbackRegistration/index.vue
index 3d97ef8..db76b1c 100644
--- a/src/views/customerService/feedbackRegistration/index.vue
+++ b/src/views/customerService/feedbackRegistration/index.vue
@@ -1,229 +1,513 @@
 <template>
-	<div class="app-container">
-		<div class="search_form">
-			<div>
-				<span class="search_title">鍙嶉鏃ユ湡锛�</span>
-				<el-date-picker
-					v-model="searchForm.feedbackDate"
-					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
-				>
-			</div>
-			<div>
-				<el-button type="primary" @click="openForm('add')">鏂板</el-button>
-				<el-button @click="handleOut">瀵煎嚭</el-button>
-				<el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
-			</div>
-		</div>
-		<div class="table_list">
-			<PIMTable
-				rowKey="id"
-				:column="tableColumn"
-				:tableData="tableData"
-				:page="page"
-				:isSelection="true"
-				@selection-change="handleSelectionChange"
-				:tableLoading="tableLoading"
-				@pagination="pagination"
-			></PIMTable>
-		</div>
-		<form-dia ref="formDia" @close="handleQuery"></form-dia>
-	</div>
+  <div class="app-container">
+    <div class="workorder-stats">
+      <div
+          v-for="(item, index) in statsList"
+          :key="index"
+          class="stat-card"
+      >
+        <div class="stat-icon" :style="{ backgroundColor: item.bgColor }">
+          <el-icon :color="item.color" :size="20">
+            <component :is="item.icon" />
+          </el-icon>
+        </div>
+        <div class="stat-info">
+          <div class="stat-number">{{ item.count }}</div>
+          <div class="stat-label">{{ item.label }}</div>
+        </div>
+      </div>
+    </div>
+    <div class="search-wrapper">
+      <el-form
+          :model="searchForm"
+          class="demo-form-inline"
+      >
+        <el-row :gutter="20">
+          <el-col :span="4">
+            <el-form-item>
+              <el-input
+                  v-model="searchForm.afterSalesServiceNo"
+                  placeholder="璇疯緭鍏ュ伐鍗曠紪鍙�"
+                  clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="4">
+            <el-form-item>
+              <el-select
+                  v-model="searchForm.status"
+                  placeholder="璇烽�夋嫨宸ュ崟鐘舵��"
+                  clearable
+              >
+                <el-option
+                    v-for="dict in workOrderStatusOptions"
+                    :key="dict.value"
+                    :label="dict.label"
+                    :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="4">
+            <el-form-item>
+              <el-select
+                  v-model="searchForm.urgency"
+                  placeholder="璇烽�夋嫨绱ф�ョ▼搴�"
+                  clearable
+              >
+                <el-option
+                    v-for="dict in degreeOfUrgencyOptions"
+                    :key="dict.value"
+                    :label="dict.label"
+                    :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+           <el-col :span="4">
+            <el-form-item>
+              <el-select
+                  v-model="searchForm.serviceType"
+                  placeholder="璇烽�夋嫨鍞悗绫诲瀷"
+                  clearable
+              >
+                <el-option
+                    v-for="dict in classificationOptions"
+                    :key="dict.value"
+                    :label="dict.label"
+                    :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+            <el-col :span="4">
+              <el-form-item>
+                <el-input
+                    v-model="searchForm.orderNo"
+                    placeholder="璇疯緭鍏ラ攢鍞崟鍙�"
+                    clearable
+                />
+              </el-form-item>
+            </el-col>
+          
+          
+
+          <!-- 鎸夐挳 -->
+          <el-col :span="4">
+            <el-form-item>
+              <el-button type="primary" @click="handleQuery">
+                鎼滅储
+              </el-button>
+              <el-button @click="handleReset">
+                閲嶇疆
+              </el-button>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </div>
+    <div class="table_list">
+      <div class="table_header" style="display: flex; justify-content: space-between; align-items: center;">
+        <div>
+          <el-button type="primary" @click="openForm('add')">鏂板鍞悗鍗�</el-button>
+        </div>
+        <div>
+          <el-button @click="handleOut">瀵煎嚭</el-button>
+          <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+        </div>
+      </div>
+      <PIMTable
+          rowKey="id"
+          :column="tableColumn"
+          :tableData="tableData"
+          :page="page"
+          :height="tableHeight"
+          :isSelection="true"
+          @selection-change="handleSelectionChange"
+          :tableLoading="tableLoading"
+          @pagination="pagination"
+      ></PIMTable>
+    </div>
+    <form-dia ref="formDia" @close="handleQuery"></form-dia>
+  </div>
 </template>
 
 <script setup>
-import {Search} from "@element-plus/icons-vue";
-import {onMounted, ref, getCurrentInstance, nextTick} from "vue";
+import {onMounted, reactive, ref, toRefs, computed, getCurrentInstance, nextTick} from "vue";
 import FormDia from "@/views/customerService/feedbackRegistration/components/formDia.vue";
 import {ElMessageBox} from "element-plus";
-import {afterSalesServiceDelete, afterSalesServiceListPage} from "@/api/customerService/index.js";
+import {afterSalesServiceDelete, afterSalesServiceListPage, getSalesLedgerDetail} from "@/api/customerService/index.js";
 import useUserStore from "@/store/modules/user.js";
 const { proxy } = getCurrentInstance();
 const userStore = useUserStore()
+import { Document, FolderOpened, UserFilled } from "@element-plus/icons-vue"
+import { markRaw } from 'vue'
+
+const statsList = ref([
+  {
+    icon: markRaw(Document),
+    count: 0,
+    label: '鍏ㄩ儴宸ュ崟',
+    color: '#4080ff',
+    bgColor: '#eaf2ff'
+  },
+  {
+    icon: markRaw(FolderOpened),
+    count: 0,
+    label: '宸插鐞�',
+    color: '#ff9a2e',
+    bgColor: '#fff5e6'
+  },
+  {
+    icon: markRaw(UserFilled),
+    count: 0,
+    label: '宸插畬鎴�',
+    color: '#00b42a',
+    bgColor: '#e6f7ed'
+  },
+])
 
 const data = reactive({
-	searchForm: {
-		feedbackDate: "",
-	},
+  searchForm : {
+    customerName: "",
+    status: "",
+    urgency: "",
+    serviceType: "",
+    reviewStatus: "",
+    orderNo: "",
+  }
 });
 const { searchForm } = toRefs(data);
 
 const tableColumn = ref([
-	{
-		label: "澶勭悊鐘舵��",
-		prop: "status",
-		dataType: "tag",
-		formatData: (params) => {
-			if (params == 1) {
-				return "寰呭鐞�";
-			} else if (params == 2) {
-				return "宸插鐞�";
-			} else {
-				return null;
-			}
-		},
-		formatType: (params) => {
-			if (params == 1) {
-				return "danger";
-			} else if (params == 2) {
-				return "success";
-			} else {
-				return null;
-			}
-		},
-	},
-	{
-		label: "鍙嶉鏃ユ湡",
-		prop: "feedbackDate",
-		width: 150,
-	},
-	{
-		label: "鐧昏浜�",
-		prop: "checkNickName",
-	},
-	{
-		label: "瀹㈡埛鍚嶇О",
-		prop: "customerName",
-		width: 200,
-	},
-	{
-		label: "闂鎻忚堪",
-		prop: "proDesc",
-		width:300
-	},
-	{
-		label: "鍏宠仈閮ㄩ棬",
-		prop: "deptName",
-		width: 200,
-	},
-	{
-		dataType: "action",
-		label: "鎿嶄綔",
-		align: "center",
-		fixed: 'right',
-		operation: [
-			{
-				name: "缂栬緫",
-				type: "text",
-				clickFun: (row) => {
-					openForm("edit", row);
-				},
-				disabled: (row) => {
-					return row.status !== 1
-				}
-			},
-		],
-	},
+  {
+    label: "宸ュ崟缂栧彿",
+    prop:"afterSalesServiceNo",
+    width: 150,
+    align: "center"
+  },
+  {
+    label: "閿�鍞崟鍙�",
+    prop:"salesContractNo",
+    width: 150,
+    align: "center"
+  },
+  {
+    label: "澶勭悊鐘舵��",
+    prop: "status",
+    dataType: "tag",
+    
+    formatData: (params) => {
+      if (params === 1) {
+        return "寰呭鐞�";
+      } else if (params === 2) {
+        return "宸插鐞�";
+      } else {
+        return null;
+      }
+    },
+    formatType: (params) => {
+      if (params === 1) {
+        return "danger";
+      } else if (params === 2) {
+        return "success";
+      } else {
+        return null;
+      }
+    },
+    align: "center"
+  },
+  {
+    label: "鍙嶉鏃ユ湡",
+    prop: "feedbackDate",
+    width: 150,
+    align: "center"
+  },
+  {
+    label: "鐧昏浜�",
+    prop: "checkNickName",
+    align: "center"
+  },
+  {
+    label: "绱ф�ョ▼搴�",
+    prop: "urgency",
+    // 鏍规嵁degreeOfUrgencyOptions瀛楀吀鍘昏嚜鍔ㄥ尮閰�
+    formatData: (params) => {
+      if (params) {
+        const item = degreeOfUrgencyOptions.value.find(item => item.value === params);
+        return item?.label || params;
+      }
+      return null;
+    },
+    align: "center"
+  },
+  {
+    label: "鍞悗绫诲瀷",
+    prop: "serviceType",
+    // 鏍规嵁classificationOptions瀛楀吀鍘昏嚜鍔ㄥ尮閰�
+    formatData: (params) => {
+      if (params) {
+        const item = classificationOptions.value.find(item => item.value === params);
+        return item?.label || params;
+      }
+      return null;
+    },
+    align: "center"
+  },
+  {
+    label: "闂鎻忚堪",
+    prop: "disRes",
+    width:300,
+  },
+  {
+    label: "鍏宠仈閮ㄩ棬",
+    prop: "deptName",
+    width: 200,
+    align: "center"
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          console.log(row)
+          openForm("edit", row);
+        },
+        disabled: (row) => {
+          return row.status !== 1
+        }
+      },
+    ],
+    align: "center"
+  },
 ]);
 const tableData = ref([]);
 const tableLoading = ref(false);
 const page = reactive({
-	current: 1,
-	size: 100,
-	total: 0,
+  current: 1,
+  size: 100,
+  total: 0,
 });
 const selectedRows = ref([]);
+const tableHeight = computed(() => "calc(100% -80px)");
 
+const handleReset = () => {
+  Object.keys(searchForm.value).forEach(key => {
+    searchForm.value[key] = ""
+  })
+}
 // 琛ㄦ牸閫夋嫨鏁版嵁
 const handleSelectionChange = (selection) => {
-	selectedRows.value = selection;
+  selectedRows.value = selection;
 };
 const formDia = ref()
+
+// 瀛楀吀鑾峰彇
+/* 
+post_sale_waiting_list 鏂板鐨勫敭鍚庡垎绫�
+degree_of_urgency 鏂板鐨勭揣鎬ョ▼搴�
+work_order_status 涓婚〉鐨勫伐鍗曠姸鎬�
+review_status 棣栭〉鐨勫鏍哥姸鎬�
+*/
+const { post_sale_waiting_list, degree_of_urgency, work_order_status, review_status } = proxy.useDict(
+  "post_sale_waiting_list",
+  "degree_of_urgency",
+  "work_order_status",
+  "review_status"
+);
+
+const classificationOptions = computed(() => post_sale_waiting_list?.value || []);
+const degreeOfUrgencyOptions = computed(() => degree_of_urgency?.value || []);
+const workOrderStatusOptions = computed(() => work_order_status?.value || []);
 
 // 鏌ヨ鍒楄〃
 /** 鎼滅储鎸夐挳鎿嶄綔 */
 const handleQuery = () => {
-	page.current = 1;
-	getList();
+  page.current = 1;
+  getList();
 };
 const pagination = (obj) => {
-	page.current = obj.page;
-	page.size = obj.limit;
-	getList();
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
 };
 const getList = () => {
-	tableLoading.value = true;
-	afterSalesServiceListPage({ ...searchForm.value, ...page }).then((res) => {
-		tableLoading.value = false;
-		tableData.value = res.data.records;
-		page.total = res.data.total;
-	});
+  tableLoading.value = true;
+  getSalesLedgerDetails()
+  afterSalesServiceListPage({ ...searchForm.value, ...page }).then((res) => {
+    tableLoading.value = false;
+    tableData.value = res.data.records;
+    page.total = res.data.total;
+  });
 };
 
 // 鎵撳紑寮规
 const openForm = (type, row) => {
-	nextTick(() => {
-		formDia.value?.openDialog(type, row)
-	})
+  nextTick(() => {
+    formDia.value?.openDialog(type, row)
+  })
 };
 
-const handleDelete = () => {
-	let ids = [];
-	if (selectedRows.value.length > 0) {
-		// 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
-		const unauthorizedData = selectedRows.value.filter(item => item.checkUserId !== userStore.id);
-		if (unauthorizedData.length > 0) {
-			proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
-			return;
-		}
-		ids = selectedRows.value.map((item) => item.id);
-	} else {
-		proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
-		return;
-	}
-	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
-		confirmButtonText: "纭",
-		cancelButtonText: "鍙栨秷",
-		type: "warning",
-	})
-		.then(() => {
-			tableLoading.value = true;
-			afterSalesServiceDelete(ids)
-				.then((res) => {
-					proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-					getList();
-				})
-				.finally(() => {
-					tableLoading.value = false;
-				});
-		})
-		.catch(() => {
-			proxy.$modal.msg("宸插彇娑�");
-		});
+function handleDelete() {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+    const unauthorizedData = selectedRows.value.filter(item => item.checkUserId !== userStore.id);
+    if (unauthorizedData.length > 0) {
+      proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+      return;
+    }
+    ids = selectedRows.value.map((item) => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+      .then(() => {
+        tableLoading.value = true;
+        afterSalesServiceDelete(ids)
+            .then(() => {
+              proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+              getList();
+            })
+            .finally(() => {
+              tableLoading.value = false;
+            });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
 };
 
 // 瀵煎嚭
 const handleOut = () => {
-	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-		confirmButtonText: "纭",
-		cancelButtonText: "鍙栨秷",
-		type: "warning",
-	})
-		.then(() => {
-			proxy.download("/afterSalesService/export", {}, "鍙嶉鐧昏.xlsx");
-		})
-		.catch(() => {
-			proxy.$modal.msg("宸插彇娑�");
-		});
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+      .then(() => {
+        proxy.download("/afterSalesService/export", {}, "鍙嶉鐧昏.xlsx");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
 };
 
+  // 鑾峰彇缁熻鏁版嵁骞跺埛鏂伴《閮ㄥ崱鐗�
+  const getSalesLedgerDetails = () => {
+    getSalesLedgerDetail({}).then((res) => {
+      if (res.code === 200) {
+        statsList.value[0].count = res.data.filter((item) => item.status === 3)[0].count;
+        statsList.value[1].count = res.data.filter((item) => item.status === 2)[0].count;
+        statsList.value[2].count = res.data.filter((item) => item.status === 1)[0].count;
+
+        // });
+      }
+    });
+  }
+
+
+
 onMounted(() => {
-	getList();
+  getList();
+  
 });
 </script>
 
-<style scoped>
+<style scoped lang="scss">
+.search-wrapper {
+  background: white;
+  padding: 1rem 1rem 0 1rem;
+  border: 8px;
+  border-radius: 16px;
+}
 
-</style>
\ No newline at end of file
+.expand-btn {
+  width: 100%;
+  padding: 20px; /* 涓婁笅宸﹀彸鍚�20px锛岀偣鍑昏繖涓寖鍥撮兘鑳借Е鍙戜簨浠� */
+  cursor: pointer; /* 榧犳爣鎮诞鏄剧ず鎵嬪瀷锛屾彁鍗囦綋楠� */
+  text-align: center;
+}
+
+.workorder-stats {
+  display: flex;
+  gap: 16px;
+  padding-bottom:1rem;
+  border-radius: 8px;
+}
+
+.stat-card {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  padding: 20px;
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
+}
+
+.stat-icon {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 48px;
+  height: 48px;
+  border-radius: 8px;
+}
+
+.stat-info {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+}
+
+.stat-number {
+  font-size: 24px;
+  font-weight: 600;
+  color: #303133;
+  line-height: 1;
+}
+
+.stat-label {
+  font-size: 14px;
+  color: #909399;
+  line-height: 1;
+}
+.table_header{
+  padding-bottom: 10px;
+}
+
+.table_list {
+  height: calc(100vh - 380px);
+  min-height: 360px;
+  background: #fff;
+  margin-top: 20px;
+  display: flex;
+  flex-direction: column;
+}
+
+:deep(.table_list .pagination-container) {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  margin-top: auto;
+  padding: 12px 0 0;
+}
+
+:deep(.table_list .el-pagination) {
+  flex-wrap: nowrap;
+  justify-content: flex-end;
+  width: 100%;
+}
+</style>

--
Gitblit v1.9.3