From c8b65690b946b28b179796fbe2f020e732043c58 Mon Sep 17 00:00:00 2001
From: 张诺 <zhang_12370@163.com>
Date: 星期四, 08 一月 2026 18:10:16 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_天津军泰伟业' into dev_天津军泰伟业

---
 src/views/procurementManagement/procurementPlan/index.vue | 1173 +++++++++++++++++++++++++++++++---------------------------
 1 files changed, 624 insertions(+), 549 deletions(-)

diff --git a/src/views/procurementManagement/procurementPlan/index.vue b/src/views/procurementManagement/procurementPlan/index.vue
index 14424cc..c3e64d1 100644
--- a/src/views/procurementManagement/procurementPlan/index.vue
+++ b/src/views/procurementManagement/procurementPlan/index.vue
@@ -1,137 +1,179 @@
 <template>
   <div class="app-container">
     <!-- 鎼滅储鍖哄煙 -->
-    <el-card class="search-card" shadow="never">
-      <el-form :model="searchForm" :inline="true" class="search-form">
+    <el-card class="search-card"
+             shadow="never">
+      <el-form :model="searchForm"
+               :inline="true"
+               class="search-form">
         <el-form-item label="璁″垝鍚嶇О">
-          <el-input v-model="searchForm.planName" placeholder="璇疯緭鍏ヨ鍒掑悕绉�" clearable />
+          <el-input v-model="searchForm.planName"
+                    placeholder="璇疯緭鍏ヨ鍒掑悕绉�"
+                    clearable />
         </el-form-item>
         <el-form-item label="鐘舵��">
-          <el-select v-model="searchForm.status" placeholder="璇烽�夋嫨鐘舵��" clearable style="width: 150px">
-            <el-option label="鍚敤" value="active" />
-            <el-option label="绂佺敤" value="disabled" />
+          <el-select v-model="searchForm.status"
+                     placeholder="璇烽�夋嫨鐘舵��"
+                     clearable
+                     style="width: 150px">
+            <el-option label="鍚敤"
+                       value="active" />
+            <el-option label="绂佺敤"
+                       value="disabled" />
           </el-select>
         </el-form-item>
         <el-form-item>
-          <el-button type="primary" @click="handleSearch">
-            <el-icon><Search /></el-icon>
+          <el-button type="primary"
+                     @click="handleSearch">
+            <el-icon>
+              <Search />
+            </el-icon>
             鎼滅储
           </el-button>
           <el-button @click="handleReset">
-            <el-icon><Refresh /></el-icon>
+            <el-icon>
+              <Refresh />
+            </el-icon>
             閲嶇疆
           </el-button>
         </el-form-item>
       </el-form>
     </el-card>
-
     <!-- 鎿嶄綔鎸夐挳 -->
-    <el-card class="table-card" shadow="never">
+    <el-card class="table-card"
+             shadow="never">
       <div class="table-header">
         <div class="table-title">閲囪喘璁″垝鍒楄〃</div>
         <div class="table-actions">
-          <el-button type="primary" @click="handleAdd">
-            <el-icon><Plus /></el-icon>
+          <el-button type="primary"
+                     @click="handleAdd">
+            <el-icon>
+              <Plus />
+            </el-icon>
             鏂板璁″垝
           </el-button>
-          <el-button type="info" @click="handleExport">
-            <el-icon><Download /></el-icon>
+          <el-button type="info"
+                     @click="handleExport">
+            <el-icon>
+              <Download />
+            </el-icon>
             瀵煎嚭
           </el-button>
         </div>
       </div>
-
       <!-- 鏁版嵁琛ㄦ牸 -->
-      <el-table
-        v-loading="loading"
-        :data="tableData"
-        stripe
-        border
-        style="width: 100%"
-      >
-        <el-table-column prop="planName" label="璁″垝鍚嶇О" min-width="150" />
-        <el-table-column prop="description" label="鎻忚堪" min-width="200" show-overflow-tooltip />
-        <el-table-column prop="formula" label="璁$畻鍏紡" min-width="200" show-overflow-tooltip>
+      <el-table v-loading="loading"
+                :data="tableData"
+                stripe
+                border
+                style="width: 100%">
+        <el-table-column prop="planName"
+                         label="璁″垝鍚嶇О"
+                         min-width="150" />
+        <el-table-column prop="description"
+                         label="鎻忚堪"
+                         min-width="200"
+                         show-overflow-tooltip />
+        <el-table-column prop="formula"
+                         label="璁$畻鍏紡"
+                         min-width="200"
+                         show-overflow-tooltip>
           <template #default="{ row }">
