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/components/formDia.vue             |  452 +++++++++++--
 src/views/customerService/feedbackRegistration/index.vue                          |  640 ++++++++++++++-----
 src/api/customerService/index.js                                                  |   32 
 src/views/customerService/afterSalesHandling/index.vue                            |  293 ++++++--
 src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue |  245 +++++++
 pnpm-lock.yaml                                                                    |  274 ++++++++
 6 files changed, 1,582 insertions(+), 354 deletions(-)

diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 871e5c2..2b3e76c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,12 +11,21 @@
       '@element-plus/icons-vue':
         specifier: 2.3.1
         version: 2.3.1(vue@3.4.31)
+      '@vue-office/docx':
+        specifier: ^1.6.3
+        version: 1.6.3(vue-demi@0.14.10(vue@3.4.31))(vue@3.4.31)
+      '@vue-office/excel':
+        specifier: ^1.7.14
+        version: 1.7.14(vue-demi@0.14.10(vue@3.4.31))(vue@3.4.31)
       '@vueup/vue-quill':
         specifier: 1.2.0
         version: 1.2.0(vue@3.4.31)
       '@vueuse/core':
         specifier: 10.11.0
         version: 10.11.0(vue@3.4.31)
+      autofit.js:
+        specifier: ^3.2.8
+        version: 3.2.8
       axios:
         specifier: 0.28.1
         version: 0.28.1
@@ -53,6 +62,12 @@
       pinia:
         specifier: 2.1.7
         version: 2.1.7(vue@3.4.31)
+      print-js:
+        specifier: ^1.6.0
+        version: 1.6.0
+      qrcode:
+        specifier: ^1.5.4
+        version: 1.5.4
       sortablejs:
         specifier: ^1.15.6
         version: 1.15.6
@@ -65,6 +80,12 @@
       vue-cropper:
         specifier: 1.1.1
         version: 1.1.1
+      vue-easy-lightbox:
+        specifier: ^1.19.0
+        version: 1.19.0(vue@3.4.31)
+      vue-esign:
+        specifier: ^1.1.4
+        version: 1.1.4
       vue-router:
         specifier: 4.4.0
         version: 4.4.0(vue@3.4.31)
@@ -341,56 +362,67 @@
     resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==}
     cpu: [arm]
     os: [linux]
+    libc: [glibc]
 
   '@rollup/rollup-linux-arm-musleabihf@4.40.2':
     resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==}
     cpu: [arm]
     os: [linux]
+    libc: [musl]
 
   '@rollup/rollup-linux-arm64-gnu@4.40.2':
     resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   '@rollup/rollup-linux-arm64-musl@4.40.2':
     resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   '@rollup/rollup-linux-loongarch64-gnu@4.40.2':
     resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==}
     cpu: [loong64]
     os: [linux]
+    libc: [glibc]
 
   '@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
     resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==}
     cpu: [ppc64]
     os: [linux]
+    libc: [glibc]
 
   '@rollup/rollup-linux-riscv64-gnu@4.40.2':
     resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==}
     cpu: [riscv64]
     os: [linux]
+    libc: [glibc]
 
   '@rollup/rollup-linux-riscv64-musl@4.40.2':
     resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==}
     cpu: [riscv64]
     os: [linux]
+    libc: [musl]
 
   '@rollup/rollup-linux-s390x-gnu@4.40.2':
     resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==}
     cpu: [s390x]
     os: [linux]
+    libc: [glibc]
 
   '@rollup/rollup-linux-x64-gnu@4.40.2':
     resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   '@rollup/rollup-linux-x64-musl@4.40.2':
     resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   '@rollup/rollup-win32-arm64-msvc@4.40.2':
     resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==}
@@ -442,6 +474,26 @@
       vite: ^5.0.0
       vue: ^3.2.25
 
+  '@vue-office/docx@1.6.3':
+    resolution: {integrity: sha512-Cs+3CAaRBOWOiW4XAhTwwxJ0dy8cPIf6DqfNvYcD3YACiLwO4kuawLF2IAXxyijhbuOeoFsfvoVbOc16A/4bZA==}
+    peerDependencies:
+      '@vue/composition-api': ^1.7.1
+      vue: ^2.0.0 || >=3.0.0
+      vue-demi: ^0.14.6
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
+  '@vue-office/excel@1.7.14':
+    resolution: {integrity: sha512-pVUgt+emDQUnW7q22CfnQ+jl43mM/7IFwYzOg7lwOwPEbiVB4K4qEQf+y/bc4xGXz75w1/e3Kz3G6wAafmFBFg==}
+    peerDependencies:
+      '@vue/composition-api': ^1.7.1
+      vue: ^2.0.0 || >=3.0.0
+      vue-demi: ^0.14.6
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
   '@vue/compiler-core@3.4.31':
     resolution: {integrity: sha512-skOiodXWTV3DxfDhB4rOf3OGalpITLlgCeOwb+Y9GJpfQ8ErigdBUHomBzvG78JoVE8MJoQsb+qhZiHfKeNeEg==}
 
@@ -453,6 +505,9 @@
 
   '@vue/compiler-dom@3.5.14':
     resolution: {integrity: sha512-1aOCSqxGOea5I80U2hQJvXYpPm/aXo95xL/m/mMhgyPUsKe9jhjwWpziNAw7tYRnbz1I61rd9Mld4W9KmmRoug==}
+
+  '@vue/compiler-sfc@2.7.16':
+    resolution: {integrity: sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==}
 
   '@vue/compiler-sfc@3.4.31':
     resolution: {integrity: sha512-einJxqEw8IIJxzmnxmJBuK2usI+lJonl53foq+9etB2HAzlPjAS/wa7r0uUpXw5ByX3/0uswVSrjNb17vJm1kQ==}
@@ -592,6 +647,9 @@
     engines: {node: '>= 4.5.0'}
     hasBin: true
 
