From 86d49bfd45dff8e89b7a102eeeff3e2fe86b7871 Mon Sep 17 00:00:00 2001
From: 张诺 <zhang_12370@163.com>
Date: 星期四, 08 一月 2026 18:08:47 +0800
Subject: [PATCH] 1、华玺砂浆采购代码移植至军泰伟业 2、华玺砂浆发货和发货审核代码移植至军泰伟业 3、华玺砂浆报修和报修审核代码移植至军泰伟业

---
 src/views/collaborativeApproval/shipmentReview/fileList.vue        |   43 ++
 src/views/procurementManagement/procurementInvoiceLedger/index.vue |    2 
 src/views/equipmentManagement/spareParts/index.vue                 |   23 
 src/views/equipmentManagement/repair/Modal/MaintainModal.vue       |    2 
 src/views/equipmentManagement/repair/Modal/RepairModal.vue         |   35 +
 src/api/procurementManagement/procurementLedger.js                 |   27 +
 src/views/equipmentManagement/repair/index.vue                     |   46 +
 src/hooks/usePaginationApi.jsx                                     |    8 
 src/views/equipmentManagement/repair/Form/RepairForm.vue           |   76 +++
 src/views/salesManagement/salesLedger/index.vue                    |  146 +++++-
 src/api/collaborativeApproval/shipmentReview.js                    |   21 +
 src/views/procurementManagement/procurementLedger/index.vue        |  393 +++++++++++++++++--
 src/api/salesManagement/salesLedger.js                             |    8 
 src/views/collaborativeApproval/shipmentReview/index.vue           |  340 +++++++++++++++++
 14 files changed, 1,030 insertions(+), 140 deletions(-)

diff --git a/src/api/collaborativeApproval/shipmentReview.js b/src/api/collaborativeApproval/shipmentReview.js
new file mode 100644
index 0000000..64fac69
--- /dev/null
+++ b/src/api/collaborativeApproval/shipmentReview.js
@@ -0,0 +1,21 @@
+// 鍙戣揣瀹℃壒
+import request from "@/utils/request";
+
+// 鑾峰彇鍙戣揣瀹℃壒鍒楄〃
+export function getShipmentApprovalList(query) {
+    return request({
+        url: '/shipmentApproval/listPage',
+        method: 'get',
+        params: query,
+    })
+}
+
+// 鍙戣揣鐢宠鎵瑰噯
+// /shipmentApproval/update
+export function approveShipment(query) {
+    return request({
+        url: '/shipmentApproval/update',
+        method: 'post',
+        data: query,
+    })
+}
\ No newline at end of file
diff --git a/src/api/procurementManagement/procurementLedger.js b/src/api/procurementManagement/procurementLedger.js
index 9fb284e..de5f811 100644
--- a/src/api/procurementManagement/procurementLedger.js
+++ b/src/api/procurementManagement/procurementLedger.js
@@ -72,3 +72,30 @@
     method: "get",
   });
 }
+export function updateApprovalStatus(query) {
+    return request({
+        url: "/purchase/ledger/updateApprovalStatus",
+        method: "post",
+        data: query,
+    });
+}
+
+// 淇濆瓨閲囪喘妯℃澘
+// /purchase/ledger/addPurchaseTemplate
+export function addPurchaseTemplate(data) {
+    return request({
+        url: "/purchase/ledger/addPurchaseTemplate",
+        method: "post",
+        data: data,
+    });
+}
+
+// 鏌ヨ閲囪喘妯℃澘
+// /purchase/ledger/getPurchaseTemplateList
+export function getPurchaseTemplateList(query) {
+    return request({
+        url: "/purchase/ledger/getPurchaseTemplateList",
+        method: "get",
+        params: query,
+    });
+}
diff --git a/src/api/salesManagement/salesLedger.js b/src/api/salesManagement/salesLedger.js
index 3a2fa22..6548927 100644
--- a/src/api/salesManagement/salesLedger.js
+++ b/src/api/salesManagement/salesLedger.js
@@ -109,3 +109,11 @@
     params: query,
   });
 }