-            <el-tag type="info" size="small">{{ row.formula }}</el-tag>
+            <el-tag type="info"
+                    size="small">{{ row.formula }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="status" label="鐘舵��" width="80" align="center">
+        <el-table-column prop="status"
+                         label="鐘舵��"
+                         width="80"
+                         align="center">
           <template #default="{ row }">
-            <el-tag :type="row.status === 'active' ? 'success' : 'info'" size="small">
+            <el-tag :type="row.status === 'active' ? 'success' : 'info'"
+                    size="small">
               {{ row.status === 'active' ? '鍚敤' : '绂佺敤' }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="updateTime" label="鏈�鍚庤绠楁椂闂�" width="160" />
-        <el-table-column label="鎿嶄綔" width="200" fixed="right" align="center">
+        <el-table-column prop="updateTime"
+                         label="鏈�鍚庤绠楁椂闂�"
+                         width="160" />
+        <el-table-column label="鎿嶄綔"
+                         width="200"
+                         fixed="right"
+                         align="center">
           <template #default="{ row }">
-            <el-button type="primary" link @click="handleEdit(row)">缂栬緫</el-button>
-            <el-button type="success" link @click="handleCalculate(row)">璁$畻</el-button>
-            <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
+            <el-button type="primary"
+                       link
+                       @click="handleEdit(row)">缂栬緫</el-button>
+            <el-button type="success"
+                       link
+                       @click="handleCalculate(row)">璁$畻</el-button>
+            <el-button type="danger"
+                       link
+                       @click="handleDelete(row)">鍒犻櫎</el-button>
           </template>
         </el-table-column>
       </el-table>
-
       <!-- 鍒嗛〉 -->
       <div class="pagination-container">
-        <el-pagination
-          v-model:current-page="pagination.current"
-          v-model:page-size="pagination.size"
-          :page-sizes="[10, 20, 50, 100]"
-          :total="total"
-          layout="total, sizes, prev, pager, next, jumper"
-          @size-change="handleSizeChange"
-          @current-change="handleCurrentChange"
-        />
+        <el-pagination v-model:current-page="pagination.current"
+                       v-model:page-size="pagination.size"
+                       :page-sizes="[10, 20, 50, 100]"
+                       :total="total"
+                       layout="total, sizes, prev, pager, next, jumper"
+                       @size-change="handleSizeChange"
+                       @current-change="handleCurrentChange" />
       </div>
     </el-card>
-
     <!-- 鏂板/缂栬緫瀵硅瘽妗� -->
-    <el-dialog
-      v-model="dialogVisible"
-      :title="dialogType === 'add' ? '鏂板閲囪喘璁″垝' : '缂栬緫閲囪喘璁″垝'"
-      width="1000px"
-      :close-on-click-modal="false"
-    >
+    <el-dialog v-model="dialogVisible"
+               :title="dialogType === 'add' ? '鏂板閲囪喘璁″垝' : '缂栬緫閲囪喘璁″垝'"
+               width="1000px"
+               :close-on-click-modal="false">
       <div class="form-container">
         <!-- 鍩烘湰淇℃伅 -->
         <div class="form-section">
           <div class="section-title">鍩烘湰淇℃伅</div>
-          <el-form
-            ref="formRef"
-            :model="formData"
-            :rules="formRules"
-            label-width="120px"
-          >
+          <el-form ref="formRef"
+                   :model="formData"
+                   :rules="formRules"
+                   label-width="120px">
             <el-row :gutter="20">
               <el-col :span="12">
-                <el-form-item label="缂栫爜" prop="code">
-                  <el-input v-model="formData.code" placeholder="绯荤粺鑷姩鐢熸垚" disabled />
+                <el-form-item label="缂栫爜"
+                              prop="code">
+                  <el-input v-model="formData.code"
+                            placeholder="绯荤粺鑷姩鐢熸垚"
+                            disabled />
                 </el-form-item>
               </el-col>
               <el-col :span="12">
-                <el-form-item label="鍚嶇О" prop="planName" required>
-                  <el-input v-model="formData.planName" placeholder="璇疯緭鍏ヨ鍒掑悕绉�" />
+                <el-form-item label="鍚嶇О"
+                              prop="planName"
+                              required>
+                  <el-input v-model="formData.planName"
+                            placeholder="璇疯緭鍏ヨ鍒掑悕绉�" />
                 </el-form-item>
               </el-col>
             </el-row>
-
-            <el-form-item label="鎻忚堪" prop="description">
-              <el-input
-                v-model="formData.description"
-                type="textarea"
-                :rows="3"
-                placeholder="璇疯緭鍏ヨ鍒掓弿杩�"
-              />
+            <el-form-item label="鎻忚堪"
+                          prop="description">
+              <el-input v-model="formData.description"
+                        type="textarea"
+                        :rows="3"
+                        placeholder="璇疯緭鍏ヨ鍒掓弿杩�" />
             </el-form-item>
-
             <el-row :gutter="20">
               <el-col :span="12">
-                <el-form-item label="鐘舵��" prop="status">
-                  <el-select v-model="formData.status" placeholder="璇烽�夋嫨鐘舵��" style="width: 100%">
-                    <el-option label="鍚敤" value="active" />
-                    <el-option label="绂佺敤" value="disabled" />
+                <el-form-item label="鐘舵��"
+                              prop="status">
+                  <el-select v-model="formData.status"
+                             placeholder="璇烽�夋嫨鐘舵��"
+                             style="width: 100%">
+                    <el-option label="鍚敤"
+                               value="active" />
+                    <el-option label="绂佺敤"
+                               value="disabled" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -143,12 +185,13 @@
             </el-row>
           </el-form>
         </div>
-
         <!-- 璁$畻鍙傛暟 -->
         <div class="form-section">
           <div class="section-title">璁$畻鍙傛暟</div>
-          <el-tabs v-model="activeTab" class="param-tabs">
-            <el-tab-pane label="闇�姹傚弬鏁�" name="demand">
+          <el-tabs v-model="activeTab"
+                   class="param-tabs">
+            <el-tab-pane label="闇�姹傚弬鏁�"
+                         name="demand">
               <div class="checkbox-group">
                 <el-checkbox v-model="formData.considerExistingStock">鑰冭檻鐜版湁搴撳瓨</el-checkbox>
                 <el-checkbox v-model="formData.warehouseControl">浠撳簱杩愯MRP鐨勬帶鍒�</el-checkbox>
@@ -159,7 +202,8 @@
                 <el-checkbox v-model="formData.negativeStockAsDemand">璐熷簱瀛樹綔涓洪渶姹�</el-checkbox>
               </div>
             </el-tab-pane>
-            <el-tab-pane label="璁$畻鍙傛暟" name="calculation">
+            <el-tab-pane label="璁$畻鍙傛暟"
+                         name="calculation">
               <div class="checkbox-group">
                 <el-checkbox v-model="formData.considerExistingStock">鑰冭檻鐜版湁搴撳瓨</el-checkbox>
                 <el-checkbox v-model="formData.warehouseControl">浠撳簱杩愯MRP鐨勬帶鍒�</el-checkbox>
@@ -172,7 +216,6 @@
             </el-tab-pane>
           </el-tabs>
         </div>
-
         <!-- 姹囨�诲悎骞堕�夐」 -->
         <div class="form-section">
           <div class="section-title">姹囨�诲悎骞堕�夐」</div>
@@ -182,129 +225,161 @@
             <el-checkbox v-model="formData.summaryDemandDate">闇�姹傛棩鏈�</el-checkbox>
           </div>
         </div>
-
         <!-- 璁$畻鍏紡 -->
         <div class="form-section">
           <div class="section-title">璁$畻鍏紡</div>
           <div class="formula-input-section">
-            <el-form-item label="璁$畻鍏紡" prop="formula" required>
-              <el-input
-                v-model="formData.formula"
-                placeholder="渚嬪: 棰勮鍑哄簱鏁伴噺 - 鐜版湁搴撳瓨 + 瀹夊叏搴撳瓨 - 棰勮鍏ュ簱鏁伴噺"
-                @input="validateFormula"
-              />
+            <el-form-item label="璁$畻鍏紡"
+                          prop="formula"
+                          required>
+              <el-input v-model="formData.formula"
+                        placeholder="渚嬪: 棰勮鍑哄簱鏁伴噺 - 鐜版湁搴撳瓨 + 瀹夊叏搴撳瓨 - 棰勮鍏ュ簱鏁伴噺"
+                        @input="validateFormula" />
             </el-form-item>
             <div class="formula-help">
-              <el-text type="info" size="small">
+              <el-text type="info"
+                       size="small">
                 鏀寔鍙橀噺锛氶璁″嚭搴撴暟閲忋�佺幇鏈夊簱瀛樸�佸畨鍏ㄥ簱瀛樸�侀璁″叆搴撴暟閲�
               </el-text>
             </div>
           </div>
         </div>
       </div>
-
       <template #footer>
         <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="handleSubmit"
+                     :loading="submitLoading">纭畾</el-button>
           <el-button @click="dialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary" @click="handleSubmit" :loading="submitLoading">纭畾</el-button>
         </div>
       </template>
     </el-dialog>
-
     <!-- 浜у搧閫夋嫨瀵硅瘽妗� -->
-    <el-dialog
-      v-model="productSelectDialogVisible"
-      title="閫夋嫨浜у搧"
-      width="800px"
-      :close-on-click-modal="false"
-    >
+    <el-dialog v-model="productSelectDialogVisible"
+               title="閫夋嫨浜у搧"
+               width="800px"
+               :close-on-click-modal="false">
       <div class="product-select">
-        <el-alert
-          title="璇烽�夋嫨瑕佽绠楃殑浜у搧"
-          type="info"
-          :closable="false"
-          show-icon
-        >
+        <el-alert title="璇烽�夋嫨瑕佽绠楃殑浜у搧"
+                  type="info"
+                  :closable="false"
+                  show-icon>
           <template #default>
             <p>閫夋嫨浜у搧鍚庯紝绯荤粺灏嗘牴鎹綋鍓嶈绠楀叕寮忓拰浜у搧搴撳瓨鎯呭喌杩涜璁$畻銆�</p>
           </template>
         </el-alert>
-
-        <el-table
-          v-loading="productLoading"
-          :data="productList"
-          @selection-change="handleProductSelectionChange"
-          stripe
-          border
-          style="width: 100%; margin-top: 20px;"
-        >
-          <el-table-column type="selection" width="55" />
-          <el-table-column prop="productCategory" label="浜у搧澶х被" min-width="150" />
-          <el-table-column prop="specificationModel" label="浜у搧瑙勬牸" width="120" />
-          <el-table-column prop="inboundNum0" label="鐜版湁搴撳瓨" width="100" align="right" />
-          <el-table-column prop="inboundNum" label="瀹夊叏搴撳瓨" width="100" align="right" />
-          <el-table-column prop="inboundNum" label="棰勮鍑哄簱" width="100" align="right" />
-          <el-table-column prop="inboundNum0" label="棰勮鍏ュ簱" width="100" align="right" />
+        <el-table v-loading="productLoading"
+                  :data="productList"
+                  @selection-change="handleProductSelectionChange"
+                  stripe
+                  border
+                  style="width: 100%; margin-top: 20px;">
+          <el-table-column type="selection"
+                           width="55" />
+          <el-table-column prop="productCategory"
+                           label="浜у搧澶х被"
+                           min-width="150" />
+          <el-table-column prop="specificationModel"
+                           label="浜у搧瑙勬牸"
+                           width="120" />
+          <el-table-column prop="inboundNum0"
+                           label="鐜版湁搴撳瓨"
+                           width="100"
+                           align="right" />
+          <el-table-column prop="inboundNum"
+                           label="瀹夊叏搴撳瓨"
+                           width="100"
+                           align="right" />
+          <el-table-column prop="inboundNum"
+                           label="棰勮鍑哄簱"
+                           width="100"
+                           align="right" />
+          <el-table-column prop="inboundNum0"
+                           label="棰勮鍏ュ簱"
+                           width="100"
+                           align="right" />
         </el-table>
       </div>
-
       <template #footer>
         <div class="dialog-footer">
-          <el-button @click="productSelectDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary" @click="handleConfirmProductSelection" :disabled="selectedProducts.length === 0">
+          <el-button type="primary"
+                     @click="handleConfirmProductSelection"
+                     :disabled="selectedProducts.length === 0">
             纭璁$畻
           </el-button>
+          <el-button @click="productSelectDialogVisible = false">鍙栨秷</el-button>
         </div>
       </template>
     </el-dialog>
-
     <!-- 璁$畻缁撴灉瀵硅瘽妗� -->
-    <el-dialog
-      v-model="calculateDialogVisible"
-      title="閲囪喘璁$畻缁撴灉"
-      width="1000px"
-      :close-on-click-modal="false"
-    >
+    <el-dialog v-model="calculateDialogVisible"
+               title="閲囪喘璁$畻缁撴灉"
+               width="1000px"
+               :close-on-click-modal="false">
       <div class="calculate-result">
-        <el-alert
-          title="璁$畻缁撴灉"
-          type="success"
-          :closable="false"
-          show-icon
-        >
+        <el-alert title="璁$畻缁撴灉"
+                  type="success"
+                  :closable="false"
+                  show-icon>
           <template #default>
             <p>鍩轰簬褰撳墠閰嶇疆鐨勮绠楀叕寮忓拰搴撳瓨鎯呭喌锛岀郴缁熷凡璁$畻鍑哄悇浜у搧鐨勯噰璐渶姹傘��</p>
           </template>
         </el-alert>
-
-        <el-table :data="calculateResult" stripe border style="width: 100%; margin-top: 20px;">
-          <el-table-column prop="productCategory" label="浜у搧澶х被" min-width="150" />
-          <el-table-column prop="specificationModel" label="浜у搧瑙勬牸" width="120" />
-          <el-table-column prop="inboundNum0" label="鐜版湁搴撳瓨" width="100" align="right" />
-          <el-table-column prop="inboundNum" label="瀹夊叏搴撳瓨" width="100" align="right" />
-          <el-table-column prop="inboundNum" label="棰勮鍑哄簱鏁伴噺" width="120" align="right" />
-          <el-table-column prop="inboundNum0" label="棰勮鍏ュ簱鏁伴噺" width="120" align="right" />
-          <el-table-column prop="weeklyNetDemand" label="鎸夊懆鍑�闇�姹�" width="120" align="right">
+        <el-table :data="calculateResult"
+                  stripe
+                  border
+                  style="width: 100%; margin-top: 20px;">
+          <el-table-column prop="productCategory"
+                           label="浜у搧澶х被"
+                           min-width="150" />
+          <el-table-column prop="specificationModel"
+                           label="浜у搧瑙勬牸"
+                           width="120" />
+          <el-table-column prop="inboundNum0"
+                           label="鐜版湁搴撳瓨"
+                           width="100"
+                           align="right" />
+          <el-table-column prop="inboundNum"
+                           label="瀹夊叏搴撳瓨"
+                           width="100"
+                           align="right" />
+          <el-table-column prop="inboundNum"
+                           label="棰勮鍑哄簱鏁伴噺"
+                           width="120"
+                           align="right" />
+          <el-table-column prop="inboundNum0"
+                           label="棰勮鍏ュ簱鏁伴噺"
+                           width="120"
+                           align="right" />
+          <el-table-column prop="weeklyNetDemand"
+                           label="鎸夊懆鍑�闇�姹�"
+                           width="120"
+                           align="right">
             <template #default="{ row }">
-              <el-tag :type="row.weeklyNetDemand > 0 ? 'warning' : 'success'" size="small">
+              <el-tag :type="row.weeklyNetDemand > 0 ? 'warning' : 'success'"
+                      size="small">
                 {{ row.weeklyNetDemand }}
               </el-tag>
             </template>
           </el-table-column>
-          <el-table-column prop="suggestedPurchase" label="寤鸿閲囪喘" width="100" align="right">
+          <el-table-column prop="suggestedPurchase"
+                           label="寤鸿閲囪喘"
+                           width="100"
+                           align="right">
             <template #default="{ row }">
-              <el-tag :type="row.suggestedPurchase > 0 ? 'danger' : 'success'" size="small">
+              <el-tag :type="row.suggestedPurchase > 0 ? 'danger' : 'success'"
+                      size="small">
                 {{ row.suggestedPurchase }}
               </el-tag>
             </template>
           </el-table-column>
         </el-table>
       </div>
-
       <template #footer>
         <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="handleCreatePurchaseOrder">纭</el-button>
           <el-button @click="calculateDialogVisible = false">鍏抽棴</el-button>
-          <el-button type="primary" @click="handleCreatePurchaseOrder">纭</el-button>
         </div>
       </template>
     </el-dialog>
@@ -312,213 +387,48 @@
 </template>
 
 <script setup>
-import {ref, reactive, onMounted, getCurrentInstance} from 'vue'
-import { ElMessage, ElMessageBox } from 'element-plus'
-import { Search, Refresh, Plus, Download } from '@element-plus/icons-vue'
-import {listPage,add,update,del,listPageCopy} from "@/api/procurementManagement/procurementPlan.js"
+  import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import { Search, Refresh, Plus, Download } from "@element-plus/icons-vue";
+  import {
+    listPage,
+    add,
+    update,
+    del,
+    listPageCopy,
+  } from "@/api/procurementManagement/procurementPlan.js";
 
-// 鍝嶅簲寮忔暟鎹�
-const loading = ref(false)
-const submitLoading = ref(false)
-const dialogVisible = ref(false)
-const productSelectDialogVisible = ref(false)
-const calculateDialogVisible = ref(false)
-const dialogType = ref('add')
-const productLoading = ref(false)
-const selectedProducts = ref([])
-const currentPlan = ref(null)
+  // 鍝嶅簲寮忔暟鎹�
+  const loading = ref(false);
+  const submitLoading = ref(false);
+  const dialogVisible = ref(false);
+  const productSelectDialogVisible = ref(false);
+  const calculateDialogVisible = ref(false);
+  const dialogType = ref("add");
+  const productLoading = ref(false);
+  const selectedProducts = ref([]);
+  const currentPlan = ref(null);
 
-// 鎼滅储琛ㄥ崟
-const searchForm = reactive({
-  planName: '',
-  status: ''
-})
+  // 鎼滅储琛ㄥ崟
+  const searchForm = reactive({
+    planName: "",
+    status: "",
+  });
 
-// 鍒嗛〉鏁版嵁
-const pagination = reactive({
-  current: 1,
-  size: 20
-})
+  // 鍒嗛〉鏁版嵁
+  const pagination = reactive({
+    current: 1,
+    size: 20,
+  });
 
-// 琛ㄥ崟鏁版嵁
-const formData = reactive({
-  code: '',
-  planName: '',
-  description: '',
-  status: '',
-  isSystemPreset: false,
-  formula: '',
-  // 璁$畻鍙傛暟
-  considerExistingStock: false,
-  warehouseControl: false,
-  calculateTotalDemand: false,
-  considerSafetyStock: false,
-  considerLockedStock: false,
-  notConsiderMaterialAux: false,
-  negativeStockAsDemand: false,
-  // 姹囨�诲悎骞堕�夐」
-  summaryMaterial: false,
-  summaryAuxAttributes: false,
-  summaryDemandDate: false
-})
-
-// 褰撳墠婵�娲荤殑鏍囩椤�
-const activeTab = ref('demand')
-
-// 琛ㄥ崟楠岃瘉瑙勫垯
-const formRules = {
-  planName: [
-    { required: true, message: '璇疯緭鍏ヨ鍒掑悕绉�', trigger: 'blur' }
-  ],
-  status: [
-    { required: true, message: '璇烽�夋嫨鐘舵��', trigger: 'change' }
-  ],
-  formula: [
-    { required: true, message: '璇疯緭鍏ヨ绠楀叕寮�', trigger: 'blur' }
-  ]
-}
-
-// 琛ㄦ牸鏁版嵁
-const tableData = ref([])
-
-// 浜у搧鍒楄〃鏁版嵁
-const productList = ref([
-  {
-    id: 4,
-    productName: '浜у搧D',
-    productCode: 'PD004',
-    existingStock: 90,
-    safetyStock: 40,
-    expectedOutbound: 160,
-    expectedInbound: 35
-  }
-])
-
-// 璁$畻缁撴灉鏁版嵁
-const calculateResult = ref([
-  {
-    productName: '浜у搧A',
-    existingStock: 100,
-    safetyStock: 50,
-    expectedOutbound: 200,
-    expectedInbound: 30,
-    weeklyNetDemand: 120,
-    suggestedPurchase: 150
-  },
-  {
-    productName: '浜у搧B',
-    existingStock: 80,
-    safetyStock: 30,
-    expectedOutbound: 150,
-    expectedInbound: 20,
-    weeklyNetDemand: 100,
-    suggestedPurchase: 120
-  }
-])
-const total = ref(0)
-// 鏂规硶
-const handleSearch = () => {
-  pagination.current = 1
-  loadData()
-}
-
-const handleReset = () => {
-  Object.assign(searchForm, {
-    planName: '',
-    status: ''
-  })
-  handleSearch()
-}
-
-const loadData = () => {
-  loading.value = true
-  listPage({...searchForm,...pagination}).then(res => {
-    if(res.code === 200){
-      tableData.value = res.data.records
-      total.value = res.data.total
-      loading.value = false
-    }
-  })
-}
-
-const handleAdd = () => {
-  dialogType.value = 'add'
-  resetForm()
-  // 鑷姩鐢熸垚缂栫爜
-  formData.code = 'CGJH' + String(Date.now()).slice(-4)
-  dialogVisible.value = true
-}
-
-const handleEdit = (row) => {
-  dialogType.value = 'edit'
-  Object.assign(formData, row)
-  dialogVisible.value = true
-}
-
-const handleDelete = async (row) => {
-  try {
-    await ElMessageBox.confirm('纭畾瑕佸垹闄よ繖涓噰璐鍒掑悧锛�', '鎻愮ず', {
-      confirmButtonText: '纭畾',
-      cancelButtonText: '鍙栨秷',
-      type: 'warning'
-    })
-    let ids = [row.id]
-    del(ids).then(res =>{
-     if(res.code === 200){
-      ElMessage.success('鍒犻櫎鎴愬姛')
-      loadData()
-    }
-   })
-  } catch {
-    // 鐢ㄦ埛鍙栨秷鍒犻櫎
-  }
-}
-
-const handleSubmit = async () => {
-  try {
-    // 琛ㄥ崟楠岃瘉
-    if (!formData.planName || !formData.formula) {
-      ElMessage.error('璇峰~鍐欏繀濉」')
-      return
-    }
-
-    submitLoading.value = true
-
-    if (dialogType.value === 'add') {
-      add(formData).then(res => {
-        if(res.code === 200){
-          ElMessage.success('鏂板鎴愬姛')
-          dialogVisible.value = false
-          loadData()
-        }
-      })
-    } else {
-      // 缂栬緫
-      update(formData).then(res => {
-        if(res.code === 200){
-          ElMessage.success('缂栬緫鎴愬姛')
-          dialogVisible.value = false
-          loadData()
-        }
-      })
-    }
-
-
-  } catch (error) {
-    ElMessage.error('鎿嶄綔澶辫触')
-  } finally {
-    submitLoading.value = false
-  }
-}
-
-const resetForm = () => {
-  Object.assign(formData, {
-    code: '',
-    planName: '',
-    description: '',
-    status: '',
+  // 琛ㄥ崟鏁版嵁
+  const formData = reactive({
+    code: "",
+    planName: "",
+    description: "",
+    status: "",
     isSystemPreset: false,
-    formula: '棰勮鍑哄簱鏁伴噺 - 鐜版湁搴撳瓨 + 瀹夊叏搴撳瓨 - 棰勮鍏ュ簱鏁伴噺',
+    formula: "",
     // 璁$畻鍙傛暟
     considerExistingStock: false,
     warehouseControl: false,
@@ -530,255 +440,420 @@
     // 姹囨�诲悎骞堕�夐」
     summaryMaterial: false,
     summaryAuxAttributes: false,
-    summaryDemandDate: false
-  })
-  activeTab.value = 'demand'
-}
+    summaryDemandDate: false,
+  });
 
-const validateFormula = () => {
-  // 绠�鍗曠殑鍏紡楠岃瘉
-  const formula = formData.formula
-  if (formula && !/^[a-zA-Z\u4e00-\u9fa5\s\*\+\-\/\(\)\d\.]+$/.test(formula)) {
-    ElMessage.warning('鍏紡鏍煎紡鍙兘涓嶆纭紝璇锋鏌�')
-  }
-}
+  // 褰撳墠婵�娲荤殑鏍囩椤�
+  const activeTab = ref("demand");
 
-const handleCalculate = (row) => {
-  currentPlan.value = row
-  productSelectDialogVisible.value = true
-  loadProductList()
-}
+  // 琛ㄥ崟楠岃瘉瑙勫垯
+  const formRules = {
+    planName: [{ required: true, message: "璇疯緭鍏ヨ鍒掑悕绉�", trigger: "blur" }],
+    status: [{ required: true, message: "璇烽�夋嫨鐘舵��", trigger: "change" }],
+    formula: [{ required: true, message: "璇疯緭鍏ヨ绠楀叕寮�", trigger: "blur" }],
+  };
 
-const loadProductList = () => {
-  productLoading.value = true
-  // 妯℃嫙鍔犺浇浜у搧鏁版嵁
-  listPageCopy({size:-1}).then(res => {
-    if(res.code === 200){
-      productList.value = res.data.records
-      productLoading.value = false
+  // 琛ㄦ牸鏁版嵁
+  const tableData = ref([]);
+
+  // 浜у搧鍒楄〃鏁版嵁
+  const productList = ref([
+    {
+      id: 4,
+      productName: "浜у搧D",
+      productCode: "PD004",
+      existingStock: 90,
+      safetyStock: 40,
+      expectedOutbound: 160,
+      expectedInbound: 35,
+    },
+  ]);
+
+  // 璁$畻缁撴灉鏁版嵁
+  const calculateResult = ref([
+    {
+      productName: "浜у搧A",
+      existingStock: 100,
+      safetyStock: 50,
+      expectedOutbound: 200,
+      expectedInbound: 30,
+      weeklyNetDemand: 120,
+      suggestedPurchase: 150,
+    },
+    {
+      productName: "浜у搧B",
+      existingStock: 80,
+      safetyStock: 30,
+      expectedOutbound: 150,
+      expectedInbound: 20,
+      weeklyNetDemand: 100,
+      suggestedPurchase: 120,
+    },
+  ]);
+  const total = ref(0);
+  // 鏂规硶
+  const handleSearch = () => {
+    pagination.current = 1;
+    loadData();
+  };
+
+  const handleReset = () => {
+    Object.assign(searchForm, {
+      planName: "",
+      status: "",
+    });
+    handleSearch();
+  };
+
+  const loadData = () => {
+    loading.value = true;
+    listPage({ ...searchForm, ...pagination }).then(res => {
+      if (res.code === 200) {
+        tableData.value = res.data.records;
+        total.value = res.data.total;
+        loading.value = false;
+      }
+    });
+  };
+
+  const handleAdd = () => {
+    dialogType.value = "add";
+    resetForm();
+    // 鑷姩鐢熸垚缂栫爜
+    formData.code = "CGJH" + String(Date.now()).slice(-4);
+    dialogVisible.value = true;
+  };
+
+  const handleEdit = row => {
+    dialogType.value = "edit";
+    Object.assign(formData, row);
+    dialogVisible.value = true;
+  };
+
+  const handleDelete = async row => {
+    try {
+      await ElMessageBox.confirm("纭畾瑕佸垹闄よ繖涓噰璐鍒掑悧锛�", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      });
+      let ids = [row.id];
+      del(ids).then(res => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          loadData();
+        }
+      });
+    } catch {
+      // 鐢ㄦ埛鍙栨秷鍒犻櫎
     }
-  })
-}
+  };
 