+  autofit.js@3.2.8:
+    resolution: {integrity: sha512-albZNwDIXvcRneEDyZLW3uAIOH0cUQG/TnCGQ7jpfnL0gPn/+1ZNVRuEz3ZuzZvVkQ4HQRplGHjUeMRtPNxjLQ==}
+
   available-typed-arrays@1.0.7:
     resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
     engines: {node: '>= 0.4'}
@@ -646,6 +704,10 @@
     resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
     engines: {node: '>= 0.4'}
 
+  camelcase@5.3.1:
+    resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+    engines: {node: '>=6'}
+
   chalk@1.1.3:
     resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
     engines: {node: '>=0.10.0'}
@@ -664,6 +726,9 @@
 
   clipboard@2.0.11:
     resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==}
+
+  cliui@6.0.0:
+    resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
 
   clone@2.1.2:
     resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
@@ -766,6 +831,10 @@
       supports-color:
         optional: true
 
+  decamelize@1.2.0:
+    resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
+    engines: {node: '>=0.10.0'}
+
   decode-uri-component@0.2.2:
     resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
     engines: {node: '>=0.10'}
@@ -800,6 +869,9 @@
 
   delegate@3.2.0:
     resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
+
+  dijkstrajs@1.0.3:
+    resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
 
   dom-serializer@0.2.2:
     resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
@@ -965,6 +1037,10 @@
     resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
     engines: {node: '>=8'}
 
+  find-up@4.1.0:
+    resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+    engines: {node: '>=8'}
+
   follow-redirects@1.15.9:
     resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
     engines: {node: '>=4.0'}
@@ -1016,6 +1092,10 @@
   fuse.js@6.6.2:
     resolution: {integrity: sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==}
     engines: {node: '>=10'}
+
+  get-caller-file@2.0.5:
+    resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+    engines: {node: 6.* || 8.* || >= 10.*}
 
   get-intrinsic@1.3.0:
     resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
@@ -1351,6 +1431,10 @@
     resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==}
     engines: {node: '>=14'}
 
+  locate-path@5.0.0:
+    resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+    engines: {node: '>=8'}
+
   lodash-es@4.17.21:
     resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
 
@@ -1514,6 +1598,18 @@
     resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
     engines: {node: '>= 0.4'}
 
+  p-limit@2.3.0:
+    resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+    engines: {node: '>=6'}
+
+  p-locate@4.1.0:
+    resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+    engines: {node: '>=8'}
+
+  p-try@2.2.0:
+    resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+    engines: {node: '>=6'}
+
   package-json-from-dist@1.0.1:
     resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
 
@@ -1523,6 +1619,10 @@
   pascalcase@0.1.1:
     resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
     engines: {node: '>=0.10.0'}
+
+  path-exists@4.0.0:
+    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+    engines: {node: '>=8'}
 
   path-key@3.1.1:
     resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
@@ -1567,6 +1667,10 @@
   pkg-types@2.1.0:
     resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==}
 
+  pngjs@5.0.0:
+    resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
+    engines: {node: '>=10.13.0'}
+
   posix-character-classes@0.1.1:
     resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==}
     engines: {node: '>=0.10.0'}
@@ -1605,11 +1709,24 @@
     resolution: {integrity: sha512-spBB5sgC4cv2YcW03f/IAUN1pgDJWNWD8FzkyY4mArLUMJW+KlQhlmUdKAHQuPfb00Jl5xIfImeOsf6YL8QK7Q==}
     engines: {node: '>=0.10.0'}
 
+  prettier@2.8.8:
+    resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+
+  print-js@1.6.0:
+    resolution: {integrity: sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==}
+
   proto-list@1.2.4:
     resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
 
   proxy-from-env@1.1.0:
     resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+  qrcode@1.5.4:
+    resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
 
   quansync@0.2.10:
     resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
@@ -1658,6 +1775,13 @@
   repeat-string@1.6.1:
     resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
     engines: {node: '>=0.10'}
+
+  require-directory@2.1.1:
+    resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+    engines: {node: '>=0.10.0'}
+
+  require-main-filename@2.0.0:
+    resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
 
   resolve-url@0.2.1:
     resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==}
@@ -1712,6 +1836,9 @@
     resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
     engines: {node: '>=10'}
     hasBin: true
+
+  set-blocking@2.0.0:
+    resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
 
   set-function-length@1.2.2:
     resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
@@ -2033,10 +2160,23 @@
       '@vue/composition-api':
         optional: true
 
+  vue-easy-lightbox@1.19.0:
+    resolution: {integrity: sha512-YxLXgjEn91UF3DuK1y8u3Pyx2sJ7a/MnBpkyrBSQkvU1glzEJASyAZ7N+5yDpmxBQDVMwCsL2VmxWGIiFrWCgA==}
+    engines: {node: '>=14.18.3'}
+    peerDependencies:
+      vue: ^3.0.0
+
+  vue-esign@1.1.4:
+    resolution: {integrity: sha512-7Ix5PdcyyhVfsvrT9a+yp5+36gbQ0/bpDO+QSLT58IgJ5t164PEptOy5Nslw8bZbk3n3Hc7SP5B8eXQ8X8W+OA==}
+
   vue-router@4.4.0:
     resolution: {integrity: sha512-HB+t2p611aIZraV2aPSRNXf0Z/oLZFrlygJm+sZbdJaW6lcFqEDQwnzUBXn+DApw+/QzDU/I9TeWx9izEjTmsA==}
     peerDependencies:
       vue: ^3.2.0
+
+  vue@2.7.16:
+    resolution: {integrity: sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==}
+    deprecated: Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.
 
   vue@3.4.31:
     resolution: {integrity: sha512-njqRrOy7W3YLAlVqSKpBebtZpDVg21FPoaq1I7f/+qqBThK9ChAIjkRWgeP6Eat+8C+iia4P3OYqpATP21BCoQ==}
@@ -2066,6 +2206,9 @@
     resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
     engines: {node: '>= 0.4'}
 
+  which-module@2.0.1:
+    resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
+
   which-typed-array@1.1.19:
     resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
     engines: {node: '>= 0.4'}
@@ -2075,6 +2218,10 @@
     engines: {node: '>= 8'}
     hasBin: true
 
