From 9625881d9c655bc22b22fd4410e07526b5a81f6c Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期一, 09 三月 2026 13:33:30 +0800
Subject: [PATCH] 。

---
 src/components/PIMTable/PIMTable.vue                    |  683 +++++++++++++++++++--------------------
 src/views/productionManagement/productionPlan/index.vue |  318 ++++++++++++++++++
 2 files changed, 648 insertions(+), 353 deletions(-)

diff --git a/src/components/PIMTable/PIMTable.vue b/src/components/PIMTable/PIMTable.vue
index a418280..976086b 100644
--- a/src/components/PIMTable/PIMTable.vue
+++ b/src/components/PIMTable/PIMTable.vue
@@ -1,82 +1,73 @@
 <template>
-  <el-table
-    ref="multipleTable"
-    v-loading="tableLoading"
-    :border="border"
-    :data="tableData"
-    :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
-    :height="height"
-    :highlight-current-row="highlightCurrentRow"
-    :row-class-name="rowClassName"
-    :row-style="rowStyle"
-    :row-key="rowKey"
-    :style="tableStyle"
-    tooltip-effect="dark"
-    :expand-row-keys="expandRowKeys"
-    :show-summary="isShowSummary"
-    :summary-method="summaryMethod"
-    @row-click="rowClick"
-    @current-change="currentChange"
-    @selection-change="handleSelectionChange"
-    @expand-change="expandChange"
-    class="lims-table"
-  >
-    <el-table-column
-      align="center"
-      type="selection"
-      width="55"
-      v-if="isSelection"
-    />
-    <el-table-column align="center" label="搴忓彿" type="index" width="60" />
-
-    <el-table-column
-      v-for="(item, index) in column"
-      :key="index"
-      :column-key="item.columnKey"
-      :filter-method="item.filterHandler"
-      :filter-multiple="item.filterMultiple"
-      :filtered-value="item.filteredValue"
-      :filters="item.filters"
-      :fixed="item.fixed"
-      :label="item.label"
-      :prop="item.prop"
-      :show-overflow-tooltip="item.dataType !== 'action' && item.dataType !== 'slot'"
-      :align="item.align"
-      :sortable="!!item.sortable"
-      :type="item.type"
-      :width="item.width"
-    >
+  <el-table ref="multipleTable"
+            v-loading="tableLoading"
+            :border="border"
+            :data="tableData"
+            :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+            :height="height"
+            :highlight-current-row="highlightCurrentRow"
+            :row-class-name="rowClassName"
+            :row-style="rowStyle"
+            :row-key="rowKey"
+            :style="tableStyle"
+            tooltip-effect="dark"
+            :expand-row-keys="expandRowKeys"
+            :show-summary="isShowSummary"
+            :summary-method="summaryMethod"
+            @row-click="rowClick"
+            @current-change="currentChange"
+            @selection-change="handleSelectionChange"
+            @expand-change="expandChange"
+            class="lims-table">
+    <el-table-column align="center"
+                     type="selection"
+                     width="55"
+                     v-if="isSelection" />
+    <el-table-column align="center"
+                     label="搴忓彿"
+                     type="index"
+                     width="60" />
+    <el-table-column v-for="(item, index) in column"
+                     :key="index"
+                     :column-key="item.columnKey"
+                     :filter-method="item.filterHandler"
+                     :filter-multiple="item.filterMultiple"
+                     :filtered-value="item.filteredValue"
+                     :filters="item.filters"
+                     :fixed="item.fixed"
+                     :label="item.label"
+                     :prop="item.prop"
+                     :show-overflow-tooltip="item.dataType !== 'action' && item.dataType !== 'slot'"
+                     :align="item.align"
+                     :sortable="!!item.sortable"
+                     :type="item.type"
+                     :width="item.width">
       <template #header="scope">
         <div class="pim-table-header-cell">
           <div class="pim-table-header-title">
             {{ item.label }}
           </div>
-          <div v-if="item.headerSlot" class="pim-table-header-extra">
-            <slot :name="item.headerSlot" :column="scope.column" />
+          <div v-if="item.headerSlot"
+               class="pim-table-header-extra">
+            <slot :name="item.headerSlot"
+                  :column="scope.column" />
           </div>
         </div>
       </template>
