From 71a9eef518f2f2f1a1eb2fb90f2eb8ab7b155bc8 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 08 一月 2026 14:57:56 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_天津军泰伟业' into dev_天津军泰伟业

---
 src/views/oaSystem/projectManagement/components/milestoneList.vue |  466 +++++++++++++++++++++++++++++----------------------------
 1 files changed, 238 insertions(+), 228 deletions(-)

diff --git a/src/views/oaSystem/projectManagement/components/milestoneList.vue b/src/views/oaSystem/projectManagement/components/milestoneList.vue
index 47b0027..08429e2 100644
--- a/src/views/oaSystem/projectManagement/components/milestoneList.vue
+++ b/src/views/oaSystem/projectManagement/components/milestoneList.vue
@@ -2,18 +2,21 @@
 <template>
   <div class="milestone-list-container">
     <el-timeline>
-      <el-timeline-item
-        v-for="milestone in milestoneList"
-        :key="milestone.phaseId"
-        :timestamp="milestone.endDate"
-      >
+      <el-timeline-item v-for="milestone in milestoneList"
+                        :key="milestone.phaseId"
+                        :timestamp="milestone.endDate">
         <el-card>
           <template #header>
             <div class="card-header">
               <span>{{ milestone.phaseName }}</span>
               <div class="milestone-actions">
-                <el-button type="text" size="small" @click="handleEdit(milestone)">缂栬緫</el-button>
-                <el-button type="text" size="small" @click="handleDelete(milestone)" danger>鍒犻櫎</el-button>
+                <el-button type="text"
+                           size="small"
+                           @click="handleEdit(milestone)">缂栬緫</el-button>
+                <el-button type="text"
+                           size="small"
+                           @click="handleDelete(milestone)"
+                           danger>鍒犻櫎</el-button>
               </div>
             </div>
           </template>
@@ -26,66 +29,67 @@
         </el-card>
       </el-timeline-item>
     </el-timeline>
-    
     <!-- 鏃犻噷绋嬬鏃剁殑鎻愮ず -->
-    <div v-if="milestoneList.length === 0" class="empty-tip">
+    <div v-if="milestoneList.length === 0"
+         class="empty-tip">
       <el-empty description="鏆傛棤閲岀▼纰戞暟鎹�" />
     </div>
-    
     <!-- 缂栬緫閲岀▼纰戝璇濇 -->
-    <el-dialog
-      v-model="dialogVisible"
-      :title="'缂栬緫閲岀▼纰�: ' + (form.phaseName || '')"
-      width="600px"
-      :close-on-click-modal="false"
-    >
-      <el-form
-        ref="formRef"
-        :model="form"
-        :rules="rules"
-        label-width="100px"
-      >
-        <el-form-item label="閲岀▼纰戝悕绉�" prop="phaseName">
-          <el-input v-model="form.phaseName" placeholder="璇疯緭鍏ラ噷绋嬬鍚嶇О" />
+    <el-dialog v-model="dialogVisible"
+               :title="'缂栬緫閲岀▼纰�: ' + (form.phaseName || '')"
+               width="600px"
+               :close-on-click-modal="false">
+      <el-form ref="formRef"
+               :model="form"
+               :rules="rules"
+               label-width="100px">
+        <el-form-item label="閲岀▼纰戝悕绉�"
+                      prop="phaseName">
+          <el-input v-model="form.phaseName"
+                    placeholder="璇疯緭鍏ラ噷绋嬬鍚嶇О" />
         </el-form-item>
         <el-row :gutter="20">