+  wrap-ansi@6.2.0:
+    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+    engines: {node: '>=8'}
+
   wrap-ansi@7.0.0:
     resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
     engines: {node: '>=10'}
@@ -2082,6 +2229,17 @@
   wrap-ansi@8.1.0:
     resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
     engines: {node: '>=12'}
+
+  y18n@4.0.3:
+    resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
+
+  yargs-parser@18.1.3:
+    resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
+    engines: {node: '>=6'}
+
+  yargs@15.4.1:
+    resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
+    engines: {node: '>=8'}
 
   zrender@5.6.0:
     resolution: {integrity: sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==}
@@ -2314,6 +2472,16 @@
       vite: 5.3.2(@types/node@22.15.18)(sass@1.77.5)
       vue: 3.4.31
 
+  '@vue-office/docx@1.6.3(vue-demi@0.14.10(vue@3.4.31))(vue@3.4.31)':
+    dependencies:
+      vue: 3.4.31
+      vue-demi: 0.14.10(vue@3.4.31)
+
+  '@vue-office/excel@1.7.14(vue-demi@0.14.10(vue@3.4.31))(vue@3.4.31)':
+    dependencies:
+      vue: 3.4.31
+      vue-demi: 0.14.10(vue@3.4.31)
+
   '@vue/compiler-core@3.4.31':
     dependencies:
       '@babel/parser': 7.27.2
@@ -2339,6 +2507,14 @@
     dependencies:
       '@vue/compiler-core': 3.5.14
       '@vue/shared': 3.5.14
+
+  '@vue/compiler-sfc@2.7.16':
+    dependencies:
+      '@babel/parser': 7.27.2
+      postcss: 8.5.3
+      source-map: 0.6.1
+    optionalDependencies:
+      prettier: 2.8.8
 
   '@vue/compiler-sfc@3.4.31':
     dependencies:
@@ -2502,6 +2678,8 @@
 
   atob@2.1.2: {}
 
+  autofit.js@3.2.8: {}
+
   available-typed-arrays@1.0.7:
     dependencies:
       possible-typed-array-names: 1.1.0
@@ -2586,6 +2764,8 @@
       call-bind-apply-helpers: 1.0.2
       get-intrinsic: 1.3.0
 
+  camelcase@5.3.1: {}
+
   chalk@1.1.3:
     dependencies:
       ansi-styles: 2.2.1
@@ -2623,6 +2803,12 @@
       good-listener: 1.2.2
       select: 1.1.2
       tiny-emitter: 2.1.0
+
+  cliui@6.0.0:
+    dependencies:
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+      wrap-ansi: 6.2.0
 
   clone@2.1.2: {}
 
@@ -2718,6 +2904,8 @@
     dependencies:
       ms: 2.1.3
 
+  decamelize@1.2.0: {}
+
   decode-uri-component@0.2.2: {}
 
   deep-equal@1.1.2:
@@ -2757,6 +2945,8 @@
   delayed-stream@1.0.0: {}
 
   delegate@3.2.0: {}
+
+  dijkstrajs@1.0.3: {}
 
   dom-serializer@0.2.2:
     dependencies:
@@ -3029,6 +3219,11 @@
     dependencies:
       to-regex-range: 5.0.1
 
+  find-up@4.1.0:
+    dependencies:
+      locate-path: 5.0.0
+      path-exists: 4.0.0
+
   follow-redirects@1.15.9: {}
 
   for-each@0.3.5:
@@ -3076,6 +3271,8 @@
   functions-have-names@1.2.3: {}
 
   fuse.js@6.6.2: {}
+
+  get-caller-file@2.0.5: {}
 
   get-intrinsic@1.3.0:
     dependencies:
@@ -3423,6 +3620,10 @@
       pkg-types: 2.1.0
       quansync: 0.2.10
 
+  locate-path@5.0.0:
+    dependencies:
+      p-locate: 4.1.0
+
   lodash-es@4.17.21: {}
 
   lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21):
@@ -3594,11 +3795,23 @@
       object-keys: 1.1.1
       safe-push-apply: 1.0.0
 
+  p-limit@2.3.0:
+    dependencies:
+      p-try: 2.2.0
+
+  p-locate@4.1.0:
+    dependencies:
+      p-limit: 2.3.0
+
+  p-try@2.2.0: {}
+
   package-json-from-dist@1.0.1: {}
 
   parchment@1.1.4: {}
 
   pascalcase@0.1.1: {}
+
+  path-exists@4.0.0: {}
 
   path-key@3.1.1: {}
 
@@ -3634,6 +3847,8 @@
       confbox: 0.2.2
       exsolve: 1.0.5
       pathe: 2.0.3
+
+  pngjs@5.0.0: {}
 
   posix-character-classes@0.1.1: {}
 
@@ -3679,9 +3894,20 @@
       posthtml-parser: 0.2.1
       posthtml-render: 1.4.0
 
+  prettier@2.8.8:
+    optional: true
+
+  print-js@1.6.0: {}
+
   proto-list@1.2.4: {}
 
   proxy-from-env@1.1.0: {}
+
+  qrcode@1.5.4:
+    dependencies:
+      dijkstrajs: 1.0.3
+      pngjs: 5.0.0
+      yargs: 15.4.1
 
   quansync@0.2.10: {}
 
@@ -3751,6 +3977,10 @@
   repeat-element@1.1.4: {}
 
   repeat-string@1.6.1: {}
+
+  require-directory@2.1.1: {}
+
+  require-main-filename@2.0.0: {}
 
   resolve-url@0.2.1: {}
 
@@ -3824,6 +4054,8 @@
   select@1.1.2: {}
 
   semver@7.7.2: {}
+
+  set-blocking@2.0.0: {}
 
   set-function-length@1.2.2:
     dependencies:
@@ -4234,10 +4466,23 @@
     dependencies:
       vue: 3.4.31
 
+  vue-easy-lightbox@1.19.0(vue@3.4.31):
+    dependencies:
+      vue: 3.4.31
+
+  vue-esign@1.1.4:
+    dependencies:
+      vue: 2.7.16
+
   vue-router@4.4.0(vue@3.4.31):
     dependencies:
       '@vue/devtools-api': 6.6.4
       vue: 3.4.31