-      <template
-        v-if="item.hasOwnProperty('colunmTemplate')"
-        #[item.colunmTemplate]="scope"
-      >
-        <slot
-          v-if="item.theadSlot"
-          :name="item.theadSlot"
-          :index="scope.$index"
-          :row="scope.row"
-        />
+      <template v-if="item.hasOwnProperty('colunmTemplate')"
+                #[item.colunmTemplate]="scope">
+        <slot v-if="item.theadSlot"
+              :name="item.theadSlot"
+              :index="scope.$index"
+              :row="scope.row" />
       </template>
-
       <template #default="scope">
         <!-- 鎻掓Ы -->
         <div v-if="item.dataType == 'slot'">
-          <slot
-            v-if="item.slot"
-            :index="scope.$index"
-            :name="item.slot"
-            :row="scope.row"
-          />
+          <slot v-if="item.slot"
+                :index="scope.$index"
+                :name="item.slot"
+                :row="scope.row" />
         </div>
         <!-- 杩涘害鏉� -->
         <div v-else-if="item.dataType == 'progress'">
@@ -84,127 +75,110 @@
         </div>
         <!-- 鍥剧墖 -->
         <div v-else-if="item.dataType == 'image'">
-          <img
-            :src="javaApi + '/img/' + scope.row[item.prop]"
-            alt=""
-            style="width: 40px; height: 40px; margin-top: 10px"
-          />
+          <img :src="javaApi + '/img/' + scope.row[item.prop]"
+               alt=""
+               style="width: 40px; height: 40px; margin-top: 10px" />
         </div>
-
         <!-- tag -->
         <div v-else-if="item.dataType == 'tag'">
-          <el-tag
-            v-if="
+          <el-tag v-if="
               typeof dataTypeFn(scope.row[item.prop], item.formatData) ===
               'string'
             "
-            :title="formatters(scope.row[item.prop], item.formatData)"
-            :type="formatType(scope.row[item.prop], item.formatType)"
-          >
+                  :title="formatters(scope.row[item.prop], item.formatData)"
+                  :type="formatType(scope.row[item.prop], item.formatType)">
             {{ formatters(scope.row[item.prop], item.formatData) }}
           </el-tag>
-
-          <el-tag
-            v-for="(tag, index) in dataTypeFn(
+          <el-tag v-for="(tag, index) in dataTypeFn(
               scope.row[item.prop],
               item.formatData
             )"
-            v-else-if="
+                  v-else-if="
               typeof dataTypeFn(scope.row[item.prop], item.formatData) ===
               'object'
             "
-            :key="index"
-            :title="formatters(scope.row[item.prop], item.formatData)"
-            :type="formatType(tag, item.formatType)"
-          >
+                  :key="index"
+                  :title="formatters(scope.row[item.prop], item.formatData)"
+                  :type="formatType(tag, item.formatType)">
             {{ item.tagGroup ? tag[item.tagGroup.label] ?? tag : tag }}
           </el-tag>
-
-          <el-tag
-            v-else
-            :title="formatters(scope.row[item.prop], item.formatData)"
-            :type="formatType(scope.row[item.prop], item.formatType)"
-          >
+          <el-tag v-else
+                  :title="formatters(scope.row[item.prop], item.formatData)"
+                  :type="formatType(scope.row[item.prop], item.formatType)">
             {{ formatters(scope.row[item.prop], item.formatData) }}
           </el-tag>
         </div>
-
         <!-- 鎸夐挳 -->
-        <div v-else-if="item.dataType == 'action'" @click.stop>
-          <template v-for="(o, key) in item.operation" :key="key">
-            <el-button
-              v-show="o.type != 'upload'"
-              v-if="o.showHide ? o.showHide(scope.row) : true"
-              :disabled="o.disabled ? o.disabled(scope.row) : false"
-              :plain="o.plain"
-              type="primary"
-              :style="{
+        <div v-else-if="item.dataType == 'action'"
+             @click.stop>
+          <template v-for="(o, key) in item.operation"
+                    :key="key">
+            <el-button v-show="o.type != 'upload'"
+                       v-if="o.showHide ? o.showHide(scope.row) : true"
+                       :disabled="o.disabled ? o.disabled(scope.row) : false"
+                       :plain="o.plain"
+                       type="primary"
+                       :style="{
                 color:
                   o.name === '鍒犻櫎' || o.name === 'delete'
                     ? '#f56c6c'
                     : o.color,
               }"