-const handleProductSelectionChange = (selection) => {
-  selectedProducts.value = selection
-}
+  const handleSubmit = async () => {
+    try {
+      // 琛ㄥ崟楠岃瘉
+      if (!formData.planName || !formData.formula) {
+        ElMessage.error("璇峰~鍐欏繀濉」");
+        return;
+      }
 
-const handleConfirmProductSelection = () => {
-  if (selectedProducts.value.length === 0) {
-    ElMessage.warning('璇烽�夋嫨瑕佽绠楃殑浜у搧')
-    return
-  }
-  
-  ElMessage.success(`姝e湪璁$畻 ${currentPlan.value.planName} 鐨勯噰璐渶姹�...`)
-  productSelectDialogVisible.value = false
-  
-  // 鏍规嵁閫夋嫨鐨勪骇鍝佸拰璁$畻鍏紡杩涜璁$畻
-  calculateWithSelectedProducts()
-}
+      submitLoading.value = true;
 
-const calculateWithSelectedProducts = () => {
-  // 妯℃嫙璁$畻杩囩▼
-  // 鏍规嵁閫夋嫨鐨勪骇鍝佹洿鏂拌绠楃粨鏋�
-  const result = selectedProducts.value.map(product => {
-    // 杩欓噷搴旇鏍规嵁瀹為檯鐨勮绠楀叕寮忚繘琛岃绠�
-    // 绀轰緥锛氶璁″嚭搴撴暟閲� - 鐜版湁搴撳瓨 + 瀹夊叏搴撳瓨 - 棰勮鍏ュ簱鏁伴噺
-    const weeklyNetDemand = product.inboundNum - product.inboundNum0 + product.inboundNum - product.inboundNum0
-    const suggestedPurchase = Math.max(0, weeklyNetDemand)
-
-    return {
-      productCategory: product.productCategory,
-      specificationModel: product.specificationModel,
-      inboundNum0: product.inboundNum0,
-      inboundNum: product.inboundNum,
-      weeklyNetDemand: weeklyNetDemand,
-      suggestedPurchase: suggestedPurchase
+      if (dialogType.value === "add") {
+        add(formData).then(res => {
+          if (res.code === 200) {
+            ElMessage.success("鏂板鎴愬姛");
+            dialogVisible.value = false;
+            loadData();
+          }
+        });
+      } else {
+        // 缂栬緫
+        update(formData).then(res => {
+          if (res.code === 200) {
+            ElMessage.success("缂栬緫鎴愬姛");
+            dialogVisible.value = false;
+            loadData();
+          }
+        });
+      }
+    } catch (error) {
+      ElMessage.error("鎿嶄綔澶辫触");
+    } finally {
+      submitLoading.value = false;
     }
-  })
+  };
 
-  calculateResult.value = result
-  calculateDialogVisible.value = true
-}
+  const resetForm = () => {
+    Object.assign(formData, {
+      code: "",
+      planName: "",
+      description: "",
+      status: "",
+      isSystemPreset: false,
+      formula: "棰勮鍑哄簱鏁伴噺 - 鐜版湁搴撳瓨 + 瀹夊叏搴撳瓨 - 棰勮鍏ュ簱鏁伴噺",
+      // 璁$畻鍙傛暟
+      considerExistingStock: false,
+      warehouseControl: false,
+      calculateTotalDemand: false,
+      considerSafetyStock: false,
+      considerLockedStock: false,
+      notConsiderMaterialAux: false,
+      negativeStockAsDemand: false,
+      // 姹囨�诲悎骞堕�夐」
+      summaryMaterial: false,
+      summaryAuxAttributes: false,
+      summaryDemandDate: false,
+    });
+    activeTab.value = "demand";
+  };
 
+  const validateFormula = () => {
+    // 绠�鍗曠殑鍏紡楠岃瘉
+    const formula = formData.formula;
+    if (formula && !/^[a-zA-Z\u4e00-\u9fa5\s\*\+\-\/\(\)\d\.]+$/.test(formula)) {
+      ElMessage.warning("鍏紡鏍煎紡鍙兘涓嶆纭紝璇锋鏌�");
+    }
+  };
 
-const handleCreatePurchaseOrder = () => {
-  calculateDialogVisible.value = false
-}
-const { proxy } = getCurrentInstance();
-const handleExport = () => {
-  ElMessageBox.confirm("鍐呭灏嗚瀵煎嚭锛屾槸鍚︾‘璁ゅ鍑猴紵", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
+  const handleCalculate = row => {
+    currentPlan.value = row;
+    productSelectDialogVisible.value = true;
+    loadProductList();
+  };
+
+  const loadProductList = () => {
+    productLoading.value = true;
+    // 妯℃嫙鍔犺浇浜у搧鏁版嵁
+    listPageCopy({ size: -1 }).then(res => {
+      if (res.code === 200) {
+        productList.value = res.data.records;
+        productLoading.value = false;
+      }
+    });
+  };
+
+  const handleProductSelectionChange = selection => {
+    selectedProducts.value = selection;
+  };
+
+  const handleConfirmProductSelection = () => {
+    if (selectedProducts.value.length === 0) {
+      ElMessage.warning("璇烽�夋嫨瑕佽绠楃殑浜у搧");
+      return;
+    }
+
+    ElMessage.success(`姝e湪璁$畻 ${currentPlan.value.planName} 鐨勯噰璐渶姹�...`);
+    productSelectDialogVisible.value = false;
+
+    // 鏍规嵁閫夋嫨鐨勪骇鍝佸拰璁$畻鍏紡杩涜璁$畻
+    calculateWithSelectedProducts();
+  };
+
+  const calculateWithSelectedProducts = () => {
+    // 妯℃嫙璁$畻杩囩▼
+    // 鏍规嵁閫夋嫨鐨勪骇鍝佹洿鏂拌绠楃粨鏋�
+    const result = selectedProducts.value.map(product => {
+      // 杩欓噷搴旇鏍规嵁瀹為檯鐨勮绠楀叕寮忚繘琛岃绠�
+      // 绀轰緥锛氶璁″嚭搴撴暟閲� - 鐜版湁搴撳瓨 + 瀹夊叏搴撳瓨 - 棰勮鍏ュ簱鏁伴噺
+      const weeklyNetDemand =
+        product.inboundNum -
+        product.inboundNum0 +
+        product.inboundNum -
+        product.inboundNum0;
+      const suggestedPurchase = Math.max(0, weeklyNetDemand);
+
+      return {
+        productCategory: product.productCategory,
+        specificationModel: product.specificationModel,
+        inboundNum0: product.inboundNum0,
+        inboundNum: product.inboundNum,
+        weeklyNetDemand: weeklyNetDemand,
+        suggestedPurchase: suggestedPurchase,
+      };
+    });
+
+    calculateResult.value = result;
+    calculateDialogVisible.value = true;
+  };
+
+  const handleCreatePurchaseOrder = () => {
+    calculateDialogVisible.value = false;
+  };
+  const { proxy } = getCurrentInstance();
+  const handleExport = () => {
+    ElMessageBox.confirm("鍐呭灏嗚瀵煎嚭锛屾槸鍚︾‘璁ゅ鍑猴紵", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
       .then(() => {
         proxy.download("/procurementPlan/export", {}, "閲囪喘璁″垝.xlsx");
       })
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
       });
-}
+  };
 
+  const handleSizeChange = size => {
+    pagination.size = size;
+    loadData();
+  };
 
-const handleSizeChange = (size) => {
-  pagination.size = size
-  loadData()
-}
+  const handleCurrentChange = current => {
+    pagination.current = current;
+    loadData();
+  };
 
-const handleCurrentChange = (current) => {
-  pagination.current = current
-  loadData()
-}
-
-// 鐢熷懡鍛ㄦ湡
-onMounted(() => {
-  loadData()
-})
+  // 鐢熷懡鍛ㄦ湡
+  onMounted(() => {
+    loadData();
+  });
 </script>
 
 <style scoped>
-.app-container {
-  padding: 20px;
-}
+  .app-container {
+    padding: 20px;
+  }
 
-.page-header {
-  margin-bottom: 20px;
-}
+  .page-header {
+    margin-bottom: 20px;
+  }
 
-.page-header h2 {
-  margin: 0 0 8px 0;
-  color: #303133;
-  font-size: 24px;
-  font-weight: 600;
-}
+  .page-header h2 {
+    margin: 0 0 8px 0;
+    color: #303133;
+    font-size: 24px;
+    font-weight: 600;
+  }
 
-.page-header p {
-  margin: 0;
-  color: #909399;
-  font-size: 14px;
-}
+  .page-header p {
+    margin: 0;
+    color: #909399;
+    font-size: 14px;
+  }
 
-.search-card {
-  margin-bottom: 20px;
-}
+  .search-card {
+    margin-bottom: 20px;
+  }
 
-.search-form {
-  margin-bottom: 0;
-}
+  .search-form {
+    margin-bottom: 0;
+  }
 
-.table-card {
-  margin-bottom: 20px;
-}
+  .table-card {
+    margin-bottom: 20px;
+  }
 
-.table-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 20px;
-}
+  .table-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+  }
 