+
+  vue@2.7.16:
+    dependencies:
+      '@vue/compiler-sfc': 2.7.16
+      csstype: 3.1.3
 
   vue@3.4.31:
     dependencies:
@@ -4285,6 +4530,8 @@
       is-weakmap: 2.0.2
       is-weakset: 2.0.4
 
+  which-module@2.0.1: {}
+
   which-typed-array@1.1.19:
     dependencies:
       available-typed-arrays: 1.0.7
@@ -4299,6 +4546,12 @@
     dependencies:
       isexe: 2.0.0
 
+  wrap-ansi@6.2.0:
+    dependencies:
+      ansi-styles: 4.3.0
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+
   wrap-ansi@7.0.0:
     dependencies:
       ansi-styles: 4.3.0
@@ -4311,6 +4564,27 @@
       string-width: 5.1.2
       strip-ansi: 7.1.0
 
+  y18n@4.0.3: {}
+
+  yargs-parser@18.1.3:
+    dependencies:
+      camelcase: 5.3.1
+      decamelize: 1.2.0
+
+  yargs@15.4.1:
+    dependencies:
+      cliui: 6.0.0
+      decamelize: 1.2.0
+      find-up: 4.1.0
+      get-caller-file: 2.0.5
+      require-directory: 2.1.1
+      require-main-filename: 2.0.0
+      set-blocking: 2.0.0
+      string-width: 4.2.3
+      which-module: 2.0.1
+      y18n: 4.0.3
+      yargs-parser: 18.1.3
+
   zrender@5.6.0:
     dependencies:
       tslib: 2.3.0
diff --git a/src/api/customerService/index.js b/src/api/customerService/index.js
index 560ffe6..571601a 100644
--- a/src/api/customerService/index.js
+++ b/src/api/customerService/index.js
@@ -99,4 +99,34 @@
     url: '/afterSalesNearExpiryService/delete?ids=' + ids,
     method: 'delete',
   })
-}
\ No newline at end of file
+}
+
+// 鏌ヨ鎵�鏈夊鎴蜂俊鎭�
+// /basic/customer/list
+export function getAllCustomerList(query) {
+    return request({
+        url: '/basic/customer/list',
+        method: 'get',
+        params: query,
+    })
+}
+
+// 鏍规嵁瀹㈡埛鏌ヨ閿�鍞鍗曞彿
+// afterSalesService/listSalesLedger
+export function getSalesLedger(query) {
+    return request({
+        url: '/afterSalesService/listSalesLedger',
+        method: 'get',
+        params: query,
+    })
+}
+
+// 鏍规嵁閿�鍞鍗曞彿鏌ヨ閿�鍞鍗曡鎯�
+// afterSalesService/count
+export function getSalesLedgerDetail(query) {
+    return request({
+        url: '/afterSalesService/count',
+        method: 'get',
+        params: query,
+    })
+}
diff --git a/src/views/customerService/afterSalesHandling/index.vue b/src/views/customerService/afterSalesHandling/index.vue
index dd07ddb..d95e327 100644
--- a/src/views/customerService/afterSalesHandling/index.vue
+++ b/src/views/customerService/afterSalesHandling/index.vue
@@ -1,38 +1,94 @@
 <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 class="search_title ml10">澶勭悊鏃ユ湡锛�</span>
-				<el-date-picker
-					v-model="searchForm.disDate"
-					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="handleOut" style="margin-left: 10px">瀵煎嚭</el-button>
-			</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">
 			<PIMTable
 				rowKey="id"
@@ -81,69 +137,107 @@
 	},
 });
 const { searchForm } = toRefs(data);
+/* 
+post_sale_waiting_list 鏂板鐨勫敭鍚庡垎绫�
+degree_of_urgency 鏂板鐨勭揣鎬ョ▼搴�
+work_order_status 涓婚〉鐨勫伐鍗曠姸鎬�
+*/
+const { post_sale_waiting_list, degree_of_urgency, work_order_status } = proxy.useDict(
+  "post_sale_waiting_list",
+  "degree_of_urgency",
+  "work_order_status",
+);
+
+const classificationOptions = computed(() => post_sale_waiting_list?.value || []);
+const degreeOfUrgencyOptions = computed(() => degree_of_urgency?.value || []);
+const workOrderStatusOptions = computed(() => work_order_status?.value || []);
 
 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,
-	},
-	{
-		label: "澶勭悊浜�",
-		prop: "disposeNickName",
-	},
-	{
-		label: "澶勭悊缁撴灉",
-		prop: "disRes",
-		width: 200,
-	},
-	{
-		label: "澶勭悊鏃ユ湡",
-		prop: "disDate",
-		width: 150,
-	},
+    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: "鎿嶄綔",
@@ -197,6 +291,12 @@
 const fileListDialogVisible = ref(false)
 const currentFileRow = ref(null)
 
