From ea34f049755d89386a342f0eceb58a6bc4b23b91 Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期一, 23 三月 2026 16:55:31 +0800
Subject: [PATCH] feat: 新增采购退货单与供应商管理功能

---
 src/pages.json                                                      |   44 +
 src/pages/basicData/supplierManage/index.vue                        |  197 ++++++
 src/pages/procurementManagement/purchaseReturnOrder/add.vue         |  758 ++++++++++++++++++++++++
 src/pages/procurementManagement/purchaseReturnOrder/productList.vue |  163 +++++
 src/pages/works.vue                                                 |   23 
 .vscode/settings.json                                               |   15 
 src/pages/indexItem.vue                                             |    4 
 src/pages/procurementManagement/purchaseReturnOrder/view.vue        |  202 ++++++
 src/pages/basicData/supplierManage/edit.vue                         |  216 ++++++
 src/pages/procurementManagement/purchaseReturnOrder/index.vue       |  185 +++++
 src/api/procurementManagement/purchaseReturnOrder.js                |   31 +
 11 files changed, 1,834 insertions(+), 4 deletions(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..17ea60e
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,15 @@
+{
+    "i18n-ally.localesPaths": [
+        "src/pages_template/common/locales",
+        "src/uni_modules/uni-table/i18n",
+        "src/uni_modules/uni-countdown/components/uni-countdown/i18n",
+        "src/uni_modules/uni-calendar/components/uni-calendar/i18n",
+        "src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n",
+        "src/uni_modules/uni-fav/components/uni-fav/i18n",
+        "src/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n",
+        "src/uni_modules/uni-load-more/components/uni-load-more/i18n",
+        "src/uni_modules/uni-popup/components/uni-popup/i18n",
+        "src/uni_modules/uni-pagination/components/uni-pagination/i18n",
+        "src/uni_modules/uni-search-bar/components/uni-search-bar/i18n"
+    ]
+}
\ No newline at end of file
diff --git a/src/api/procurementManagement/purchaseReturnOrder.js b/src/api/procurementManagement/purchaseReturnOrder.js
new file mode 100644
index 0000000..80d171f
--- /dev/null
+++ b/src/api/procurementManagement/purchaseReturnOrder.js
@@ -0,0 +1,31 @@
+import request from "@/utils/request";
+
+export function findPurchaseReturnOrderListPage(query) {
+  return request({
+    url: "/purchaseReturnOrders/listPage",
+    method: "get",
+    params: query,
+  });
+}
+
+export function createPurchaseReturnOrder(data) {
+  return request({
+    url: "/purchaseReturnOrders/add",
+    method: "post",
+    data,
+  });
+}
+
+export function getPurchaseReturnOrderDetail(id) {
+  return request({
+    url: "/purchaseReturnOrders/selectById/" + id,
+    method: "get",
+  });
+}
+
+export function deletePurchaseReturnOrder(id) {
+  return request({
+    url: "/purchaseReturnOrders/deleteById/" + id,
+    method: "post",
+  });
+}
diff --git a/src/pages.json b/src/pages.json
index 044361a..5d7da6d 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -262,6 +262,48 @@
       }
     },
     {
+      "path": "pages/procurementManagement/purchaseReturnOrder/index",
+      "style": {
+        "navigationBarTitleText": "閲囪喘閫�璐у崟",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/procurementManagement/purchaseReturnOrder/add",
+      "style": {
+        "navigationBarTitleText": "鏂板閲囪喘閫�璐�",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/procurementManagement/purchaseReturnOrder/view",
+      "style": {
+        "navigationBarTitleText": "閲囪喘閫�璐ц鎯�",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/procurementManagement/purchaseReturnOrder/productList",
+      "style": {
+        "navigationBarTitleText": "閫夋嫨浜у搧",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/basicData/supplierManage/index",
+      "style": {
+        "navigationBarTitleText": "渚涘簲鍟嗙鐞�",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/basicData/supplierManage/edit",
+      "style": {
+        "navigationBarTitleText": "渚涘簲鍟嗕俊鎭�",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/cooperativeOffice/collaborativeApproval/index1",
       "style": {
         "navigationBarTitleText": "鍏嚭绠$悊",
@@ -1225,4 +1267,4 @@
     "navigationBarTitleText": "RuoYi",
     "navigationBarBackgroundColor": "#FFFFFF"
   }
-}
\ No newline at end of file
+}
diff --git a/src/pages/basicData/supplierManage/edit.vue b/src/pages/basicData/supplierManage/edit.vue
new file mode 100644
index 0000000..c890e88
--- /dev/null
+++ b/src/pages/basicData/supplierManage/edit.vue
@@ -0,0 +1,216 @@
+<template>
+  <view class="account-detail">
+    <PageHeader :title="pageTitle" @back="goBack" />
+    <up-form ref="formRef" :model="form" :rules="rules" label-width="120">
+      <u-cell-group title="渚涘簲鍟嗕俊鎭�" class="form-section">
+        <up-form-item label="渚涘簲鍟嗗悕绉�" prop="supplierName" required>
+          <up-input v-model="form.supplierName" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="绾崇◣浜鸿瘑鍒彿" prop="taxpayerIdentificationNum" required>
+          <up-input v-model="form.taxpayerIdentificationNum" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="鍏徃鍦板潃" prop="companyAddress" required>
+          <up-input v-model="form.companyAddress" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="鍏徃鐢佃瘽" prop="companyPhone" required>
+          <up-input v-model="form.companyPhone" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="寮�鎴疯" prop="bankAccountName" required>
+          <up-input v-model="form.bankAccountName" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="璐﹀彿" prop="bankAccountNum" required>
+          <up-input v-model="form.bankAccountNum" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="鑱旂郴浜�" prop="contactUserName">
+          <up-input v-model="form.contactUserName" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="鑱旂郴鐢佃瘽" prop="contactUserPhone">
+          <up-input v-model="form.contactUserPhone" placeholder="璇疯緭鍏�" clearable />
+        </up-form-item>
+        <up-form-item label="渚涘簲鍟嗙被鍨�" prop="supplierType" required>
+          <up-input
+            v-model="supplierTypeText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showSupplierTypeSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showSupplierTypeSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="鏄惁鐧藉悕鍗�" prop="isWhite" required>
+          <up-input v-model="isWhiteText" placeholder="璇烽�夋嫨" readonly @click="showIsWhiteSheet = true" />
+          <template #right>
+            <up-icon name="arrow-right" @click="showIsWhiteSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="缁存姢浜�" prop="maintainUserName">
+          <up-input v-model="form.maintainUserName" disabled placeholder="鑷姩濉厖" />
+        </up-form-item>
+        <up-form-item label="缁存姢鏃堕棿" prop="maintainTime">
+          <up-input v-model="form.maintainTime" disabled placeholder="鑷姩濉厖" />
+        </up-form-item>
+      </u-cell-group>
+    </up-form>
+    <FooterButtons :loading="loading" confirmText="淇濆瓨" @cancel="goBack" @confirm="handleSubmit" />
+
+    <up-action-sheet
+      :show="showSupplierTypeSheet"
+      title="閫夋嫨渚涘簲鍟嗙被鍨�"
+      :actions="supplierTypeActions"
+      @select="onSelectSupplierType"
+      @close="showSupplierTypeSheet = false"
+    />
+    <up-action-sheet
+      :show="showIsWhiteSheet"
+      title="閫夋嫨鐧藉悕鍗�"
+      :actions="isWhiteActions"
+      @select="onSelectIsWhite"
+      @close="showIsWhiteSheet = false"
+    />
+  </view>
+</template>
+
+<script setup>
+  import { computed, onMounted, ref } from "vue";
+  import { onLoad } from "@dcloudio/uni-app";
+  import FooterButtons from "@/components/FooterButtons.vue";
+  import useUserStore from "@/store/modules/user";
+  import { formatDateToYMD } from "@/utils/ruoyi";
+  import { addSupplier, getSupplier, updateSupplier } from "@/api/basicData/supplierManageFile";
+
+  const userStore = useUserStore();
+  const formRef = ref();
+  const loading = ref(false);
+  const supplierId = ref(undefined);
+
+  const form = ref({
+    supplierName: "",
+    taxpayerIdentificationNum: "",
+    companyAddress: "",
+    companyPhone: "",
+    bankAccountName: "",
+    bankAccountNum: "",
+    contactUserName: "",
+    contactUserPhone: "",
+    maintainUserId: "",
+    maintainUserName: "",
+    maintainTime: "",
+    supplierType: "",
+    isWhite: 0,
+  });
+
+  const rules = {
+    supplierName: [{ required: true, message: "璇疯緭鍏ヤ緵搴斿晢鍚嶇О", trigger: "blur" }],
+    taxpayerIdentificationNum: [{ required: true, message: "璇疯緭鍏ョ撼绋庝汉璇嗗埆鍙�", trigger: "blur" }],
+    companyAddress: [{ required: true, message: "璇疯緭鍏ュ叕鍙稿湴鍧�", trigger: "blur" }],
+    companyPhone: [{ required: true, message: "璇疯緭鍏ュ叕鍙哥數璇�", trigger: "blur" }],
+    bankAccountName: [{ required: true, message: "璇疯緭鍏ュ紑鎴疯", trigger: "blur" }],
+    bankAccountNum: [{ required: true, message: "璇疯緭鍏ヨ处鍙�", trigger: "blur" }],
+    supplierType: [{ required: true, message: "璇烽�夋嫨渚涘簲鍟嗙被鍨�", trigger: "change" }],
+    isWhite: [{ required: true, message: "璇烽�夋嫨鐧藉悕鍗�", trigger: "change" }],
+  };
+
+  const pageTitle = computed(() => {
+    return supplierId.value ? "缂栬緫渚涘簲鍟�" : "鏂板渚涘簲鍟�";
+  });
+
+  const supplierTypeActions = [
+    { name: "鐢�", value: "鐢�" },
+    { name: "涔�", value: "涔�" },
+    { name: "涓�", value: "涓�" },
+    { name: "涓�", value: "涓�" },
+  ];
+  const isWhiteActions = [
+    { name: "鏄�", value: 0 },
+    { name: "鍚�", value: 1 },
+  ];
+
+  const showSupplierTypeSheet = ref(false);
+  const showIsWhiteSheet = ref(false);
+
+  const supplierTypeText = computed(() => form.value.supplierType || "");
+  const isWhiteText = computed(() => {
+    return String(form.value.isWhite) === "0" ? "鏄�" : "鍚�";
+  });
+
+  const onSelectSupplierType = action => {
+    form.value.supplierType = action.value;
+    showSupplierTypeSheet.value = false;
+  };
+
+  const onSelectIsWhite = action => {
+    form.value.isWhite = action.value;
+    showIsWhiteSheet.value = false;
+  };
+
+  const initForAdd = () => {
+    form.value.maintainUserId = userStore.id;
+    form.value.maintainUserName = userStore.nickName;
+    form.value.maintainTime = formatDateToYMD(Date.now());
+    form.value.isWhite = 0;
+  };
+
+  const loadDetail = () => {
+    if (!supplierId.value) return;
+    uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+    getSupplier(supplierId.value)
+      .then(res => {
+        form.value = { ...form.value, ...(res.data || {}) };
+      })
+      .catch(() => {
+        uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        uni.hideLoading();
+      });
+  };
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const handleSubmit = async () => {
+    const valid = await formRef.value.validate().catch(() => false);
+    if (!valid) return;
+    loading.value = true;
+    const action = supplierId.value ? updateSupplier : addSupplier;
+    action({ ...form.value, id: supplierId.value })
+      .then(() => {
+        uni.showToast({ title: "淇濆瓨鎴愬姛", icon: "success" });
+        uni.navigateBack();
+      })
+      .catch(() => {
+        uni.showToast({ title: "淇濆瓨澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        loading.value = false;
+      });
+  };
+
+  onMounted(() => {
+    userStore.getInfo();
+    initForAdd();
+  });
+
+  onLoad(options => {
+    if (options?.id) supplierId.value = options.id;
+    if (supplierId.value) loadDetail();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+
+  .account-detail {
+    min-height: 100vh;
+    background: #f8f9fa;
+    padding-bottom: 90px;
+  }
+
+  .form-section {
+    margin: 12px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+</style>
diff --git a/src/pages/basicData/supplierManage/index.vue b/src/pages/basicData/supplierManage/index.vue
new file mode 100644
index 0000000..a7c01a0
--- /dev/null
+++ b/src/pages/basicData/supplierManage/index.vue
@@ -0,0 +1,197 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="渚涘簲鍟嗙鐞�" @back="goBack">
+      <template #right>
+        <up-button
+          type="primary"
+          size="small"
+          text="鏂板"
+          :customStyle="{ marginRight: '12px' }"
+          @click="goAdd"
+        />
+      </template>
+    </PageHeader>
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input
+            class="search-text"
+            placeholder="璇疯緭鍏ヤ緵搴斿晢鍚嶇О"
+            v-model="supplierName"
+            @change="getList"
+            clearable
+          />
+        </view>
+        <view class="filter-button" @click="getList">
+          <up-icon name="search" size="24" color="#999"></up-icon>
+        </view>
+      </view>
+    </view>
+    <view class="tabs-section">
+      <up-tabs
+        v-model="tabValue"
+        :list="tabList"
+        itemStyle="width: 50%;height: 80rpx;"
+        @change="onTabChange"
+      >
+      </up-tabs>
+    </view>
+    <view class="ledger-list" v-if="list.length > 0">
+      <view v-for="item in list" :key="item.id">
+        <view class="ledger-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.supplierName || "-" }}</text>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">渚涘簲鍟嗙被鍨�</text>
+              <text class="detail-value">{{ item.supplierType || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">绾崇◣浜鸿瘑鍒彿</text>
+              <text class="detail-value">{{ item.taxpayerIdentificationNum || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍏徃鐢佃瘽</text>
+              <text class="detail-value">{{ item.companyPhone || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鑱旂郴浜�</text>
+              <text class="detail-value">{{ item.contactUserName || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鑱旂郴鐢佃瘽</text>
+              <text class="detail-value">{{ item.contactUserPhone || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">缁存姢浜�</text>
+              <text class="detail-value">{{ item.maintainUserName || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">缁存姢鏃堕棿</text>
+              <text class="detail-value">{{ item.maintainTime || "-" }}</text>
+            </view>
+          </view>
+          <view class="action-buttons">
+            <u-button size="small" class="action-btn" @click="goEdit(item)">缂栬緫</u-button>
+            <u-button
+              type="error"
+              size="small"
+              class="action-btn"
+              @click="handleDelete(item)"
+            >
+              鍒犻櫎
+            </u-button>
+          </view>
+        </view>
+      </view>
+    </view>
+    <view v-else class="no-data">
+      <text>鏆傛棤渚涘簲鍟嗘暟鎹�</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { reactive, ref } from "vue";
+  import { onShow } from "@dcloudio/uni-app";
+  import useUserStore from "@/store/modules/user";
+  import { delSupplier, listSupplier } from "@/api/basicData/supplierManageFile";
+
+  const userStore = useUserStore();
+  const supplierName = ref("");
+  const list = ref([]);
+
+  const tabList = reactive([
+    { name: "姝e父渚涘簲鍟�", value: 0 },
+    { name: "榛戝悕鍗�", value: 1 },
+  ]);
+  const tabValue = ref(0);
+
+  const page = {
+    current: -1,
+    size: -1,
+  };
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const goAdd = () => {
+    uni.navigateTo({ url: "/pages/basicData/supplierManage/edit" });
+  };
+
+  const goEdit = item => {
+    uni.navigateTo({ url: `/pages/basicData/supplierManage/edit?id=${item.id}` });
+  };
+
+  const onTabChange = val => {
+    tabValue.value = val.value;
+    getList();
+  };
+
+  const getList = () => {
+    uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+    listSupplier({
+      ...page,
+      supplierName: supplierName.value,
+      isWhite: tabValue.value,
+    })
+      .then(res => {
+        list.value = res?.data?.records || [];
+      })
+      .catch(() => {
+        uni.showToast({ title: "鏌ヨ澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        uni.hideLoading();
+      });
+  };
+
+  const handleDelete = item => {
+    if (!item?.id) return;
+    if (item.maintainUserName && item.maintainUserName !== userStore.nickName) {
+      uni.showToast({ title: "涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�", icon: "none" });
+      return;
+    }
+    uni.showModal({
+      title: "鍒犻櫎鎻愮ず",
+      content: "纭畾瑕佸垹闄ゅ悧锛熷垹闄ゅ悗鏃犳硶鎭㈠",
+      success: res => {
+        if (!res.confirm) return;
+        uni.showLoading({ title: "鍒犻櫎涓�...", mask: true });
+        delSupplier([item.id])
+          .then(() => {
+            uni.showToast({ title: "鍒犻櫎鎴愬姛", icon: "success" });
+            getList();
+          })
+          .catch(() => {
+            uni.showToast({ title: "鍒犻櫎澶辫触", icon: "error" });
+          })
+          .finally(() => {
+            uni.hideLoading();
+          });
+      },
+    });
+  };
+
+  onShow(() => {
+    userStore.getInfo();
+    getList();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+
+  .tabs-section {
+    background: #fff;
+    padding: 0 12px 8px 12px;
+  }
+</style>
diff --git a/src/pages/indexItem.vue b/src/pages/indexItem.vue
index 21b4958..61f6c15 100644
--- a/src/pages/indexItem.vue
+++ b/src/pages/indexItem.vue
@@ -49,6 +49,8 @@
     "浠樻鐧昏": "/pages/procurementManagement/paymentEntry/index",
     "浠樻娴佹按": "/pages/procurementManagement/receiptPaymentHistory/index",
     "渚涘簲鍟嗗線鏉�": "/pages/procurementManagement/paymentLedger/index",
+    "閲囪喘閫�璐у崟": "/pages/procurementManagement/purchaseReturnOrder/index",
+    "渚涘簲鍟嗙鐞�": "/pages/basicData/supplierManage/index",
     "鍏嚭绠$悊": "/pages/cooperativeOffice/collaborativeApproval/index1",
     "璇峰亣绠$悊": "/pages/cooperativeOffice/collaborativeApproval/index2",
     "鍑哄樊绠$悊": "/pages/cooperativeOffice/collaborativeApproval/index3",
@@ -831,4 +833,4 @@
       box-shadow: 0 0.375rem 1.25rem rgba(0, 0, 0, 0.4);
     }
   }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/pages/procurementManagement/purchaseReturnOrder/add.vue b/src/pages/procurementManagement/purchaseReturnOrder/add.vue
new file mode 100644
index 0000000..fd5591e
--- /dev/null
+++ b/src/pages/procurementManagement/purchaseReturnOrder/add.vue
@@ -0,0 +1,758 @@
+<template>
+  <view class="account-detail">
+    <PageHeader title="鏂板閲囪喘閫�璐�" @back="goBack" />
+    <up-form ref="formRef" :model="form" :rules="rules" label-width="120">
+      <u-cell-group title="鍩烘湰淇℃伅" class="form-section">
+        <up-form-item label="閫�鏂欏崟鍙�" prop="no">
+          <up-input
+            v-model="form.no"
+            :disabled="form.isDefaultNo"
+            :placeholder="form.isDefaultNo ? '浣跨敤绯荤粺缂栧彿' : '璇疯緭鍏ラ��鏂欏崟鍙�'"
+            clearable
+          />
+          <template #right>
+            <up-switch v-model="form.isDefaultNo" @change="onDefaultNoChange" />
+          </template>
+        </up-form-item>
+        <up-form-item label="閫�璐ф柟寮�" prop="returnType" required>
+          <up-input
+            v-model="returnTypeText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showReturnTypeSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showReturnTypeSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="渚涘簲鍟�" prop="supplierId" required>
+          <up-input
+            v-model="supplierText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showSupplierSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showSupplierSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="椤圭洰闃舵" prop="projectPhase">
+          <up-input
+            v-model="projectPhaseText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showProjectPhaseSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showProjectPhaseSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="鍒朵綔鏃ユ湡" prop="preparedAt" required>
+          <up-input
+            v-model="form.preparedAt"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showPreparedAtPicker = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showPreparedAtPicker = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="鍒跺崟浜�" prop="preparedUserId" required>
+          <up-input
+            v-model="preparedUserText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showPreparedUserSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showPreparedUserSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="閫�鏂欎汉" prop="returnUserId" required>
+          <up-input
+            v-model="returnUserText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showReturnUserSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showReturnUserSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="閲囪喘鍚堝悓鍙�" prop="purchaseLedgerId" required>
+          <up-input
+            v-model="purchaseContractText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showPurchaseLedgerSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showPurchaseLedgerSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+        <up-form-item label="澶囨敞" prop="remark">
+          <up-textarea v-model="form.remark" placeholder="璇疯緭鍏�" auto-height />
+        </up-form-item>
+      </u-cell-group>
+
+      <u-cell-group title="浜у搧鍒楄〃" class="form-section">
+        <view class="product-actions">
+          <up-button
+            type="primary"
+            size="small"
+            text="閫夋嫨浜у搧"
+            :disabled="!form.purchaseLedgerId"
+            @click="goSelectProducts"
+          />
+          <view class="amount-summary">
+            <text class="amount-text">鍚堣锛歿{ formatAmount(baseAmount) }}</text>
+          </view>
+        </view>
+        <view v-if="form.purchaseReturnOrderProductsDtos.length === 0" class="empty-products">
+          <text>鏆傛棤浜у搧锛岃鍏堥�夋嫨浜у搧</text>
+        </view>
+        <view v-else class="product-list">
+          <view
+            v-for="(item, index) in form.purchaseReturnOrderProductsDtos"
+            :key="item.salesLedgerProductId || item.id || index"
+            class="product-card"
+          >
+            <view class="product-header">
+              <view class="product-title">
+                <view class="document-icon">
+                  <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
+                </view>
+                <text class="product-name">浜у搧 {{ index + 1 }}</text>
+              </view>
+              <up-icon name="trash" size="18" color="#ee0a24" @click="removeProduct(index)" />
+            </view>
+            <up-divider></up-divider>
+            <view class="product-body">
+              <view class="detail-row">
+                <text class="detail-label">浜у搧澶х被</text>
+                <text class="detail-value">{{ item.productCategory || "-" }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">瑙勬牸鍨嬪彿</text>
+                <text class="detail-value">{{ item.specificationModel || "-" }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鏁伴噺</text>
+                <text class="detail-value">{{ item.quantity ?? "-" }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鍚◣鍗曚环(鍏�)</text>
+                <text class="detail-value">{{ formatAmount(item.taxInclusiveUnitPrice) }}</text>
+              </view>
+              <view class="qty-row">
+                <text class="qty-label">閫�璐ф暟閲�</text>
+                <up-number-box
+                  v-model="item.returnQuantity"
+                  :min="0"
+                  :max="getReturnQtyMax(item)"
+                  :step="1"
+                  @change="syncRowTotal(item)"
+                />
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">閫�璐ф�讳环(鍏�)</text>
+                <text class="detail-value highlight">{{ formatAmount(item.taxInclusiveTotalPrice) }}</text>
+              </view>
+            </view>
+          </view>
+        </view>
+      </u-cell-group>
+
+      <u-cell-group title="璐圭敤淇℃伅" class="form-section">
+        <up-form-item label="鏁村崟鎶樻墸棰�" prop="totalDiscountAmount">
+          <up-input
+            v-model="form.totalDiscountAmount"
+            type="number"
+            placeholder="璇疯緭鍏�"
+            @blur="onDiscountAmountBlur"
+            clearable
+          />
+        </up-form-item>
+        <up-form-item label="鏁村崟鎶樻墸鐜�(%)" prop="totalDiscountRate">
+          <up-input
+            v-model="form.totalDiscountRate"
+            type="number"
+            placeholder="璇疯緭鍏�"
+            @blur="onDiscountRateBlur"
+            clearable
+          />
+        </up-form-item>
+        <up-form-item label="鎴愪氦閲戦" prop="totalAmount" required>
+          <up-input v-model="form.totalAmount" disabled placeholder="鑷姩璁$畻" />
+        </up-form-item>
+        <up-form-item label="鏀舵鏂瑰紡" prop="incomeType" required>
+          <up-input
+            v-model="incomeTypeText"
+            placeholder="璇烽�夋嫨"
+            readonly
+            @click="showIncomeTypeSheet = true"
+          />
+          <template #right>
+            <up-icon name="arrow-right" @click="showIncomeTypeSheet = true"></up-icon>
+          </template>
+        </up-form-item>
+      </u-cell-group>
+    </up-form>
+
+    <FooterButtons :loading="loading" confirmText="鎻愪氦" @cancel="goBack" @confirm="handleSubmit" />
+
+    <up-action-sheet
+      :show="showReturnTypeSheet"
+      title="閫夋嫨閫�璐ф柟寮�"
+      :actions="returnTypeActions"
+      @select="onSelectReturnType"
+      @close="showReturnTypeSheet = false"
+    />
+    <up-action-sheet
+      :show="showProjectPhaseSheet"
+      title="閫夋嫨椤圭洰闃舵"
+      :actions="projectPhaseActions"
+      @select="onSelectProjectPhase"
+      @close="showProjectPhaseSheet = false"
+    />
+    <up-action-sheet
+      :show="showSupplierSheet"
+      title="閫夋嫨渚涘簲鍟�"
+      :actions="supplierActions"
+      @select="onSelectSupplier"
+      @close="showSupplierSheet = false"
+    />
+    <up-action-sheet
+      :show="showPreparedUserSheet"
+      title="閫夋嫨鍒跺崟浜�"
+      :actions="userActions"
+      @select="onSelectPreparedUser"
+      @close="showPreparedUserSheet = false"
+    />
+    <up-action-sheet
+      :show="showReturnUserSheet"
+      title="閫夋嫨閫�鏂欎汉"
+      :actions="userActions"
+      @select="onSelectReturnUser"
+      @close="showReturnUserSheet = false"
+    />
+    <up-action-sheet
+      :show="showPurchaseLedgerSheet"
+      title="閫夋嫨閲囪喘鍚堝悓鍙�"
+      :actions="purchaseLedgerActions"
+      @select="onSelectPurchaseLedger"
+      @close="showPurchaseLedgerSheet = false"
+    />
+    <up-action-sheet
+      :show="showIncomeTypeSheet"
+      title="閫夋嫨鏀舵鏂瑰紡"
+      :actions="incomeTypeActions"
+      @select="onSelectIncomeType"
+      @close="showIncomeTypeSheet = false"
+    />
+    <up-datetime-picker
+      :show="showPreparedAtPicker"
+      v-model="preparedAtPickerValue"
+      mode="date"
+      @confirm="onPreparedAtConfirm"
+      @cancel="showPreparedAtPicker = false"
+    />
+  </view>
+</template>
+
+<script setup>
+  import { computed, onMounted, ref, watch } from "vue";
+  import { onShow } from "@dcloudio/uni-app";
+  import FooterButtons from "@/components/FooterButtons.vue";
+  import { formatDateToYMD } from "@/utils/ruoyi";
+  import { createPurchaseReturnOrder } from "@/api/procurementManagement/purchaseReturnOrder";
+  import { getOptions, purchaseListPage, productList } from "@/api/procurementManagement/procurementLedger";
+  import { userListNoPageByTenantId } from "@/api/system/user";
+
+  const formRef = ref();
+  const loading = ref(false);
+
+  const form = ref({
+    no: "",
+    isDefaultNo: true,
+    returnType: 0,
+    supplierId: undefined,
+    supplierName: "",
+    projectPhase: undefined,
+    preparedAt: "",
+    preparedUserId: undefined,
+    preparedUserName: "",
+    returnUserId: undefined,
+    returnUserName: "",
+    purchaseLedgerId: undefined,
+    purchaseContractNumber: "",
+    remark: "",
+    totalDiscountAmount: 0,
+    totalDiscountRate: "",
+    totalAmount: 0,
+    incomeType: undefined,
+    purchaseReturnOrderProductsDtos: [],
+  });
+
+  const rules = {
+    returnType: [{ required: true, message: "璇烽�夋嫨閫�璐ф柟寮�", trigger: "change" }],
+    supplierId: [{ required: true, message: "璇烽�夋嫨渚涘簲鍟�", trigger: "change" }],
+    preparedAt: [{ required: true, message: "璇烽�夋嫨鍒朵綔鏃ユ湡", trigger: "change" }],
+    preparedUserId: [{ required: true, message: "璇烽�夋嫨鍒跺崟浜�", trigger: "change" }],
+    returnUserId: [{ required: true, message: "璇烽�夋嫨閫�鏂欎汉", trigger: "change" }],
+    purchaseLedgerId: [{ required: true, message: "璇烽�夋嫨閲囪喘鍚堝悓鍙�", trigger: "change" }],
+    totalAmount: [{ required: true, message: "鎴愪氦閲戦涓嶈兘涓虹┖", trigger: "change" }],
+    incomeType: [{ required: true, message: "璇烽�夋嫨鏀舵鏂瑰紡", trigger: "change" }],
+  };
+
+  const showReturnTypeSheet = ref(false);
+  const showProjectPhaseSheet = ref(false);
+  const showSupplierSheet = ref(false);
+  const showPreparedUserSheet = ref(false);
+  const showReturnUserSheet = ref(false);
+  const showPurchaseLedgerSheet = ref(false);
+  const showIncomeTypeSheet = ref(false);
+  const showPreparedAtPicker = ref(false);
+  const preparedAtPickerValue = ref(Date.now());
+
+  const supplierOptions = ref([]);
+  const userOptions = ref([]);
+  const purchaseLedgerOptions = ref([]);
+
+  const returnTypeActions = [
+    { name: "閫�璐ч��娆�", value: 0 },
+    { name: "鎷掓敹", value: 1 },
+  ];
+  const projectPhaseActions = [
+    { name: "绔嬮」", value: 0 },
+    { name: "璁捐", value: 1 },
+    { name: "閲囪喘", value: 2 },
+    { name: "鐢熶骇", value: 3 },
+    { name: "鍑鸿揣", value: 4 },
+  ];
+  const incomeTypeActions = [
+    { name: "鐜伴噾", value: "0" },
+    { name: "鏀エ", value: "1" },
+    { name: "閾惰杞处", value: "2" },
+    { name: "鍏朵粬", value: "3" },
+  ];
+
+  const returnTypeText = computed(() => {
+    return returnTypeActions.find(i => String(i.value) === String(form.value.returnType))?.name || "";
+  });
+  const projectPhaseText = computed(() => {
+    return projectPhaseActions.find(i => String(i.value) === String(form.value.projectPhase))?.name || "";
+  });
+  const supplierText = computed(() => {
+    return supplierOptions.value.find(i => String(i.id) === String(form.value.supplierId))?.supplierName || "";
+  });
+  const preparedUserText = computed(() => {
+    return userOptions.value.find(i => String(i.userId) === String(form.value.preparedUserId))?.nickName || "";
+  });
+  const returnUserText = computed(() => {
+    return userOptions.value.find(i => String(i.userId) === String(form.value.returnUserId))?.nickName || "";
+  });
+  const purchaseContractText = computed(() => {
+    return purchaseLedgerOptions.value.find(i => String(i.id) === String(form.value.purchaseLedgerId))?.purchaseContractNumber || "";
+  });
+  const incomeTypeText = computed(() => {
+    return incomeTypeActions.find(i => String(i.value) === String(form.value.incomeType))?.name || "";
+  });
+
+  const supplierActions = computed(() => {
+    return supplierOptions.value.map(i => ({ name: i.supplierName, value: i.id }));
+  });
+  const userActions = computed(() => {
+    return userOptions.value.map(i => ({ name: i.nickName, value: i.userId }));
+  });
+  const purchaseLedgerActions = computed(() => {
+    return purchaseLedgerOptions.value.map(i => ({ name: i.purchaseContractNumber, value: i.id }));
+  });
+
+  const toNumber = val => {
+    const num = Number(val);
+    return Number.isNaN(num) ? 0 : num;
+  };
+
+  const formatAmount = value => {
+    if (value === null || value === undefined || value === "") return "0.00";
+    const num = Number(value);
+    if (Number.isNaN(num)) return "0.00";
+    return num.toFixed(2);
+  };
+
+  const baseAmount = computed(() => {
+    const rows = form.value.purchaseReturnOrderProductsDtos || [];
+    return rows.reduce((sum, item) => sum + toNumber(item.taxInclusiveTotalPrice), 0);
+  });
+
+  const syncTotalAmount = () => {
+    const total = baseAmount.value - toNumber(form.value.totalDiscountAmount);
+    form.value.totalAmount = Number(total.toFixed(2));
+  };
+
+  const getReturnQtyMax = row => {
+    const qty = Number(row?.quantity);
+    if (Number.isNaN(qty) || qty < 0) return 0;
+    return qty;
+  };
+
+  const syncRowTotal = row => {
+    if (!row) return;
+    const qty = toNumber(row.returnQuantity);
+    const unitPrice = toNumber(row.taxInclusiveUnitPrice);
+    row.taxInclusiveTotalPrice = Number((qty * unitPrice).toFixed(2));
+    syncTotalAmount();
+  };
+
+  const removeProduct = index => {
+    form.value.purchaseReturnOrderProductsDtos.splice(index, 1);
+    syncTotalAmount();
+  };
+
+  const resetFeeInfo = () => {
+    form.value.totalDiscountAmount = 0;
+    form.value.totalDiscountRate = "";
+    form.value.totalAmount = 0;
+    form.value.incomeType = undefined;
+  };
+
+  const onDefaultNoChange = checked => {
+    if (checked) form.value.no = "";
+  };
+
+  const onSelectReturnType = action => {
+    form.value.returnType = action.value;
+    showReturnTypeSheet.value = false;
+  };
+  const onSelectProjectPhase = action => {
+    form.value.projectPhase = action.value;
+    showProjectPhaseSheet.value = false;
+  };
+  const onSelectSupplier = action => {
+    form.value.supplierId = action.value;
+    form.value.supplierName = supplierOptions.value.find(i => String(i.id) === String(action.value))?.supplierName || "";
+    form.value.purchaseLedgerId = undefined;
+    form.value.purchaseContractNumber = "";
+    form.value.purchaseReturnOrderProductsDtos = [];
+    resetFeeInfo();
+    showSupplierSheet.value = false;
+    fetchPurchaseLedgerOptions();
+  };
+  const onSelectPreparedUser = action => {
+    form.value.preparedUserId = action.value;
+    form.value.preparedUserName = userOptions.value.find(i => String(i.userId) === String(action.value))?.nickName || "";
+    showPreparedUserSheet.value = false;
+  };
+  const onSelectReturnUser = action => {
+    form.value.returnUserId = action.value;
+    form.value.returnUserName = userOptions.value.find(i => String(i.userId) === String(action.value))?.nickName || "";
+    showReturnUserSheet.value = false;
+  };
+  const onSelectPurchaseLedger = action => {
+    form.value.purchaseLedgerId = action.value;
+    form.value.purchaseContractNumber =
+      purchaseLedgerOptions.value.find(i => String(i.id) === String(action.value))?.purchaseContractNumber || "";
+    form.value.purchaseReturnOrderProductsDtos = [];
+    resetFeeInfo();
+    showPurchaseLedgerSheet.value = false;
+  };
+  const onSelectIncomeType = action => {
+    form.value.incomeType = action.value;
+    showIncomeTypeSheet.value = false;
+  };
+
+  const onPreparedAtConfirm = e => {
+    form.value.preparedAt = formatDateToYMD(e.value);
+    showPreparedAtPicker.value = false;
+  };
+
+  const onDiscountRateBlur = () => {
+    const rate = toNumber(form.value.totalDiscountRate);
+    if (rate < 0 || rate > 100) {
+      uni.showToast({ title: "鎶樻墸鐜囬渶鍦�0-100", icon: "none" });
+      return;
+    }
+    form.value.totalDiscountAmount = Number((baseAmount.value * (rate / 100)).toFixed(2));
+    syncTotalAmount();
+  };
+
+  const onDiscountAmountBlur = () => {
+    const amount = toNumber(form.value.totalDiscountAmount);
+    if (amount < 0) {
+      form.value.totalDiscountAmount = 0;
+    }
+    const base = baseAmount.value;
+    if (base <= 0) {
+      form.value.totalDiscountRate = "";
+      syncTotalAmount();
+      return;
+    }
+    if (toNumber(form.value.totalDiscountAmount) > base) {
+      form.value.totalDiscountAmount = Number(base.toFixed(2));
+    }
+    const rate = (toNumber(form.value.totalDiscountAmount) / base) * 100;
+    form.value.totalDiscountRate = Number(rate.toFixed(2));
+    syncTotalAmount();
+  };
+
+  const goBack = () => {
+    uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
+    uni.navigateBack();
+  };
+
+  const goSelectProducts = () => {
+    if (!form.value.purchaseLedgerId) return;
+    uni.navigateTo({
+      url: `/pages/procurementManagement/purchaseReturnOrder/productList?purchaseLedgerId=${form.value.purchaseLedgerId}`,
+    });
+  };
+
+  const fetchSupplierOptions = () => {
+    getOptions()
+      .then(res => {
+        supplierOptions.value = res.data || [];
+      })
+      .catch(() => {
+        supplierOptions.value = [];
+      });
+  };
+
+  const fetchUserOptions = () => {
+    userListNoPageByTenantId()
+      .then(res => {
+        userOptions.value = res.data || [];
+      })
+      .catch(() => {
+        userOptions.value = [];
+      });
+  };
+
+  const fetchPurchaseLedgerOptions = () => {
+    purchaseLedgerOptions.value = [];
+    if (!form.value.supplierId) return;
+    purchaseListPage({
+      current: -1,
+      size: -1,
+      supplierId: form.value.supplierId,
+      approvalStatus: 3,
+    })
+      .then(res => {
+        purchaseLedgerOptions.value = res?.data?.records || [];
+      })
+      .catch(() => {
+        purchaseLedgerOptions.value = [];
+      });
+  };
+
+  const mergeSelectedProducts = selectedRows => {
+    const existing = new Set((form.value.purchaseReturnOrderProductsDtos || []).map(i => String(i.salesLedgerProductId || i.id)));
+    const toAdd = (selectedRows || [])
+      .filter(i => !existing.has(String(i.id)))
+      .map(i => ({
+        ...i,
+        salesLedgerProductId: i.id,
+        returnQuantity: 0,
+        taxInclusiveTotalPrice: 0,
+      }));
+    form.value.purchaseReturnOrderProductsDtos.push(...toAdd);
+    syncTotalAmount();
+  };
+
+  const loadProductsFromPurchaseLedger = () => {
+    if (!form.value.purchaseLedgerId) return;
+    uni.showLoading({ title: "鍔犺浇浜у搧...", mask: true });
+    productList({ salesLedgerId: form.value.purchaseLedgerId, type: 2 })
+      .then(res => {
+        const rows = res.data || [];
+        mergeSelectedProducts(rows);
+      })
+      .catch(() => {
+        uni.showToast({ title: "鍔犺浇浜у搧澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        uni.hideLoading();
+      });
+  };
+
+  const validateProducts = () => {
+    const rows = form.value.purchaseReturnOrderProductsDtos || [];
+    if (rows.length === 0) {
+      uni.showToast({ title: "璇峰厛閫夋嫨浜у搧", icon: "none" });
+      return false;
+    }
+    const invalid = rows.findIndex(i => {
+      const qty = toNumber(i.returnQuantity);
+      if (qty <= 0) return true;
+      if (qty > getReturnQtyMax(i)) return true;
+      return false;
+    });
+    if (invalid !== -1) {
+      uni.showToast({ title: `绗�${invalid + 1}琛岄��璐ф暟閲忎笉鍚堟硶`, icon: "none" });
+      return false;
+    }
+    return true;
+  };
+
+  const handleSubmit = async () => {
+    if (!validateProducts()) return;
+    const valid = await formRef.value.validate().catch(() => false);
+    if (!valid) return;
+    loading.value = true;
+    const rows = (form.value.purchaseReturnOrderProductsDtos || []).map(i => {
+      const cloned = { ...i };
+      syncRowTotal(cloned);
+      return cloned;
+    });
+    const payload = {
+      ...form.value,
+      purchaseReturnOrderProductsDtos: rows.filter(i => toNumber(i.returnQuantity) > 0),
+    };
+    createPurchaseReturnOrder(payload)
+      .then(() => {
+        uni.showToast({ title: "鎻愪氦鎴愬姛", icon: "success" });
+        uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
+        uni.navigateBack();
+      })
+      .catch(() => {
+        uni.showToast({ title: "鎻愪氦澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        loading.value = false;
+      });
+  };
+
+  watch(
+    () => baseAmount.value,
+    () => {
+      syncTotalAmount();
+    }
+  );
+
+  onMounted(() => {
+    form.value.preparedAt = formatDateToYMD(Date.now());
+    preparedAtPickerValue.value = Date.now();
+    fetchSupplierOptions();
+    fetchUserOptions();
+  });
+
+  onShow(() => {
+    const stored = uni.getStorageSync("purchaseReturnOrderSelectedProducts");
+    if (stored) {
+      try {
+        const rows = JSON.parse(stored);
+        mergeSelectedProducts(rows);
+        uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
+      } catch {
+        uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
+      }
+    }
+  });
+
+  const showAutoLoadModalOnceKey = "purchaseReturnOrderAutoLoadShown";
+  watch(
+    () => form.value.purchaseLedgerId,
+    (val, oldVal) => {
+      if (!val || String(val) === String(oldVal)) return;
+      if (uni.getStorageSync(showAutoLoadModalOnceKey)) return;
+      uni.setStorageSync(showAutoLoadModalOnceKey, "1");
+      uni.showModal({
+        title: "鎻愮ず",
+        content: "鏄惁鑷姩鍔犺浇璇ラ噰璐悎鍚屼笅鍏ㄩ儴浜у搧锛�",
+        success: res => {
+          if (res.confirm) loadProductsFromPurchaseLedger();
+        },
+      });
+    }
+  );
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+
+  .account-detail {
+    min-height: 100vh;
+    background: #f8f9fa;
+    padding-bottom: 90px;
+  }
+
+  .form-section {
+    margin: 12px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .product-actions {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 12px 12px 0 12px;
+  }
+
+  .amount-summary {
+    display: flex;
+    align-items: center;
+  }
+
+  .amount-text {
+    font-size: 14px;
+    color: #333;
+    font-weight: 600;
+  }
+
+  .empty-products {
+    padding: 16px 12px;
+    color: #999;
+    font-size: 14px;
+  }
+
+  .product-list {
+    padding: 12px;
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+  }
+
+  .product-card {
+    background: #fff;
+    border-radius: 12px;
+    padding: 0 12px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  }
+
+  .product-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 12px 0;
+  }
+
+  .product-title {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+
+  .product-name {
+    font-size: 14px;
+    color: #333;
+    font-weight: 500;
+  }
+
+  .product-body {
+    padding: 12px 0;
+  }
+
+  .qty-row {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 8px 0;
+  }
+
+  .qty-label {
+    font-size: 12px;
+    color: #777;
+  }
+</style>
diff --git a/src/pages/procurementManagement/purchaseReturnOrder/index.vue b/src/pages/procurementManagement/purchaseReturnOrder/index.vue
new file mode 100644
index 0000000..2cd1a14
--- /dev/null
+++ b/src/pages/procurementManagement/purchaseReturnOrder/index.vue
@@ -0,0 +1,185 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="閲囪喘閫�璐у崟" @back="goBack">
+      <template #right>
+        <up-button
+          type="primary"
+          size="small"
+          text="鏂板"
+          :customStyle="{ marginRight: '12px' }"
+          @click="goAdd"
+        />
+      </template>
+    </PageHeader>
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input
+            class="search-text"
+            placeholder="璇疯緭鍏ラ��鏂欏崟鍙�"
+            v-model="searchNo"
+            @change="getList"
+            clearable
+          />
+        </view>
+        <view class="filter-button" @click="getList">
+          <up-icon name="search" size="24" color="#999"></up-icon>
+        </view>
+      </view>
+    </view>
+    <view class="ledger-list" v-if="list.length > 0">
+      <view v-for="item in list" :key="item.id">
+        <view class="ledger-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.no || "-" }}</text>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">閫�璐ф柟寮�</text>
+              <text class="detail-value">{{ getReturnTypeLabel(item.returnType) }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">渚涘簲鍟嗗悕绉�</text>
+              <text class="detail-value">{{ item.supplierName || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">椤圭洰闃舵</text>
+              <text class="detail-value">{{ getProjectPhaseLabel(item.projectPhase) }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍒朵綔鏃ユ湡</text>
+              <text class="detail-value">{{ item.preparedAt || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鎴愪氦閲戦(鍏�)</text>
+              <text class="detail-value highlight">{{ formatAmount(item.totalAmount) }}</text>
+            </view>
+          </view>
+          <view class="action-buttons">
+            <u-button size="small" class="action-btn" @click="goView(item)">璇︽儏</u-button>
+            <u-button
+              type="error"
+              size="small"
+              class="action-btn"
+              @click="handleDelete(item)"
+            >
+              鍒犻櫎
+            </u-button>
+          </view>
+        </view>
+      </view>
+    </view>
+    <view v-else class="no-data">
+      <text>鏆傛棤閲囪喘閫�璐у崟鏁版嵁</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref } from "vue";
+  import { onShow } from "@dcloudio/uni-app";
+  import { findPurchaseReturnOrderListPage, deletePurchaseReturnOrder } from "@/api/procurementManagement/purchaseReturnOrder";
+
+  const searchNo = ref("");
+  const list = ref([]);
+
+  const page = {
+    current: -1,
+    size: -1,
+  };
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const goAdd = () => {
+    uni.navigateTo({
+      url: "/pages/procurementManagement/purchaseReturnOrder/add",
+    });
+  };
+
+  const goView = item => {
+    uni.navigateTo({
+      url: `/pages/procurementManagement/purchaseReturnOrder/view?id=${item.id}`,
+    });
+  };
+
+  const getReturnTypeLabel = value => {
+    if (String(value) === "0") return "閫�璐ч��娆�";
+    if (String(value) === "1") return "鎷掓敹";
+    return "-";
+  };
+
+  const getProjectPhaseLabel = value => {
+    const map = {
+      0: "绔嬮」",
+      1: "璁捐",
+      2: "閲囪喘",
+      3: "鐢熶骇",
+      4: "鍑鸿揣",
+    };
+    const key = String(value);
+    return map[key] || "-";
+  };
+
+  const formatAmount = value => {
+    if (value === null || value === undefined || value === "") return "-";
+    const num = Number(value);
+    if (Number.isNaN(num)) return "-";
+    return num.toFixed(2);
+  };
+
+  const getList = () => {
+    uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+    findPurchaseReturnOrderListPage({
+      ...page,
+      no: searchNo.value,
+    })
+      .then(res => {
+        list.value = res?.data?.records || [];
+      })
+      .catch(() => {
+        uni.showToast({ title: "鏌ヨ澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        uni.hideLoading();
+      });
+  };
+
+  const handleDelete = item => {
+    if (!item?.id) return;
+    uni.showModal({
+      title: "鍒犻櫎鎻愮ず",
+      content: "纭畾瑕佸垹闄ゅ悧锛熷垹闄ゅ悗鏃犳硶鎭㈠",
+      success: res => {
+        if (!res.confirm) return;
+        uni.showLoading({ title: "鍒犻櫎涓�...", mask: true });
+        deletePurchaseReturnOrder(item.id)
+          .then(() => {
+            uni.showToast({ title: "鍒犻櫎鎴愬姛", icon: "success" });
+            getList();
+          })
+          .catch(() => {
+            uni.showToast({ title: "鍒犻櫎澶辫触", icon: "error" });
+          })
+          .finally(() => {
+            uni.hideLoading();
+          });
+      },
+    });
+  };
+
+  onShow(() => {
+    getList();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+</style>
diff --git a/src/pages/procurementManagement/purchaseReturnOrder/productList.vue b/src/pages/procurementManagement/purchaseReturnOrder/productList.vue
new file mode 100644
index 0000000..048d975
--- /dev/null
+++ b/src/pages/procurementManagement/purchaseReturnOrder/productList.vue
@@ -0,0 +1,163 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="閫夋嫨浜у搧" @back="goBack" />
+    <view class="ledger-list" v-if="list.length > 0">
+      <view v-for="item in list" :key="item.id">
+        <view class="ledger-item" @click="toggle(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.productCategory || "浜у搧" }}</text>
+            </view>
+            <view class="item-right">
+              <u-tag :type="isSelected(item.id) ? 'success' : 'info'">
+                {{ isSelected(item.id) ? "宸查��" : "鏈��" }}
+              </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.specificationModel || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍗曚綅</text>
+              <text class="detail-value">{{ item.unit || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鏁伴噺</text>
+              <text class="detail-value">{{ item.quantity ?? "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍚◣鍗曚环(鍏�)</text>
+              <text class="detail-value highlight">{{ formatAmount(item.taxInclusiveUnitPrice) }}</text>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+    <view v-else class="no-data">
+      <text>鏆傛棤浜у搧鏁版嵁</text>
+    </view>
+    <view class="footer">
+      <u-button class="cancel-btn" @click="goBack">鍙栨秷</u-button>
+      <u-button class="save-btn" type="primary" @click="confirm">纭({{ selectedIds.size }})</u-button>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { onLoad } from "@dcloudio/uni-app";
+  import { ref } from "vue";
+  import { productList } from "@/api/procurementManagement/procurementLedger";
+
+  const purchaseLedgerId = ref(undefined);
+  const list = ref([]);
+  const selectedIds = ref(new Set());
+  const selectedRows = ref(new Map());
+
+  const formatAmount = value => {
+    if (value === null || value === undefined || value === "") return "0.00";
+    const num = Number(value);
+    if (Number.isNaN(num)) return "0.00";
+    return num.toFixed(2);
+  };
+
+  const isSelected = id => {
+    return selectedIds.value.has(String(id));
+  };
+
+  const toggle = item => {
+    const key = String(item.id);
+    if (selectedIds.value.has(key)) {
+      selectedIds.value.delete(key);
+      selectedRows.value.delete(key);
+    } else {
+      selectedIds.value.add(key);
+      selectedRows.value.set(key, item);
+    }
+  };
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const confirm = () => {
+    const rows = Array.from(selectedRows.value.values());
+    uni.setStorageSync("purchaseReturnOrderSelectedProducts", JSON.stringify(rows));
+    uni.navigateBack();
+  };
+
+  const loadList = () => {
+    if (!purchaseLedgerId.value) return;
+    uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+    productList({ salesLedgerId: purchaseLedgerId.value, type: 2 })
+      .then(res => {
+        list.value = res.data || [];
+      })
+      .catch(() => {
+        uni.showToast({ title: "鍔犺浇澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        uni.hideLoading();
+      });
+  };
+
+  const initSelectionFromStorage = () => {
+    const stored = uni.getStorageSync("purchaseReturnOrderSelectedProducts");
+    if (!stored) return;
+    try {
+      const rows = JSON.parse(stored) || [];
+      rows.forEach(r => {
+        const key = String(r.id);
+        selectedIds.value.add(key);
+        selectedRows.value.set(key, r);
+      });
+    } catch {}
+  };
+
+  onLoad(options => {
+    if (options?.purchaseLedgerId) {
+      purchaseLedgerId.value = options.purchaseLedgerId;
+    }
+    initSelectionFromStorage();
+    loadList();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+
+  .footer {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: #fff;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    padding: 12px 0;
+    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
+    z-index: 1000;
+  }
+
+  .cancel-btn {
+    width: 120px;
+    background: #c7c9cc;
+    color: #fff;
+    border-radius: 40px;
+  }
+
+  .save-btn {
+    width: 200px;
+    border-radius: 40px;
+  }
+
+  .sales-account {
+    padding-bottom: 90px;
+  }
+</style>
diff --git a/src/pages/procurementManagement/purchaseReturnOrder/view.vue b/src/pages/procurementManagement/purchaseReturnOrder/view.vue
new file mode 100644
index 0000000..bc33f1c
--- /dev/null
+++ b/src/pages/procurementManagement/purchaseReturnOrder/view.vue
@@ -0,0 +1,202 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="閲囪喘閫�璐ц鎯�" @back="goBack" />
+    <view class="ledger-list" v-if="loaded">
+      <view class="ledger-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">{{ detail.no || "-" }}</text>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row">
+            <text class="detail-label">閫�璐ф柟寮�</text>
+            <text class="detail-value">{{ getReturnTypeLabel(detail.returnType) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">渚涘簲鍟嗗悕绉�</text>
+            <text class="detail-value">{{ detail.supplierName || "-" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">椤圭洰闃舵</text>
+            <text class="detail-value">{{ getProjectPhaseLabel(detail.projectPhase) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鍏宠仈鍗曞彿</text>
+            <text class="detail-value">{{ detail.purchaseContractNumber || "-" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鍒朵綔鏃ユ湡</text>
+            <text class="detail-value">{{ detail.preparedAt || "-" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鍒跺崟浜�</text>
+            <text class="detail-value">{{ detail.preparedUserName || "-" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">閫�鏂欎汉</text>
+            <text class="detail-value">{{ detail.returnUserName || "-" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鏁村崟鎶樻墸棰�</text>
+            <text class="detail-value">{{ formatAmount(detail.totalDiscountAmount) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鏁村崟鎶樻墸鐜�</text>
+            <text class="detail-value">{{ detail.totalDiscountRate ?? "-" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">鎴愪氦閲戦</text>
+            <text class="detail-value highlight">{{ formatAmount(detail.totalAmount) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">澶囨敞</text>
+            <text class="detail-value">{{ detail.remark || "-" }}</text>
+          </view>
+        </view>
+      </view>
+
+      <view class="section-title">
+        <text class="section-text">浜у搧鍒楄〃</text>
+      </view>
+
+      <view v-if="products.length === 0" class="no-data">
+        <text>鏆傛棤浜у搧鏁版嵁</text>
+      </view>
+      <view v-else>
+        <view v-for="(p, idx) in products" :key="idx" class="ledger-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">浜у搧 {{ idx + 1 }}</text>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">浜у搧澶х被</text>
+              <text class="detail-value">{{ p.productCategory || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">瑙勬牸鍨嬪彿</text>
+              <text class="detail-value">{{ p.specificationModel || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍗曚綅</text>
+              <text class="detail-value">{{ p.unit || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鏁伴噺</text>
+              <text class="detail-value">{{ p.quantity ?? "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">閫�璐ф暟閲�</text>
+              <text class="detail-value highlight">{{ p.returnQuantity ?? "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">绋庣巼(%)</text>
+              <text class="detail-value">{{ p.taxRate ?? "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍚◣鍗曚环(鍏�)</text>
+              <text class="detail-value">{{ formatAmount(p.taxInclusiveUnitPrice) }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍚◣鎬讳环(鍏�)</text>
+              <text class="detail-value">{{ formatAmount(p.taxInclusiveTotalPrice) }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鏄惁璐ㄦ</text>
+              <text class="detail-value">{{ p.isChecked ? "鏄�" : "鍚�" }}</text>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref } from "vue";
+  import { onLoad } from "@dcloudio/uni-app";
+  import { getPurchaseReturnOrderDetail } from "@/api/procurementManagement/purchaseReturnOrder";
+
+  const id = ref(undefined);
+  const loaded = ref(false);
+  const detail = ref({});
+  const products = ref([]);
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const getReturnTypeLabel = value => {
+    if (String(value) === "0") return "閫�璐ч��娆�";
+    if (String(value) === "1") return "鎷掓敹";
+    return "-";
+  };
+
+  const getProjectPhaseLabel = value => {
+    const map = {
+      0: "绔嬮」",
+      1: "璁捐",
+      2: "閲囪喘",
+      3: "鐢熶骇",
+      4: "鍑鸿揣",
+    };
+    const key = String(value);
+    return map[key] || "-";
+  };
+
+  const formatAmount = value => {
+    if (value === null || value === undefined || value === "") return "-";
+    const num = Number(value);
+    if (Number.isNaN(num)) return "-";
+    return num.toFixed(2);
+  };
+
+  const loadDetail = () => {
+    if (!id.value) return;
+    uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+    getPurchaseReturnOrderDetail(id.value)
+      .then(res => {
+        const payload = res?.data || {};
+        detail.value = payload;
+        const rows = payload.purchaseReturnOrderProductsDetailVoList || [];
+        products.value = rows.map(i => ({ ...i, ...(i.salesLedgerProduct || {}) }));
+        loaded.value = true;
+      })
+      .catch(() => {
+        uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        uni.hideLoading();
+      });
+  };
+
+  onLoad(options => {
+    if (options?.id) id.value = options.id;
+    loadDetail();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+
+  .section-title {
+    padding: 0 20px;
+    margin: 12px 0 8px 0;
+  }
+
+  .section-text {
+    font-size: 14px;
+    color: #333;
+    font-weight: 600;
+  }
+</style>
diff --git a/src/pages/works.vue b/src/pages/works.vue
index 3d7c2c9..41aad95 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -297,6 +297,14 @@
       icon: "/static/images/icon/gongyingshangwanglai.svg",
       label: "渚涘簲鍟嗗線鏉�",
     },
+    {
+      icon: "/static/images/icon/caigouguanli.svg",
+      label: "閲囪喘閫�璐�",
+    },
+    {
+      icon: "/static/images/icon/gongchuguanli.svg",
+      label: "渚涘簲鍟嗘。妗�",
+    },
   ]);
 
   // 璐㈠姟绠$悊鍔熻兘鏁版嵁
@@ -547,6 +555,16 @@
       case "渚涘簲鍟嗗線鏉�":
         uni.navigateTo({
           url: "/pages/procurementManagement/paymentLedger/index",
+        });
+        break;
+      case "閲囪喘閫�璐�":
+        uni.navigateTo({
+          url: "/pages/procurementManagement/purchaseReturnOrder/index",
+        });
+        break;
+      case "渚涘簲鍟嗘。妗�":
+        uni.navigateTo({
+          url: "/pages/basicData/supplierManage/index",
         });
         break;
       case "鍏嚭绠$悊":
@@ -963,6 +981,7 @@
 
     // 鏀堕泦鎵�鏈夋湁鏉冮檺鐨勮彍鍗曟爣棰橈紙鏍规嵁 meta.title锛�
     const allowedMenuTitles = new Set();
+    const alwaysShowTitles = new Set(["閲囪喘閫�璐у崟", "渚涘簲鍟嗙鐞�"]);
     const collectMenuTitles = routes => {
       if (!Array.isArray(routes)) return;
       routes.forEach(route => {
@@ -980,7 +999,7 @@
     const menuMapping = {
       collaboration: { target: collaborationItems, specialMapping: { "瑙勭珷鍒跺害": "瑙勭珷鍒跺害绠$悊" } },
     };
-
+    console.log(allowedMenuTitles)
     // 閫氱敤杩囨护鍑芥暟
     const filterArray = (targetArray, specialMapping) => {
       const filtered = targetArray.filter(item => {
@@ -1702,4 +1721,4 @@
       box-shadow: 0 0.375rem 1.25rem rgba(0, 0, 0, 0.4);
     }
   }
-</style>
\ No newline at end of file
+</style>

--
Gitblit v1.9.3