From dd630fede0cc46500fe898c75464e3e04ce82b0f Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期三, 25 三月 2026 18:01:03 +0800
Subject: [PATCH] feat(财务与售后): 新增财务管理与售后管理模块

---
 src/pages/productionManagement/productionDispatching/components/formDia.vue |    2 
 src/pages.json                                                              |   77 +
 src/pages/financialManagement/revenueManagement/index.vue                   |  149 +++
 src/pages/customerService/feedbackRegistration/index.vue                    |  323 +++++++
 src/pages/works.vue                                                         |   61 +
 src/pages/financialManagement/expenseManagement/index.vue                   |  149 +++
 src/pages/customerService/feedbackRegistration/edit.vue                     |  472 ++++++++++
 src/pages/financialManagement/loanManagement/index.vue                      |  196 ++++
 src/pages/financialManagement/revenueManagement/edit.vue                    |  120 ++
 src/api/customerService/index.js                                            |   93 ++
 src/api/financialManagement/expenseManagement.js                            |   40 
 src/pages/financialManagement/loanManagement/edit.vue                       |   87 ++
 src/api/financialManagement/revenueManagement.js                            |   40 
 src/pages/customerService/afterSalesHandling/fileList.vue                   |  300 ++++++
 src/pages/customerService/afterSalesHandling/handle.vue                     |  121 ++
 src/pages/financialManagement/expenseManagement/edit.vue                    |  120 ++
 src/api/financialManagement/loanManagement.js                               |   33 
 src/pages/customerService/afterSalesHandling/index.vue                      |  181 ++++
 18 files changed, 2,555 insertions(+), 9 deletions(-)