+// 閲嶇疆
+const handleReset = () => {
+  Object.keys(searchForm.value).forEach(key => {
+    searchForm.value[key] = ""
+  })
+}
 
 // 鎵撳紑闄勪欢寮规
 const openFilesFormDia = async (row) => {
@@ -386,5 +486,10 @@
 </script>
 
 <style scoped>
-
+.search-wrapper {
+  background: white;
+  padding: 1rem 1rem 0 1rem;
+  border: 8px;
+  border-radius: 16px;
+}
 </style>
\ No newline at end of file
diff --git a/src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue b/src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue
new file mode 100644
index 0000000..4df22bc
--- /dev/null
+++ b/src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue
@@ -0,0 +1,245 @@
+<template>
+  <el-dialog v-model="visible" title="閫夋嫨浜у搧" width="900px" destroy-on-close :close-on-click-modal="false">
+    <el-form :inline="true" :model="query" class="mb-2">
+      <el-form-item label="浜у搧鍒嗙被">
+        <el-input v-model="query.productCategory" placeholder="杈撳叆浜у搧鍒嗙被" clearable @keyup.enter="onSearch" />
+      </el-form-item>
+
+      <el-form-item label="鍩烘湰鍗曚綅">
+        <el-input v-model="query.unit" placeholder="杈撳叆鍩烘湰鍗曚綅" clearable @keyup.enter="onSearch" />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" @click="onSearch">鎼滅储</el-button>
+        <el-button @click="columnsDialogVisible = true">鍒楄〃瀛楁</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 鍒楄〃 -->
+    <el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row row-key="id"
+      @selection-change="handleSelectionChange" @select="handleSelect">
+      <el-table-column type="selection" width="55" />
+      <el-table-column type="index" label="搴忓彿" width="60" />
+      <template v-for="column in visibleColumns" :key="column.prop">
+        <el-table-column :prop="column.prop" :label="column.label" :min-width="column.minWidth" show-overflow-tooltip align="center" />
+      </template>
+    </el-table>
+
+    <div class="mt-3" style="margin-top: 10px;display: flex; justify-content: flex-end;">
+
+
+      <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total"
+        v-model:page-size="page.pageSize" v-model:current-page="page.pageNum" :page-sizes="[10, 20, 50, 100]"
+        @size-change="onPageChange" @current-change="onPageChange" />
+    </div>
+
+    <template #footer>
+      <el-button type="primary" :disabled="multipleSelection.length === 0" @click="onConfirm">
+        纭畾
+      </el-button>
+      <el-button @click="close()">鍙栨秷</el-button>
+    </template>
+  </el-dialog>
+
+  <el-dialog v-model="columnsDialogVisible" title="鑷畾涔夋樉绀哄垪椤�" width="600px">
+    <el-checkbox-group v-model="selectedColumns">
+      <el-checkbox v-for="column in allColumns" :key="column.prop" :label="column.prop" :disabled="column.disabled">
+        {{ column.label }}
+      </el-checkbox>
+    </el-checkbox-group>
+    <template #footer>
+      <el-button @click="resetColumns">鎭㈠榛樿</el-button>
+      <el-button type="primary" @click="saveColumns">淇濆瓨</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { computed, onMounted, reactive, ref, watch, nextTick } from "vue";
+import { ElMessage } from "element-plus";
+
+const props = defineProps({
+  modelValue: Boolean,
+  single: Boolean, // 鏄惁鍙兘閫夋嫨涓�涓紝榛樿false锛堝彲閫夋嫨澶氫釜锛�
+  products: {
+    type: Array,
+    default: () => []
+  },
+  selectedIds: {
+    type: Array,
+    default: () => []
+  }
+});
+
+const emit = defineEmits(['update:modelValue', 'confirm']);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (v) => emit("update:modelValue", v),
+});
+
+const query = reactive({
+  productName: "",
+  model: "",
+});
+
+const page = reactive({
+  pageNum: 1,
+  pageSize: 10,
+});
+
+const loading = ref(false);
+const tableData = ref([]);
+const total = ref(0);
+const multipleSelection = ref([]);
+const tableRef = ref();
+
+const columnsDialogVisible = ref(false);
+
+const allColumns = ref([
+    { prop: 'productCategory', label: '浜у搧鍒嗙被', selected: true, disabled: false },
+    { prop: 'unit', label: '鍩烘湰鍗曚綅', selected: true, disabled: false },
+]);
+
+const selectedColumns = ref(allColumns.value.filter(c => c.selected).map(c => c.prop));
+
+const visibleColumns = computed(() => {
+  return allColumns.value.filter(c => selectedColumns.value.includes(c.prop));
+});
+
+const resetColumns = () => {
+  selectedColumns.value = allColumns.value.filter(c => c.selected).map(c => c.prop);
+};
+
+const saveColumns = () => {
+  if (selectedColumns.value.length < 1) {
+    ElMessage.warning("鍒楄〃椤规樉绀轰笉寰楀皯浜�1椤�");
+    return;
+  }
+  columnsDialogVisible.value = false;
+};
+
+function close() {
+  visible.value = false;
+}
+
+const handleSelectionChange = (val) => {
+  if (props.single && val.length > 1) {
+    // 濡傛灉闄愬埗涓哄崟涓�夋嫨锛屽彧淇濈暀鏈�鍚庝竴涓�変腑鐨�
+    const lastSelected = val[val.length - 1];
+    multipleSelection.value = [lastSelected];
+    // 娓呯┖琛ㄦ牸閫変腑鐘舵�侊紝鐒跺悗閲嶆柊閫変腑鏈�鍚庝竴涓�
+    nextTick(() => {
+      if (tableRef.value) {
+        tableRef.value.clearSelection();
+        tableRef.value.toggleRowSelection(lastSelected, true);
+      }
+    });
+  } else {
+    multipleSelection.value = val;
+  }
+}
+
+// 澶勭悊鍗曚釜閫夋嫨
+const handleSelect = (selection, row) => {
+  if (props.single) {
+    // 濡傛灉闄愬埗涓哄崟涓紝娓呯┖鍏朵粬閫夋嫨锛屽彧淇濈暀褰撳墠琛�
+    if (selection.includes(row)) {
+      // 閫変腑褰撳墠琛屾椂锛屾竻绌哄叾浠栭�変腑
+      multipleSelection.value = [row];
+      nextTick(() => {
+        if (tableRef.value) {
+          tableData.value.forEach((item) => {
+            if (item.id !== row.id) {
+              tableRef.value.toggleRowSelection(item, false);
+            }
+          });
+        }
+      });
+    }
+  }
+}
+
+function onSearch() {
+  page.pageNum = 1;
+  loadData();
+}
+
+function onReset() {
+  query.productName = "";
+  query.model = "";
+  page.pageNum = 1;
+  loadData();
+}
+
+function onPageChange() {
+  loadData();
+}
+
+function onConfirm() {
+  if (multipleSelection.value.length === 0) {
+    ElMessage.warning("璇烽�夋嫨涓�鏉′骇鍝�");
+    return;
+  }
+  if (props.single && multipleSelection.value.length > 1) {
+    ElMessage.warning("鍙兘閫夋嫨涓�涓骇鍝�");
+    return;
+  }
+  emit("confirm", props.single ? [multipleSelection.value[0]] : multipleSelection.value);
+  close();
+}
+
+async function loadData() {
+  loading.value = true;
+  try {
+    multipleSelection.value = []; // 缈婚〉/鎼滅储鍚庢竻绌洪�夋嫨鏇寸鍚堥鏈�
+
+    let filtered = props.products || [];
+    // 鏈湴鎼滅储杩囨护
+    if (query.productName) {
+      filtered = filtered.filter(item => item.productName && item.productName.includes(query.productName));
+    }
+    if (query.model) {
+      filtered = filtered.filter(item => item.model && item.model.includes(query.model));
+    }
+
+    total.value = filtered.length;
+    // 鍓嶇鍒嗛〉
+    const start = (page.pageNum - 1) * page.pageSize;
+    const end = start + page.pageSize;
+    tableData.value = filtered.slice(start, end);
+
+    // 鑷姩鍥炴樉閫変腑鐘舵��
+    nextTick(() => {
+      if (tableRef.value) {
+        tableData.value.forEach(row => {
+          if (props.selectedIds && props.selectedIds.includes(row.id)) {
+            tableRef.value.toggleRowSelection(row, true);
+          }
+        });
+      }
+    });
+  } finally {
+    loading.value = false;
+  }
+}
+
+// 鐩戝惉寮圭獥鎵撳紑锛岄噸缃�夋嫨
+watch(() => props.modelValue, (visible) => {
+  if (visible) {
+    // 姣忔鎵撳紑鏃堕噸鏂板垵濮嬪寲閫変腑鐘舵�侊紙multipleSelection 浼氶�氳繃 loadData 涓殑鍥炴樉閫昏緫鑷姩鏇存柊锛屼絾鍒濆闇�缃┖閬垮厤閲嶅锛�
+    multipleSelection.value = [];
+    page.pageNum = 1;
+    loadData();
+  }
+});
+
+// 鐩戝惉鏁版嵁婧愬彉鍖�
+watch(() => props.products, () => {
+  loadData();
+}, { deep: true });
+
+onMounted(() => {
+  loadData()
+})
+</script>
diff --git a/src/views/customerService/feedbackRegistration/components/formDia.vue b/src/views/customerService/feedbackRegistration/components/formDia.vue
index 41c8ac6..2af71da 100644
--- a/src/views/customerService/feedbackRegistration/components/formDia.vue
+++ b/src/views/customerService/feedbackRegistration/components/formDia.vue
@@ -2,70 +2,118 @@
   <div>
     <el-dialog
         v-model="dialogFormVisible"