+// 閿�鍞彴璐﹂〉闈㈠彂璐э紝鏌ヨ搴撳瓨鏄惁鍏呰冻
+export function getProductInventory(query) {
+    return request({
+        url: "/sales/ledger/getProductInventory",
+        method: "get",
+        params: query,
+    });
+}
\ No newline at end of file
diff --git a/src/hooks/usePaginationApi.jsx b/src/hooks/usePaginationApi.jsx
index f1e8967..553d88a 100644
--- a/src/hooks/usePaginationApi.jsx
+++ b/src/hooks/usePaginationApi.jsx
@@ -87,7 +87,7 @@
       current: pagination.currentPage,
       size: pagination.pageSize
     }).then(({ code, data, msg, ...rest }) => {
-      if (code == 200) {
+      if (code === 200) {
         // pagination.currentPage = meta.current_page;
         // pagination.pageSize = meta.per_page;
         pagination.total = data.total;
@@ -99,7 +99,11 @@
         loading.value = false;
         ElMessage({ message: msg, type: "error" });
       }
-    });
+    }).catch(() => {
+        loading.value = false;
+        ElMessage({ message: msg, type: "error" });
+
+    }).finally(() => {});
   }
 
   function onSizeChange(val) {
diff --git a/src/views/collaborativeApproval/shipmentReview/fileList.vue b/src/views/collaborativeApproval/shipmentReview/fileList.vue
new file mode 100644
index 0000000..da37db2
--- /dev/null
+++ b/src/views/collaborativeApproval/shipmentReview/fileList.vue
@@ -0,0 +1,43 @@
+<template>
+  <el-dialog v-model="dialogVisible" title="闄勪欢" width="40%" :before-close="handleClose">
+    <el-table :data="tableData" border height="40vh">
+      <el-table-column label="闄勪欢鍚嶇О" prop="name" min-width="400" show-overflow-tooltip />
+      <el-table-column fixed="right" label="鎿嶄綔" width="100" align="center">
+        <template #default="scope">
+          <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">涓嬭浇</el-button>
+          <el-button link type="primary" size="small" @click="lookFile(scope.row)">棰勮</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </el-dialog>
+  <filePreview ref="filePreviewRef" />
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import filePreview from '@/components/filePreview/index.vue'
+
+const dialogVisible = ref(false)
+const tableData = ref([])
+const { proxy } = getCurrentInstance();
+const filePreviewRef = ref()
+const handleClose = () => {
+  dialogVisible.value = false
+}
+const open = (list) => {
+  dialogVisible.value = true
+  tableData.value = list
+}
+const downLoadFile = (row) => {
+  proxy.$download.name(row.url);
+
+}
+const lookFile = (row) => {
+  filePreviewRef.value.open(row.url)
+}
+defineExpose({
+  open
+})
+</script>
+
+<style></style>
\ No newline at end of file
diff --git a/src/views/collaborativeApproval/shipmentReview/index.vue b/src/views/collaborativeApproval/shipmentReview/index.vue
new file mode 100644
index 0000000..ac2b790
--- /dev/null
+++ b/src/views/collaborativeApproval/shipmentReview/index.vue
@@ -0,0 +1,340 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">閿�鍞悎鍚屽彿锛�</span>
+        <el-input
+            v-model="searchForm.salesContractNo"
+            style="width: 240px"
+            placeholder="璇疯緭鍏ラ攢鍞悎鍚屽彿鎼滅储"
+            @change="handleQuery"
+            clearable
+            :prefix-icon="Search"
+        />
+        <span class="search_title ml10">瀹℃壒鐘舵�侊細</span>
+        <el-select v-model="searchForm.approveStatus" clearable @change="handleQuery" style="width: 240px">
+          <el-option label="寰呭鏍�" :value="2" />
+          <el-option label="瀹℃牳鎴愬姛" :value="3" />
+          <el-option label="瀹℃牳澶辫触" :value="4" />
+        </el-select>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+        >鎼滅储</el-button
+        >
+      </div>
+      <div>
+<!--        <el-button type="primary" @click="openForm('add')">鏂板</el-button>-->
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+<!--        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>-->
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable
+          rowKey="id"
+          :column="tableColumn"
+          :tableData="tableData"
+          :page="page"
+          :isSelection="true"
+          @selection-change="handleSelectionChange"
+          :tableLoading="tableLoading"
+          @pagination="pagination"
+          :total="page.total"
+      ></PIMTable>
+    </div>
+    <info-form-dia ref="infoFormDia" @close="handleQuery" :approveType="approveType"></info-form-dia>
+    <approval-dia ref="approvalDia" @close="handleQuery"></approval-dia>
+    <FileList ref="fileListRef" />
+  </div>
+</template>
+
+<script setup>
+import FileList from "./fileList.vue";
+import { Search } from "@element-plus/icons-vue";
+import {onMounted, ref} from "vue";
+import {ElMessageBox} from "element-plus";
+import InfoFormDia from "@/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue";
+import ApprovalDia from "@/views/collaborativeApproval/approvalProcess/components/approvalDia.vue";
+import {getShipmentApprovalList, approveShipment} from "@/api/collaborativeApproval/shipmentReview.js";
+// import {approveProcessDelete, approveProcessListPage} from "@/api/collaborativeApproval/approvalProcess.js";
+import useUserStore from "@/store/modules/user";
+import { userListNoPage } from "@/api/system/user.js";
+
+// 瀹氫箟缁勪欢鎺ユ敹鐨刾rops
+const props = defineProps({
+  approveType: {
+    type: [Number, String],
+    default: 6
+  }
+});
+
+const userList = ref([]);
+
+const userStore = useUserStore();
+
+
+const data = reactive({
+  searchForm: {
+    approveId: "",
+    approveStatus: "",
+  },
+});
+const { searchForm } = toRefs(data);
+const tableColumn = ref([
+  {
+    label: "瀹℃壒鐘舵��",
+    prop: "approveStatus",
+    dataType: "tag",
+    width: 100,
+    formatData: (params) => {
+      if (params === 2) {
+        return "寰呭鏍�";
+      } else if (params === 3) {
+        return "瀹℃牳瀹屾垚";
+      } else if (params === 4) {
+        return "瀹℃牳椹冲洖";
+      } else {
+        return '鏈煡鐘舵��';
+      }
+    },
+    formatType: (params) => {
+      if (params === 0) {
+        return "warning";
+      } else if (params === 2) {
+        return "info";
+      } else if (params === 3) {
+        return "success";
+      } else if (params === 4) {
+        return "danger";
+      } else {
+        return 'danger';
+      }
+    },
+  },
+  {
+    label: "閿�鍞悎鍚屽彿",
+    prop: "salesContractNo",
+    width: 170
+  },
+  {
+    label: "瀹㈡埛鍚嶇О",
+    prop: "customerName",
+    width: 200
+  },
+  {
+    label: "浜у搧澶х被",
+    prop: "productCategory",
+    width: 200
+  },
+  {
+    label: "瑙勬牸鍨嬪彿",
+    prop: "specificationModel",
+    width: 220
+  },
+  {
+    label: "鐢宠浜�",
+    prop: "approveUserId",
+    width: 120,
+    align: "center",
+    formatData:(params)=>{
+      const user = userList.value.find(item => item.userId === params)
+      return user ? user.nickName : '--'
+    }
+  },
+  {
+    label: "杞︾墝鍙�",
+    prop: "shippingCarNumber",
+    width: 120,
+  },
+  {
+    label: "鐢宠浜�",
+    prop: "approveUserId",
+    width: 120,
+  },
+  {
+    label: "鐢宠鏃ユ湡",
+    prop: "executionDate",
+    width: 200
+  },
+  {
+    label: "褰撳墠瀹℃壒浜�",
+    prop: "salesman",
+    width: 120
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: "right",
+    width: 120,
+    operation: [
+      {
+        name: "閫氳繃",
+        type: "text",
+        clickFun: (row) => {
+          handleApproval("閫氳繃", row);
+        },
+        disabled: (row) => row.approveStatus !== 2
+      },
+      {
+        name: "椹冲洖",
+        type: "text",
+        clickFun: (row) => {
+          handleApproval("椹冲洖", row);
+        },
+        disabled: (row) => row.approveStatus !== 2
+      },
+      // {
+      //   name: "缂栬緫",
+      //   type: "text",
+      //   clickFun: (row) => {
+      //     openForm("edit", row);
+      //   },
+      //   disabled: (row) => row.approveStatus == 2 || row.approveStatus == 1 || row.approveStatus == 4
+      // },
+      // {
+      //   name: "瀹℃牳",
+      //   type: "text",
+      //   clickFun: (row) => {
+      //     openApprovalDia("approval", row);
+      //   },
+      //   disabled: (row) => row.approveUserCurrentId == null || row.approveStatus == 2 || row.approveStatus == 3 || row.approveStatus == 4 || row.approveUserCurrentId !== userStore.id
+      // },
+      // {
+      //   name: "璇︽儏",
+      //   type: "text",
+      //   clickFun: (row) => {
+      //     openApprovalDia('view', row);
+      //   },
+      // },
+      // {
+      //   name: "闄勪欢",
+      //   type: "text",
+      //   clickFun: (row) => {
+      //     downLoadFile(row);
+      //   },
+      // },
+    ],
+  },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0
+});
+const infoFormDia = ref()
+const approvalDia = ref()
+const { proxy } = getCurrentInstance()
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const fileListRef = ref(null)
+const downLoadFile = (row) => {
+  fileListRef.value.open(row.commonFileList)
+
+}
+const pagination = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList =async () => {
+  let userLists = await userListNoPage();
+  userList.value = userLists.data;
+  tableLoading.value = true;
+  getShipmentApprovalList({...page, ...searchForm.value,approveType:props.approveType}).then(res => {
+    tableLoading.value = false;
+    tableData.value = res.data.records
+    page.total = res.data.total;
+  }).catch(err => {
+    tableLoading.value = false;
+  })
+};
+// 瀵煎嚭
+const handleOut = () => {
+  const type = Number(props.approveType || 6)
+  const urlMap = {
+    0: "/shipmentApproval/export",
+  }
+  const url = urlMap[type] || urlMap[0]
+  const nameMap = {
+    0: "鍙戣揣瀹℃牳琛�",
+  }
+  const fileName = nameMap[type] || nameMap[0]
+  proxy.download(url, {}, `${fileName}.xlsx`)
+}
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+
+// 鎵撳紑鏂板銆佺紪杈戝脊妗�
+const openForm = (type, row) => {
+  nextTick(() => {
+    infoFormDia.value?.openDialog(type, row)
+  })
+};
+// 鎵撳紑鏂板妫�楠屽脊妗�
+const openApprovalDia = (type, row) => {
+  nextTick(() => {
+    approvalDia.value?.openDialog(type, row)
+  })
+};
+
+// 瀹℃牳閫氳繃/椹冲洖
+const handleApproval = (name = "瀹℃牳",row) => {
+  ElMessageBox.confirm(`閫変腑鐨勫唴瀹瑰皢琚�${name}锛屾槸鍚︾‘璁�${name}锛焋, "鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(async()=>{
+    let res = await approveShipment({
+      id: row.id,
+      approveStatus: name === "閫氳繃" ? 3 : 4
+    });
+    if(res.code === 200){
+      proxy.$modal.msgSuccess(`${name}鎴愬姛`);
+    }else{
+      proxy.$modal.msgError(`${name}澶辫触`);
+    }
+    await getList()
+  }).catch(err=>{
+    proxy.$modal.msgError(`鏈煡閿欒,璇疯仈绯荤鐞嗗憳`);
+  })
+};
+
+// 鍒犻櫎
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    ids = selectedRows.value.map((item) => item.approveId);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+      .then(() => {
+        approveProcessDelete(ids).then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+};
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped></style>
diff --git a/src/views/equipmentManagement/repair/Form/RepairForm.vue b/src/views/equipmentManagement/repair/Form/RepairForm.vue
index eaef93f..f374172 100644
--- a/src/views/equipmentManagement/repair/Form/RepairForm.vue
+++ b/src/views/equipmentManagement/repair/Form/RepairForm.vue
@@ -1,9 +1,9 @@
 <template>
-  <el-form :model="form" label-width="100px">
+  <el-form :model="form" ref="formModelRefs" :rules="rules" label-width="100px">
     <el-row>
       <el-col :span="12">
-        <el-form-item label="璁惧鍚嶇О">
-          <el-select v-model="form.deviceLedgerId" @change="setDeviceModel">
+        <el-form-item label="璁惧鍚嶇О" prop="deviceLedgerId">
+          <el-select v-model="form.deviceLedgerId" @change="setDeviceModel" filterable>
             <el-option
               v-for="(item, index) in deviceOptions"
               :key="index"
@@ -14,7 +14,7 @@
         </el-form-item>
       </el-col>
       <el-col :span="12">
-        <el-form-item label="瑙勬牸鍨嬪彿">
+        <el-form-item label="瑙勬牸鍨嬪彿" prop="deviceModel">
           <el-input
             v-model="form.deviceModel"
             placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
@@ -23,7 +23,7 @@
         </el-form-item>
       </el-col>
       <el-col :span="12">
-        <el-form-item label="鎶ヤ慨鏃ユ湡">
+        <el-form-item label="鎶ヤ慨鏃ユ湡" prop="repairTime">
           <el-date-picker
             v-model="form.repairTime"
             placeholder="璇烽�夋嫨鎶ヤ慨鏃ユ湡"
@@ -36,15 +36,15 @@
         </el-form-item>
       </el-col>
       <el-col :span="12">
-        <el-form-item label="鎶ヤ慨浜�">
-          <el-input v-model="form.repairName" placeholder="璇疯緭鍏ユ姤淇汉" />
+        <el-form-item label="鎶ヤ慨浜哄憳" prop="repairName">
+          <el-input v-model="form.repairName" placeholder="璇疯緭鍏ユ姤淇汉鍛�" />
         </el-form-item>
       </el-col>
     </el-row>
     <el-row v-if="id">
       <el-col :span="12">
         <el-form-item label="鎶ヤ慨鐘舵��">
-          <el-select v-model="form.status">
+          <el-select v-model="form.status" prop="status">
             <el-option label="寰呯淮淇�" :value="0"></el-option>
             <el-option label="瀹岀粨" :value="1"></el-option>
             <el-option label="澶辫触" :value="2"></el-option>
@@ -53,8 +53,27 @@
       </el-col>
     </el-row>
     <el-row>
+      <el-col :span="12">
+        <el-form-item label="鎶ヤ慨閲戦" prop="maintenancePrice">
+          <el-input-number
+              style="width: 100%"
+              :min="0"
+              v-model="form.maintenancePrice"
+              placeholder="璇疯緭鍏ヤ繚淇噾棰�"
+          />
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="瀹℃壒浜哄憳" prop="approverId">
+          <el-select v-model="form.approverId" placeholder="璇烽�夋嫨瀹℃壒浜哄憳" clearable>
+            <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
+          </el-select>
+        </el-form-item>
+      </el-col>
+    </el-row>
+    <el-row>
       <el-col :span="24">
-        <el-form-item label="鏁呴殰鐜拌薄">
+        <el-form-item label="鏁呴殰鐜拌薄" prop="remark">
           <el-input
             v-model="form.remark"
             :rows="2"
@@ -68,9 +87,12 @@
 </template>
 
 <script setup>
+import {onMounted} from "vue"
+import dayjs from "dayjs";
 import useFormData from "@/hooks/useFormData";
 import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
 import useUserStore from "@/store/modules/user";
+import { userListNoPage } from "@/api/system/user.js";
 
 const { id } = defineProps(["id"])
 
@@ -80,20 +102,44 @@
 
 const userStore = useUserStore();
 const deviceOptions = ref([]);
+const formModelRefs = ref(null)
+const userList = ref(null)
 
 const loadDeviceName = async () => {
   const { data } = await getDeviceLedger();
   deviceOptions.value = data;
 };
 
+const rules = {
+  deviceLedgerId: [{ required: true, message: "璇烽�夋嫨璁惧鍚嶇О", trigger: "change" }],
+  repairTime: [{ required: true, message: "璇烽�夋嫨鎶ヤ慨鏃ユ湡", trigger: "change" }],
+  repairName: [{ required: true, message: "璇疯緭鍏ユ姤淇汉", trigger: "blur" }],
+  remark: [{ required: true, message: "璇疯緭鍏ユ晠闅滅幇璞�", trigger: "blur" }],
+  maintenancePrice: [{ required: true, message: "璇疯緭鍏ヤ繚淇噾棰�", trigger: "blur" }],
+  approverId:[{required: true,message: "璇烽�夋嫨瀹℃壒浜�", trigger: "change"}]
+};
+
+// 鏍¢獙琛ㄥ崟鏄惁鍚堣
+const submitForm = async () => {
+  if (!formModelRefs.value) return false;
+
+  try {
+    await formModelRefs.value.validate();
+    return true; // 琛ㄥ崟楠岃瘉閫氳繃
+  } catch (error) {
+    return false; // 琛ㄥ崟楠岃瘉澶辫触
+  }
+};
+
 const { form, resetForm } = useFormData({
   deviceLedgerId: undefined, // 璁惧Id
   deviceName: undefined, // 璁惧鍚嶇О
   deviceModel: undefined, // 瑙勬牸鍨嬪彿
-  repairTime: undefined, // 鎶ヤ慨鏃ユ湡
+  repairTime: dayjs().format("YYYY-MM-DD"), // 鎶ヤ慨鏃ユ湡锛岄粯璁ゅ綋澶�
   repairName: userStore.nickName, // 鎶ヤ慨浜�
   remark: undefined, // 鏁呴殰鐜拌薄
   status: 0, // 鎶ヤ慨鐘舵��
+  maintenancePrice:0, // 淇濅慨閲戦
 });
 
 const setDeviceModel = (id) => {
@@ -113,17 +159,21 @@
   form.repairName = data.repairName;
   form.remark = data.remark;
   form.status = data.status;
+  form.maintenancePrice = data.maintenancePrice
 };
 
-// onMounted(() => {
-//   loadDeviceName();
-// });
+onMounted(async() => {
+  // loadDeviceName();
+  let userLists = await userListNoPage();
+  userList.value = userLists.data;
+});
 
 defineExpose({
   loadDeviceName,
   resetForm,
   getForm,
   setForm,
+  submitForm
 });
 </script>
 
diff --git a/src/views/equipmentManagement/repair/Modal/MaintainModal.vue b/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
index 309be0e..a578a58 100644
--- a/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
+++ b/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
@@ -1,5 +1,5 @@
 <template>
-  <el-dialog v-model="visible" :title="modalOptions.title" direction="ltr">
+  <el-dialog v-model="visible" :title="modalOptions.title" direction="ltr" draggable>
     <MaintainForm ref="maintainFormRef" />
     <template #footer>
 			<el-button type="primary" @click="sendForm" :loading="loading">
diff --git a/src/views/equipmentManagement/repair/Modal/RepairModal.vue b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
index 0ae3bbe..e89b0ac 100644
--- a/src/views/equipmentManagement/repair/Modal/RepairModal.vue
+++ b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
@@ -1,5 +1,5 @@
 <template>
-  <el-dialog v-model="visible" :title="modalOptions.title" @close="close">
+  <el-dialog v-model="visible" :title="modalOptions.title" @close="close" draggable>
     <RepairForm ref="repairFormRef" :id="id" />
     <template #footer>
 			<el-button type="primary" @click="sendForm" :loading="loading">
@@ -38,17 +38,32 @@
 } = useModal({ title: "璁惧鎶ヤ慨" });
 
 const sendForm = async () => {
-  loading.value = true;
-  const form = await repairFormRef.value.getForm();
-  const { code } = id.value
-    ? await editRepair({ id: unref(id), ...form })
-    : await addRepair(form);
-  if (code == 200) {
-    ElMessage.success(`${id ? "缂栬緫" : "鏂板"}鎶ヤ慨鎴愬姛`);
+  try {
+    // 寮�濮嬪姞杞�
+    loading.value = true;
+    // 鎻愪氦琛ㄥ崟骞惰幏鍙栨牎楠岀粨鏋�
+    const submitStatus = await repairFormRef.value.submitForm();
+    if (!submitStatus) {
+      // 濡傛灉琛ㄥ崟楠岃瘉澶辫触锛屽彇娑堝姞杞界姸鎬�
+      loading.value = false;
+      return;
+    }
+    // 鑾峰彇琛ㄥ崟鏁版嵁
+    const form = await repairFormRef.value.getForm();
+    // 鏍规嵁鏄惁鏈塈D鍐冲畾鏄紪杈戣繕鏄柊澧�
+    const { code } = id.value
+        ? await editRepair({ id: unref(id), ...form })
+        : await addRepair(form);
+    if (code === 200) {
+      ElMessage.success(`${id ? "缂栬緫" : "鏂板"}鎶ヤ慨鎴愬姛`);
+      emits("ok");
+    }
+  } catch (error) {
+  } finally {
+    // 鏃犺鎴愬姛杩樻槸澶辫触锛岄兘鍙栨秷鍔犺浇鐘舵��
+    loading.value = false;
     closeModal();
-    emits("ok");
   }
-  loading.value = false;
 };
 
 const openAdd = async () => {
diff --git a/src/views/equipmentManagement/repair/index.vue b/src/views/equipmentManagement/repair/index.vue
index 08cbcc2..341b654 100644
--- a/src/views/equipmentManagement/repair/index.vue
+++ b/src/views/equipmentManagement/repair/index.vue
@@ -71,7 +71,7 @@
           <el-button
             type="primary"
             icon="Plus"
-            :disabled="multipleList.length !== 1"
+            :disabled="multipleList.length !== 1 || multipleList[0]?.status !== 1"
             @click="addMaintain"
           >
             鏂板缁翠慨
@@ -86,7 +86,7 @@
             type="danger"
             icon="Delete"
             :disabled="multipleList.length <= 0"
-            @click="delRepairByIds(multipleList.map((item) => item.id))"
+            @click="delRepairByIds(multipleList)"
           >
             鎵归噺鍒犻櫎
           </el-button>
@@ -106,9 +106,12 @@
         @pagination="changePage"
       >
         <template #statusRef="{ row }">
-          <el-tag v-if="row.status === 2" type="danger">澶辫触</el-tag>
-          <el-tag v-if="row.status === 1" type="success">瀹岀粨</el-tag>
-          <el-tag v-if="row.status === 0" type="warning">寰呯淮淇�</el-tag>
+          <el-tag v-if="row.status === 5" type="danger">缁翠慨澶辫触</el-tag>
+          <el-tag v-if="row.status === 4" type="danger">缁翠慨鎴愬姛</el-tag>
+          <el-tag v-if="row.status === 3" type="danger">缁翠慨涓�</el-tag>
+          <el-tag v-if="row.status === 2" type="danger">瀹℃牳澶辫触</el-tag>
+          <el-tag v-if="row.status === 1" type="success">瀹℃牳閫氳繃</el-tag>
+          <el-tag v-if="row.status === 0" type="warning">瀹℃牳涓�</el-tag>
         </template>
         <template #operation="{ row }">
           <el-button
@@ -116,6 +119,7 @@
             text
             icon="editPen"
             @click="editRepair(row.id)"
+            :disabled="row.status !== 0"
           >
             缂栬緫
           </el-button>
@@ -123,7 +127,8 @@
             type="danger"
             text
             icon="delete"
-            @click="delRepairByIds(row.id)"
+            @click="delRepairByIds(row)"
+            :disabled="row.status !== 0"
           >
             鍒犻櫎
           </el-button>
@@ -282,15 +287,40 @@
 
 // 鍗曡鍒犻櫎
 const delRepairByIds = async (ids) => {
+  let isDel = false
+  if(Array.isArray(ids)){
+    ids.forEach((item)=>{
+      if(item.status !== 0){
+        isDel = true
+      }
+    })
+  }else{
+    if(ids.status !== 0){
+      isDel = true
+    }
+  }
+
+  if(isDel){
+    ElMessage.warning("鍙兘鍒犻櫎瀹℃牳涓殑鎶ヤ慨鏁版嵁");
+    return
+  }
+
   ElMessageBox.confirm("纭鍒犻櫎鎶ヤ慨鏁版嵁, 姝ゆ搷浣滀笉鍙��?", "璀﹀憡", {
     confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   }).then(async () => {
-    const { code } = await delRepair(ids);
+    let idsList = ""
+    if(Array.isArray(ids)){
+      idsList = multipleList.value.map((item) => item.id);
+      console.log(idsList)
+    }else{
+      idsList = ids.id
+    }
+    const { code } = await delRepair(idsList);
     if (code === 200) {
       ElMessage.success("鍒犻櫎鎴愬姛");
-      getTableData();
+      await getTableData();
     }
   });
 };
diff --git a/src/views/equipmentManagement/spareParts/index.vue b/src/views/equipmentManagement/spareParts/index.vue
index f91d76f..e0bbe77 100644
--- a/src/views/equipmentManagement/spareParts/index.vue
+++ b/src/views/equipmentManagement/spareParts/index.vue
@@ -41,8 +41,7 @@
               缂栬緫
             </el-button>
             <el-button
-              type="text"
-              size="small"
+							link
               @click="() => deleteCategory(row.id)"
               style="color: #f56c6c;"
               :disabled="loading"
@@ -70,17 +69,15 @@
         <el-form-item label="鎻忚堪" prop="description">
           <el-input v-model="form.description"></el-input>
         </el-form-item>
-        <el-form-item label="涓婄骇鍒嗙被" prop="parentId">
-          <el-select v-model="form.parentId" placeholder="璇烽�夋嫨涓婄骇鍒嗙被">
-            <el-option label="鏃犱笂绾у垎绫�" :value="null"></el-option>
-            <el-option
-              v-for="(item, index) in categories"
-              :key="index"
-              :label="item.name"
-              :value="item.id"
-              
-            ></el-option>
-          </el-select>
+        <el-form-item label="浠锋牸" prop="price">
+          <el-input-number
+            v-model="form.price"
+            placeholder="璇疯緭鍏ヤ环鏍�"
+            :min="0"
+            :step="0.01"
+            :precision="2"
+            style="width: 100%"
+          ></el-input-number>
         </el-form-item>
       </el-form>
       <template #footer>
diff --git a/src/views/procurementManagement/procurementInvoiceLedger/index.vue b/src/views/procurementManagement/procurementInvoiceLedger/index.vue
index 5c01e3a..bc05272 100644
--- a/src/views/procurementManagement/procurementInvoiceLedger/index.vue
+++ b/src/views/procurementManagement/procurementInvoiceLedger/index.vue
@@ -222,7 +222,7 @@
     },
     {
       fixed: "right",
-      width: 190,
+      width: 150,
       label: "鎿嶄綔",
       dataType: "slot",
       slot: "operation",
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index abdc474..7b81814 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -238,16 +238,25 @@
             </el-form-item>
           </el-col>
 					<el-col :span="12">
-						<el-form-item label="浠樻鏂瑰紡">
-							<el-input
-								v-model="form.paymentMethod"
-								placeholder="璇疯緭鍏�"
-								clearable
-							/>
-						</el-form-item>
+            <el-form-item label="椤圭洰鍚嶇О" prop="projectName">
+              <el-input
+                  v-model="form.projectName"
+                  placeholder="璇疯緭鍏�"
+                  clearable
+              />
+            </el-form-item>
 					</el-col>
         </el-row>
 				<el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="浠樻鏂瑰紡">
+              <el-input
+                  v-model="form.paymentMethod"
+                  placeholder="璇疯緭鍏�"
+                  clearable
+              />
+            </el-form-item>
+          </el-col>
 					<el-col :span="12">
 						<el-form-item label="绛捐鏃ユ湡锛�" prop="executionDate">
 							<el-date-picker
@@ -264,14 +273,26 @@
 				</el-row>
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="褰曞叆浜猴細" prop="recorderId">
+            <el-form-item label="瀹℃壒浜猴細" prop="approverId">
               <el-select
-                v-model="form.recorderId"
-                placeholder="璇烽�夋嫨"
-                clearable
-                filterable
-                default-first-option
-                :reserve-keyword="false"
+                  v-model="form.approverId"
+                  placeholder="璇烽�夋嫨瀹℃壒浜�"
+                  clearable
+              >
+                <el-option
+                    v-for="item in userList"
+                    :key="item.userId"
+                    :label="item.nickName"
+                    :value="item.userId"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="褰曞叆浜猴細" prop="recorderId" v-show="false">
+              <el-select
+                  v-model="form.recorderId"
+                  placeholder="璇烽�夋嫨"
+                  clearable
+                  disabled
               >
                 <el-option
                   v-for="item in userList"
@@ -305,6 +326,37 @@
               >鍒犻櫎</el-button
             >
           </el-form-item>
+          <div class="select-button-group" style="width: 220px; margin: 20px 0;" v-if="operationType === 'add'">
+            <el-select
+                filterable
+                allow-create
+                :reserve-keyword="true"
+                :default-first-option="false"
+                v-model="templateName"
+                :input-value="filterInputValue"
+                @filter-change="onTemplateFilterChange"
+                @change="onTemplateChange"
+                style="width: 180px; border-right: none; border-radius: 4px 0 0 4px;"
+                placeholder="璇烽�夋嫨"
+                class="no-arrow-select"
+            >
+              <el-option
+                  v-for="item in templateList"
+                  :key="item.value"
+                  :label="item.templateName"
+                  :value="item.templateName"
+              ></el-option>
+            </el-select>
+            <!-- 鎸夐挳锛氫笌 Select 楂樺害鍖归厤锛屽幓鎺夊乏渚ц竟妗嗭紝鏃犵紳琛旀帴 -->
+            <el-button
+                size="small"
+                style="height: 32px; border-radius: 0 4px 4px 0; margin-left: -1px;"
+                @click="handleButtonClick"
+                :disabled="!templateName || templateName.trim() === '' || isTemplateNameDuplicate"
+            >
+              淇濆瓨
+            </el-button>
+          </div>
         </el-row>
         <el-table
           :data="productData"
@@ -776,7 +828,7 @@
 import pagination from "@/components/PIMTable/Pagination.vue";
 import { ref, onMounted, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
 import { Search } from "@element-plus/icons-vue";
-import { ElMessageBox } from "element-plus";
+import { ElMessageBox,ElMessage } from "element-plus";
 import { userListNoPage } from "@/api/system/user.js";
 import FileList from "./fileList.vue";
 import {
@@ -795,6 +847,8 @@
   getPurchaseById,
   getOptions,
   createPurchaseNo,
+  getPurchaseTemplateList,
+  addPurchaseTemplate,
 } from "@/api/procurementManagement/procurementLedger.js";
 import useFormData from "@/hooks/useFormData.js";
 import QRCode from "qrcode";
@@ -825,6 +879,103 @@
 const qrCodeDialogVisible = ref(false);
 const qrCodeUrl = ref("");
 
+// 璁㈠崟瀹℃壒鐘舵�佹樉绀烘枃鏈�
+const approvalStatusText = {
+  0: '瀹℃壒涓�',
+  1: '瀹℃壒閫氳繃',
+  2: '瀹℃壒澶辫触'
+};
+
+
+const templateName = ref('');
+const filterInputValue = ref('');
+const templateList = ref([]);
+const isTemplateNameDuplicate = ref(false); // 鏍囪妯℃澘鍚嶇О鏄惁閲嶅
+
+// 妫�鏌ユā鏉垮悕绉版槸鍚﹂噸澶�
+const checkTemplateNameDuplicate = (name) => {
+  if (!name || name.trim() === '') {
+    isTemplateNameDuplicate.value = false;
+    return false;
+  }
+  const isDuplicate = templateList.value.some(item => item.templateName === name.trim());
+  isTemplateNameDuplicate.value = isDuplicate;
+  return isDuplicate;
+};
+
+// 闃叉姈瀹氭椂鍣�
+let duplicateCheckTimer = null;
+const onTemplateFilterChange = (val) => {
+  filterInputValue.value = val ?? '';
+  // 娓呴櫎涔嬪墠鐨勫畾鏃跺櫒
+  if (duplicateCheckTimer) {
+    clearTimeout(duplicateCheckTimer);
+  }
+  // 瀹炴椂妫�鏌ユā鏉垮悕绉版槸鍚﹂噸澶嶏紙闃叉姈澶勭悊锛岄伩鍏嶉绻佹彁绀猴級
+  if (val && val.trim()) {
+    duplicateCheckTimer = setTimeout(() => {
+      const isDuplicate = checkTemplateNameDuplicate(val);
+      if (isDuplicate) {
+        ElMessage({
+          message: '妯℃澘鍚嶇О宸插瓨鍦紝璇锋洿鎹㈡ā鏉垮悕绉�',
+          type: 'warning',
+          duration: 2000
+        });
+      }
+    }, 300); // 300ms 闃叉姈
+  } else {
+    isTemplateNameDuplicate.value = false;
+  }
+};
+
+// allow-create 鏃讹紝杈撳叆涓嶅瓨鍦ㄧ殑鍐呭浼氫綔涓� string 鍊艰繑鍥烇紱杩欓噷鍚屾鍥炶緭鍏ユ浠ョ‘淇濇枃瀛椾笉涓�
+const onTemplateChange = async (val) => {
+  if (typeof val === 'string') {
+    filterInputValue.value = val;
+    // 閫夋嫨鎴栬緭鍏ユ椂妫�鏌ラ噸澶�
+    checkTemplateNameDuplicate(val);
+  }
+
+  // 杩囨护鏁版嵁锛屾煡鎵惧尮閰嶇殑妯℃澘
+  const matchedTemplate = templateList.value.find(item => item.templateName === val);
+
+  if (matchedTemplate?.id) {
+    // 濡傛灉鎵惧埌妯℃澘锛屽姞杞芥ā鏉挎暟鎹�
+    form.value = {
+      ...form.value,
+      ...matchedTemplate,
+    };
+    productData.value = matchedTemplate.productData || [];
+    // 鐢熸垚鏂扮殑閲囪喘鍚堝悓鍙�
+    try {
+      const res = await createPurchaseNo();
+      if (res?.data) {
+        form.value.purchaseContractNumber = res.data;
+      }
+    } catch (error) {
+      console.error('鐢熸垚閲囪喘鍚堝悓鍙峰け璐�:', error);
+    }
+  } else {
+    // 濡傛灉娌℃湁鎵惧埌妯℃澘锛岄噸缃〃鍗曪紙淇濇寔褰撳墠琛ㄥ崟鐘舵�侊級
+    const currentFormData = { ...form.value };
+    const currentProductData = [...productData.value];
+
+    // 濡傛灉瀵硅瘽妗嗘湭鎵撳紑锛屽厛鎵撳紑
+    if (!dialogFormVisible.value) {
+      operationType.value = 'add';
+      dialogFormVisible.value = true;
+    }
+
+    // 绛夊緟涓嬩竴涓� tick 鍚庢仮澶嶆暟鎹�
+    await nextTick();
+    form.value = {
+      ...form.value,
+      ...currentFormData,
+    };
+    productData.value = currentProductData;
+  }
+};
+
 // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
 const operationType = ref("");
 const dialogFormVisible = ref(false);
@@ -852,7 +1003,8 @@
     purchaseContractNumber: [
       { required: true, message: "璇疯緭鍏�", trigger: "blur" },
     ],
-    supplierId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    approverId:[{ required: true, message: "璇烽�夋嫨瀹℃壒浜�", trigger: "change" }],
+    projectName:[{ required:true, message:"璇疯緭鍏ラ」鐩悕绉�", trigger:"blur"}],
 		entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
   },
@@ -933,6 +1085,83 @@
   page.current = 1;
   getList();
 };
+
+// 淇濆瓨妯℃澘
+const handleButtonClick = async () => {
+  // 妫�鏌ユā鏉垮悕绉版槸鍚︿负绌�
+  if (!templateName.value || templateName.value.trim() === '') {
+    ElMessage({
+      message: '璇疯緭鍏ユā鏉垮悕绉�',
+      type: 'warning',
+    });
+    return;
+  }
+
+  // 妫�鏌ユā鏉垮悕绉版槸鍚﹂噸澶�
+  const isDuplicate = checkTemplateNameDuplicate(templateName.value);
+  if (isDuplicate) {
+    ElMessage({
+      message: '妯℃澘鍚嶇О宸插瓨鍦紝璇锋洿鎹㈡ā鏉垮悕绉�',
+      type: 'warning',
+    });
+    return;
+  }
+
+  // 妫�鏌ヤ緵搴斿晢鏄惁閫夋嫨
+  if (!form.value.supplierId) {
+    ElMessage({
+      message: '璇峰厛閫夋嫨渚涘簲鍟�',
+      type: 'warning',
+    });
+    return;
+  }
+
+  // 妫�鏌ユ槸鍚︽湁浜у搧鏁版嵁
+  // if (!productData.value || productData.value.length === 0) {
+  //   ElMessage({
+  //     message: '璇峰厛娣诲姞浜у搧淇℃伅',
+  //     type: 'warning',
+  //   });
+  //   return;
+  // }
+
+  try {
+    let params = {
+      productData: proxy.HaveJson(productData.value),
+      supplierId: form.value.supplierId,
+      paymentMethod: form.value.paymentMethod,
+      recorderId: form.value.recorderId,
+      approverId: form.value.approverId,
+      templateName: templateName.value.trim()
+    };
+    console.log(params);
+    let res = await addPurchaseTemplate(params);
+
+    if (res && res.code === 200) {
+      ElMessage({
+        message: '妯℃澘淇濆瓨鎴愬姛',
+        type: 'success',
+      });
+      // 淇濆瓨鎴愬姛鍚庨噸鏂拌幏鍙栨ā鏉垮垪琛�
+      await getTemplateList();
+      // 娓呯┖妯℃澘鍚嶇О杈撳叆
+      templateName.value = '';
+      filterInputValue.value = '';
+      isTemplateNameDuplicate.value = false;
+    } else {
+      ElMessage({
+        message: res?.msg || '妯℃澘淇濆瓨澶辫触',
+        type: 'error',
+      });
+    }
+  } catch (error) {
+    console.error('淇濆瓨妯℃澘澶辫触:', error);
+    ElMessage({
+      message: '妯℃澘淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯',
+      type: 'error',
+    });
+  }
+};
 // 瀛愯〃鍚堣鏂规硶
 const summarizeChildrenTable = (param) => {
   return proxy.summarizeTable(
@@ -983,19 +1212,24 @@
 };
 const expandedRowKeys = ref([]);
 // 灞曞紑琛�
-const expandChange = (row, expandedRows) => {
+const expandChange = async (row, expandedRows) => {
   if (expandedRows.length > 0) {
     expandedRowKeys.value = [];
     try {
-      productList({ salesLedgerId: row.id, type: 2 }).then((res) => {
-        const index = tableData.value.findIndex((item) => item.id === row.id);
-        if (index > -1) {
-          tableData.value[index].children = res.data;
-        }
+      const res = await productList({ salesLedgerId: row.id, type: 2 });
+      const index = tableData.value.findIndex((item) => item.id === row.id);
+      if (index > -1) {
+        tableData.value[index].children = res.data || [];
         expandedRowKeys.value.push(row.id);
-      });
+      }
     } catch (error) {
-      console.log(error);
+      console.error('鍔犺浇浜у搧鍒楄〃澶辫触:', error);
+      proxy.$modal.msgError('鍔犺浇浜у搧鍒楄〃澶辫触');
+      // 灞曞紑澶辫触鏃讹紝绉婚櫎灞曞紑鐘舵��
+      const index = expandedRows.findIndex(item => item.id === row.id);
+      if (index > -1) {
+        expandedRows.splice(index, 1);
+      }
     }
   } else {
     expandedRowKeys.value = [];
@@ -1014,40 +1248,63 @@
   ]);
 };
 // 鎵撳紑寮规
-const openForm = (type, row) => {
+const openForm = async (type, row) => {
+  await getTemplateList()
   operationType.value = type;
   form.value = {};
   productData.value = [];
   fileList.value = [];
-  if (operationType.value == "add") {
-    createPurchaseNo().then((res) => {
-      form.value.purchaseContractNumber = res.data;
-    });
-  }
-  userListNoPage().then((res) => {
-    userList.value = res.data;
-  });
-  getSalesNo().then((res) => {
-    salesContractList.value = res;
-  });
-  getOptions().then((res) => {
-    supplierList.value = res.data;
-  });
-  form.value.recorderId = userStore.id;
-  form.value.entryDate = getCurrentDate();
-  if (type === "edit") {
-    currentId.value = row.id;
-    getPurchaseById({ id: row.id, type: 2 }).then((res) => {
-      form.value = { ...res };
-      productData.value = form.value.productData;
-      if (form.value.salesLedgerFiles) {
-        fileList.value = form.value.salesLedgerFiles;
-      } else {
-        fileList.value = [];
+  templateName.value = '';
+  filterInputValue.value = '';
+  isTemplateNameDuplicate.value = false;
+  try {
+    // 骞惰鍔犺浇鍩虹鏁版嵁
+    const [userRes, salesRes, supplierRes] = await Promise.all([
+      userListNoPage(),
+      getSalesNo(),
+      getOptions()
+    ]);
+
+    userList.value = userRes.data || [];
+    salesContractList.value = salesRes || [];
+    // 渚涘簲鍟嗚繃婊ゅ嚭isWhite=0 鐨勬暟鎹�
+    supplierList.value = (supplierRes.data || []).filter((item) => item.isWhite === 0);
+
+    // 璁剧疆榛樿鍊�
+    form.value.recorderId = userStore.id;
+    form.value.entryDate = getCurrentDate();
+
+    if (type === "add") {
+      // 鏂板鏃剁敓鎴愰噰璐悎鍚屽彿
+      try {
+        const purchaseNoRes = await createPurchaseNo();
+        if (purchaseNoRes?.data) {
+          form.value.purchaseContractNumber = purchaseNoRes.data;
+        }
+      } catch (error) {
+        console.error('鐢熸垚閲囪喘鍚堝悓鍙峰け璐�:', error);
+        proxy.$modal.msgWarning('鐢熸垚閲囪喘鍚堝悓鍙峰け璐�');
       }
-    });
+    } else if (type === "edit" && row?.id) {
+      // 缂栬緫鏃跺姞杞芥暟鎹�
+      currentId.value = row.id;
+      try {
+        const purchaseRes = await getPurchaseById({ id: row.id, type: 2 });
+        form.value = { ...purchaseRes };
+        productData.value = purchaseRes.productData || [];
+        fileList.value = purchaseRes.salesLedgerFiles || [];
+      } catch (error) {
+        console.error('鍔犺浇閲囪喘鍙拌处鏁版嵁澶辫触:', error);
+        proxy.$modal.msgError('鍔犺浇鏁版嵁澶辫触');
+        return;
+      }
+    }
+
+    dialogFormVisible.value = true;
+  } catch (error) {
+    console.error('鎵撳紑琛ㄥ崟澶辫触:', error);
+    proxy.$modal.msgError('鍔犺浇鍩虹鏁版嵁澶辫触');
   }
-  dialogFormVisible.value = true;
 };
 // 涓婁紶鍓嶆牎妫�
 function handleBeforeUpload(file) {
@@ -1586,11 +1843,41 @@
   return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
 }
 
+// 娣诲姞琛岀被鍚嶆柟娉�
+const tableRowClassName = ({ row }) => {
+  return row.isInvalid ? 'invalid-row' : '';
+};
 
+// 鑾峰彇妯℃澘淇℃伅
+const getTemplateList =async ()=>{
+  let res = await getPurchaseTemplateList()
+  if(res && res.code===200 && Array.isArray(res.data)){
+    templateList.value = res.data
+  }
+}
 
 onMounted(() => {
   getList();
+  getTemplateList();
+
 });
 </script>
 
-<style scoped lang="scss"></style>
\ No newline at end of file
+<style scoped lang="scss">
+.invalid-row {
+  opacity: 0.6;
+  background-color: #f5f7fa;
+}
+.el-row{
+  justify-content: space-between;
+  align-items: center
+}
+.no-arrow-select {
+  --el-select-suffix-icon-color: transparent; /* 闅愯棌榛樿涓嬫媺绠ご */
+}
+.select-button-group {
+  display: flex;
+  align-items: center;
+}
+
+</style>
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index d599868..f9d9052 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -42,18 +42,60 @@
               <el-table-column label="浜у搧澶х被" prop="productCategory" />
               <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
               <el-table-column label="鍗曚綅" prop="unit" />
+              <el-table-column label="鐢熶骇鐘舵��" width="100px" align="center">
+                <template #default="scope">
+                  <el-tag v-if="scope.row.productionStatus === '宸插畬鎴�'" type="success">宸插畬鎴�</el-tag>
+                  <el-tag v-if="scope.row.productionStatus === '鐢熶骇涓�'" type="warning">鐢熶骇涓�</el-tag>
+                  <el-tag v-if="scope.row.productionStatus === '鏈紑濮�'" type="danger">鏈紑濮�</el-tag>
+                  <el-tag v-if="!scope.row.productionStatus" type="info">鏆傛棤鐘舵��</el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="浜у搧鐘舵��" width="100px" align="center">
+                <template #default="scope">
+                  <el-tag v-if="scope.row.approveStatus === 0" type="info">鏈嚭搴�</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 1" type="success">宸插嚭搴�</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 2" type="warning">瀹℃牳涓�</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 3" type="success">瀹℃牳鎴愬姛</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 4" type="danger">瀹℃牳澶辫触</el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="鍙戣揣杞︾墝" minWidth="100px" align="center">
+                <template #default="scope">
+                  <div>
+                    <el-tag type="success" v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag>
+                    <el-tag v-else type="info">鏈彂璐�</el-tag>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column label="鍙戣揣鏃ユ湡" minWidth="100px" align="center">
+                <template #default="scope">
+                  <div>
+                    <div v-if="scope.row.shippingDate">{{ scope.row.shippingDate }}</div>
+                    <el-tag v-else type="info">鏈彂璐�</el-tag>
+                  </div>
+                </template>
+              </el-table-column>
               <el-table-column label="鏁伴噺" prop="quantity" />
               <el-table-column label="绋庣巼(%)" prop="taxRate" />
               <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
               <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
               <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
+            <!--鎿嶄綔-->
+              <el-table-column Width="60px" label="鎿嶄綔" align="center">
+                <template #default="scope">
+                  <el-button :disabled="scope.row.approveStatus!==1" link type="primary" size="small" @click="openDeliveryForm(scope.row)">鍙戣揣</el-button>
+                </template>
+              </el-table-column>
             </el-table>
           </template>
         </el-table-column>
         <el-table-column align="center" label="搴忓彿" type="index" width="60" />
         <el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" width="180" show-overflow-tooltip />
+        <el-table-column label="瀹㈡埛鍚堝悓鍙�" prop="customerContractNo" width="180" show-overflow-tooltip />
         <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" width="300" show-overflow-tooltip />
         <el-table-column label="涓氬姟鍛�" prop="salesman" width="100" show-overflow-tooltip />
+        <el-table-column label="椤圭洰鍚嶇О" prop="projectName" width="180" show-overflow-tooltip />
+        <el-table-column label="浠樻鏂瑰紡" prop="paymentMethod" show-overflow-tooltip />
         <el-table-column label="鍚堝悓閲戦(鍏�)" prop="contractAmount" width="220" show-overflow-tooltip
           :formatter="formattedNumber" />
         <el-table-column label="褰曞叆浜�" prop="entryPersonName" width="100" show-overflow-tooltip />
@@ -68,12 +110,12 @@
         <el-table-column label="鍙戣揣鏃ユ湡" prop="shippingDate" width="120" show-overflow-tooltip />
         <el-table-column label="褰曞叆鏃ユ湡" prop="entryDate" width="120" show-overflow-tooltip />
         <el-table-column label="绛捐鏃ユ湡" prop="executionDate" width="120" show-overflow-tooltip />
-        <el-table-column fixed="right" label="鎿嶄綔" min-width="200" align="center">
+        <el-table-column fixed="right" label="鎿嶄綔" min-width="100" align="center">
           <template #default="scope">
             <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">缂栬緫</el-button>
 <!--            <el-button link type="primary" size="small" @click="openForm('view', scope.row)">璇︽儏</el-button>-->
             <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">闄勪欢</el-button>
-            <el-button v-if="!scope.row.shippingCarNumber" link type="primary" size="small" @click="openDeliveryForm(scope.row)">鍙戣揣</el-button>
+<!--            <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">鍙戣揣</el-button>-->
           </template>
         </el-table-column>
       </el-table>
@@ -136,7 +178,13 @@
             </el-form-item>
           </el-col>
         </el-row>
-
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="浠樻鏂瑰紡">
+              <el-input v-model="form.paymentMethod" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-row>
           <el-form-item label="浜у搧淇℃伅锛�" prop="entryDate">
             <el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">娣诲姞</el-button>
@@ -429,22 +477,23 @@
 				<el-row :gutter="30">
 					<el-col :span="24">
 						<el-form-item label="鍙戣揣杞︾墝鍙凤細" prop="shippingCarNumber">
-              <el-select v-model="deliveryForm.shippingCarNumber" filterable allow-create placeholder="璇烽�夋嫨鍙戣揣杞︾墝鍙�">
-                <el-option key="1" label="鏂癆 H5153" value="鏂癆 H5153"/>
-                <el-option key="2" label="鏂癆 H4232" value="鏂癆 H4232"/>
-                <el-option key="3" label="鏂癆 H4001" value="鏂癆 H4001"/>
-                <el-option key="4" label="鏂癆 H6409" value="鏂癆 H6409"/>
-                <el-option key="5" label="鏂癆 G7446" value="鏂癆 G7446"/>
-                <el-option key="6" label="鏂癏 80369" value="鏂癏 80369"/>
-              </el-select>
-							<!-- <el-input
+							<el-input
 								v-model="deliveryForm.shippingCarNumber"
 								placeholder="璇疯緭鍏ュ彂璐ц溅鐗屽彿"
 								clearable
-							/> -->
+							/>
 						</el-form-item>
 					</el-col>
 				</el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="瀹℃壒浜猴細" prop="approverId">
+              <el-select v-model="deliveryForm.approverId" placeholder="璇烽�夋嫨瀹℃壒浜�" clearable :disabled="operationType === 'view'">
+                <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
 			</el-form>
 			<template #footer>
 				<div class="dialog-footer">
@@ -462,7 +511,7 @@
 import pagination from "@/components/PIMTable/Pagination.vue";
 import {onMounted, ref} from "vue";
 import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
-import { ElMessageBox } from "element-plus";
+import {ElMessage, ElMessageBox} from "element-plus";
 import useUserStore from "@/store/modules/user";
 import { userListNoPage } from "@/api/system/user.js";
 import FileList from "./fileList.vue";
@@ -475,7 +524,7 @@
   delLedger,
   addOrUpdateSalesLedgerProduct,
   delProduct,
-  delLedgerFile,
+  delLedgerFile, getProductInventory,
 } from "@/api/salesManagement/salesLedger.js";
 import { modelList, productTreeList } from "@/api/basicData/product.js";
 import useFormData from "@/hooks/useFormData.js";
@@ -513,7 +562,9 @@
   form: {
     salesContractNo: "",
     salesman: "",
+    customerContractNo: "",
     customerId: "",
+    projectName: "",
     entryPerson: "",
     entryDate: "",
     maintenanceTime: "",
@@ -522,7 +573,11 @@
   },
   rules: {
     salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    customerContractNo: [
+      { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+    ],
     customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    projectName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
@@ -596,6 +651,11 @@
     shippingCarNumber: [
       { required: true, message: "璇疯緭鍏ュ彂璐ц溅鐗屽彿", trigger: "blur" }
     ],
+    approverId:[
+      {
+        required: true,message: "",
+      }
+    ]
   },
 });
 const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
@@ -627,14 +687,12 @@
   page.size = obj.limit;
   getList();
 };
-const getList = () => {
+const getList =async () => {
+  let userLists = await userListNoPage();
+  userList.value = userLists.data;
   tableLoading.value = true;
   const { entryDate, ...rest } = searchForm;
-  // 灏嗚寖鍥存棩鏈熷瓧娈典紶閫掔粰鍚庣
-  const params = { ...rest, ...page };
-  // 绉婚櫎褰曞叆鏃ユ湡鐨勯粯璁ゅ�艰缃紝鍙繚鐣欒寖鍥存棩鏈熷瓧娈�
-  delete params.entryDate;
-  ledgerListPage(params)
+  ledgerListPage({ ...rest, ...page })
     .then((res) => {
       tableLoading.value = false;
       tableData.value = res.records;
@@ -714,23 +772,31 @@
   productSelectedRows.value = selectedRows;
 };
 const expandedRowKeys = ref([]);
-// 灞曞紑琛�
-const expandChange = (row, expandedRows) => {
-  if (expandedRows.length > 0) {
+// 灞曞紑琛岋紙濮嬬粓鍙睍寮�涓�琛岋級
+const expandChange = (row) => {
+  const rowKey = row.id;
+  const isExpanded = expandedRowKeys.value.includes(rowKey);
+
+  if (isExpanded) {
+    // 褰撳墠琛屽凡灞曞紑 -> 鏀惰捣
     expandedRowKeys.value = [];
-    try {
-      productList({ salesLedgerId: row.id, type: 1 }).then((res) => {
-        const index = tableData.value.findIndex((item) => item.id === row.id);
-        if (index > -1) {
-          tableData.value[index].children = res.data;
-        }
-        expandedRowKeys.value.push(row.id);
-      });
-    } catch (error) {
-      console.log(error);
-    }
-  } else {
-    expandedRowKeys.value = [];
+    return;
+  }
+
+  // 灞曞紑褰撳墠琛屽墠锛屽厛鏀惰捣鍏跺畠琛�
+  expandedRowKeys.value = [];
+
+  try {
+    productList({ salesLedgerId: row.id, type: 1 }).then((res) => {
+      const index = tableData.value.findIndex((item) => item.id === row.id);
+      if (index > -1) {
+        tableData.value[index].children = res.data;
+      }
+      // 鍙繚鐣欏綋鍓嶈繖涓�琛屽浜庡睍寮�鐘舵��
+      expandedRowKeys.value = [rowKey];
+    });
+  } catch (error) {
+    console.log(error);
   }
 };
 // 涓昏〃鍚堣鏂规硶
@@ -775,7 +841,7 @@
   //     form.value.entryPerson = userAll.user.userId // 璁剧疆榛樿涓氬姟鍛樹负褰撳墠鐢ㄦ埛
   //   }
   // });
-  // 绉婚櫎褰曞叆鏃ユ湡榛樿鍊艰缃紝鍙鐞嗚寖鍥存棩鏈熷瓧娈�
+  form.value.entryDate = getCurrentDate(); // 璁剧疆榛樿褰曞叆鏃ユ湡涓哄綋鍓嶆棩鏈�
   dialogFormVisible.value = true;
 };
 function changs(val) {
@@ -1542,7 +1608,9 @@
   proxy.$refs["deliveryFormRef"].validate((valid) => {
     if (valid) {
       addShippingInfo({
-        salesLedgerId: currentDeliveryRow.value.id,
+        approverId:deliveryForm.value.approverId,
+        salesLedgerId: currentDeliveryRow.value.salesLedgerId,
+        salesLedgerProductId: currentDeliveryRow.value.id,
         shippingDate: deliveryForm.value.shippingDate,
         shippingCarNumber: deliveryForm.value.shippingCarNumber,
       })

--
Gitblit v1.9.3