diff --git a/src/api/customerService/index.js b/src/api/customerService/index.js
new file mode 100644
index 0000000..b5d9cea
--- /dev/null
+++ b/src/api/customerService/index.js
@@ -0,0 +1,93 @@
+import request from "@/utils/request";
+
+// 鍙嶉鐧昏-鍒嗛〉鏌ヨ
+export function afterSalesServiceListPage(query) {
+  return request({
+    url: '/afterSalesService/listPage',
+    method: 'get',
+    params: query,
+  })
+}
+// 鍙嶉鐧昏-鍒犻櫎
+export function afterSalesServiceDelete(query) {
+  return request({
+    url: '/afterSalesService/delete',
+    method: 'delete',
+    data: query,
+  })
+}
+// 鍙嶉鐧昏-鏂板
+export function afterSalesServiceAdd(query) {
+  return request({
+    url: '/afterSalesService/add',
+    method: 'post',
+    data: query,
+  })
+}
+// 鍙嶉鐧昏-鏇存柊
+export function afterSalesServiceUpdate(query) {
+  return request({
+    url: '/afterSalesService/update',
+    method: 'post',
+    data: query,
+  })
+}
+// 鍞悗澶勭悊-鎻愪氦澶勭悊
+export function afterSalesServiceDispose(query) {
+  return request({
+    url: '/afterSalesService/dispose',
+    method: 'post',
+    data: query,
+  })
+}
+
+// 鍞悗澶勭悊-闄勪欢鍒楄〃
+export function afterSalesServiceFileListPage(query) {
+  return request({
+    url: '/afterSalesService/file/listPage',
+    method: 'get',
+    params: query,
+  })
+}
+// 鍞悗澶勭悊-闄勪欢鏂板
+export function afterSalesServiceFileAdd(data) {
+  return request({
+    url: '/afterSalesService/file/add',
+    method: 'post',
+    data,
+  })
+}
+// 鍞悗澶勭悊-闄勪欢鍒犻櫎
+export function afterSalesServiceFileDel(id) {
+  return request({
+    url: `/afterSalesService/file/del/${id}`,
+    method: 'delete',
+  })
+}
+
+// 鏌ヨ鎵�鏈夊鎴蜂俊鎭�
+export function getAllCustomerList(query) {
+    return request({
+        url: '/basic/customer/list',
+        method: 'get',
+        params: query,
+    })
+}
+
+// 鏍规嵁瀹㈡埛鏌ヨ閿�鍞鍗曞彿
+export function getSalesLedger(query) {
+    return request({
+        url: '/afterSalesService/listSalesLedger',
+        method: 'get',
+        params: query,
+    })
+}
+
+// 鑾峰彇缁熻鏁版嵁
+export function getSalesLedgerDetail(query) {
+    return request({
+        url: '/afterSalesService/count',
+        method: 'get',
+        params: query,
+    })
+}
diff --git a/src/api/financialManagement/expenseManagement.js b/src/api/financialManagement/expenseManagement.js
new file mode 100644
index 0000000..49e63ac
--- /dev/null
+++ b/src/api/financialManagement/expenseManagement.js
@@ -0,0 +1,40 @@
+import request from "@/utils/request";
+
+export const listPage = (params) => {
+  return request({
+    url: "/account/accountExpense/listPage",
+    method: "get",
+    params,
+  });
+};
+
+export function add(data) {
+  return request({
+    url: "/account/accountExpense/add",
+    method: "post",
+    data,
+  });
+}
+
+export function update(data) {
+  return request({
+    url: "/account/accountExpense/update",
+    method: "post",
+    data,
+  });
+}
+
+export const delAccountExpense = (data) => {
+  return request({
+    url: "account/accountExpense/del",
+    method: "delete",
+    data,
+  });
+};
+
+export const getAccountExpense = (id) => {
+  return request({
+    url: `/account/accountExpense/${id}`,
+    method: "get",
+  });
+};
diff --git a/src/api/financialManagement/loanManagement.js b/src/api/financialManagement/loanManagement.js
new file mode 100644
index 0000000..251da1c
--- /dev/null
+++ b/src/api/financialManagement/loanManagement.js
@@ -0,0 +1,33 @@
+import request from "@/utils/request";
+
+export const listPage = (params) => {
+  return request({
+    url: "/borrowInfo/listPage",
+    method: "get",
+    params,
+  });
+};
+
+export function add(data) {
+  return request({
+    url: "/borrowInfo/add",
+    method: "post",
+    data,
+  });
+}
+
+export function update(data) {
+  return request({
+    url: "/borrowInfo/update",
+    method: "post",
+    data,
+  });
+}
+
+export const delAccountLoan = (data) => {
+  return request({
+    url: "/borrowInfo/delete",
+    method: "delete",
+    data,
+  });
+};
diff --git a/src/api/financialManagement/revenueManagement.js b/src/api/financialManagement/revenueManagement.js
new file mode 100644
index 0000000..3a270fd
--- /dev/null
+++ b/src/api/financialManagement/revenueManagement.js
@@ -0,0 +1,40 @@
+import request from "@/utils/request";
+
+export const listPage = (params) => {
+  return request({
+    url: "/account/accountIncome/listPage",
+    method: "get",
+    params,
+  });
+};
+
+export function add(data) {
+  return request({
+    url: "/account/accountIncome/add",
+    method: "post",
+    data,
+  });
+}
+
+export function update(data) {
+  return request({
+    url: "/account/accountIncome/update",
+    method: "post",
+    data,
+  });
+}
+
+export const delAccountIncome = (data) => {
+  return request({
+    url: "account/accountIncome/del",
+    method: "delete",
+    data,
+  });
+};
+
+export const getAccountIncome = (id) => {
+  return request({
+    url: `/account/accountIncome/${id}`,
+    method: "get",
+  });
+};
diff --git a/src/pages.json b/src/pages.json
index 5d7da6d..5c4283d 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -19,6 +19,48 @@
       }
     },
     {
+      "path": "pages/financialManagement/revenueManagement/index",
+      "style": {
+        "navigationBarTitleText": "鏀跺叆绠$悊",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/financialManagement/revenueManagement/edit",
+      "style": {
+        "navigationBarTitleText": "鏀跺叆缂栬緫",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/financialManagement/expenseManagement/index",
+      "style": {
+        "navigationBarTitleText": "鏀嚭绠$悊",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/financialManagement/expenseManagement/edit",
+      "style": {
+        "navigationBarTitleText": "鏀嚭缂栬緫",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/financialManagement/loanManagement/index",
+      "style": {
+        "navigationBarTitleText": "鍊熸绠$悊",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/financialManagement/loanManagement/edit",
+      "style": {
+        "navigationBarTitleText": "鍊熸缂栬緫",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/index",
       "style": {
         "navigationBarTitleText": "棣栭〉",
@@ -999,6 +1041,41 @@
       }
     },
     {
+      "path": "pages/customerService/feedbackRegistration/index",
+      "style": {
+        "navigationBarTitleText": "鍞悗鐧昏",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/customerService/feedbackRegistration/edit",
+      "style": {
+        "navigationBarTitleText": "鍞悗鍗曡鎯�",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/customerService/afterSalesHandling/index",
+      "style": {
+        "navigationBarTitleText": "鍞悗澶勭悊",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/customerService/afterSalesHandling/handle",
+      "style": {
+        "navigationBarTitleText": "鍞悗澶勭悊璇︽儏",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/customerService/afterSalesHandling/fileList",
+      "style": {
+        "navigationBarTitleText": "鍞悗闄勪欢",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/qualityManagement/finalInspection/add",
       "style": {
         "navigationBarTitleText": "鍑哄巶妫�楠屾坊鍔�",
diff --git a/src/pages/customerService/afterSalesHandling/fileList.vue b/src/pages/customerService/afterSalesHandling/fileList.vue
new file mode 100644
index 0000000..7e0194b
--- /dev/null
+++ b/src/pages/customerService/afterSalesHandling/fileList.vue
@@ -0,0 +1,300 @@
+<template>
+  <view class="file-list-page">
+    <PageHeader title="鍞悗闄勪欢" @back="goBack" />
+
+    <view class="file-list-container">
+      <view v-if="fileList.length > 0" class="file-list">
+        <view v-for="(file, index) in fileList" :key="file.id || index" class="file-item">
+          <view class="file-info">
+            <text class="file-name">{{ file.name }}</text>
+          </view>
+          <view class="file-actions">
+            <u-button size="small" type="info" plain @click="downloadFile(file)">涓嬭浇骞堕瑙�</u-button>
+            <u-button size="small" type="error" plain @click="confirmDelete(file)">鍒犻櫎</u-button>
+          </view>
+        </view>
+      </view>
+
+      <view v-else class="empty-state">
+        <up-icon name="document" size="64" color="#c0c4cc" />
+        <text class="empty-text">鏆傛棤闄勪欢</text>
+      </view>
+    </view>
+
+    <view class="upload-button" @click="chooseFile">
+      <up-icon name="plus" size="24" color="#ffffff" />
+      <text class="upload-text">涓婁紶闄勪欢</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from "vue";
+import PageHeader from "@/components/PageHeader.vue";
+import config from "@/config";
+import { getToken } from "@/utils/auth";
+import { afterSalesServiceFileListPage, afterSalesServiceFileDel } from "@/api/customerService/index";
+
+const fileList = ref([]);
+const afterSalesServiceId = ref("");
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+const showToast = (message) => {
+  uni.showToast({
+    title: message,
+    icon: "none",
+  });
+};
+
+const normalizeFileRow = (row) => {
+  return {
+    id: row?.id,
+    name: row?.name || row?.fileName || "-",
+    url: row?.url || row?.fileUrl || "",
+  };
+};
+
+const getFileList = () => {
+  if (!afterSalesServiceId.value) {
+    fileList.value = [];
+    return;
+  }
+  uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+  afterSalesServiceFileListPage({
+    afterSalesServiceId: afterSalesServiceId.value,
+    current: 1,
+    size: 100,
+  })
+    .then((res) => {
+      const records = res?.data?.records ?? res?.records ?? [];
+      const list = Array.isArray(records) ? records : [];
+      fileList.value = list.map(normalizeFileRow);
+    })
+    .catch(() => {
+      showToast("鑾峰彇闄勪欢鍒楄〃澶辫触");
+      fileList.value = [];
+    })
+    .finally(() => {
+      uni.hideLoading();
+    });
+};
+
+const chooseFile = () => {
+  if (!afterSalesServiceId.value) {
+    showToast("缂哄皯鍞悗鍗旾D");
+    return;
+  }
+  uni.chooseImage({
+    count: 9,
+    sizeType: ["original", "compressed"],
+    sourceType: ["album", "camera"],
+    success: (res) => {
+      uploadFiles(res.tempFiles || []);
+    },
+    fail: () => {
+      showToast("閫夋嫨鏂囦欢澶辫触");
+    },
+  });
+};
+
+const uploadFiles = (tempFiles) => {
+  if (!Array.isArray(tempFiles) || tempFiles.length === 0) return;
+  tempFiles.forEach((tempFile) => {
+    uni.showLoading({ title: "涓婁紶涓�...", mask: true });
+    uni.uploadFile({
+      url: config.baseUrl + "/afterSalesService/file/upload",
+      filePath: tempFile.path,
+      name: "file",
+      formData: {
+        id: String(afterSalesServiceId.value),
+      },
+      header: {
+        Authorization: "Bearer " + getToken(),
+      },
+      success: (uploadRes) => {
+        uni.hideLoading();
+        try {
+          const data = JSON.parse(uploadRes.data || "{}");
+          if (data.code === 200 || data.code === undefined) {
+            showToast("涓婁紶鎴愬姛");
+            getFileList();
+            return;
+          }
+          showToast(data.msg || "涓婁紶澶辫触");
+        } catch (e) {
+          showToast("涓婁紶澶辫触");
+        }
+      },
+      fail: () => {
+        uni.hideLoading();
+        showToast("涓婁紶澶辫触");
+      },
+    });
+  });
+};
+
+const downloadFile = (file) => {
+  if (!file?.url) {
+    showToast("鏂囦欢鍦板潃涓虹┖");
+    return;
+  }
+  const url =
+    config.baseUrl +
+    "/common/download?fileName=" +
+    encodeURIComponent(file.url) +
+    "&delete=true";
+
+  uni
+    .downloadFile({
+      url,
+      responseType: "blob",
+      header: { Authorization: "Bearer " + getToken() },
+    })
+    .then((res) => {
+      const osType = uni.getStorageSync("deviceInfo")?.osName;
+      const filePath = res.tempFilePath;
+      if (osType === "ios") {
+        uni.openDocument({
+          filePath,
+          showMenu: true,
+        });
+      } else {
+        uni.saveFile({
+          tempFilePath: filePath,
+          success: (fileRes) => {
+            setTimeout(() => {
+              uni.openDocument({
+                filePath: fileRes.savedFilePath,
+              });
+            }, 300);
+          },
+          fail: () => {
+            showToast("淇濆瓨澶辫触");
+          },
+        });
+      }
+    })
+    .catch(() => {
+      showToast("涓嬭浇澶辫触");
+    });
+};
+
+const confirmDelete = (file) => {
+  uni.showModal({
+    title: "鍒犻櫎纭",
+    content: `纭畾瑕佸垹闄ら檮浠� \"${file.name}\" 鍚楋紵`,
+    success: (res) => {
+      if (res.confirm) {
+        deleteFile(file);
+      }
+    },
+  });
+};
+
+const deleteFile = (file) => {
+  if (!file?.id) return;
+  uni.showLoading({ title: "鍒犻櫎涓�...", mask: true });
+  afterSalesServiceFileDel(file.id)
+    .then((res) => {
+      if (res?.code === 200 || res?.code === undefined) {
+        showToast("鍒犻櫎鎴愬姛");
+        getFileList();
+        return;
+      }
+      showToast(res?.msg || "鍒犻櫎澶辫触");
+    })
+    .catch(() => {
+      showToast("鍒犻櫎澶辫触");
+    })
+    .finally(() => {
+      uni.hideLoading();
+    });
+};
+
+onMounted(() => {
+  afterSalesServiceId.value = String(uni.getStorageSync("afterSalesServiceFileId") || "");
+  getFileList();
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+
+.file-list-page {
+  min-height: 100vh;
+  background: #f8f9fa;
+  padding-bottom: 100rpx;
+}
+
+.file-list-container {
+  padding: 20rpx;
+}
+
+.file-list {
+  background: #ffffff;
+  border-radius: 8rpx;
+  overflow: hidden;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+}
+
+.file-item {
+  display: flex;
+  align-items: center;
+  padding: 20rpx;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+
+.file-info {
+  flex: 1;
+  margin-right: 20rpx;
+}
+
+.file-name {
+  font-size: 28rpx;
+  color: #333;
+  font-weight: 500;
+  display: block;
+}
+
+.file-actions {
+  display: flex;
+  gap: 16rpx;
+}
+
+.empty-state {
+  padding: 80rpx 0;
+  text-align: center;
+}
+
+.empty-text {
+  display: block;
+  margin-top: 20rpx;
+  color: #999;
+  font-size: 28rpx;
+}
+
+.upload-button {
+  position: fixed;
+  bottom: calc(30rpx + env(safe-area-inset-bottom));
+  right: 30rpx;
+  height: 88rpx;
+  padding: 0 28rpx;
+  background: #2979ff;
+  border-radius: 44rpx;
+  display: flex;
+  align-items: center;
+  gap: 14rpx;
+  box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.3);
+  z-index: 1000;
+}
+
+.upload-text {
+  color: #ffffff;
+  font-size: 28rpx;
+  font-weight: 500;
+}
+</style>
+
diff --git a/src/pages/customerService/afterSalesHandling/handle.vue b/src/pages/customerService/afterSalesHandling/handle.vue
new file mode 100644
index 0000000..57f6054
--- /dev/null
+++ b/src/pages/customerService/afterSalesHandling/handle.vue
@@ -0,0 +1,121 @@
+<template>
+  <view class="after-sales-handle">
+    <PageHeader :title="operationType === 'approve' ? '鍞悗澶勭悊' : '鍞悗璇︽儏'" @back="goBack" />
+
+    <view class="form-container">
+      <up-form ref="formRef" :model="form" :rules="rules" label-width="100">
+        <up-form-item label="鍙嶉鏃ユ湡" prop="feedbackDate">
+          <up-input v-model="form.feedbackDate" disabled />
+        </up-form-item>
+
+        <up-form-item label="鐧昏浜�" prop="checkNickName">
+          <up-input v-model="form.checkNickName" disabled />
+        </up-form-item>
+
+        <up-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+          <up-input v-model="form.customerName" disabled />
+        </up-form-item>
+
+        <up-form-item label="闂鎻忚堪" prop="proDesc" required>
+          <up-textarea v-model="form.proDesc" :disabled="operationType === 'view'" placeholder="璇疯緭鍏ラ棶棰樻弿杩�" count autoHeight></up-textarea>
+        </up-form-item>
+
+        <up-form-item label="澶勭悊缁撴灉" prop="disRes" required>
+          <up-textarea v-model="form.disRes" :disabled="operationType === 'view'" placeholder="璇疯緭鍏ュ鐞嗙粨鏋�" count autoHeight></up-textarea>
+        </up-form-item>
+
+        <up-form-item label="澶勭悊浜�" prop="disposeNickName" v-if="form.disposeNickName || operationType === 'approve'">
+          <up-input v-model="form.disposeNickName" disabled />
+        </up-form-item>
+
+        <up-form-item label="澶勭悊鏃ユ湡" prop="disDate" v-if="form.disDate || operationType === 'approve'">
+          <up-input v-model="form.disDate" disabled />
+        </up-form-item>
+      </up-form>
+    </view>
+
+    <FooterButtons :show="operationType === 'approve'" cancelText="鍙栨秷" confirmText="鎻愪氦" @cancel="goBack" @confirm="submitForm" />
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue';
+import { afterSalesServiceDispose } from '@/api/customerService/index';
+import PageHeader from '@/components/PageHeader.vue';
+import FooterButtons from '@/components/FooterButtons.vue';
+import useUserStore from '@/store/modules/user';
+
+const userStore = useUserStore();
+const operationType = ref('view');
+const formRef = ref(null);
+const form = reactive({
+  id: null,
+  feedbackDate: '',
+  checkUserId: null,
+  checkNickName: '',
+  customerName: '',
+  proDesc: '',
+  disRes: '',
+  disposeUserId: null,
+  disposeNickName: '',
+  disDate: '',
+});
+
+const rules = {
+  proDesc: [{ required: true, message: '璇疯緭鍏ラ棶棰樻弿杩�', trigger: 'blur' }],
+  disRes: [{ required: true, message: '璇疯緭鍏ュ鐞嗙粨鏋�', trigger: 'blur' }],
+};
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+const submitForm = () => {
+  formRef.value.validate().then(valid => {
+    if (valid) {
+      afterSalesServiceDispose(form).then(() => {
+        uni.showToast({ title: '澶勭悊鎴愬姛', icon: 'success' });
+        setTimeout(() => goBack(), 1500);
+      });
+    }
+  });
+};
+
+onMounted(() => {
+  operationType.value = uni.getStorageSync('afterSalesHandleType') || 'view';
+  const dataStr = uni.getStorageSync('afterSalesHandleData');
+  
+  if (dataStr) {
+    const data = JSON.parse(dataStr);
+    Object.assign(form, data);
+    
+    // Normalize field names if they differ between API and web view
+    if (!form.proDesc) form.proDesc = data.disRes; // Fallback to disRes if proDesc is empty
+    
+    if (operationType.value === 'approve') {
+      if (!form.disposeUserId) {
+        form.disposeUserId = userStore.id;
+        form.disposeNickName = userStore.nickName;
+      }
+      if (!form.disDate) {
+        const now = new Date();
+        form.disDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
+      }
+    }
+  }
+});
+</script>
+
+<style scoped lang="scss">
+.after-sales-handle {
+  min-height: 100vh;
+  background: #f8f9fa;
+  padding-bottom: 100px;
+}
+
+.form-container {
+  background: #ffffff;
+  padding: 10px 20px;
+  margin-top: 10px;
+}
+</style>
diff --git a/src/pages/customerService/afterSalesHandling/index.vue b/src/pages/customerService/afterSalesHandling/index.vue
new file mode 100644
index 0000000..1fa568a
--- /dev/null
+++ b/src/pages/customerService/afterSalesHandling/index.vue
@@ -0,0 +1,181 @@
+<template>
+  <view class="after-sales-handling">
+    <PageHeader title="鍞悗澶勭悊" @back="goBack" />
+
+    <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text" placeholder="璇疯緭鍏ュ伐鍗曠紪鍙锋悳绱�" v-model="searchForm.afterSalesServiceNo" @change="handleQuery" clearable />
+        </view>
+        <view class="filter-button" @click="handleQuery">
+          <up-icon name="search" size="24" color="#999"></up-icon>
+        </view>
+      </view>
+    </view>
+
+    <!-- 鍞悗澶勭悊鍒楄〃 -->
+    <view class="ledger-list" v-if="tableData.length > 0">
+      <view v-for="(item, index) in tableData" :key="index" class="ledger-item" @click="openHandleForm('view', item)">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
+            </view>
+            <text class="item-id">{{ item.afterSalesServiceNo }}</text>
+          </view>
+          <view class="item-tag">
+            <up-tag :text="getStatusLabel(item.status)" :type="getStatusType(item.status)" size="mini"></up-tag>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row">
+            <text class="detail-label">閿�鍞崟鍙�</text>
+            <text class="detail-value">{{ item.salesContractNo }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">瀹㈡埛鍚嶇О</text>
+            <text class="detail-value">{{ item.customerName }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鍙嶉鏃ユ湡</text>
+            <text class="detail-value">{{ item.feedbackDate }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鍞悗绫诲瀷</text>
+            <text class="detail-value">{{ getDictLabel(post_sale_waiting_list, item.serviceType) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">绱ф�ョ▼搴�</text>
+            <text class="detail-value">{{ getDictLabel(degree_of_urgency, item.urgency) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">闂鎻忚堪</text>
+            <text class="detail-value">{{ item.proDesc || item.disRes }}</text>
+          </view>
+          <view class="detail-row" v-if="item.status === 2">
+            <text class="detail-label">澶勭悊缁撴灉</text>
+            <text class="detail-value highlight">{{ item.disRes }}</text>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="detail-buttons">
+          <up-button size="small" type="primary" v-if="item.status === 1" @click.stop="openHandleForm('approve', item)">澶勭悊</up-button>
+          <up-button size="small" type="primary" plain @click.stop="openHandleForm('view', item)">鏌ョ湅</up-button>
+          <up-button size="small" type="info" plain @click.stop="openFiles(item)">闄勪欢</up-button>
+        </view>
+      </view>
+    </view>
+    <view v-else class="no-data">
+      <text>鏆傛棤鍞悗澶勭悊鏁版嵁</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue';
+import { onShow } from '@dcloudio/uni-app';
+import { afterSalesServiceListPage } from '@/api/customerService/index';
+import PageHeader from '@/components/PageHeader.vue';
+import { useDict } from '@/utils/dict';
+
+const { post_sale_waiting_list, degree_of_urgency } = useDict('post_sale_waiting_list', 'degree_of_urgency');
+
+const searchForm = reactive({
+  afterSalesServiceNo: '',
+  status: '',
+});
+
+const tableData = ref([]);
+const loading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 20,
+  total: 0,
+});
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+
+const getList = () => {
+  loading.value = true;
+  uni.showLoading({ title: '鍔犺浇涓�...' });
+  
+  afterSalesServiceListPage({ ...searchForm, ...page })
+    .then((res) => {
+      const records = res?.data?.records ?? res?.records ?? [];
+      const total = res?.data?.total ?? res?.total ?? 0;
+      tableData.value = Array.isArray(records) ? records : [];
+      page.total = Number.isFinite(Number(total)) ? Number(total) : 0;
+    })
+    .finally(() => {
+      loading.value = false;
+      uni.hideLoading();
+    });
+};
+
+const getStatusLabel = (status) => {
+  if (status === 1) return '寰呭鐞�';
+  if (status === 2) return '宸插鐞�';
+  return '鏈煡';
+};
+
+const getStatusType = (status) => {
+  if (status === 1) return 'error';
+  if (status === 2) return 'success';
+  return 'info';
+};
+
+const getDictLabel = (dict, value) => {
+  if (!dict || !dict.value) return value;
+  const item = dict.value.find(i => i.value == value);
+  return item ? item.label : value;
+};
+
+const openHandleForm = (type, row) => {
+  uni.setStorageSync('afterSalesHandleType', type);
+  uni.setStorageSync('afterSalesHandleData', JSON.stringify(row));
+  uni.navigateTo({
+    url: '/pages/customerService/afterSalesHandling/handle'
+  });
+};
+
+const openFiles = (row) => {
+  uni.setStorageSync('afterSalesFileData', JSON.stringify(row));
+  uni.setStorageSync('afterSalesServiceFileId', row?.id);
+  uni.navigateTo({
+    url: '/pages/customerService/afterSalesHandling/fileList'
+  });
+};
+
+onShow(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+
+.after-sales-handling {
+  min-height: 100vh;
+  background: #f8f9fa;
+}
+
+.detail-buttons {
+  display: flex;
+  gap: 10px;
+  justify-content: flex-end;
+  padding: 12px 0;
+}
+
+.ledger-item {
+  padding: 0 16px;
+}
+</style>
diff --git a/src/pages/customerService/feedbackRegistration/edit.vue b/src/pages/customerService/feedbackRegistration/edit.vue
new file mode 100644
index 0000000..93db74f
--- /dev/null
+++ b/src/pages/customerService/feedbackRegistration/edit.vue
@@ -0,0 +1,472 @@
+<template>
+  <view class="after-sales-edit">
+    <PageHeader :title="pageTitle" @back="goBack" />
+
+    <view class="form-container">
+      <up-form ref="formRef" :model="form" :rules="isReadonly ? {} : rules" label-width="100">
+        <up-form-item label="瀹㈡埛鍚嶇О" prop="customerName" required @click="openCustomerPicker">
+          <up-input v-model="form.customerName" readonly placeholder="璇烽�夋嫨瀹㈡埛" />
+          <template #right>
+            <up-icon v-if="!isReadonly" name="arrow-right" @click="openCustomerPicker"></up-icon>
+          </template>
+        </up-form-item>
+
+        <up-form-item label="鍞悗绫诲瀷" prop="serviceType" required @click="openServiceTypePicker">
+          <up-input v-model="serviceTypeLabel" readonly placeholder="璇烽�夋嫨鍞悗绫诲瀷" />
+          <template #right>
+            <up-icon v-if="!isReadonly" name="arrow-right" @click="openServiceTypePicker"></up-icon>
+          </template>
+        </up-form-item>
+
+        <up-form-item label="鍏宠仈閿�鍞崟" prop="salesContractNo" required @click="openSalesOrderPicker">
+          <up-input v-model="form.salesContractNo" readonly placeholder="璇烽�夋嫨閿�鍞崟鍙�" />
+          <template #right>
+            <up-icon v-if="!isReadonly" name="arrow-right" @click="openSalesOrderPicker"></up-icon>
+          </template>
+        </up-form-item>
+
+        <up-form-item label="绱ф�ョ▼搴�" prop="urgency" required @click="openUrgencyPicker">
+          <up-input v-model="urgencyLabel" readonly placeholder="璇烽�夋嫨绱ф�ョ▼搴�" />
+          <template #right>
+            <up-icon v-if="!isReadonly" name="arrow-right" @click="openUrgencyPicker"></up-icon>
+          </template>
+        </up-form-item>
+
+        <up-form-item label="闂鎻忚堪" prop="disRes">
+          <up-textarea v-model="form.disRes" :disabled="isReadonly" placeholder="璇疯緭鍏ラ棶棰樻弿杩�" count autoHeight></up-textarea>
+        </up-form-item>
+      </up-form>
+
+      <!-- 鍏宠仈浜у搧鍖哄煙 -->
+      <view class="product-section">
+        <view class="section-header">
+          <up-button type="primary" size="small" @click="showProductSelect = true" v-if="!isReadonly && form.salesContractNo">閫夋嫨浜у搧</up-button>
+        </view>
+
+        <view class="product-list" v-if="tableData.length > 0">
+          <view v-for="(item, index) in tableData" :key="index" class="product-item">
+            <view class="product-info">
+              <view class="info-row">
+                <text class="info-label">浜у搧鍒嗙被锛�</text>
+                <text class="info-value">{{ item.productCategory }}</text>
+              </view>
+              <view class="info-row">
+                <text class="info-label">瑙勬牸鍨嬪彿锛�</text>
+                <text class="info-value">{{ item.specificationModel }}</text>
+              </view>
+              <view class="info-row">
+                <text class="info-label">鍗曚綅锛�</text>
+                <text class="info-value">{{ item.unit }}</text>
+              </view>
+              <view class="info-row">
+                <text class="info-label">鏁伴噺锛�</text>
+                <text class="info-value">{{ item.quantity }}</text>
+              </view>
+            </view>
+            <view class="product-action" v-if="!isReadonly">
+              <up-icon name="trash" color="#fa3534" size="20" @click="removeProduct(index)"></up-icon>
+            </view>
+          </view>
+        </view>
+        <view v-else class="no-product">
+          <text>鏆傛棤鍏宠仈浜у搧</text>
+        </view>
+      </view>
+    </view>
+
+    <!-- 鍚勭閫夋嫨鍣� -->
+    <up-action-sheet :show="showCustomerPicker" :actions="customerActions" title="閫夋嫨瀹㈡埛" @select="onCustomerSelect" @close="showCustomerPicker = false" />
+    <up-action-sheet :show="showServiceTypePicker" :actions="serviceTypeActions" title="閫夋嫨鍞悗绫诲瀷" @select="onServiceTypeSelect" @close="showServiceTypePicker = false" />
+    <up-action-sheet :show="showSalesOrderPicker" :actions="salesOrderActions" title="閫夋嫨鍏宠仈閿�鍞崟" @select="onSalesOrderSelect" @close="showSalesOrderPicker = false" />
+    <up-action-sheet :show="showUrgencyPicker" :actions="urgencyActions" title="閫夋嫨绱ф�ョ▼搴�" @select="onUrgencySelect" @close="showUrgencyPicker = false" />
+
+    <!-- 浜у搧閫夋嫨寮圭獥 -->
+    <up-popup :show="showProductSelect" mode="bottom" @close="showProductSelect = false" round="10">
+      <view class="product-select-popup">
+        <view class="popup-header">
+          <text class="popup-title">閫夋嫨浜у搧</text>
+          <up-icon name="close" size="20" @click="showProductSelect = false"></up-icon>
+        </view>
+        <scroll-view scroll-y class="product-scroll">
+          <view v-for="(item, index) in availableProducts" :key="index" class="selectable-product" @click="toggleProduct(item)">
+            <view class="product-checkbox">
+              <up-icon :name="isProductSelected(item) ? 'checkbox-mark' : 'minus-circle'" :color="isProductSelected(item) ? '#2979ff' : '#ccc'" size="20"></up-icon>
+            </view>
+            <view class="product-details">
+              <text class="p-name">{{ item.productCategory }}</text>
+              <text class="p-model">{{ item.specificationModel }} | {{ item.unit }}</text>
+            </view>
+          </view>
+        </scroll-view>
+        <view class="popup-footer">
+          <up-button type="primary" @click="showProductSelect = false">纭畾</up-button>
+        </view>
+      </view>
+    </up-popup>
+
+    <FooterButtons :show="!isReadonly" @cancel="goBack" @confirm="submitForm" />
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted } from 'vue';
+import { getAllCustomerList, getSalesLedger, afterSalesServiceAdd, afterSalesServiceUpdate } from '@/api/customerService/index';
+import PageHeader from '@/components/PageHeader.vue';
+import FooterButtons from '@/components/FooterButtons.vue';
+import { useDict } from '@/utils/dict';
+import useUserStore from '@/store/modules/user';
+
+const userStore = useUserStore();
+const { post_sale_waiting_list, degree_of_urgency } = useDict('post_sale_waiting_list', 'degree_of_urgency');
+
+const operationType = ref('add');
+const isReadonly = computed(() => operationType.value === 'view');
+const pageTitle = computed(() => {
+  if (operationType.value === 'view') return '鍞悗鍗曡鎯�';
+  if (operationType.value === 'add') return '鏂板鍞悗鍗�';
+  return '缂栬緫鍞悗鍗�';
+});
+const formRef = ref(null);
+const form = reactive({
+  id: null,
+  customerName: '',
+  customerId: null,
+  serviceType: '',
+  salesContractNo: '',
+  salesLedgerId: null,
+  urgency: '',
+  disRes: '',
+  productModelIds: '',
+  checkUserId: null,
+  feedbackDate: '',
+});
+
+const rules = {
+  customerName: [{ required: true, message: '璇烽�夋嫨瀹㈡埛', trigger: 'change' }],
+  serviceType: [{ required: true, message: '璇烽�夋嫨鍞悗绫诲瀷', trigger: 'change' }],
+  salesContractNo: [{ required: true, message: '璇烽�夋嫨鍏宠仈閿�鍞崟', trigger: 'change' }],
+  urgency: [{ required: true, message: '璇烽�夋嫨绱ф�ョ▼搴�', trigger: 'change' }],
+};
+
+const tableData = ref([]);
+const customerList = ref([]);
+const salesOrderList = ref([]);
+const availableProducts = ref([]);
+
+const showCustomerPicker = ref(false);
+const showServiceTypePicker = ref(false);
+const showSalesOrderPicker = ref(false);
+const showUrgencyPicker = ref(false);
+const showProductSelect = ref(false);
+
+const customerActions = computed(() => customerList.value.map(item => ({ name: item.customerName, value: item.id })));
+const serviceTypeActions = computed(() => (post_sale_waiting_list.value || []).map(item => ({ name: item.label, value: item.value })));
+const salesOrderActions = computed(() => salesOrderList.value.map(item => ({ name: item.salesContractNo, value: item.salesContractNo, id: item.id, products: item.productData })));
+const urgencyActions = computed(() => (degree_of_urgency.value || []).map(item => ({ name: item.label, value: item.value })));
+
+const serviceTypeLabel = computed(() => {
+  const item = (post_sale_waiting_list.value || []).find(i => i.value == form.serviceType);
+  return item ? item.label : '';
+});
+
+const urgencyLabel = computed(() => {
+  const item = (degree_of_urgency.value || []).find(i => i.value == form.urgency);
+  return item ? item.label : '';
+});
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+const openCustomerPicker = () => {
+  if (isReadonly.value) return;
+  showCustomerPicker.value = true;
+};
+const openServiceTypePicker = () => {
+  if (isReadonly.value) return;
+  showServiceTypePicker.value = true;
+};
+const openSalesOrderPicker = () => {
+  if (isReadonly.value) return;
+  if (!form.customerName) {
+    uni.showToast({ title: '璇峰厛閫夋嫨瀹㈡埛', icon: 'none' });
+    return;
+  }
+  showSalesOrderPicker.value = true;
+};
+const openUrgencyPicker = () => {
+  if (isReadonly.value) return;
+  showUrgencyPicker.value = true;
+};
+
+const onCustomerSelect = (item) => {
+  form.customerName = item.name;
+  form.customerId = item.value;
+  form.salesContractNo = '';
+  form.salesLedgerId = null;
+  tableData.value = [];
+  availableProducts.value = [];
+  fetchSalesOrders(item.name);
+};
+
+const onServiceTypeSelect = (item) => {
+  form.serviceType = item.value;
+};
+
+const onSalesOrderSelect = (item) => {
+  form.salesContractNo = item.name;
+  form.salesLedgerId = item.id;
+  setProductsFromSalesOrder(item, true);
+};
+
+const onUrgencySelect = (item) => {
+  form.urgency = item.value;
+};
+
+const normalizeProduct = (p) => {
+  return {
+    ...p,
+    id: p.id || p.productModelId || p.modelId,
+    productCategory: p.productCategory || p.productName || '',
+    specificationModel: p.specificationModel || p.model || '',
+  };
+};
+
+const setProductsFromSalesOrder = (orderAction, selectAll = false) => {
+  const products = Array.isArray(orderAction?.products) ? orderAction.products : [];
+  const normalizedProducts = products.map(p => normalizeProduct(p));
+  availableProducts.value = normalizedProducts;
+  if (selectAll) {
+    tableData.value = normalizedProducts.slice();
+    return;
+  }
+  const ids = String(form.productModelIds || '')
+    .split(',')
+    .map(s => s.trim())
+    .filter(Boolean);
+  if (ids.length === 0) {
+    tableData.value = normalizedProducts.slice();
+    return;
+  }
+  const idSet = new Set(ids.map(String));
+  tableData.value = normalizedProducts.filter(p => idSet.has(String(p.id)));
+};
+
+const fetchCustomers = () => {
+  getAllCustomerList({ current: 1, size: 1000 }).then(res => {
+    const records = res?.records ?? res?.data?.records ?? [];
+    customerList.value = Array.isArray(records) ? records : [];
+  });
+};
+
+const fetchSalesOrders = (customerName) => {
+  getSalesLedger({ customerName }).then(res => {
+    const records = res?.records ?? res?.data?.records ?? [];
+    salesOrderList.value = Array.isArray(records) ? records : [];
+    if (form.salesContractNo) {
+      const match = salesOrderList.value.find(i => String(i.salesContractNo) === String(form.salesContractNo));
+      if (match) {
+        setProductsFromSalesOrder({ id: match.id, name: match.salesContractNo, products: match.productData }, false);
+        form.salesLedgerId = match.id;
+      }
+    }
+  });
+};
+
+const removeProduct = (index) => {
+  tableData.value.splice(index, 1);
+};
+
+const isProductSelected = (product) => {
+  const id = product.id || product.productModelId || product.modelId;
+  return tableData.value.some(p => (p.id || p.productModelId || p.modelId) === id);
+};
+
+const toggleProduct = (product) => {
+  if (isReadonly.value) return;
+  const id = product.id || product.productModelId || product.modelId;
+  const index = tableData.value.findIndex(p => (p.id || p.productModelId || p.modelId) === id);
+  if (index > -1) {
+    tableData.value.splice(index, 1);
+  } else {
+    tableData.value.push(normalizeProduct(product));
+  }
+};
+
+const submitForm = () => {
+  if (isReadonly.value) return;
+  formRef.value.validate().then(valid => {
+    if (valid) {
+      form.productModelIds = tableData.value.map(p => p.id || p.productModelId || p.modelId).join(',');
+      if (!form.checkUserId) {
+        form.checkUserId = userStore.id;
+      }
+      if (!form.feedbackDate) {
+        const now = new Date();
+        form.feedbackDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
+      }
+      const api = operationType.value === 'add' ? afterSalesServiceAdd : afterSalesServiceUpdate;
+      
+      api(form).then((res) => {
+        if (res?.code === 200 || res?.code === undefined) {
+          uni.showToast({ title: operationType.value === 'add' ? '鏂板鎴愬姛' : '淇敼鎴愬姛', icon: 'success' });
+          setTimeout(() => goBack(), 500);
+          return;
+        }
+        uni.showToast({ title: res?.msg || '鎿嶄綔澶辫触', icon: 'none' });
+      }).catch(() => {});
+    }
+  });
+};
+
+onMounted(() => {
+  operationType.value = uni.getStorageSync('afterSalesOperationType') || 'add';
+  const editDataStr = uni.getStorageSync('afterSalesEditData');
+  
+  fetchCustomers();
+  
+  if (editDataStr) {
+    const editData = JSON.parse(editDataStr);
+    Object.assign(form, editData);
+    if (form.customerName) {
+      fetchSalesOrders(form.customerName);
+    }
+  } else {
+    form.checkUserId = userStore.id;
+    const now = new Date();
+    form.feedbackDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
+  }
+});
+</script>
+
+<style scoped lang="scss">
+.after-sales-edit {
+  min-height: 100vh;
+  background: #f8f9fa;
+  padding-bottom: 100px;
+}
+
+.form-container {
+  background: #ffffff;
+  padding: 10px 20px;
+  margin-top: 10px;
+}
+
+.product-section {
+  margin-top: 20px;
+  border-top: 1px solid #f0f0f0;
+  padding-top: 20px;
+}
+
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 15px;
+}
+
+.section-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+}
+
+.product-list {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.product-item {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.product-info {
+  flex: 1;
+}
+
+.info-row {
+  display: flex;
+  margin-bottom: 4px;
+  font-size: 13px;
+}
+
+.info-label {
+  color: #909399;
+  width: 70px;
+}
+
+.info-value {
+  color: #303133;
+  flex: 1;
+}
+
+.no-product {
+  text-align: center;
+  padding: 30px 0;
+  color: #999;
+  font-size: 14px;
+}
+
+.product-select-popup {
+  height: 60vh;
+  display: flex;
+  flex-direction: column;
+  background: #fff;
+}
+
+.popup-header {
+  padding: 15px 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.popup-title {
+  font-size: 16px;
+  font-weight: 600;
+}
+
+.product-scroll {
+  flex: 1;
+  padding: 10px 20px;
+}
+
+.selectable-product {
+  display: flex;
+  align-items: center;
+  padding: 15px 0;
+  border-bottom: 1px solid #f5f5f5;
+}
+
+.product-checkbox {
+  margin-right: 15px;
+}
+
+.product-details {
+  display: flex;
+  flex-direction: column;
+}
+
+.p-name {
+  font-size: 14px;
+  color: #333;
+  margin-bottom: 4px;
+}
+
+.p-model {
+  font-size: 12px;
+  color: #999;
+}
+
+.popup-footer {
+  padding: 20px;
+  border-top: 1px solid #f0f0f0;
+}
+</style>
diff --git a/src/pages/customerService/feedbackRegistration/index.vue b/src/pages/customerService/feedbackRegistration/index.vue
new file mode 100644
index 0000000..e2a681e
--- /dev/null
+++ b/src/pages/customerService/feedbackRegistration/index.vue
@@ -0,0 +1,323 @@
+<template>
+  <view class="after-sales-registration">
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+    <PageHeader title="鍞悗鐧昏" @back="goBack" />
+
+    <!-- 缁熻鍗$墖鍖哄煙 -->
+    <view class="stats-container">
+      <view v-for="(item, index) in statsList" :key="index" class="stat-card">
+        <view class="stat-icon" :style="{ backgroundColor: item.bgColor }">
+          <up-icon :name="item.icon" :color="item.color" size="20"></up-icon>
+        </view>
+        <view class="stat-info">
+          <text class="stat-number">{{ item.count }}</text>
+          <text class="stat-label">{{ item.label }}</text>
+        </view>
+      </view>
+    </view>
+
+    <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text" placeholder="璇疯緭鍏ュ伐鍗曠紪鍙锋悳绱�" v-model="searchForm.afterSalesServiceNo" @change="handleQuery" clearable />
+        </view>
+        <view class="filter-button" @click="handleQuery">
+          <up-icon name="search" size="24" color="#999"></up-icon>
+        </view>
+      </view>
+    </view>
+
+    <!-- 鍞悗鍗曞垪琛� -->
+    <view class="ledger-list" v-if="tableData.length > 0">
+      <view v-for="(item, index) in tableData" :key="index" class="ledger-item" @click="handleRowClick(item)">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
+            </view>
+            <text class="item-id">{{ item.afterSalesServiceNo }}</text>
+          </view>
+          <view class="item-tag">
+            <up-tag :text="getStatusLabel(item.status)" :type="getStatusType(item.status)" size="mini"></up-tag>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row">
+            <text class="detail-label">閿�鍞崟鍙�</text>
+            <text class="detail-value">{{ item.salesContractNo }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">瀹㈡埛鍚嶇О</text>
+            <text class="detail-value">{{ item.customerName }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鍙嶉鏃ユ湡</text>
+            <text class="detail-value">{{ item.feedbackDate }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鍞悗绫诲瀷</text>
+            <text class="detail-value">{{ getDictLabel(post_sale_waiting_list, item.serviceType) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">绱ф�ョ▼搴�</text>
+            <text class="detail-value">{{ getDictLabel(degree_of_urgency, item.urgency) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鐧昏浜�</text>
+            <text class="detail-value">{{ item.checkNickName }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">闂鎻忚堪</text>
+            <text class="detail-value">{{ item.disRes }}</text>
+          </view>
+        </view>
+        <up-divider v-if="canEdit(item)"></up-divider>
+        <view class="detail-buttons" v-if="canEdit(item)">
+          <up-button size="small" type="primary" plain @click.stop="openForm('edit', item)">缂栬緫</up-button>
+          <up-button size="small" type="error" plain @click.stop="handleDelete(item)">鍒犻櫎</up-button>
+        </view>
+      </view>
+    </view>
+    <view v-else class="no-data">
+      <text>鏆傛棤鍞悗鐧昏鏁版嵁</text>
+    </view>
+
+    <!-- 娴姩鎿嶄綔鎸夐挳 -->
+    <view class="fab-button" @click="openForm('add')">
+      <up-icon name="plus" size="24" color="#ffffff"></up-icon>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted } from 'vue';
+import { onShow } from '@dcloudio/uni-app';
+import { afterSalesServiceListPage, afterSalesServiceDelete, getSalesLedgerDetail } from '@/api/customerService/index';
+import useUserStore from '@/store/modules/user';
+import PageHeader from '@/components/PageHeader.vue';
+import { useDict } from '@/utils/dict';
+
+const userStore = useUserStore();
+
+// 瀛楀吀
+const { post_sale_waiting_list, degree_of_urgency, work_order_status } = useDict(
+  'post_sale_waiting_list',
+  'degree_of_urgency',
+  'work_order_status'
+);
+
+const statsList = ref([
+  {
+    icon: 'file-text',
+    count: 0,
+    label: '鍏ㄩ儴宸ュ崟',
+    color: '#4080ff',
+    bgColor: '#eaf2ff'
+  },
+  {
+    icon: 'file-text',
+    count: 0,
+    label: '宸插鐞�',
+    color: '#ff9a2e',
+    bgColor: '#fff5e6'
+  },
+  {
+    icon: 'account',
+    count: 0,
+    label: '宸插畬鎴�',
+    color: '#00b42a',
+    bgColor: '#e6f7ed'
+  },
+]);
+
+const searchForm = reactive({
+  afterSalesServiceNo: '',
+  status: '',
+  urgency: '',
+  serviceType: '',
+  orderNo: '',
+});
+
+const tableData = ref([]);
+const loading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 20,
+  total: 0,
+});
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+
+const getList = () => {
+  loading.value = true;
+  uni.showLoading({ title: '鍔犺浇涓�...' });
+  
+  getStats();
+  
+  afterSalesServiceListPage({ ...searchForm, ...page })
+    .then((res) => {
+      const records = res?.data?.records ?? res?.records ?? [];
+      const total = res?.data?.total ?? res?.total ?? 0;
+      tableData.value = Array.isArray(records) ? records : [];
+      page.total = Number.isFinite(Number(total)) ? Number(total) : 0;
+    })
+    .finally(() => {
+      loading.value = false;
+      uni.hideLoading();
+    });
+};
+
+const getStats = () => {
+  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);
+    }
+  });
+};
+
+const getStatsCountByStatus = (list, status) => {
+  if (!Array.isArray(list)) return 0;
+  return list.find((item) => item?.status === status)?.count || 0;
+};
+
+const getStatusLabel = (status) => {
+  if (status === 1) return '寰呭鐞�';
+  if (status === 2) return '宸插鐞�';
+  return '鏈煡';
+};
+
+const getStatusType = (status) => {
+  if (status === 1) return 'error';
+  if (status === 2) return 'success';
+  return 'info';
+};
+
+const getDictLabel = (dict, value) => {
+  if (!dict || !dict.value) return value;
+  const item = dict.value.find(i => i.value == value);
+  return item ? item.label : value;
+};
+
+const canEdit = (row) => {
+  if (!row) return false;
+  return row.status === 1 && String(row.checkUserId) === String(userStore.id);
+}
+
+const handleRowClick = (row) => {
+  if (canEdit(row)) {
+    openForm('edit', row)
+    return
+  }
+  openForm('view', row)
+}
+
+const openForm = (type, row) => {
+  uni.setStorageSync('afterSalesOperationType', type);
+  if (row) {
+    uni.setStorageSync('afterSalesEditData', JSON.stringify(row));
+  } else {
+    uni.removeStorageSync('afterSalesEditData');
+  }
+  uni.navigateTo({
+    url: '/pages/customerService/feedbackRegistration/edit'
+  });
+};
+
+const handleDelete = (row) => {
+  if (row.checkUserId !== userStore.id) {
+    uni.showToast({ title: '涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�', icon: 'none' });
+    return;
+  }
+  
+  uni.showModal({
+    title: '鎻愮ず',
+    content: '閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�',
+    success: (res) => {
+      if (res.confirm) {
+        afterSalesServiceDelete([row.id]).then(() => {
+          uni.showToast({ title: '鍒犻櫎鎴愬姛', icon: 'success' });
+          getList();
+        });
+      }
+    }
+  });
+};
+
+onShow(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+
+.after-sales-registration {
+  min-height: 100vh;
+  background: #f8f9fa;
+}
+
+.stats-container {
+  display: flex;
+  gap: 10px;
+  padding: 15px 20px;
+  background: #ffffff;
+}
+
+.stat-card {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  padding: 12px 10px;
+  background-color: #f8f9fa;
+  border-radius: 8px;
+}
+
+.stat-icon {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 36px;
+  height: 36px;
+  border-radius: 6px;
+}
+
+.stat-info {
+  display: flex;
+  flex-direction: column;
+}
+
+.stat-number {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.stat-label {
+  font-size: 10px;
+  color: #909399;
+}
+
+.detail-buttons {
+  display: flex;
+  gap: 10px;
+  justify-content: flex-end;
+  padding: 12px 0;
+}
+
+.ledger-item {
+  padding: 0 16px;
+}
+</style>
diff --git a/src/pages/financialManagement/expenseManagement/edit.vue b/src/pages/financialManagement/expenseManagement/edit.vue
new file mode 100644
index 0000000..292957a
--- /dev/null
+++ b/src/pages/financialManagement/expenseManagement/edit.vue
@@ -0,0 +1,120 @@
+<template>
+  <view class="sales-account">
+    <PageHeader :title="pageTitle" @back="goBack" />
+    <view class="search-section">
+      <up-form :model="form" :rules="rules" ref="formRef">
+        <up-form-item label="鏀嚭鏃ユ湡" prop="expenseDate">
+          <uni-datetime-picker type="date" v-model="form.expenseDate" />
+        </up-form-item>
+        <up-form-item label="鏀嚭绫诲瀷" prop="expenseType">
+          <up-picker :columns="[expenseTypes]" key-name="label" v-model="expenseTypeIndex" @confirm="onExpenseTypeConfirm" />
+        </up-form-item>
+        <up-form-item label="渚涘簲鍟嗗悕绉�" prop="supplierName">
+          <up-input v-model="form.supplierName" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="鏀嚭閲戦" prop="expenseMoney">
+          <up-input type="number" v-model="form.expenseMoney" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="鏀嚭鎻忚堪" prop="expenseDescribed">
+          <up-input v-model="form.expenseDescribed" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="浠樻鏂瑰紡" prop="expenseMethod">
+          <up-picker :columns="[checkoutPayment]" key-name="label" v-model="expenseMethodIndex" @confirm="onMethodConfirm" />
+        </up-form-item>
+        <up-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
+          <up-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="澶囨敞" prop="note">
+          <up-textarea v-model="form.note" placeholder="璇疯緭鍏�" autoHeight />
+        </up-form-item>
+      </up-form>
+      <view class="actions">
+        <u-button type="primary" @click="submitForm">淇濆瓨</u-button>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import { onLoad } from "@dcloudio/uni-app";
+import { useDict } from "@/utils/dict";
+import { add, update, getAccountExpense } from "@/api/financialManagement/expenseManagement";
+
+const operationType = ref("add");
+const id = ref(undefined);
+
+const { checkout_payment, expense_types } = useDict("checkout_payment", "expense_types");
+const checkoutPayment = ref([]);
+const expenseTypes = ref([]);
+const expenseTypeIndex = ref([0]);
+const expenseMethodIndex = ref([0]);
+
+const formRef = ref();
+const form = reactive({
+  expenseDate: undefined,
+  expenseType: undefined,
+  supplierName: "",
+  expenseMoney: undefined,
+  expenseDescribed: "",
+  expenseMethod: undefined,
+  invoiceNumber: "",
+  note: "",
+});
+
+const rules = {
+  expenseDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+  expenseType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+  supplierName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  expenseMoney: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  expenseDescribed: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  expenseMethod: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+};
+
+const pageTitle = computed(() => (operationType.value === "edit" ? "缂栬緫鏀嚭" : "鏂板鏀嚭"));
+
+const onExpenseTypeConfirm = (e) => {
+  const item = expenseTypes.value[e.value[0]];
+  if (item) form.expenseType = item.value;
+};
+const onMethodConfirm = (e) => {
+  const item = checkoutPayment.value[e.value[0]];
+  if (item) form.expenseMethod = item.value;
+};
+
+const syncDict = () => {
+  checkoutPayment.value = (checkout_payment?.value || []).map(i => ({ label: i.label, value: i.value }));
+  expenseTypes.value = (expense_types?.value || []).map(i => ({ label: i.label, value: i.value }));
+};
+
+const submitForm = () => {
+  formRef.value?.validate(async (valid) => {
+    if (!valid) return;
+    const payload = { ...form };
+    const res = operationType.value === "edit" ? await update({ id: id.value, ...payload }) : await add(payload);
+    if (res?.code === 200) {
+      uni.navigateBack();
+    }
+  });
+};
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+onLoad(async (query) => {
+  syncDict();
+  operationType.value = query?.type || "add";
+  if (query?.id) {
+    id.value = query.id;
+    const res = await getAccountExpense(id.value);
+    const data = res?.data ?? res;
+    Object.assign(form, data || {});
+  }
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+.actions { margin-top: 16px; }
+</style>
diff --git a/src/pages/financialManagement/expenseManagement/index.vue b/src/pages/financialManagement/expenseManagement/index.vue
new file mode 100644
index 0000000..397414b
--- /dev/null
+++ b/src/pages/financialManagement/expenseManagement/index.vue
@@ -0,0 +1,149 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="鏀嚭绠$悊" @back="goBack" />
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <uni-datetime-picker type="daterange" v-model="filters.entryDate" @change="onDateChange" />
+        </view>
+        <view class="search-input">
+          <up-input readonly placeholder="浠樻鏂瑰紡" v-model="expenseMethodLabel" @click="methodPickerShow = true" />
+        </view>
+        <view class="filter-button" @click="getList">
+          <up-icon name="search" size="24" color="#999" />
+        </view>
+      </view>
+    <view class="actions">
+        <u-button type="primary" size="small" @click="goAdd">鏂板</u-button>
+      </view>
+    </view>
+    <view class="ledger-list" v-if="list.length>0">
+      <view class="ledger-item" v-for="item in list" :key="item.id">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon"><up-icon name="file-text" color="#fff" size="16" /></view>
+            <text class="item-id">{{ item.supplierName || '--' }}</text>
+          </view>
+          <view class="item-tag">
+            <u-tag>{{ methodText(item.expenseMethod) }}</u-tag>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row"><text class="detail-label">鏀嚭鏃ユ湡</text><text class="detail-value">{{ item.expenseDate || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">鏀嚭绫诲瀷</text><text class="detail-value">{{ expenseTypeText(item.expenseType) || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">鏀嚭閲戦(鍏�)</text><text class="detail-value highlight">{{ fmtAmount(item.expenseMoney) }}</text></view>
+          <view class="detail-row"><text class="detail-label">鍙戠エ鍙风爜</text><text class="detail-value">{{ item.invoiceNumber || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">澶囨敞</text><text class="detail-value">{{ item.note || '--' }}</text></view>
+        </view>
+        <view class="card-actions">
+          <u-button size="small" @click="goEdit(item)" :disabled="!!item.businessId">缂栬緫</u-button>
+          <u-button size="small" type="error" @click="confirmDelete(item)" :disabled="!!item.businessId">鍒犻櫎</u-button>
+        </view>
+      </view>
+    </view>
+    <view class="no-data" v-else><text>鏆傛棤鏁版嵁</text></view>
+
+    <up-action-sheet :show="methodPickerShow" :actions="checkoutPayment" title="浠樻鏂瑰紡" @select="onSelectMethod" @close="methodPickerShow=false" />
+  </view>
+  </template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { onShow } from "@dcloudio/uni-app";
+import { listPage, delAccountExpense } from "@/api/financialManagement/expenseManagement";
+import { useDict } from "@/utils/dict";
+
+const list = ref([]);
+const filters = reactive({ entryDate: null, expenseMethod: undefined, entryDateStart: undefined, entryDateEnd: undefined });
+const { checkout_payment, expense_types } = useDict("checkout_payment", "expense_types");
+const checkoutPayment = ref([]);
+const expenseTypes = ref([]);
+const methodPickerShow = ref(false);
+const expenseMethodLabel = ref("");
+
+const syncDict = () => {
+  checkoutPayment.value = (checkout_payment?.value || []).map(i => ({ label: i.label, value: i.value }));
+  expenseTypes.value = (expense_types?.value || []).map(i => ({ label: i.label, value: i.value }));
+};
+
+const getList = () => {
+  listPage({ expenseMethod: filters.expenseMethod, entryDateStart: filters.entryDateStart, entryDateEnd: filters.entryDateEnd, current: 1, size: 100 })
+    .then(res => {
+      const records = res?.data?.records ?? res?.records ?? [];
+      list.value = records;
+    });
+};
+
+const onDateChange = (val) => {
+  if (val && val.length === 2) {
+    filters.entryDateStart = val[0];
+    filters.entryDateEnd = val[1];
+  } else {
+    filters.entryDateStart = undefined;
+    filters.entryDateEnd = undefined;
+  }
+};
+
+const onSelectMethod = (e) => {
+  filters.expenseMethod = e.value;
+  expenseMethodLabel.value = e.label;
+  methodPickerShow.value = false;
+};
+
+const methodText = (v) => {
+  const m = checkoutPayment.value.find(i=>String(i.value)===String(v));
+  return m?.label || "--";
+};
+const expenseTypeText = (v) => {
+  const m = expenseTypes.value.find(i=>String(i.value)===String(v));
+  return m?.label || null;
+};
+const fmtAmount = (v) => {
+  const n = parseFloat(v || 0);
+  return n.toFixed(2);
+};
+
+const goAdd = () => {
+  uni.navigateTo({ url: "/pages/financialManagement/expenseManagement/edit?type=add" });
+};
+const goEdit = (row) => {
+  uni.navigateTo({ url: `/pages/financialManagement/expenseManagement/edit?type=edit&id=${row.id}` });
+};
+const confirmDelete = (row) => {
+  uni.showModal({
+    title: "鎻愮ず",
+    content: "纭鍒犻櫎璇ヨ褰曪紵",
+    success: async (r) => {
+      if (r.confirm) {
+        const ids = Array.isArray(row) ? row.map(i=>i.id) : [row.id];
+        const res = await delAccountExpense(ids);
+        if (res?.code === 200) getList();
+      }
+    },
+  });
+};
+
+const onExpenseTypeConfirm = (e) => {
+  const item = expenseTypes.value[e.value[0]];
+  if (item) form.expenseType = item.value;
+};
+const onMethodConfirm = (e) => {
+  const item = checkoutPayment.value[e.value[0]];
+  if (item) form.expenseMethod = item.value;
+};
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+syncDict();
+onShow(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+.actions { margin-top: 8px; }
+</style>
diff --git a/src/pages/financialManagement/loanManagement/edit.vue b/src/pages/financialManagement/loanManagement/edit.vue
new file mode 100644
index 0000000..a5226ed
--- /dev/null
+++ b/src/pages/financialManagement/loanManagement/edit.vue
@@ -0,0 +1,87 @@
+<template>
+  <view class="sales-account">
+    <PageHeader :title="pageTitle" @back="goBack" />
+    <view class="search-section">
+      <up-form :model="form" :rules="rules" ref="formRef">
+        <up-form-item label="鍊熸浜哄鍚�" prop="borrowerName">
+          <up-input v-model="form.borrowerName" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="鍊熸閲戦(鍏�)" prop="borrowAmount">
+          <up-input type="number" v-model="form.borrowAmount" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="鍊熸鍒╃巼(%)" prop="interestRate">
+          <up-input type="number" v-model="form.interestRate" placeholder="渚嬪 5.85" />
+        </up-form-item>
+        <up-form-item label="鍊熸鏃ユ湡" prop="borrowDate">
+          <uni-datetime-picker type="date" v-model="form.borrowDate" />
+        </up-form-item>
+        <up-form-item v-if="operationType==='repay'" label="瀹為檯杩樻鏃ユ湡" prop="repayDate">
+          <uni-datetime-picker type="date" v-model="form.repayDate" />
+        </up-form-item>
+        <up-form-item label="澶囨敞" prop="remark">
+          <up-textarea v-model="form.remark" autoHeight />
+        </up-form-item>
+      </up-form>
+      <view class="actions">
+        <u-button type="primary" @click="submitForm">淇濆瓨</u-button>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import { onLoad } from "@dcloudio/uni-app";
+import { add, update } from "@/api/financialManagement/loanManagement";
+
+const operationType = ref("add");
+const id = ref(undefined);
+
+const formRef = ref();
+const form = reactive({
+  borrowerName: "",
+  borrowAmount: undefined,
+  interestRate: undefined,
+  borrowDate: undefined,
+  repayDate: undefined,
+  remark: "",
+});
+
+const rules = {
+  borrowerName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  borrowAmount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  interestRate: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  borrowDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+  repayDate: [{ validator: (_r, v, cb) => { if (operationType.value==='repay' && !v) return cb(new Error('璇烽�夋嫨')); cb(); }, trigger: "change" }],
+};
+
+const pageTitle = computed(() => operationType.value==='repay' ? "杩樻" : operationType.value==='edit' ? "缂栬緫鍊熸" : "鏂板鍊熸");
+
+const submitForm = () => {
+  formRef.value?.validate(async (valid) => {
+    if (!valid) return;
+    const payload = operationType.value==='repay' ? { ...form, status: 2 } : { ...form };
+    const res = operationType.value==='add' ? await add(payload) : await update({ id: id.value, ...payload });
+    if (res?.code === 200) {
+      uni.navigateBack();
+    }
+  });
+};
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+onLoad((query) => {
+  operationType.value = query?.type || "add";
+  if (query?.id) {
+    id.value = query.id;
+    // 閫氳繃瀵艰埅鍙傛暟鎼哄甫鐨勫瓧娈靛洖濉敱 index 椤靛喅瀹氾紝杩欓噷浠呬繚鐣欐渶绠�閫昏緫
+  }
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+.actions { margin-top: 16px; }
+</style>
diff --git a/src/pages/financialManagement/loanManagement/index.vue b/src/pages/financialManagement/loanManagement/index.vue
new file mode 100644
index 0000000..5383b9c
--- /dev/null
+++ b/src/pages/financialManagement/loanManagement/index.vue
@@ -0,0 +1,196 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="鍊熸绠$悊" @back="goBack" />
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input v-model="filters.borrowerName" placeholder="鍊熸浜哄鍚�" clearable />
+        </view>
+        <view class="search-input">
+          <uni-datetime-picker type="daterange" v-model="filters.borrowDate" @change="onDateChange" />
+        </view>
+        <view class="search-input">
+          <up-picker :columns="[statusOptions]" key-name="label" v-model="statusIndex" @confirm="onStatusConfirm">
+            <up-input readonly :value="statusLabel" placeholder="鍊熸鐘舵��" />
+          </up-picker>
+        </view>
+        <view class="filter-button" @click="getList">
+          <up-icon name="search" size="24" color="#999" />
+        </view>
+      </view>
+    <view class="actions">
+        <u-button type="primary" size="small" @click="goAdd">鏂板</u-button>
+      </view>
+    </view>
+    <view class="ledger-list" v-if="list.length>0">
+      <view class="ledger-item" v-for="item in list" :key="item.id">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon"><up-icon name="file-text" color="#fff" size="16" /></view>
+            <text class="item-id">{{ item.borrowerName || '--' }}</text>
+          </view>
+          <view class="item-tag">
+            <u-tag :type="statusType(item.status)">{{ statusText(item.status) }}</u-tag>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row"><text class="detail-label">鍊熸閲戦(鍏�)</text><text class="detail-value highlight">{{ fmtAmount(item.borrowAmount) }}</text></view>
+          <view class="detail-row"><text class="detail-label">鍊熸鍒╃巼(%)</text><text class="detail-value">{{ fmtRate(item.interestRate) }}</text></view>
+          <view class="detail-row"><text class="detail-label">鍊熸鏃ユ湡</text><text class="detail-value">{{ item.borrowDate || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">瀹為檯杩樻鏃ユ湡</text><text class="detail-value">{{ item.repayDate || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">澶囨敞</text><text class="detail-value">{{ item.remark || '--' }}</text></view>
+        </view>
+        <view class="card-actions">
+          <u-button size="small" @click="goEdit(item)">缂栬緫</u-button>
+          <u-button size="small" type="warning" @click="goRepay(item)" :disabled="item.status!==1">杩樻</u-button>
+          <u-button size="small" type="error" @click="confirmDelete(item)">鍒犻櫎</u-button>
+        </view>
+      </view>
+    </view>
+    <view class="no-data" v-else><text>鏆傛棤鏁版嵁</text></view>
+
+    <up-popup :show="formShow" mode="bottom" @close="closeForm">
+      <view class="popup">
+        <view class="popup-header">{{ formMode==='add'?'鏂板鍊熸': formMode==='repay'?'杩樻':'缂栬緫鍊熸' }}</view>
+        <up-form :model="form" :rules="rules" ref="formRef">
+          <up-form-item label="鍊熸浜哄鍚�" prop="borrowerName">
+            <up-input v-model="form.borrowerName" placeholder="璇疯緭鍏�" />
+          </up-form-item>
+          <up-form-item label="鍊熸閲戦" prop="borrowAmount">
+            <up-input type="number" v-model="form.borrowAmount" placeholder="璇疯緭鍏�" />
+          </up-form-item>
+          <up-form-item label="鍊熸鍒╃巼(%)" prop="interestRate">
+            <up-input type="number" v-model="form.interestRate" placeholder="渚嬪 5.85" />
+          </up-form-item>
+          <up-form-item label="鍊熸鏃ユ湡" prop="borrowDate">
+            <uni-datetime-picker type="date" v-model="form.borrowDate" />
+          </up-form-item>
+          <up-form-item v-if="formMode==='repay'" label="瀹為檯杩樻鏃ユ湡" prop="repayDate">
+            <uni-datetime-picker type="date" v-model="form.repayDate" />
+          </up-form-item>
+          <up-form-item label="澶囨敞" prop="remark">
+            <up-textarea v-model="form.remark" autoHeight />
+          </up-form-item>
+        </up-form>
+        <view class="popup-actions">
+          <u-button @click="closeForm">鍙栨秷</u-button>
+          <u-button type="primary" @click="submitForm">淇濆瓨</u-button>
+        </view>
+      </view>
+    </up-popup>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { onShow } from "@dcloudio/uni-app";
+import { listPage, delAccountLoan } from "@/api/financialManagement/loanManagement";
+
+const list = ref([]);
+const filters = reactive({ borrowerName: "", borrowDate: null, entryDateStart: undefined, entryDateEnd: undefined, status: undefined });
+const statusOptions = ref([{ label: "鍏ㄩ儴", value: undefined }, { label: "寰呰繕娆�", value: 1 }, { label: "宸茶繕娆�", value: 2 }]);
+const statusIndex = ref([0]);
+const statusLabel = ref("");
+
+const formShow = ref(false);
+const formMode = ref("add");
+const formRef = ref();
+const form = reactive({
+  id: undefined,
+  borrowerName: "",
+  borrowAmount: undefined,
+  interestRate: undefined,
+  borrowDate: undefined,
+  repayDate: undefined,
+  remark: "",
+  status: undefined,
+});
+const rules = {
+  borrowerName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  borrowAmount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  interestRate: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  borrowDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+  repayDate: [{ validator: (_r, v, cb)=>{ if (formMode.value==='repay' && !v) return cb(new Error('璇烽�夋嫨')); cb(); }, trigger: "change" }],
+};
+
+const getList = () => {
+  const extra = {};
+  if (filters.entryDateStart && filters.entryDateEnd) {
+    extra.entryDateStart = filters.entryDateStart;
+    extra.entryDateEnd = filters.entryDateEnd;
+  }
+  if (filters.status) extra.status = filters.status;
+  listPage({ borrowerName: filters.borrowerName, ...extra, current: 1, size: 100 })
+    .then(res => {
+      const records = res?.data?.records ?? res?.records ?? [];
+      list.value = records;
+    });
+};
+
+const onDateChange = (val) => {
+  if (val && val.length === 2) {
+    filters.entryDateStart = val[0];
+    filters.entryDateEnd = val[1];
+  } else {
+    filters.entryDateStart = undefined;
+    filters.entryDateEnd = undefined;
+  }
+};
+
+const statusText = (s) => s===1?'寰呰繕娆�': s===2?'宸茶繕娆�':'';
+const statusType = (s) => s===1?'error': s===2?'success':'primary';
+const fmtAmount = (v) => {
+  const n = parseFloat(v || 0);
+  return n.toFixed(2);
+};
+const fmtRate = (v) => {
+  if (v===undefined || v===null || v==='') return '-';
+  const n = parseFloat(v);
+  return n.toFixed(2) + '%';
+};
+
+const goAdd = () => {
+  uni.navigateTo({ url: "/pages/financialManagement/loanManagement/edit?type=add" });
+};
+const goEdit = (row) => {
+  uni.navigateTo({ url: `/pages/financialManagement/loanManagement/edit?type=edit&id=${row.id}` });
+};
+const goRepay = (row) => {
+  uni.navigateTo({ url: `/pages/financialManagement/loanManagement/edit?type=repay&id=${row.id}` });
+};
+const confirmDelete = (row) => {
+  uni.showModal({
+    title: "鎻愮ず",
+    content: "纭鍒犻櫎璇ヨ褰曪紵",
+    success: async (r) => {
+      if (r.confirm) {
+        const ids = Array.isArray(row) ? row.map(i=>i.id) : [row.id];
+        const res = await delAccountLoan(ids);
+        if (res?.code === 200) getList();
+      }
+    },
+  });
+};
+
+const onStatusConfirm = (e) => {
+  const item = statusOptions.value[e.value[0]];
+  if (item) {
+    filters.status = item.value;
+    statusLabel.value = item.label || "";
+  }
+};
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+onShow(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+.actions { margin-top: 8px; }
+</style>
diff --git a/src/pages/financialManagement/revenueManagement/edit.vue b/src/pages/financialManagement/revenueManagement/edit.vue
new file mode 100644
index 0000000..869e12c
--- /dev/null
+++ b/src/pages/financialManagement/revenueManagement/edit.vue
@@ -0,0 +1,120 @@
+<template>
+  <view class="sales-account">
+    <PageHeader :title="pageTitle" @back="goBack" />
+    <view class="search-section">
+      <up-form :model="form" :rules="rules" ref="formRef">
+        <up-form-item label="鏀跺叆鏃ユ湡" prop="incomeDate">
+          <uni-datetime-picker type="date" v-model="form.incomeDate" />
+        </up-form-item>
+        <up-form-item label="鏀跺叆绫诲瀷" prop="incomeType">
+          <up-picker :columns="[incomeTypes]" key-name="label" v-model="incomeTypeIndex" @confirm="onIncomeTypeConfirm" />
+        </up-form-item>
+        <up-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+          <up-input v-model="form.customerName" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="鏀跺叆閲戦" prop="incomeMoney">
+          <up-input type="number" v-model="form.incomeMoney" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="鏀跺叆鎻忚堪" prop="incomeDescribed">
+          <up-input v-model="form.incomeDescribed" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="鏀舵鏂瑰紡" prop="incomeMethod">
+          <up-picker :columns="[paymentMethods]" key-name="label" v-model="incomeMethodIndex" @confirm="onMethodConfirm" />
+        </up-form-item>
+        <up-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
+          <up-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
+        </up-form-item>
+        <up-form-item label="澶囨敞" prop="note">
+          <up-textarea v-model="form.note" placeholder="璇疯緭鍏�" autoHeight />
+        </up-form-item>
+      </up-form>
+      <view class="actions">
+        <u-button type="primary" @click="submitForm">淇濆瓨</u-button>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import { onLoad } from "@dcloudio/uni-app";
+import { useDict } from "@/utils/dict";
+import { add, update, getAccountIncome } from "@/api/financialManagement/revenueManagement";
+
+const operationType = ref("add");
+const id = ref(undefined);
+
+const { payment_methods, income_types } = useDict("payment_methods", "income_types");
+const paymentMethods = ref([]);
+const incomeTypes = ref([]);
+const incomeTypeIndex = ref([0]);
+const incomeMethodIndex = ref([0]);
+
+const formRef = ref();
+const form = reactive({
+  incomeDate: undefined,
+  incomeType: undefined,
+  customerName: "",
+  incomeMoney: undefined,
+  incomeDescribed: "",
+  incomeMethod: undefined,
+  invoiceNumber: "",
+  note: "",
+});
+
+const rules = {
+  incomeDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+  incomeType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+  customerName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  incomeMoney: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  incomeDescribed: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  incomeMethod: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+};
+
+const pageTitle = computed(() => (operationType.value === "edit" ? "缂栬緫鏀跺叆" : "鏂板鏀跺叆"));
+
+const onIncomeTypeConfirm = (e) => {
+  const item = incomeTypes.value[e.value[0]];
+  if (item) form.incomeType = item.value;
+};
+const onMethodConfirm = (e) => {
+  const item = paymentMethods.value[e.value[0]];
+  if (item) form.incomeMethod = item.value;
+};
+
+const syncDict = () => {
+  paymentMethods.value = (payment_methods?.value || []).map(i => ({ label: i.label, value: i.value }));
+  incomeTypes.value = (income_types?.value || []).filter(i=>i.value!=3).map(i => ({ label: i.label, value: i.value }));
+};
+
+const submitForm = () => {
+  formRef.value?.validate(async (valid) => {
+    if (!valid) return;
+    const payload = { ...form };
+    const res = operationType.value === "edit" ? await update({ id: id.value, ...payload }) : await add(payload);
+    if (res?.code === 200) {
+      uni.navigateBack();
+    }
+  });
+};
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+onLoad(async (query) => {
+  syncDict();
+  operationType.value = query?.type || "add";
+  if (query?.id) {
+    id.value = query.id;
+    const res = await getAccountIncome(id.value);
+    const data = res?.data ?? res;
+    Object.assign(form, data || {});
+  }
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+.actions { margin-top: 16px; }
+</style>
diff --git a/src/pages/financialManagement/revenueManagement/index.vue b/src/pages/financialManagement/revenueManagement/index.vue
new file mode 100644
index 0000000..e7a4de5
--- /dev/null
+++ b/src/pages/financialManagement/revenueManagement/index.vue
@@ -0,0 +1,149 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="鏀跺叆绠$悊" @back="goBack" />
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <uni-datetime-picker type="daterange" v-model="filters.entryDate" @change="onDateChange" />
+        </view>
+        <view class="search-input">
+          <up-input readonly placeholder="鏀舵鏂瑰紡" v-model="incomeMethodLabel" @click="methodPickerShow = true" />
+        </view>
+        <view class="filter-button" @click="getList">
+          <up-icon name="search" size="24" color="#999" />
+        </view>
+      </view>
+    <view class="actions">
+        <u-button type="primary" size="small" @click="goAdd">鏂板</u-button>
+    </view>
+    </view>
+    <view class="ledger-list" v-if="list.length>0">
+      <view class="ledger-item" v-for="item in list" :key="item.id">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon"><up-icon name="file-text" color="#fff" size="16" /></view>
+            <text class="item-id">{{ item.customerName || '--' }}</text>
+          </view>
+          <view class="item-tag">
+            <u-tag>{{ methodText(item.incomeMethod) }}</u-tag>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row"><text class="detail-label">鏀跺叆鏃ユ湡</text><text class="detail-value">{{ item.incomeDate || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">鏀跺叆绫诲瀷</text><text class="detail-value">{{ incomeTypeText(item.incomeType) || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">鏀跺叆閲戦(鍏�)</text><text class="detail-value highlight">{{ fmtAmount(item.incomeMoney) }}</text></view>
+          <view class="detail-row"><text class="detail-label">鍙戠エ鍙风爜</text><text class="detail-value">{{ item.invoiceNumber || '--' }}</text></view>
+          <view class="detail-row"><text class="detail-label">澶囨敞</text><text class="detail-value">{{ item.note || '--' }}</text></view>
+        </view>
+        <view class="card-actions">
+          <u-button size="small" @click="goEdit(item)" :disabled="!!item.businessId">缂栬緫</u-button>
+          <u-button size="small" type="error" @click="confirmDelete(item)" :disabled="!!item.businessId">鍒犻櫎</u-button>
+        </view>
+      </view>
+    </view>
+    <view class="no-data" v-else><text>鏆傛棤鏁版嵁</text></view>
+
+    <up-action-sheet :show="methodPickerShow" :actions="paymentMethods" title="鏀舵鏂瑰紡" @select="onSelectMethod" @close="methodPickerShow=false" />
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { onShow } from "@dcloudio/uni-app";
+import { listPage, delAccountIncome } from "@/api/financialManagement/revenueManagement";
+import { useDict } from "@/utils/dict";
+
+const list = ref([]);
+const filters = reactive({ entryDate: null, incomeMethod: undefined, entryDateStart: undefined, entryDateEnd: undefined });
+const { payment_methods, income_types } = useDict("payment_methods", "income_types");
+const paymentMethods = ref([]);
+const incomeTypes = ref([]);
+const methodPickerShow = ref(false);
+const incomeMethodLabel = ref("");
+
+const syncDict = () => {
+  paymentMethods.value = (payment_methods?.value || []).map(i => ({ label: i.label, value: i.value }));
+  incomeTypes.value = (income_types?.value || []).filter(i=>i.value!=3).map(i => ({ label: i.label, value: i.value }));
+};
+
+const getList = () => {
+  listPage({ incomeMethod: filters.incomeMethod, entryDateStart: filters.entryDateStart, entryDateEnd: filters.entryDateEnd, current: 1, size: 100 })
+    .then(res => {
+      const records = res?.data?.records ?? res?.records ?? [];
+      list.value = records;
+    });
+};
+
+const onDateChange = (val) => {
+  if (val && val.length === 2) {
+    filters.entryDateStart = val[0];
+    filters.entryDateEnd = val[1];
+  } else {
+    filters.entryDateStart = undefined;
+    filters.entryDateEnd = undefined;
+  }
+};
+
+const onSelectMethod = (e) => {
+  filters.incomeMethod = e.value;
+  incomeMethodLabel.value = e.label;
+  methodPickerShow.value = false;
+};
+
+const methodText = (v) => {
+  const m = paymentMethods.value.find(i=>String(i.value)===String(v));
+  return m?.label || "--";
+};
+const incomeTypeText = (v) => {
+  const m = incomeTypes.value.find(i=>String(i.value)===String(v));
+  return m?.label || null;
+};
+const fmtAmount = (v) => {
+  const n = parseFloat(v || 0);
+  return n.toFixed(2);
+};
+
+const goAdd = () => {
+  uni.navigateTo({ url: "/pages/financialManagement/revenueManagement/edit?type=add" });
+};
+const goEdit = (row) => {
+  uni.navigateTo({ url: `/pages/financialManagement/revenueManagement/edit?type=edit&id=${row.id}` });
+};
+const confirmDelete = (row) => {
+  uni.showModal({
+    title: "鎻愮ず",
+    content: "纭鍒犻櫎璇ヨ褰曪紵",
+    success: async (r) => {
+      if (r.confirm) {
+        const ids = Array.isArray(row) ? row.map(i=>i.id) : [row.id];
+        const res = await delAccountIncome(ids);
+        if (res?.code === 200) getList();
+      }
+    },
+  });
+};
+
+const onIncomeTypeConfirm = (e) => {
+  const item = incomeTypes.value[e.value[0]];
+  if (item) form.incomeType = item.value;
+};
+const onMethodConfirm = (e) => {
+  const item = paymentMethods.value[e.value[0]];
+  if (item) form.incomeMethod = item.value;
+};
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
+syncDict();
+onShow(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/sales-common.scss";
+.actions { margin-top: 8px; }
+</style>
diff --git a/src/pages/productionManagement/productionDispatching/components/formDia.vue b/src/pages/productionManagement/productionDispatching/components/formDia.vue
index a60f751..72227ac 100644
--- a/src/pages/productionManagement/productionDispatching/components/formDia.vue
+++ b/src/pages/productionManagement/productionDispatching/components/formDia.vue
@@ -94,7 +94,7 @@
 import {getStaffJoinInfo, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js";
 import {userListNoPageByTenantId} from "@/api/system/user.js";
 import {productionDispatch} from "@/api/productionManagement/productionOrder.js";
-import useUserStore from "@/store/modules/user.js";
+import useUserStore from "@/store/modules/user";
 import dayjs from "dayjs";
 const { proxy } = getCurrentInstance()
 const emit = defineEmits(['close'])
diff --git a/src/pages/works.vue b/src/pages/works.vue
index 41aad95..76ffe24 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -301,10 +301,6 @@
       icon: "/static/images/icon/caigouguanli.svg",
       label: "閲囪喘閫�璐�",
     },
-    {
-      icon: "/static/images/icon/gongchuguanli.svg",
-      label: "渚涘簲鍟嗘。妗�",
-    },
   ]);
 
   // 璐㈠姟绠$悊鍔熻兘鏁版嵁
@@ -341,14 +337,38 @@
       icon: "/static/images/icon/fukuanliushui.svg",
       label: "浠樻娴佹按",
     },
+    {
+      icon: "/static/images/icon/huikuandengji.svg",
+      label: "鏀跺叆绠$悊",
+    },
+    {
+      icon: "/static/images/icon/fukuandengji.svg",
+      label: "鏀嚭绠$悊",
+    },
+    {
+      icon: "/static/images/icon/huikuanliushui.svg",
+      label: "鍊熸绠$悊",
+    },
   ]);
 
   // 妗f绠$悊鍔熻兘鏁版嵁
   const archiveManagementItems = reactive([
+    {
+      icon: "/static/images/icon/gongchuguanli.svg",
+      label: "渚涘簲鍟嗘。妗�",
+    },
   ]);
 
   // 鍞悗鏈嶅姟鍔熻兘鏁版嵁
   const afterSalesServiceItems = reactive([
+    {
+      icon: "/static/images/icon/xiaoshoutaizhang.svg",
+      label: "鍙嶉鐧昏",
+    },
+    {
+      icon: "/static/images/icon/caigouguanli.svg",
+      label: "鍞悗澶勭悊",
+    },
   ]);
 
   const humanResourcesItems = reactive([
@@ -550,6 +570,21 @@
       case "浠樻娴佹按":
         uni.navigateTo({
           url: "/pages/procurementManagement/receiptPaymentHistory/index",
+        });
+        break;
+      case "鏀跺叆绠$悊":
+        uni.navigateTo({
+          url: "/pages/financialManagement/revenueManagement/index",
+        });
+        break;
+      case "鏀嚭绠$悊":
+        uni.navigateTo({
+          url: "/pages/financialManagement/expenseManagement/index",
+        });
+        break;
+      case "鍊熸绠$悊":
+        uni.navigateTo({
+          url: "/pages/financialManagement/loanManagement/index",
         });
         break;
       case "渚涘簲鍟嗗線鏉�":
@@ -810,6 +845,16 @@
           url: "/pages/qualityManagement/finalInspection/index",
         });
         break;
+      case "鍙嶉鐧昏":
+        uni.navigateTo({
+          url: "/pages/customerService/feedbackRegistration/index",
+        });
+        break;
+      case "鍞悗澶勭悊":
+        uni.navigateTo({
+          url: "/pages/customerService/afterSalesHandling/index",
+        });
+        break;
       default:
         uni.showToast({
           title: `鐐瑰嚮浜�${item.label}`,
@@ -998,6 +1043,7 @@
     // 瀹氫箟鑿滃崟閰嶇疆鏄犲皠
     const menuMapping = {
       collaboration: { target: collaborationItems, specialMapping: { "瑙勭珷鍒跺害": "瑙勭珷鍒跺害绠$悊" } },
+      archiveManagement: { target: archiveManagementItems, specialMapping: { "渚涘簲鍟嗘。妗�": "渚涘簲鍟嗙鐞�" } },
     };
     console.log(allowedMenuTitles)
     // 閫氱敤杩囨护鍑芥暟
@@ -1016,8 +1062,7 @@
     filterArray(marketingItems);
     filterArray(purchaseItems);
     filterArray(financeManagementItems);
-    filterArray(archiveManagementItems);
-    filterArray(afterSalesServiceItems);
+    filterArray(archiveManagementItems, menuMapping.archiveManagement.specialMapping);
     filterArray(collaborationItems, menuMapping.collaboration.specialMapping);
     filterArray(safetyItems);
     filterArray(humanResourcesItems);
@@ -1030,8 +1075,8 @@
   const hasMarketingItems = computed(() => marketingItems.length > 0);
   const hasPurchaseItems = computed(() => purchaseItems.length > 0);
   const hasFinanceManagementItems = computed(() => financeManagementItems.length > 0);
-  const hasArchiveManagementItems = computed(() => true);
-  const hasAfterSalesServiceItems = computed(() => true);
+  const hasArchiveManagementItems = computed(() => archiveManagementItems.length > 0);
+  const hasAfterSalesServiceItems = computed(() => afterSalesServiceItems.length > 0);
   const hasCollaborationItems = computed(() => collaborationItems.length > 0);
   const hasSafetyItems = computed(() => safetyItems.length > 0);
   const hasQualityItems = computed(() => qualityItems.length > 0);

--
Gitblit v1.9.3