-        title="鍞悗鐧昏"
-        width="70%"
+        title="鏂板鍞悗鍗�"
+        width="90%"
         @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="feedbackDate">
-							<el-date-picker
-								style="width: 100%"
-								v-model="form.feedbackDate"
-								value-format="YYYY-MM-DD"
-								format="YYYY-MM-DD"
-								type="date"
-								placeholder="璇烽�夋嫨"
-								clearable
-							/>
-						</el-form-item>
-					</el-col>
-					<el-col :span="12">
-						<el-form-item label="鐧昏浜猴細" prop="checkUserId">
-							<el-select
-								v-model="form.checkUserId"
-								placeholder="璇烽�夋嫨"
-								clearable
-							>
-								<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-row>
-				<el-row :gutter="30">
-					<el-col :span="12">
-						<el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerName">
-							<el-input
-								v-model="form.customerName"
-								placeholder="璇疯緭鍏�"
-								clearable
-							/>
-						</el-form-item>
-					</el-col>
-					<el-col :span="12">
-						<el-form-item label="闂鎻忚堪锛�" prop="proDesc">
-							<el-input
-								v-model="form.proDesc"
-								placeholder="璇疯緭鍏�"
-								clearable
-								type="textarea"
-							/>
-						</el-form-item>
-					</el-col>
-				</el-row>
-			</el-form>
+      <div>
+        <span class="descriptions">鍩虹璧勬枡</span>
+        <el-form
+            :model="form"
+            label-width="140px"
+            label-position="top"
+            :rules="rules"
+            ref="formRef"
+        >
+          <el-row :gutter="30">
+            <el-col :span="4">
+              <el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerName">
+                <el-select
+                    v-model="form.customerName"
+                    filterable
+                    @change="customerNameChange"
+                >
+                  <el-option
+                      v-for="item in customerNameOptions"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="4">
+              <el-form-item label="鍞悗绫诲瀷锛�" prop="serviceType">
+                <el-select
+                    v-model="form.serviceType"
+                    filterable
+                >
+                  <el-option
+                      v-for="dict in serviceTypeOptions"
+                      :key="dict.value"
+                      :label="dict.label"
+                      :value="dict.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="4">
+              <el-form-item label="鍏宠仈閿�鍞崟鍙凤細" prop="salesContractNo">
+                <el-select
+                    v-model="form.salesContractNo"
+                    @change="associatedSalesOrderNumberChange"
+                    filterable
+                >
+                  <el-option
+                      v-for="item in associatedSalesOrderNumberOptions"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="4">
+              <el-form-item label="绱ф�ョ▼搴︼細" prop="urgency">
+                <el-select
+                    v-model="form.urgency"
+                    filterable
+                >
+                  <el-option
+                      v-for="dict in urgencyOptions"
+                      :key="dict.value"
+                      :label="dict.label"
+                      :value="dict.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="4">
+              <el-form-item label="闂鎻忚堪锛�" prop="disRes">
+                <el-input
+                    v-model="form.disRes"
+                    placeholder="璇疯緭鍏ラ棶棰樻弿杩�"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+        <hr>
+          <div style="padding-top: 20px">
+            <div style="display: flex; justify-content: space-between">
+              <span class="descriptions">鍏宠仈浜у搧</span>
+            <el-button
+              type="primary"
+              style="margin-right: 12px; margin-bottom: 10px"
+              @click="isShowProductSelectDialog = true"
+            >
+              閫夋嫨浜у搧
+            </el-button>
+            </div>
+            <PIMTable
+                :isShowPagination="false"
+                rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+            >
+              <template #shippingStatus="{ row }">
+                <el-tag :type="getShippingStatusType(row)" size="small">
+                  {{ getShippingStatusText(row) }}
+                </el-tag>
+              </template>
+            </PIMTable>
+          </div>
+      </div>
 			<template #footer>
 				<div class="dialog-footer">
 					<el-button type="primary" @click="submitForm">纭</el-button>