-.table-title {
-  font-size: 16px;
-  font-weight: 600;
-  color: #303133;
-}
+  .table-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #303133;
+  }
 
-.table-actions {
-  display: flex;
-  gap: 10px;
-}
+  .table-actions {
+    display: flex;
+    gap: 10px;
+  }
 
-.pagination-container {
-  margin-top: 20px;
-  display: flex;
-  justify-content: end;
-}
+  .pagination-container {
+    margin-top: 20px;
+    display: flex;
+    justify-content: end;
+  }
 
-.form-container {
-  padding: 0 20px;
-}
+  .form-container {
+    padding: 0 20px;
+  }
 
-.formula-help {
-  margin-top: 5px;
-}
+  .formula-help {
+    margin-top: 5px;
+  }
 
-.calculate-result {
-  padding: 20px 0;
-}
+  .calculate-result {
+    padding: 20px 0;
+  }
 
-.dialog-footer {
-  text-align: right;
-}
+  .dialog-footer {
+    text-align: right;
+  }
 
-:deep(.el-card__body) {
-  padding: 20px;
-}
+  :deep(.el-card__body) {
+    padding: 20px;
+  }
 
-:deep(.el-table) {
-  font-size: 14px;
-}
+  :deep(.el-table) {
+    font-size: 14px;
+  }
 