-      <el-col :span="12">
-        <el-form-item label="寮�濮嬫棩鏈�" prop="startDate">
-          <el-date-picker
-            v-model="form.startDate"
-            type="date"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            placeholder="閫夋嫨寮�濮嬫棩鏈�"
-            style="width: 100%"
-          />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="缁撴潫鏃ユ湡" prop="endDate">
-          <el-date-picker
-            v-model="form.endDate"
-            type="date"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            placeholder="閫夋嫨缁撴潫鏃ユ湡"
-            style="width: 100%"
-          />
-        </el-form-item>
-      </el-col>
-    </el-row>
-        <el-form-item label="鐘舵��" prop="status">
-          <el-select v-model="form.status" placeholder="璇烽�夋嫨鐘舵��">
-            <el-option label="鏈紑濮�" value="notStarted" />
-            <el-option label="宸插畬鎴�" value="completed" />
-            <el-option label="宸插欢杩�" value="delayed" />
+          <el-col :span="12">
+            <el-form-item label="寮�濮嬫棩鏈�"
+                          prop="startDate">
+              <el-date-picker v-model="form.startDate"
+                              type="date"
+                              format="YYYY-MM-DD"
+                              value-format="YYYY-MM-DD"
+                              placeholder="閫夋嫨寮�濮嬫棩鏈�"
+                              style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁撴潫鏃ユ湡"
+                          prop="endDate">
+              <el-date-picker v-model="form.endDate"
+                              type="date"
+                              format="YYYY-MM-DD"
+                              value-format="YYYY-MM-DD"
+                              placeholder="閫夋嫨缁撴潫鏃ユ湡"
+                              style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="鐘舵��"
+                      prop="status">
+          <el-select v-model="form.status"
+                     placeholder="璇烽�夋嫨鐘舵��">
+            <el-option label="鏈紑濮�"
+                       value="notStarted" />
+            <el-option label="宸插畬鎴�"
+                       value="completed" />
+            <el-option label="宸插欢杩�"
+                       value="delayed" />
           </el-select>
         </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitEditForm">纭畾</el-button>
           <el-button @click="dialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary" @click="submitEditForm">纭畾</el-button>
         </div>
       </template>
     </el-dialog>
@@ -93,197 +97,203 @@
 </template>
 
 <script setup>
-import { ref, onMounted, watch, reactive } from 'vue';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import { getProject, listProjectPhase, updateProjectPhase,delProjectPhase } from '@/api/oaSystem/projectManagement';
+  import { ref, onMounted, watch, reactive } from "vue";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import {
+    getProject,
+    listProjectPhase,
+    updateProjectPhase,
+    delProjectPhase,
+  } from "@/api/oaSystem/projectManagement";
 