@@ -73,63 +121,286 @@
 				</div>
 			</template>
     </el-dialog>
+    <!-- 閫夋嫨浜у搧寮圭獥 -->
+    <ProductSelectDialog
+      v-model="isShowProductSelectDialog"
+      :products="currentSalesOrderProducts"
+      :selected-ids="currentSelectedProductIds"
+      @confirm="handleSelectProducts"
+    />
   </div>
 </template>
 
 <script setup>
-import {ref} from "vue";
+import { ref, reactive, toRefs, getCurrentInstance, computed } from "vue";
+import ProductSelectDialog from "./ProductSelectDialog.vue";
 import useUserStore from "@/store/modules/user.js";
 import {userListNoPageByTenantId} from "@/api/system/user.js";
-import {afterSalesServiceAdd, afterSalesServiceUpdate} from "@/api/customerService/index.js";
+import {afterSalesServiceAdd, afterSalesServiceUpdate, getAllCustomerList, getSalesLedger } from "@/api/customerService/index.js";
 import { getCurrentDate } from "@/utils/index.js";
 const { proxy } = getCurrentInstance()
 const emit = defineEmits(['close'])
 const dialogFormVisible = ref(false);
 const operationType = ref('')
+const formRef = ref(null)
+const customerNameOptions = ref([])
 const userStore = useUserStore();
 
 const data = reactive({
 	form: {
-		feedbackDate: "",
-		checkUserId: "",
-		customerName: "",
-		proDesc: "",
+    topic: "",
+    serviceType: "",
+    urgency: "",
+    salesLedgerId: null,
+    productModelIds: "",
+    customerId: null,
+    salesContractNo: "",
+    disRes: "",
+    customerName: ""
 	},
 	rules: {
+    customerName: [{required: true, message: "璇烽�夋嫨瀹㈡埛鍚嶇О", trigger: "change"}],
+    serviceType: [{required: true, message: "璇烽�夋嫨鍞悗绫诲瀷", trigger: "change"}],
+    urgency: [{required: true, message: "璇烽�夋嫨绱ф�ョ▼搴�", trigger: "change"}],
 		feedbackDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-		checkUserId: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-		customerName: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
-		proDesc: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
 	}
 })
+
+// 鑷畾涔夋牎楠屽嚱鏁帮細鍒ゆ柇鏄惁闇�瑕佹牎楠屽敭鍚庣紪鍙�
+
 const { form, rules } = toRefs(data);
 const userList = ref([])
 