-              link
-              @click.stop="o.clickFun(scope.row)"
-              :key="key"
-            >
+                       link
+                       @click.stop="o.clickFun(scope.row)"
+                       :key="key">
               {{ o.name }}
             </el-button>
-            <el-upload
-              :action="
+            <el-upload :action="
                 javaApi +
                 o.url +
                 '?id=' +
                 (o.uploadIdFun ? o.uploadIdFun(scope.row) : scope.row.id)
               "
-              ref="uploadRef"
-              :multiple="o.multiple ? o.multiple : false"
-              :limit="1"
-              :disabled="o.disabled ? o.disabled(scope.row) : false"
-              :accept="
+                       ref="uploadRef"
+                       :multiple="o.multiple ? o.multiple : false"
+                       :limit="1"
+                       :disabled="o.disabled ? o.disabled(scope.row) : false"
+                       :accept="
                 o.accept
                   ? o.accept
                   : '.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'
               "
-              v-if="o.type == 'upload'"
-              style="display: inline-block; width: 50px"
-              v-show="o.showHide ? o.showHide(scope.row) : true"
-              :headers="uploadHeader"
-              :before-upload="(file) => beforeUpload(file, scope.$index)"
-              :on-change="
+                       v-if="o.type == 'upload'"
+                       style="display: inline-block; width: 50px"
+                       v-show="o.showHide ? o.showHide(scope.row) : true"
+                       :headers="uploadHeader"
+                       :before-upload="(file) => beforeUpload(file, scope.$index)"
+                       :on-change="
                 (file, fileList) => handleChange(file, fileList, scope.$index)
               "
-              :on-error="
+                       :on-error="
                 (error, file, fileList) =>
                   onError(error, file, fileList, scope.$index)
               "
-              :on-success="
+                       :on-success="
                 (response, file, fileList) =>
                   handleSuccessUp(response, file, fileList, scope.$index)
               "
-              :on-exceed="onExceed"
-              :show-file-list="false"
-            >
-              <el-button
-                link
-                type="primary"
-                :disabled="o.disabled ? o.disabled(scope.row) : false"
-                >{{ o.name }}</el-button
-              >
+                       :on-exceed="onExceed"
+                       :show-file-list="false">
+              <el-button link
+                         type="primary"
+                         :disabled="o.disabled ? o.disabled(scope.row) : false">{{ o.name }}</el-button>
             </el-upload>
           </template>
         </div>
         <!-- 鍙偣鍑荤殑鏂囧瓧 -->
-        <div
-          v-else-if="item.dataType == 'link'"
-          class="cell link"
-          style="width: 100%"
-          @click="goLink(scope.row, item.linkMethod)"
-        >
+        <div v-else-if="item.dataType == 'link'"
+             class="cell link"
+             style="width: 100%"
+             @click="goLink(scope.row, item.linkMethod)">
           <span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
         </div>
         <!-- 榛樿绾睍绀烘暟鎹� -->