-:deep(.el-form-item__label) {
-  font-weight: 500;
-}
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+  }
 
-.form-container {
-  padding: 0;
-}
+  .form-container {
+    padding: 0;
+  }
 
-.form-section {
-  margin-bottom: 24px;
-  border: 1px solid #e4e7ed;
-  border-radius: 6px;
-  overflow: hidden;
-}
+  .form-section {
+    margin-bottom: 24px;
+    border: 1px solid #e4e7ed;
+    border-radius: 6px;
+    overflow: hidden;
+  }
 
-.section-title {
-  background-color: #f5f7fa;
-  padding: 12px 16px;
-  font-weight: 600;
-  color: #303133;
-  border-bottom: 1px solid #e4e7ed;
-}
+  .section-title {
+    background-color: #f5f7fa;
+    padding: 12px 16px;
+    font-weight: 600;
+    color: #303133;
+    border-bottom: 1px solid #e4e7ed;
+  }
 
-.form-section .el-form {
-  padding: 20px;
-}
+  .form-section .el-form {
+    padding: 20px;
+  }
 
-.param-tabs {
-  padding: 20px;
-}
+  .param-tabs {
+    padding: 20px;
+  }
 
-.param-tabs :deep(.el-tabs__header) {
-  margin-bottom: 20px;
-}
+  .param-tabs :deep(.el-tabs__header) {
+    margin-bottom: 20px;
+  }
 
-.param-tabs :deep(.el-tabs__item.is-active) {
-  color: #f56c6c;
-  border-bottom-color: #f56c6c;
-}
+  .param-tabs :deep(.el-tabs__item.is-active) {
+    color: #f56c6c;
+    border-bottom-color: #f56c6c;
+  }
 
-.checkbox-group {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 16px;
-}
+  .checkbox-group {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 16px;
+  }
 
-.checkbox-group .el-checkbox {
-  margin-right: 0;
-  margin-bottom: 8px;
-}
+  .checkbox-group .el-checkbox {
+    margin-right: 0;
+    margin-bottom: 8px;
+  }
 
-.formula-input-section {
-  padding: 20px;
-}
+  .formula-input-section {
+    padding: 20px;
+  }
 
-.formula-input-section .el-form-item {
-  margin-bottom: 12px;
-}
+  .formula-input-section .el-form-item {
+    margin-bottom: 12px;
+  }
 
-.formula-help {
-  text-align: center;
-  margin-top: 8px;
-}
+  .formula-help {
+    text-align: center;
+    margin-top: 8px;
+  }
 </style>

--
Gitblit v1.9.3