+const formatCurrency = (val) => {
+  if (val === null || val === undefined || val === '') return '-'
+  const num = Number(val)
+  return Number.isFinite(num) ? num.toFixed(2) : '-'
+}
+
+const { post_sale_waiting_list, degree_of_urgency } = proxy.useDict(
+  "post_sale_waiting_list",
+  "degree_of_urgency"
+);
+
+const serviceTypeOptions = computed(() => post_sale_waiting_list?.value || []);
+const urgencyOptions = computed(() => degree_of_urgency?.value || []);
+
+const tableColumn = ref([
+  { label: "浜у搧澶х被", prop: "productCategory" },
+  { label: "瑙勬牸鍨嬪彿", prop: "specificationModel" },
+  { label: "鍗曚綅", prop: "unit" },
+  {
+    label: "浜у搧鐘舵��",
+    prop: "approveStatus",
+    width: 100,
+    align: "center",
+    dataType: "tag",
+    formatData: (v) => (v === 1 ? "鍏呰冻" : "涓嶈冻"),
+    formatType: (v) => (v === 1 ? "success" : "danger"),
+  },
+  {
+    label: "鍙戣揣鐘舵��",
+    align: "center",
+    width: 140,
+    dataType: "slot",
+    slot: "shippingStatus",
+  },
+  { label: "蹇�掑叕鍙�", prop: "expressCompany", width: 140 },
+  { label: "蹇�掑崟鍙�", prop: "expressNumber", width: 160 },
+  { label: "鍙戣揣杞︾墝", prop: "shippingCarNumber", minWidth: 100, align: "center" },
+  { label: "鍙戣揣鏃ユ湡", prop: "shippingDate", minWidth: 100, align: "center" },
+  { label: "鏁伴噺", prop: "quantity", width: 100 },
+  { label: "绋庣巼(%)", prop: "taxRate", width: 100 },
+  {
+    label: "鍚◣鍗曚环(鍏�)",
+    prop: "taxInclusiveUnitPrice",
+    width: 160,
+    formatData: formatCurrency,
+  },
+  {
+    label: "鍚◣鎬讳环(鍏�)",
+    prop: "taxInclusiveTotalPrice",
+    width: 160,
+    formatData: formatCurrency,
+  },
+  {
+    label: "涓嶅惈绋庢�讳环(鍏�)",
+    prop: "taxExclusiveTotalPrice",
+    width: 160,
+    formatData: formatCurrency,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    operation: [
+      {
+        name: "鍒犻櫎",
+        type: "text",
+        clickFun: (row) => {
+          tableData.value = tableData.value.filter(i => i.id !== row.id)
+        },
+
+      },
+    ],
+  },
+])
+const tableData = ref([])
+// 閫夋嫨浜у搧寮圭獥
+const isShowProductSelectDialog = ref(false)
+const handleSelectProducts = (rows) => {
+  if (!Array.isArray(rows)) return
+  const existingIds = new Set(tableData.value.map(i => i.id))
+  const mapped = rows
+    .filter(r => !existingIds.has(r.id))
+    .map(r => ({
+      id: r.id,
+      productCategory: r.productName,
+      specificationModel: r.model,
+      unit: r.unit || '',
+      approveStatus: null,
+      shippingStatus: '',
+      expressCompany: '',
+      expressNumber: '',
+      shippingCarNumber: '',
+      shippingDate: '',
+      quantity: 0,
+      taxRate: 0,
+      taxInclusiveUnitPrice: 0,
+      taxInclusiveTotalPrice: 0,
+      taxExclusiveTotalPrice: 0,
+    }))
+  tableData.value = tableData.value.concat(mapped)
+}
+const currentSelectedProductIds = computed(() => {
+  return tableData.value.map(item => item.id)
+})
+
+const associatedSalesOrderNumberChange = () => {
+  const opt = associatedSalesOrderNumberOptions.value.find(
+    (item) => item.value === form.value.salesContractNo
+  )
+  tableData.value = opt?.productData || []
+  form.value.salesLedgerId = opt?.id || null
+}
+
+const associatedSalesOrderNumberOptions = ref([])
+
+const currentSalesOrderProducts = computed(() => {
+  const opt = associatedSalesOrderNumberOptions.value.find(
+    (item) => item.value === form.value.salesContractNo
+  )
+  return opt?.productData || []
+})
+
+const customerNameChange = (val) => {
+  const opt = customerNameOptions.value.find(item => item.value === val);
+  if (opt) {
+    form.value.customerId = opt.id;
+  }
+  getSalesLedger({
+    customerName: form.value.customerName
+  }).then(res => {
+    if(res.code === 200){
+      associatedSalesOrderNumberOptions.value = res.data.records.map(item => ({
+        label: item.salesContractNo,
+        value: item.salesContractNo,
+        productData:item.productData,
+        id: item.id
+      }))
+    }
+  })
+}
+
+const getShippingStatusText = (row) => {
+  if (!row) return '寰呭彂璐�'
+  if (row.shippingDate || row.shippingCarNumber) {
+    return '宸插彂璐�'
+  }
+  const status = row.shippingStatus
+  if (status === null || status === undefined || status === '') {
+    return '寰呭彂璐�'
+  }
+  const map = {
+    '寰呭彂璐�': '寰呭彂璐�',
+    '寰呭鏍�': '寰呭鏍�',
+    '瀹℃牳涓�': '瀹℃牳涓�',
+    '瀹℃牳鎷掔粷': '瀹℃牳鎷掔粷',
+    '瀹℃牳閫氳繃': '瀹℃牳閫氳繃',
+    '宸插彂璐�': '宸插彂璐�'
+  }
+  return map[String(status).trim()] || '寰呭彂璐�'
+}
+
+const getShippingStatusType = (row) => {
+  if (!row) return 'info'
+  if (row.shippingDate || row.shippingCarNumber) {
+    return 'success'
+  }
+  const status = row.shippingStatus
+  if (status === null || status === undefined || status === '') {
+    return 'info'
+  }
+  const map = {
+    '寰呭彂璐�': 'info',
+    '寰呭鏍�': 'warning',
+    '瀹℃牳涓�': 'warning',
+    '瀹℃牳鎷掔粷': 'danger',
+    '瀹℃牳閫氳繃': 'success',
+    '宸插彂璐�': 'success'
+  }
+  return map[String(status).trim()] || 'info'
+}
+
 // 鎵撳紑寮规
-const openDialog = (type, row) => {
+const openDialog =async (type, row) => {
+  // 璇锋眰澶氫釜鎺ュ彛锛岃幏鍙栨暟鎹�
+  let res = await getAllCustomerList();
+  if(res.records){
+    customerNameOptions.value = res.records.map(item => ({
+      label: item.customerName,
+      value: item.customerName,
+      id: item.id
+    }));
+  }
+
+
   operationType.value = type;
   dialogFormVisible.value = true;
 	form.value = {}
 	proxy.resetForm("formRef");
 	form.value.checkUserId = userStore.id;
 	form.value.feedbackDate = getCurrentDate();
+  // 鏂板鏃舵竻绌哄凡閫夊叧鑱斾骇鍝�
+  if (type === "add") {
+    tableData.value = []
+  }
 	userListNoPageByTenantId().then((res) => {
 		userList.value = res.data;
 	});
 	if (type === "edit") {
 		form.value = {...row}
+    if (form.value.customerName) {
+      const res = await getSalesLedger({ customerName: form.value.customerName })
+      if (res?.code === 200) {
+        console.log(res)
+        associatedSalesOrderNumberOptions.value = (res.data?.records || []).map(item => ({
+          label: item.salesContractNo,
+          value: item.salesContractNo,
+          productData: item.productData,
+          id: item.id
+        }))
+      }
+    }
+    console.log(form.value)
 	}
 }
-// const setName = (code) => {
-// 	const index = userList.value.findIndex(item => item.deviceModel === code);
-// 	if (index > -1) {
-// 		console.log(userList)
-// 		form.value.name = userList.value[index].deviceName;
-// 	}
-// }
 const submitForm = () => {
 	proxy.$refs["formRef"].validate(valid => {
 		if (valid) {
+      // 鍖归厤浜у搧鍨嬪彿IDs
+      form.value.productModelIds = tableData.value.map(item => item.id).join(",")
 			if (operationType.value === "add") {
 				afterSalesServiceAdd(form.value).then(response => {
 					proxy.$modal.msgSuccess("鏂板鎴愬姛")
@@ -155,6 +426,25 @@
 });
 </script>
 
-<style scoped>
+<style scoped lang="scss">
+.descriptions {
+  margin-bottom: 20px;
+  display: inline-block;
+  font-size: 1rem;
+  font-weight: 600;
+  padding-left: 12px;
+  position: relative;
+}
 
-</style>
\ No newline at end of file
+.descriptions::before {
+  content: "";
+  position: absolute;
+  left: 0;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 4px;
+  height: 1rem;
+  background-color: #002FA7; /* Element 榛樿绾㈣壊 */
+  border-radius: 2px;
+}
+</style>
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