-        <div v-else class="cell" style="width: 100%">
+        <div v-else
+             class="cell"
+             style="width: 100%">
           <span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
           <span v-else>{{
             formatters(scope.row[item.prop], item.formatData)
@@ -213,244 +187,247 @@
       </template>
     </el-table-column>
   </el-table>
-  <pagination
-		v-if="isShowPagination"
-    :total="page.total"
-    :layout="page.layout"
-    :page="page.current"
-    :limit="page.size"
-    @pagination="paginationSearch"
-  />
+  <pagination v-if="isShowPagination"
+              :total="page.total"
+              :layout="page.layout"
+              :page="page.current"
+              :limit="page.size"
+              @pagination="paginationSearch" />
 </template>
 
 <script setup>
-import pagination from "./Pagination.vue";
-import { ref, inject, getCurrentInstance } from "vue";
-import { ElMessage } from "element-plus";
+  import pagination from "./Pagination.vue";
+  import { ref, inject, getCurrentInstance } from "vue";
+  import { ElMessage } from "element-plus";
 
-// 鑾峰彇鍏ㄥ眬鐨� uploadHeader
-const { proxy } = getCurrentInstance();
-const uploadHeader = proxy.uploadHeader;
-const javaApi = proxy.javaApi;
+  // 鑾峰彇鍏ㄥ眬鐨� uploadHeader
+  const { proxy } = getCurrentInstance();
+  const uploadHeader = proxy.uploadHeader;
+  const javaApi = proxy.javaApi;
 
-const emit = defineEmits(["pagination", "expand-change", "selection-change", "row-click"]);
+  const emit = defineEmits([
+    "pagination",
+    "expand-change",
+    "selection-change",
+    "row-click",
+  ]);
 
-// Filters
-const typeFn = (val, row) => {
-  return typeof val === "function" ? val(row) : val;
-};
+  // Filters
+  const typeFn = (val, row) => {
+    return typeof val === "function" ? val(row) : val;
+  };
 
-const formatters = (val, format) => {
-  return typeof format === "function" ? format(val) : val;
-};
+  const formatters = (val, format) => {
+    return typeof format === "function" ? format(val) : val;
+  };
 
-// Props锛堜娇鐢� defineProps 鐨勯潪 TS 褰㈠紡锛�
-const props = defineProps({
-  tableLoading: {
-    type: Boolean,
-    default: false,
-  },
-  height: {
-    type: [Number, String],
-    default: "calc(100vh - 22em)",
-  },
-  expandRowKeys: {
-    type: Array,
-    default: () => [],
-  },
-  summaryMethod: {
-    type: Function,
-    default: () => {},
-  },
-  rowClick: {
-    type: Function,
-    default: () => {},
-  },
-  currentChange: {
-    type: Function,
-    default: () => {},
-  },
-  border: {
-    type: Boolean,
-    default: true,
-  },
-  isSelection: {
-    type: Boolean,
-    default: false,
-  },
-	isShowPagination: {
-    type: Boolean,
-    default: true,
-  },
-  isShowSummary: {
-    type: Boolean,
-    default: false,
-  },
-  highlightCurrentRow: {
-    type: Boolean,
-    default: false,
-  },
-  headerCellStyle: {
-    type: Object,
-    default: () => ({}),
-  },
-  column: {
-    type: Array,
-    default: () => [],
-  },
-  rowClassName: {
-    type: Function,
-    default: () => "",
-  },
-  rowStyle: {
-    type: [Object, Function],
-    default: () => ({}),
-  },
-  tableData: {
-    type: Array,
-    default: () => [],
-  },
-  rowKey: {
-    type: String,
-    default: 'id',
-  },
-  page: {
-    type: Object,
-    default: () => ({
-      total: 0,
-      current: 0,
-      size: 10,
-      layout: "total, sizes, prev, pager, next, jumper",
-    }),
-  },
-  total: {
-    type: Number,
-    default: 0,
-  },
-  tableStyle: {
-    type: [String, Object],
-    default: () => ({ width: "100%" }),
-  },
-});
+  // Props锛堜娇鐢� defineProps 鐨勯潪 TS 褰㈠紡锛�
+  const props = defineProps({
+    tableLoading: {
+      type: Boolean,
+      default: false,
+    },
+    height: {
+      type: [Number, String],
+      default: "calc(100vh - 22em)",
+    },
+    expandRowKeys: {
+      type: Array,
+      default: () => [],
+    },
+    summaryMethod: {
+      type: Function,
+      default: () => {},
+    },
+    rowClick: {
+      type: Function,
+      default: () => {},
+    },
+    currentChange: {
+      type: Function,
+      default: () => {},
+    },
+    border: {
+      type: Boolean,
+      default: true,
+    },
+    isSelection: {
+      type: Boolean,
+      default: false,
+    },
+    isShowPagination: {
+      type: Boolean,
+      default: true,
+    },
+    isShowSummary: {
+      type: Boolean,
+      default: false,
+    },
+    highlightCurrentRow: {
+      type: Boolean,
+      default: false,
+    },
+    headerCellStyle: {
+      type: Object,
+      default: () => ({}),
+    },
+    column: {
+      type: Array,
+      default: () => [],
+    },
+    rowClassName: {
+      type: Function,
+      default: () => "",
+    },
+    rowStyle: {
+      type: [Object, Function],
+      default: () => ({}),
+    },
+    tableData: {
+      type: Array,
+      default: () => [],
+    },
+    rowKey: {
+      type: String,
+      default: "id",
+    },
+    page: {
+      type: Object,
+      default: () => ({
+        total: 0,
+        current: 0,
+        size: 10,
+        layout: "total, sizes, prev, pager, next, jumper",
+      }),
+    },
+    total: {
+      type: Number,
+      default: 0,
+    },
+    tableStyle: {
+      type: [String, Object],
+      default: () => ({ width: "100%" }),
+    },
+  });
 
-// Data
-const uploadRefs = ref([]);
-const currentFiles = ref({});
-const uploadKeys = ref({});
+  // Data
+  const uploadRefs = ref([]);
+  const currentFiles = ref({});
+  const uploadKeys = ref({});
 
-const indexMethod = (index) => {
-  return (props.page.current - 1) * props.page.size + index + 1;
-};
+  const indexMethod = index => {
+    return (props.page.current - 1) * props.page.size + index + 1;
+  };
 
-// 鐐瑰嚮 link 浜嬩欢
-const goLink = (row, linkMethod) => {
-  if (!linkMethod) {
-    return ElMessage.warning("璇烽厤缃� link 浜嬩欢");
-  }
-  const parentMethod = getParentMethod(linkMethod);
-  if (typeof parentMethod === "function") {
-    parentMethod(row);
-  } else {
-    console.warn(`鐖剁粍浠朵腑鏈壘鍒版柟娉�: ${linkMethod}`);
-  }
-};
-
-// 鑾峰彇鐖剁粍浠舵柟娉曪紙绀轰緥瀹炵幇锛�
-const getParentMethod = (methodName) => {
-  const parentMethods = inject("parentMethods", {});
-  return parentMethods[methodName];
-};
-
-const dataTypeFn = (val, format) => {
-  if (typeof format === "function") {
-    return format(val);
-  } else return val;
-};
-
-const formatType = (val, format) => {
-  if (typeof format === "function") {
-    return format(val);
-  } else return "";
-};
-
-// 鏂囦欢鍙樺寲澶勭悊
-const handleChange = (file, fileList, index) => {
-  if (fileList.length > 1) {
-    const earliestFile = fileList[0];
-    uploadRefs.value[index]?.handleRemove(earliestFile);
-  }
-  currentFiles.value[index] = file;
-};
-
-// 鏂囦欢涓婁紶鍓嶆牎楠�
-const beforeUpload = (rawFile, index) => {
-  currentFiles.value[index] = {};
-  if (rawfile.size > 1024 * 1024 * 10 * 10) {
-    ElMessage.error("涓婁紶鏂囦欢涓嶈秴杩�10M");
-    return false;
-  }
-  return true;
-};
-
-// 涓婁紶鎴愬姛
-const handleSuccessUp = (response, file, fileList, index) => {
-  if (response.code == 200) {
-    if (uploadRefs[index]) {
-      uploadRefs[index].clearFiles();
+  // 鐐瑰嚮 link 浜嬩欢
+  const goLink = (row, linkMethod) => {
+    if (!linkMethod) {
+      return ElMessage.warning("璇烽厤缃� link 浜嬩欢");
     }
-    currentFiles[index] = file;
-    ElMessage.success("涓婁紶鎴愬姛");
-    resetUploadComponent(index);
-  } else {
-    ElMessage.error(response.message);
-  }
-};
+    const parentMethod = getParentMethod(linkMethod);
+    if (typeof parentMethod === "function") {
+      parentMethod(row);
+    } else {
+      console.warn(`鐖剁粍浠朵腑鏈壘鍒版柟娉�: ${linkMethod}`);
+    }
+  };
 
-const resetUploadComponent = (index) => {
-  uploadKeys[index] = Date.now();
-};
+  // 鑾峰彇鐖剁粍浠舵柟娉曪紙绀轰緥瀹炵幇锛�
+  const getParentMethod = methodName => {
+    const parentMethods = inject("parentMethods", {});
+    return parentMethods[methodName];
+  };
 
-// 涓婁紶澶辫触
-const onError = (error, file, fileList, index) => {
-  ElMessage.error("鏂囦欢涓婁紶澶辫触锛岃閲嶈瘯");
-  if (uploadRefs.value[index]) {
-    uploadRefs.value[index].clearFiles();
-  }
-};
+  const dataTypeFn = (val, format) => {
+    if (typeof format === "function") {
+      return format(val);
+    } else return val;
+  };
 
-// 鏂囦欢鏁伴噺瓒呴檺鎻愮ず
-const onExceed = () => {
-  ElMessage.warning("瓒呭嚭鏂囦欢涓暟");
-};
+  const formatType = (val, format) => {
+    if (typeof format === "function") {
+      return format(val);
+    } else return "";
+  };
 
-const paginationSearch = ({ page, limit }) => {
-  emit("pagination", { page: page, limit: limit });
-};
+  // 鏂囦欢鍙樺寲澶勭悊
+  const handleChange = (file, fileList, index) => {
+    if (fileList.length > 1) {
+      const earliestFile = fileList[0];
+      uploadRefs.value[index]?.handleRemove(earliestFile);
+    }
+    currentFiles.value[index] = file;
+  };
 
-const rowClick = (row) => {
-  emit("row-click", row);
-};
+  // 鏂囦欢涓婁紶鍓嶆牎楠�
+  const beforeUpload = (rawFile, index) => {
+    currentFiles.value[index] = {};
+    if (rawfile.size > 1024 * 1024 * 10 * 10) {
+      ElMessage.error("涓婁紶鏂囦欢涓嶈秴杩�10M");
+      return false;
+    }
+    return true;
+  };
 
-const expandChange = (row, expandedRows) => {
-  emit("expand-change", row, expandedRows);
-};
+  // 涓婁紶鎴愬姛
+  const handleSuccessUp = (response, file, fileList, index) => {
+    if (response.code == 200) {
+      if (uploadRefs[index]) {
+        uploadRefs[index].clearFiles();
+      }
+      currentFiles[index] = file;
+      ElMessage.success("涓婁紶鎴愬姛");
+      resetUploadComponent(index);
+    } else {
+      ElMessage.error(response.message);
+    }
+  };
 
-const handleSelectionChange = (newSelection) => {
-  emit("selection-change", newSelection);
-};
+  const resetUploadComponent = index => {
+    uploadKeys[index] = Date.now();
+  };
+
+  // 涓婁紶澶辫触
+  const onError = (error, file, fileList, index) => {
+    ElMessage.error("鏂囦欢涓婁紶澶辫触锛岃閲嶈瘯");
+    if (uploadRefs.value[index]) {
+      uploadRefs.value[index].clearFiles();
+    }
+  };
+
+  // 鏂囦欢鏁伴噺瓒呴檺鎻愮ず
+  const onExceed = () => {
+    ElMessage.warning("瓒呭嚭鏂囦欢涓暟");
+  };
+
+  const paginationSearch = ({ page, limit }) => {
+    emit("pagination", { page: page, limit: limit });
+  };
+
+  const rowClick = row => {
+    emit("row-click", row);
+  };
+
+  const expandChange = (row, expandedRows) => {
+    emit("expand-change", row, expandedRows);
+  };
+
+  const handleSelectionChange = newSelection => {
+    emit("selection-change", newSelection);
+  };
 </script>
 
 <style scoped lang="scss">
-.cell {
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  padding-right: 0 !important;
-  padding-left: 0 !important;
-}
+  .cell {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    padding-right: 0 !important;
+    padding-left: 0 !important;
+  }
 
-.pim-table-header-extra :deep(.el-input),
-.pim-table-header-extra :deep(.el-select) {
-  width: 100%;
-}
+  .pim-table-header-extra :deep(.el-input),
+  .pim-table-header-extra :deep(.el-select) {
+    width: 100%;
+  }
 </style>
diff --git a/src/views/productionManagement/productionPlan/index.vue b/src/views/productionManagement/productionPlan/index.vue
new file mode 100644
index 0000000..855a64c
--- /dev/null
+++ b/src/views/productionManagement/productionPlan/index.vue
@@ -0,0 +1,318 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <el-button type="primary"
+                   @click="isShowNewModal = true">鏂板</el-button>
+        <el-button type="danger"
+                   @click="handleDelete">鍒犻櫎</el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+                :page="page"
+                :tableLoading="tableLoading"
+                :isSelection="true"
+                @selection-change="handleSelectionChange"
+                @pagination="pagination">
+      </PIMTable>
+    </div>
+  </div>
+</template>
+
+<script setup>
+  import { onMounted, ref } from "vue";
+  import { ElMessageBox } from "element-plus";
+  import dayjs from "dayjs";
+  import { delProductOrder } from "@/api/productionManagement/productionOrder.js";
+  import PIMTable from "@/components/PIMTable/PIMTable.vue";
+
+  const { proxy } = getCurrentInstance();
+
+  const isShowNewModal = ref(false);
+
+  const tableColumn = ref([
+    {
+      label: "搴忓彿",
+      type: "index",
+      width: "60px",
+      align: "center",
+    },
+    {
+      label: "鏉ユ簮",
+      prop: "source",
+      width: "100px",
+    },
+    {
+      label: "鐘舵��",
+      prop: "status",
+      width: "80px",
+    },
+    {
+      label: "瀹℃牳鐘舵��",
+      prop: "auditStatus",
+      width: "100px",
+    },
+    {
+      label: "璁㈠崟鍙�",
+      prop: "orderNo",
+      width: "120px",
+    },
+    {
+      label: "鐢熶骇璁″垝鍙�",
+      prop: "productionPlanNo",
+      width: "140px",
+    },
+    {
+      label: "闆朵欢鍙�",
+      prop: "partNo",
+      width: "120px",
+    },
+    {
+      label: "闆朵欢",
+      prop: "partName",
+      width: "120px",
+    },
+    {
+      label: "宸ヨ壓鏂囦欢鍙�",
+      prop: "processFileNo",
+      width: "140px",
+    },
+    {
+      label: "閿�鍞暟閲�",
+      prop: "salesQuantity",
+      width: "100px",
+      align: "right",
+    },
+    {
+      label: "鍒堕�犳暟閲�",
+      prop: "manufactureQuantity",
+      width: "100px",
+      align: "right",
+    },
+    {
+      label: "闆朵欢鍗曚綅",
+      prop: "partUnit",
+      width: "80px",
+    },
+    {
+      label: "涓昏鍒掗渶姹傛棩鏈�",
+      prop: "mainPlanDemandDate",
+      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+      width: "140px",
+    },
+    {
+      label: "鎵胯鏃ユ湡",
+      prop: "commitmentDate",
+      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+      width: "120px",
+    },
+    {
+      label: "鍒堕�犲睘鎬�",
+      prop: "manufactureProperty",
+      width: "100px",
+    },
+    {
+      label: "澶囨敞",
+      prop: "remark",
+      width: "150px",
+    },
+    {
+      label: "鏇存柊鏃堕棿",
+      prop: "updateTime",
+      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+      width: "120px",
+    },
+    {
+      label: "鏇存柊浜�",
+      prop: "updateBy",
+      width: "100px",
+    },
+    {
+      label: "鍒涘缓鏃堕棿",
+      prop: "createTime",
+      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+      width: "120px",
+    },
+    {
+      label: "鍒涘缓浜�",
+      prop: "createBy",
+      width: "100px",
+    },
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      align: "center",
+      fixed: "right",
+      width: 200,
+      operation: [
+        {
+          name: "涓嬪彂",
+          type: "text",
+          clickFun: row => {
+            // 涓嬪彂鎿嶄綔
+          },
+        },
+        {
+          name: "杩借釜杩涘害",
+          type: "text",
+          clickFun: row => {
+            // 杩借釜杩涘害鎿嶄綔
+          },
+        },
+      ],
+    },
+  ]);
+  const tableData = ref([]);
+  const tableLoading = ref(false);
+  const page = reactive({
+    current: 1,
+    size: 100,
+    total: 0,
+  });
+  const selectedRows = ref([]);
+
+  // 妯℃嫙鏁版嵁
+  const mockData = [
+    {
+      id: 1,
+      source: "閿�鍞鍗�",
+      status: "鎵ц涓�",
+      auditStatus: "宸插鏍�",
+      orderNo: "SO20260301",
+      productionPlanNo: "PP20260301001",
+      partNo: "P001",
+      partName: "榻胯疆",
+      processFileNo: "PF20260301",
+      salesQuantity: 100,
+      manufactureQuantity: 105,
+      partUnit: "涓�",
+      mainPlanDemandDate: "2026-03-15",
+      commitmentDate: "2026-03-10",
+      manufactureProperty: "甯歌",
+      remark: "鏃�",
+      updateTime: "2026-03-05",
+      updateBy: "寮犱笁",
+      createTime: "2026-03-01",
+      createBy: "鏉庡洓",
+    },
+    {
+      id: 2,
+      source: "搴撳瓨琛ュ厖",
+      status: "宸插畬鎴�",
+      auditStatus: "宸插鏍�",
+      orderNo: "SO20260302",
+      productionPlanNo: "PP20260301002",
+      partNo: "P002",
+      partName: "杞存壙",
+      processFileNo: "PF20260302",
+      salesQuantity: 200,
+      manufactureQuantity: 200,
+      partUnit: "濂�",
+      mainPlanDemandDate: "2026-03-20",
+      commitmentDate: "2026-03-15",
+      manufactureProperty: "甯歌",
+      remark: "绱ф�ヨ鍗�",
+      updateTime: "2026-03-06",
+      updateBy: "鐜嬩簲",
+      createTime: "2026-03-02",
+      createBy: "璧靛叚",
+    },
+    {
+      id: 3,
+      source: "閿�鍞鍗�",
+      status: "寰呮墽琛�",
+      auditStatus: "寰呭鏍�",
+      orderNo: "SO20260303",
+      productionPlanNo: "PP20260301003",
+      partNo: "P003",
+      partName: "杞�",
+      processFileNo: "PF20260303",
+      salesQuantity: 150,
+      manufactureQuantity: 155,
+      partUnit: "鏍�",
+      mainPlanDemandDate: "2026-03-25",
+      commitmentDate: "2026-03-20",
+      manufactureProperty: "瀹氬埗",
+      remark: "鐗规畩瑙勬牸",
+      updateTime: "2026-03-07",
+      updateBy: "瀛欎竷",
+      createTime: "2026-03-03",
+      createBy: "鍛ㄥ叓",
+    },
+  ];
+
+  // 鏌ヨ鍒楄〃
+  const getList = () => {
+    tableLoading.value = true;
+    // 浣跨敤妯℃嫙鏁版嵁
+    setTimeout(() => {
+      tableData.value = mockData;
+      page.total = mockData.length;
+      tableLoading.value = false;
+    }, 500);
+  };
+
+  const pagination = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  // 琛ㄦ牸閫夋嫨鏁版嵁
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+
+  const handleDelete = () => {
+    let ids = [];
+    if (selectedRows.value.length > 0) {
+      ids = selectedRows.value.map(item => item.id);
+    } else {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎纭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        // 妯℃嫙鍒犻櫎鎿嶄綔
+        tableData.value = tableData.value.filter(item => !ids.includes(item.id));
+        page.total = tableData.value.length;
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  // 瀵煎嚭
+  const handleOut = () => {
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        proxy.$modal.msgSuccess("瀵煎嚭鎴愬姛");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  onMounted(() => {
+    getList();
+  });
+</script>
+
+<style scoped lang="scss">
+  .search_form {
+    margin-bottom: 20px;
+  }
+</style>

--
Gitblit v1.9.3