From 1678465c039ce6255105c1fcdb3ace56860f44f9 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期一, 08 六月 2026 17:29:25 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro

---
 src/views/customerService/feedbackRegistration/index.vue |  704 ++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 510 insertions(+), 194 deletions(-)

diff --git a/src/views/customerService/feedbackRegistration/index.vue b/src/views/customerService/feedbackRegistration/index.vue
index 09ecf9e..1e57bdb 100644
--- a/src/views/customerService/feedbackRegistration/index.vue
+++ b/src/views/customerService/feedbackRegistration/index.vue
@@ -1,207 +1,523 @@
 <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"
-				/>
-				<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 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} 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 useUserStore from "@/store/modules/user.js";
-const { proxy } = getCurrentInstance();
-const userStore = useUserStore()
+  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,
+    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 data = reactive({
-	searchForm: {
-		feedbackDate: "",
-	},
-});
-const { searchForm } = toRefs(data);
+  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 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.checkUserId !== userStore.id || row.status !== 1
-				}
-			},
-		],
-	},
-]);
-const tableData = ref([]);
-const tableLoading = ref(false);
-const page = reactive({
-	current: 1,
-	size: 100,
-	total: 0,
-});
-const selectedRows = ref([]);
+  const data = reactive({
+    searchForm: {
+      customerName: "",
+      status: "",
+      urgency: "",
+      serviceType: "",
+      reviewStatus: "",
+      orderNo: "",
+    },
+  });
+  const { searchForm } = toRefs(data);
 
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
-	selectedRows.value = selection;
-};
-const formDia = ref()
+  const tableColumn = ref([
+    {
+      label: "宸ュ崟缂栧彿",
+      prop: "afterSalesServiceNo",
+      width: 150,
+      align: "center",
+    },
+    {
+      label: "閿�鍞崟鍙�",
+      prop: "salesContractNo",
+      width: 150,
+      align: "center",
+    },
+    {
+      label: "澶勭悊鐘舵��",
+      prop: "status",
+      dataType: "tag",
 
-// 鏌ヨ鍒楄〃
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
-	page.current = 1;
-	getList();
-};
-const pagination = (obj) => {
-	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;
-	});
-};
+      formatData: params => {
+        if (params) {
+          let part = String(params);
+          const item = workOrderStatusOptions.value.find(
+            item => item.value === part
+          );
+          return item?.label || params;
+        }
+        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: "proDesc",
+      width: 300,
+    },
+    {
+      label: "鍏宠仈閮ㄩ棬",
+      prop: "deptName",
+      width: 200,
+      align: "center",
+    },
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      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,
+  });
+  const selectedRows = ref([]);
+  const tableHeight = computed(() => "calc(100% -80px)");
 
-// 鎵撳紑寮规
-const openForm = (type, row) => {
-	nextTick(() => {
-		formDia.value?.openDialog(type, row)
-	})
-};
+  const handleReset = () => {
+    Object.keys(searchForm.value).forEach(key => {
+      searchForm.value[key] = "";
+    });
+    page.current = 1;
+    getList();
+  };
+  // 琛ㄦ牸閫夋嫨鏁版嵁
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+  const formDia = ref();
 
-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("宸插彇娑�");
-		});
-};
-onMounted(() => {
-	getList();
-});
+  // 瀛楀吀鑾峰彇
+  /*
+  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();
+  };
+  const pagination = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+  const getList = () => {
+    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);
+    });
+  };
+
+  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("宸插彇娑�");
+      });
+  };
+
+  const getStatsCountByStatus = (list, status) => {
+    if (!Array.isArray(list)) return 0;
+    return list.find(item => item?.status === status)?.count || 0;
+  };
+
+  // 鑾峰彇缁熻鏁版嵁骞跺埛鏂伴《閮ㄥ崱鐗�
+  const getSalesLedgerDetails = () => {
+    getSalesLedgerDetail({}).then(res => {
+      if (res.code === 200) {
+        const statsData = Array.isArray(res.data) ? res.data : [];
+        statsList.value[0].count = getStatsCountByStatus(statsData, 3);
+        statsList.value[1].count = getStatsCountByStatus(statsData, 2);
+        statsList.value[2].count = getStatsCountByStatus(statsData, 1);
+      }
+    });
+  };
+
+  onMounted(() => {
+    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);
+    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