-const props = defineProps({
-  projectId: {
-    type: String,
-    required: true
-  }
-});
-
-const emit = defineEmits(['refresh']);
-
-const milestoneList = ref([]);
-const dialogVisible = ref(false);
-const formRef = ref(null);
-const form = reactive({
-  phaseId: '',
-  phaseName: '',
-  startDate: '',
-  endDate: '',
-  status: 'notStarted',
-  projectId: props.projectId
-});
-
-// 琛ㄥ崟楠岃瘉瑙勫垯
-const rules = {
-  phaseName: [
-    { required: true, message: '璇疯緭鍏ラ噷绋嬬鍚嶇О', trigger: 'blur' },
-    { min: 2, max: 50, message: '闀垮害鍦� 2 鍒� 50 涓瓧绗�', trigger: 'blur' }
-  ],
-  status: [
-    { required: true, message: '璇烽�夋嫨鐘舵��', trigger: 'change' }
-  ]
-};
-
-// 鑾峰彇閲岀▼纰戝垪琛�
-const getMilestoneList = async () => {
-  try {
-    listProjectPhase(props.projectId).then(res => {
-      milestoneList.value = res.data.rows || res.data;
-      // 鎸夌洰鏍囨棩鏈熸帓搴�
-      // milestoneList.value.sort((a, b) => new Date(a.endDate) - new Date(b.endDate));
-    })
-  } catch (error) {
-    ElMessage.error('鑾峰彇閲岀▼纰戝垪琛ㄥけ璐�');
-    console.error('鑾峰彇閲岀▼纰戝垪琛ㄥけ璐�:', error);
-  }
-};
-
-// 缂栬緫閲岀▼纰�
-const handleEdit = (milestone) => {
-  // 澶嶅埗閲岀▼纰戞暟鎹埌琛ㄥ崟
-  Object.assign(form, {
-    phaseId: milestone.phaseId,
-    phaseName: milestone.phaseName,
-    description: milestone.description,
-    endDate: milestone.endDate,
-    status: milestone.status,
-    projectId: props.projectId
+  const props = defineProps({
+    projectId: {
+      type: String,
+      required: true,
+    },
   });
-  dialogVisible.value = true;
-};
 
-// 鎻愪氦缂栬緫琛ㄥ崟
-const submitEditForm = async () => {
-  try {
-    await formRef.value.validate();
-    
-    // 鍙戦�佹洿鏂拌姹�
-    const res = await updateProjectPhase(form);
-    
-    if (res.code === 200) {
-      ElMessage.success('閲岀▼纰戠紪杈戞垚鍔�');
-      dialogVisible.value = false;
-      getMilestoneList(); // 鍒锋柊鍒楄〃
-      emit('refresh'); // 閫氱煡鐖剁粍浠跺埛鏂�
-    } else {
-      ElMessage.error(res.msg || '閲岀▼纰戠紪杈戝け璐�');
-    }
-  } catch (error) {
-    if (error.name === 'ValidationError') {
-      // 琛ㄥ崟楠岃瘉澶辫触锛孍lement Plus浼氳嚜鍔ㄦ彁绀�
-      return;
-    }
-    ElMessage.error('閲岀▼纰戠紪杈戝け璐�');
-    console.error('缂栬緫閲岀▼纰戝け璐�:', error);
-  }
-};
+  const emit = defineEmits(["refresh"]);
 
-// 鍒犻櫎閲岀▼纰�
-const handleDelete = (milestone) => {
-  ElMessageBox.confirm(
-    `纭畾瑕佸垹闄ら噷绋嬬 "${milestone.phaseName}" 鍚楋紵鍒犻櫎鍚庡皢鏃犳硶鎭㈠銆俙,
-    '鍒犻櫎纭',
-    {
-      confirmButtonText: '纭畾',
-      cancelButtonText: '鍙栨秷',
-      type: 'warning'
+  const milestoneList = ref([]);
+  const dialogVisible = ref(false);
+  const formRef = ref(null);
+  const form = reactive({
+    phaseId: "",
+    phaseName: "",
+    startDate: "",
+    endDate: "",
+    status: "notStarted",
+    projectId: props.projectId,
+  });
+
+  // 琛ㄥ崟楠岃瘉瑙勫垯
+  const rules = {
+    phaseName: [
+      { required: true, message: "璇疯緭鍏ラ噷绋嬬鍚嶇О", trigger: "blur" },
+      { min: 2, max: 50, message: "闀垮害鍦� 2 鍒� 50 涓瓧绗�", trigger: "blur" },
+    ],
+    status: [{ required: true, message: "璇烽�夋嫨鐘舵��", trigger: "change" }],
+  };
+
+  // 鑾峰彇閲岀▼纰戝垪琛�
+  const getMilestoneList = async () => {
+    try {
+      listProjectPhase(props.projectId).then(res => {
+        milestoneList.value = res.data.rows || res.data;
+        // 鎸夌洰鏍囨棩鏈熸帓搴�
+        // milestoneList.value.sort((a, b) => new Date(a.endDate) - new Date(b.endDate));
+      });
+    } catch (error) {
+      ElMessage.error("鑾峰彇閲岀▼纰戝垪琛ㄥけ璐�");
+      console.error("鑾峰彇閲岀▼纰戝垪琛ㄥけ璐�:", error);
     }
-  )
-    .then(async () => {
-      try {
-        // 璋冪敤鍒犻櫎API
-        const res = await delProjectPhase(milestone.phaseId);
-        
-        if (res.code === 200) {
-          ElMessage.success('閲岀▼纰戝垹闄ゆ垚鍔�');
-          getMilestoneList(); // 鍒锋柊鍒楄〃
-          emit('refresh'); // 閫氱煡鐖剁粍浠跺埛鏂�
-        } else {
-          ElMessage.error(res.msg || '閲岀▼纰戝垹闄ゅけ璐�');
-        }
-      } catch (error) {
-        ElMessage.error('閲岀▼纰戝垹闄ゅけ璐�');
-        console.error('鍒犻櫎閲岀▼纰戝け璐�:', error);
-      }
-    })
-    .catch(() => {
-      // 鐢ㄦ埛鍙栨秷鍒犻櫎
-      ElMessage.info('宸插彇娑堝垹闄�');
+  };
+
+  // 缂栬緫閲岀▼纰�
+  const handleEdit = milestone => {
+    // 澶嶅埗閲岀▼纰戞暟鎹埌琛ㄥ崟
+    Object.assign(form, {
+      phaseId: milestone.phaseId,
+      phaseName: milestone.phaseName,
+      description: milestone.description,
+      endDate: milestone.endDate,
+      status: milestone.status,
+      projectId: props.projectId,
     });
-};
-
-// 鑾峰彇鐘舵�佹爣绛剧被鍨�
-const getStatusType = (status) => {
-  const statusTypeMap = {
-    notStarted: 'info',
-    completed: 'success',
-    delayed: 'danger'
+    dialogVisible.value = true;
   };
-  return statusTypeMap[status] || 'default';
-};
 
-// 鑾峰彇鐘舵�佹枃鏈�
-const getStatusText = (status) => {
-  const statusTextMap = {
-    notStarted: '鏈紑濮�',
-    completed: '宸插畬鎴�',
-    delayed: '宸插欢杩�'
+  // 鎻愪氦缂栬緫琛ㄥ崟
+  const submitEditForm = async () => {
+    try {
+      await formRef.value.validate();
+
+      // 鍙戦�佹洿鏂拌姹�
+      const res = await updateProjectPhase(form);
+
+      if (res.code === 200) {
+        ElMessage.success("閲岀▼纰戠紪杈戞垚鍔�");
+        dialogVisible.value = false;
+        getMilestoneList(); // 鍒锋柊鍒楄〃
+        emit("refresh"); // 閫氱煡鐖剁粍浠跺埛鏂�
+      } else {
+        ElMessage.error(res.msg || "閲岀▼纰戠紪杈戝け璐�");
+      }
+    } catch (error) {
+      if (error.name === "ValidationError") {
+        // 琛ㄥ崟楠岃瘉澶辫触锛孍lement Plus浼氳嚜鍔ㄦ彁绀�
+        return;
+      }
+      ElMessage.error("閲岀▼纰戠紪杈戝け璐�");
+      console.error("缂栬緫閲岀▼纰戝け璐�:", error);
+    }
   };
-  return statusTextMap[status] || status;
-};
 
-// 鐩戝惉椤圭洰ID鍙樺寲
-watch(() => props.projectId, () => {
-  if (props.projectId) {
-    getMilestoneList();
-  }
-});
+  // 鍒犻櫎閲岀▼纰�
+  const handleDelete = milestone => {
+    ElMessageBox.confirm(
+      `纭畾瑕佸垹闄ら噷绋嬬 "${milestone.phaseName}" 鍚楋紵鍒犻櫎鍚庡皢鏃犳硶鎭㈠銆俙,
+      "鍒犻櫎纭",
+      {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      }
+    )
+      .then(async () => {
+        try {
+          // 璋冪敤鍒犻櫎API
+          const res = await delProjectPhase(milestone.phaseId);
 
-// 鍒濆鍖�
-onMounted(() => {
-  if (props.projectId) {
-    getMilestoneList();
-  }
-});
+          if (res.code === 200) {
+            ElMessage.success("閲岀▼纰戝垹闄ゆ垚鍔�");
+            getMilestoneList(); // 鍒锋柊鍒楄〃
+            emit("refresh"); // 閫氱煡鐖剁粍浠跺埛鏂�
+          } else {
+            ElMessage.error(res.msg || "閲岀▼纰戝垹闄ゅけ璐�");
+          }
+        } catch (error) {
+          ElMessage.error("閲岀▼纰戝垹闄ゅけ璐�");
+          console.error("鍒犻櫎閲岀▼纰戝け璐�:", error);
+        }
+      })
+      .catch(() => {
+        // 鐢ㄦ埛鍙栨秷鍒犻櫎
+        ElMessage.info("宸插彇娑堝垹闄�");
+      });
+  };
+
+  // 鑾峰彇鐘舵�佹爣绛剧被鍨�
+  const getStatusType = status => {
+    const statusTypeMap = {
+      notStarted: "info",
+      completed: "success",
+      delayed: "danger",
+    };
+    return statusTypeMap[status] || "default";
+  };
+
+  // 鑾峰彇鐘舵�佹枃鏈�
+  const getStatusText = status => {
+    const statusTextMap = {
+      notStarted: "鏈紑濮�",
+      completed: "宸插畬鎴�",
+      delayed: "宸插欢杩�",
+    };
+    return statusTextMap[status] || status;
+  };
+
+  // 鐩戝惉椤圭洰ID鍙樺寲
+  watch(
+    () => props.projectId,
+    () => {
+      if (props.projectId) {
+        getMilestoneList();
+      }
+    }
+  );
+
+  // 鍒濆鍖�
+  onMounted(() => {
+    if (props.projectId) {
+      getMilestoneList();
+    }
+  });
 </script>
 
 <style scoped>
-.milestone-list-container {
-  padding: 10px 0;
-}
+  .milestone-list-container {
+    padding: 10px 0;
+  }
 
-.card-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
 
-.milestone-actions {
-  display: flex;
-  gap: 10px;
-}
+  .milestone-actions {
+    display: flex;
+    gap: 10px;
+  }
 
-.milestone-content {
-  padding: 10px 0;
-}
+  .milestone-content {
+    padding: 10px 0;
+  }
 
-.milestone-status {
-  margin-top: 10px;
-}
+  .milestone-status {
+    margin-top: 10px;
+  }
 
-.empty-tip {
-  margin-top: 40px;
-  text-align: center;
-}
+  .empty-tip {
+    margin-top: 40px;
+    text-align: center;
+  }
 
-.dialog-footer {
-  display: flex;
-  justify-content: flex-end;
-  gap: 10px;
-}
+  .dialog-footer {
+    display: flex;
+    justify-content: flex-end;
+    gap: 10px;
+  }
 </style>

--
Gitblit v1.9.3