From bd7d4f9e1c7e09723d9eb35be324545d66718b2a Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期一, 11 五月 2026 16:46:56 +0800
Subject: [PATCH] 清除OA模块

---
 /dev/null |  565 --------------------------------------------------------
 1 files changed, 0 insertions(+), 565 deletions(-)

diff --git a/src/api/oaSystem/projectManagement.js b/src/api/oaSystem/projectManagement.js
deleted file mode 100644
index 56c9287..0000000
--- a/src/api/oaSystem/projectManagement.js
+++ /dev/null
@@ -1,154 +0,0 @@
-import request from "@/utils/request";
-import { parseStrEmpty } from "@/utils/ruoyi";
-
-// 鏌ヨ椤圭洰鍒楄〃
-export function listProject(query) {
-  return request({
-    url: "/oA/project/listPage",
-    method: "get",
-    params: query
-  });
-}
-
-// 鏌ヨ椤圭洰鍒楄〃璇︾粏
-export function getProject(query) {
-  return request({
-    url: "oA/project/getList",
-    method: "get"
-  });
-}
-
-// 鏂板椤圭洰
-export function addProject(data) {
-  return request({
-    url: "/oA/project/add",
-    method: "post",
-    data: data
-  });
-}
-
-// 淇敼椤圭洰
-export function updateProject(data) {
-  return request({
-    url: "/oA/project/update",
-    method: "post",
-    data: data
-  });
-}
-
-// 鍒犻櫎椤圭洰
-export function delProject(projectId) {
-  return request({
-    url: "/oA/project/delete/" + projectId,
-    method: "delete"
-  });
-}
-// 瀵煎嚭椤圭洰
-export function exportProject(data) {
-  return request({
-    url: "/oA/project/export",
-    method: "post",
-    data: data
-  });
-}
-// // 鎵归噺鍒犻櫎椤圭洰
-// export function delProjectBatch(projectIds) {
-//   return request({
-//     url: "/oaSystem/project/batch",
-//     method: "delete",
-//     data: projectIds
-//   });
-// }
-
-// 鏍规嵁椤圭洰闃舵id鏌ヨ椤圭洰闃舵浠诲姟鍒楄〃
-export function listProjectTask(phaseId) {
-  return request({
-    url: "/oA/projectPhaseTask/listByPhaseId/"+ phaseId,
-    method: "get"
-  });
-}
-
-// // 鏌ヨ椤圭洰浠诲姟璇︾粏
-// export function getProjectTask(taskId) {
-//   return request({
-//     url: "/oaSystem/project/task/" + taskId,
-//     method: "get"
-//   });
-// }
-
-// 鏂板椤圭洰闃舵浠诲姟
-export function addProjectTask(data) {
-  return request({
-    url: "/oA/projectPhaseTask/add",
-    method: "post",
-    data: data
-  });
-}
-
-// 淇敼椤圭洰闃舵浠诲姟
-export function updateProjectTask(data) {
-  return request({
-    url: "/oA/projectPhaseTask/update",
-    method: "post",
-    data: data
-  });
-}
-
-// 鍒犻櫎椤圭洰闃舵浠诲姟
-export function delProjectTask(taskId) {
-  return request({
-    url: "/oA/projectPhaseTask/delete/" + taskId,
-    method: "delete"
-  });
-}
-
-// 椤圭洰id鏌ヨ椤圭洰闃舵鍒楄〃
-export function listProjectPhase(projectId) {
-  return request({
-    url: "/oA/projectPhase/listByProjectId/" + projectId,
-    method: "get"
-  });
-}
-// 鏂板椤圭洰闃舵
-export function addProjectPhase(data) {
-  return request({
-    url: "/oA/projectPhase/add",
-    method: "post",
-    data: data
-  });
-}
-
-// 淇敼椤圭洰闃舵
-export function updateProjectPhase(data) {
-  return request({
-    url: "/oA/projectPhase/update",
-    method: "post",
-    data: data
-  });
-
-}
-// 鍒犻櫎椤圭洰闃舵
-export function delProjectPhase(phaseId) {
-  return request({
-    url: "/oA/projectPhase/delete/" + phaseId,
-    method: "delete"
-  })
-}
-//
-
-// // 鏌ヨ椤圭洰閲岀▼纰戝垪琛�
-// export function listProjectMilestone(query) {
-//   return request({
-//     url: "/oaSystem/project/milestone/list",
-//     method: "get",
-//     params: query
-//   });
-// }
-
-// // 椤圭洰缁熻淇℃伅
-// export function getProjectStatistics() {
-//   return request({
-//     url: "/oaSystem/project/statistics",
-//     method: "get"
-//   });
-// }
\ No newline at end of file
diff --git a/src/views/oaSystem/projectManagement/components/milestoneList.vue b/src/views/oaSystem/projectManagement/components/milestoneList.vue
deleted file mode 100644
index ed31772..0000000
--- a/src/views/oaSystem/projectManagement/components/milestoneList.vue
+++ /dev/null
@@ -1,289 +0,0 @@
-// ... existing code ...
-<template>
-  <div class="milestone-list-container">
-    <el-timeline>
-      <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>
-              </div>
-            </div>
-          </template>
-          <div class="milestone-content">
-            <p>{{ milestone.description }}</p>
-            <div class="milestone-status">
-              <el-tag :type="getStatusType(milestone.status)">{{ getStatusText(milestone.status) }}</el-tag>
-            </div>
-          </div>
-        </el-card>
-      </el-timeline-item>
-    </el-timeline>
-    
-    <!-- 鏃犻噷绋嬬鏃剁殑鎻愮ず -->
-    <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-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-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>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
-</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';
-
-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
-  });
-  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 handleDelete = (milestone) => {
-  ElMessageBox.confirm(
-    `纭畾瑕佸垹闄ら噷绋嬬 "${milestone.phaseName}" 鍚楋紵鍒犻櫎鍚庡皢鏃犳硶鎭㈠銆俙,
-    '鍒犻櫎纭',
-    {
-      confirmButtonText: '纭畾',
-      cancelButtonText: '鍙栨秷',
-      type: 'warning'
-    }
-  )
-    .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 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;
-}
-
-.card-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.milestone-actions {
-  display: flex;
-  gap: 10px;
-}
-
-.milestone-content {
-  padding: 10px 0;
-}
-
-.milestone-status {
-  margin-top: 10px;
-}
-
-.empty-tip {
-  margin-top: 40px;
-  text-align: center;
-}
-
-.dialog-footer {
-  display: flex;
-  justify-content: flex-end;
-  gap: 10px;
-}
-</style>
diff --git a/src/views/oaSystem/projectManagement/components/phaseGoalList.vue b/src/views/oaSystem/projectManagement/components/phaseGoalList.vue
deleted file mode 100644
index 5054299..0000000
--- a/src/views/oaSystem/projectManagement/components/phaseGoalList.vue
+++ /dev/null
@@ -1,165 +0,0 @@
-
-<template>
-  <div class="phase-goal-list-container">
-    <el-table
-      v-loading="loading"
-      :data="phaseGoalList"
-      style="width: 100%"
-    >
-      <el-table-column prop="phaseName" label="鎵�灞為樁娈�" width="180" />
-      <el-table-column prop="taskName" label="鐩爣鍚嶇О" min-width="200" />
-      <el-table-column prop="targetValue" label="鐩爣鍊�" width="120" />
-      <el-table-column prop="currentValue" label="褰撳墠鍊�" width="120" />
-      <el-table-column prop="unit" label="鍗曚綅" width="80" />
-      <el-table-column prop="targetDate" label="鐩爣鏃ユ湡" width="120" />
-      <el-table-column prop="status" label="鐘舵��" width="100">
-        <template #default="scope">
-          <el-tag :type="getStatusType(scope.row.status)">{{ getStatusText(scope.row.status) }}</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column prop="completionRate" label="瀹屾垚搴�" width="120">
-        <template #default="scope">
-          <el-progress :percentage="scope.row.completionRate" :stroke-width="6" />
-        </template>
-      </el-table-column>
-      <el-table-column label="鎿嶄綔" width="150" fixed="right">
-        <template #default="scope">
-          <el-button type="text" size="small" @click="handleEdit(scope.row)">缂栬緫</el-button>
-          <el-button type="text" size="small" @click="handleDelete(scope.row)" danger>鍒犻櫎</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    
-    <!-- 鏃犻樁娈电洰鏍囨椂鐨勬彁绀� -->
-    <div v-if="!loading && phaseGoalList.length === 0" class="empty-tip">
-      <el-empty description="鏆傛棤闃舵鐩爣鏁版嵁" />
-    </div>
-  </div>
-</template>
-
-<script setup>
-import { ref, onMounted, watch } from 'vue';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import { listProjectPhase, updateProjectTask, delProjectTask } from '@/api/oaSystem/projectManagement';
-
-const props = defineProps({
-  projectId: {
-    type: String,
-    required: true
-  }
-});
-
-const emit = defineEmits(['refresh']);
-
-const phaseGoalList = ref([]);
-const loading = ref(true);
-
-// 鑾峰彇闃舵鐩爣鍒楄〃
-const getPhaseGoalList = async () => {
-  loading.value = true;
-  try {
-    const { data } = await listProjectPhase(props.projectId);
-    // 鍋囪phase鏁版嵁涓寘鍚簡鐩爣淇℃伅
-    // 杩欓噷绠�鍖栧鐞嗭紝瀹為檯搴旇璋冪敤涓撻棬鐨勮幏鍙栭樁娈电洰鏍囩殑API
-    const phases = data.rows || data;
-    phaseGoalList.value = [];
-    
-    phases.forEach(phase => {
-      if (phase.oaProjectPhaseTasks && phase.oaProjectPhaseTasks.length > 0) {
-        phase.oaProjectPhaseTasks.forEach(goal => {
-          phaseGoalList.value.push({
-            ...goal,
-            phaseName: phase.phaseName
-          });
-        });
-      }
-    });
-  } catch (error) {
-    ElMessage.error('鑾峰彇闃舵鐩爣鍒楄〃澶辫触');
-    console.error('鑾峰彇闃舵鐩爣鍒楄〃澶辫触:', error);
-  } finally {
-    loading.value = false;
-  }
-};
-
-// 缂栬緫闃舵鐩爣
-const handleEdit = (goal) => {
-  // 瑙﹀彂鐖剁粍浠剁殑缂栬緫浜嬩欢锛屼紶閫掔洰鏍囨暟鎹�
-  emit('editGoal', goal);
-};
-
-// 鍒犻櫎闃舵鐩爣
-const handleDelete = async (goal) => {
-  try {
-    await ElMessageBox.confirm(
-      `纭畾瑕佸垹闄ょ洰鏍囥��${goal.taskName}銆嶅悧锛焋,
-      '纭鍒犻櫎',
-      {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      }
-    );
-    
-    // 璋冪敤鍒犻櫎API
-    await delProjectTask(goal.taskId);
-    ElMessage.success('鍒犻櫎闃舵鐩爣鎴愬姛');
-    
-    // 鍒锋柊鍒楄〃
-    getPhaseGoalList();
-    emit('refresh');
-  } catch (error) {
-    if (error !== 'cancel') {
-      ElMessage.error('鍒犻櫎闃舵鐩爣澶辫触');
-      console.error('鍒犻櫎闃舵鐩爣澶辫触:', error);
-    }
-  }
-};
-
-// 鑾峰彇鐘舵�佹爣绛剧被鍨�
-const getStatusType = (status) => {
-  const statusTypeMap = {
-    notStarted: 'info',
-    inProgress: 'primary',
-    completed: 'success',
-    delayed: 'danger'
-  };
-  return statusTypeMap[status] || 'default';
-};
-
-// 鑾峰彇鐘舵�佹枃鏈�
-const getStatusText = (status) => {
-  const statusTextMap = {
-    notStarted: '鏈紑濮�',
-    inProgress: '杩涜涓�',
-    completed: '宸插畬鎴�',
-    delayed: '宸插欢杩�'
-  };
-  return statusTextMap[status] || status;
-};
-
-// 鐩戝惉椤圭洰ID鍙樺寲
-watch(() => props.projectId, () => {
-  if (props.projectId) {
-    getPhaseGoalList();
-  }
-});
-
-// 鍒濆鍖�
-onMounted(() => {
-  if (props.projectId) {
-    getPhaseGoalList();
-  }
-});
-</script>
-
-<style scoped>
-.phase-goal-list-container {
-  padding: 10px 0;
-}
-
-.empty-tip {
-  margin-top: 40px;
-  text-align: center;
-}
-</style>
diff --git a/src/views/oaSystem/projectManagement/components/projectForm.vue b/src/views/oaSystem/projectManagement/components/projectForm.vue
deleted file mode 100644
index 50b671c..0000000
--- a/src/views/oaSystem/projectManagement/components/projectForm.vue
+++ /dev/null
@@ -1,221 +0,0 @@
-<template>
-  <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
-    <el-form-item label="椤圭洰鍚嶇О" prop="projectName">
-      <el-input
-        v-model="form.projectName"
-        placeholder="璇疯緭鍏ラ」鐩悕绉�"
-        maxlength="50"
-      />
-    </el-form-item>
-    <el-form-item label="椤圭洰鎻忚堪" prop="description">
-      <el-input
-        v-model="form.description"
-        type="textarea"
-        :rows="4"
-        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="managerId">
-      <!-- <el-input
-        v-model="form.managerName"
-        placeholder="璇烽�夋嫨椤圭洰璐熻矗浜�"
-        readonly
-        @focus="showUserSelect = true"
-      /> -->
-      <!-- <el-input
-        v-model="userSearchKey"
-        placeholder="鎼滅储鐢ㄦ埛"
-        v-if="showUserSelect"
-        @keyup.enter="searchUsers"
-        style="margin-top: 10px"
-      /> -->
-      <el-select
-        v-model="form.managerId"
-        style="width: 100%; margin-top: 10px"
-        @change="selectUser"
-        filterable
-        remote
-        :remote-method="searchUsers"
-        :loading="userLoading"
-        placeholder="閫夋嫨椤圭洰璐熻矗浜�"
-      >
-        <el-option
-          v-for="user in userList"
-          :key="user.userId"
-          :label="user.nickName"
-          :value="user.userId"
-        />
-      </el-select>
-    </el-form-item>
-    <el-form-item label="椤圭洰瀹屾垚搴�" prop="completionRate">
-      <el-slider v-model="form.completionRate" :max="100" />
-    </el-form-item>
-    <el-form-item label="椤圭洰鐘舵��" prop="status">
-      <el-radio-group v-model="form.status">
-        <el-radio label="planning">瑙勫垝涓�</el-radio>
-        <el-radio label="inProgress">杩涜涓�</el-radio>
-        <el-radio label="completed">宸插畬鎴�</el-radio>
-        <el-radio label="paused">宸叉殏鍋�</el-radio>
-      </el-radio-group>
-    </el-form-item>
-  </el-form>
-</template>
-
-<script setup>
-import { ref, watch, defineExpose } from 'vue';
-import { listUser } from '@/api/system/user';
-import { ElMessage } from 'element-plus';
-const props = defineProps({
-  form: {
-    type: Object,
-    required: true
-  },
-  rules: {
-    type: Object,
-    required: true
-  },
-  visible: {
-    type: Boolean,
-    required: true
-  }
-});
-
-const formRef = ref();
-const showUserSelect = ref(false);
-const userSearchKey = ref('');
-const userList = ref([]);
-const userLoading = ref(false);
-// 妯℃嫙鐢ㄦ埛鏁版嵁
-const mockUserData = [
-  { userId: '1', nickName: '寮犱笁', userName: 'zhangsan' },
-  { userId: '2', nickName: '鏉庡洓', userName: 'lisi' },
-  { userId: '3', nickName: '鐜嬩簲', userName: 'wangwu' },
-  { userId: '4', nickName: '璧靛叚', userName: 'zhaoliu' },
-  { userId: '5', nickName: '閽变竷', userName: 'qianqi' },
-  { userId: '6', nickName: '瀛欏叓', userName: 'sunba' },
-  { userId: '7', nickName: '鍛ㄤ節', userName: 'zhoujiu' },
-  { userId: '8', nickName: '鍚村崄', userName: 'wushi' }
-];
-// 鎼滅储鐢ㄦ埛
-const searchUsers = async (query) => {
-  userLoading.value = true;
-  try {
-    // 妯℃嫙缃戠粶寤惰繜
-    await new Promise(resolve => setTimeout(resolve, 300));
-    
-    // 姝g‘璁剧疆鐢ㄦ埛鍒楄〃
-    if (!query) {
-      userList.value = [...mockUserData];
-    } else {
-      userList.value = mockUserData.filter(user => 
-        user.nickName.includes(query) || user.userName.includes(query)
-      );
-    }
-  } catch (error) {
-    console.error('鎼滅储鐢ㄦ埛澶辫触:', error);
-  } finally {
-    userLoading.value = false;
-  }
-};
-
-// 閫夋嫨鐢ㄦ埛
-const selectUser = (userId) => {
-    // 鍏堜粠userList鏌ユ壘锛屽鏋滄壘涓嶅埌鍐嶄粠mockUserData涓煡鎵�
-  let selectedUser = userList.value.find(user => user.userId === userId);
-  if (!selectedUser) {
-    selectedUser = mockUserData.find(user => user.userId === userId);
-  }
-
-    // 浣跨敤Vue.set纭繚鍝嶅簲寮忔洿鏂�
-  if (selectedUser) {
-    Object.assign(props.form, { managerName: selectedUser.nickName });
-  } else {
-    Object.assign(props.form, { managerName: '' });
-  }
-  showUserSelect.value = false;
-};
-
-// 閲嶇疆琛ㄥ崟
-const resetFields = () => {
-  if (formRef.value) {
-    formRef.value.resetFields();
-  }
-  showUserSelect.value = false;
-  userSearchKey.value = '';
-  userList.value = [];
-};
-
-// 楠岃瘉琛ㄥ崟
-const validate = () => {
-  return new Promise((resolve, reject) => {
-    if (formRef.value) {
-      formRef.value.validate((valid) => {
-        if (valid) {
-          // 棰濆楠岃瘉锛氱粨鏉熸棩鏈熶笉鑳芥棭浜庡紑濮嬫棩鏈�
-          if (props.form.startDate && props.form.endDate) {
-            const startDate = new Date(props.form.startDate);
-            const endDate = new Date(props.form.endDate);
-            if (endDate < startDate) {
-              ElMessage.error('缁撴潫鏃ユ湡涓嶈兘鏃╀簬寮�濮嬫棩鏈�');
-              reject(new Error('鏃ユ湡楠岃瘉澶辫触'));
-              return;
-            }
-          }
-          resolve();
-        } else {
-          reject(new Error('琛ㄥ崟楠岃瘉澶辫触'));
-        }
-      });
-    } else {
-      resolve();
-    }
-  });
-};
-
-// 鐩戝惉瀵硅瘽妗嗘樉绀虹姸鎬�
-watch(() => props.visible, (newVisible) => {
-  if (!newVisible) {
-    resetFields();
-    // 寤惰繜閲嶇疆锛岀‘淇濇暟鎹凡缁忔彁浜ゅ埌鍚庣
-    // setTimeout(() => {
-    //   resetFields();
-    // }, 300);
-  }
-});
-
-// 鏆撮湶鏂规硶
-defineExpose({
-  resetFields,
-  validate
-});
-</script>
-
-<style scoped>
-
-</style>
\ No newline at end of file
diff --git a/src/views/oaSystem/projectManagement/components/taskTree.vue b/src/views/oaSystem/projectManagement/components/taskTree.vue
deleted file mode 100644
index 03a1a15..0000000
--- a/src/views/oaSystem/projectManagement/components/taskTree.vue
+++ /dev/null
@@ -1,834 +0,0 @@
-<template>
-  <div class="task-tree-container">
-    <!-- 浠诲姟鏍戞搷浣滄寜閽� -->
-    <div class="tree-actions mb10">
-      <el-button type="primary" size="small" icon="Plus" @click="handleAddTask">娣诲姞浠诲姟</el-button>
-      <el-button type="success" size="small" icon="RefreshRight" @click="refreshTree">鍒锋柊</el-button>
-      <el-button type="info" size="small" icon="Filter" @click="toggleFilter">
-        {{ showFilter ? '闅愯棌绛涢��' : '鏄剧ず绛涢��' }}
-      </el-button>
-    </div>
-
-    <!-- 绛涢�夋潯浠� -->
-    <div v-if="showFilter" class="filter-section mb10">
-      <el-form :inline="true" :model="filterParams">
-        <el-form-item label="浠诲姟鐘舵��">
-          <el-select v-model="filterParams.status" placeholder="鍏ㄩ儴" clearable style="width: 120px">
-            <el-option label="鏈紑濮�" value="notStarted" />
-            <el-option label="杩涜涓�" value="inProgress" />
-            <el-option label="宸插畬鎴�" value="completed" />
-            <el-option label="宸查�炬湡" value="overdue" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="璐熻矗浜�">
-          <el-input v-model="filterParams.assignee" placeholder="杈撳叆璐熻矗浜�" clearable style="width: 150px" />
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" size="small" @click="filterTree">绛涢��</el-button>
-          <el-button size="small" @click="resetFilter">閲嶇疆</el-button>
-        </el-form-item>
-      </el-form>
-    </div>
-
-    <!-- 浠诲姟鏍� -->
-    <div class="tree-content">
-      <el-tree
-        v-loading="loading"
-        :data="taskTreeData"
-        :props="defaultProps"
-        :expand-on-click-node="false"
-        node-key="nodeId"
-        ref="treeRef"
-        @node-contextmenu="handleContextMenu"
-        @node-click="handleNodeClick"
-      >
-        <template #default="{ node, data }">
-          <!-- 鑺傜偣鍐呭 -->
-          <div class="tree-node-content" :class="{ 'phase-node': data.type === 'phase', 'task-node': data.type === 'task' }">
-            <!-- 鑺傜偣鍥炬爣 -->
-            <div class="node-icon">
-              <i v-if="data.type === 'phase'" class="el-icon-folder text-primary" />
-              <i v-else-if="data.status === 'completed'" class="el-icon-circle-check text-success" />
-              <i v-else-if="data.status === 'inProgress'" class="el-icon-circle-check text-primary" />
-              <i v-else-if="data.status === 'overdue'" class="el-icon-alarm-clock text-danger" />
-              <i v-else class="el-icon-circle-close text-gray-400" />
-            </div>
-
-            <!-- 鑺傜偣鏍囬鍜屾弿杩� -->
-            <div class="node-info">
-              <div class="node-title" :class="{ 'overdue-title': data.type === 'task' && data.status === 'overdue' }">
-                {{ node.label }}
-                <span v-if="data.type === 'task' && data.priority === 'high'" class="priority-tag">楂樹紭</span>
-                <span v-else-if="data.type === 'task' && data.priority === 'medium'" class="priority-tag medium">涓紭</span>
-              </div>
-              <div v-if="data.description" class="node-description">{{ data.description }}</div>
-              
-              <!-- 浠诲姟鍏冧俊鎭� -->
-              <div v-if="data.type === 'task'" class="task-meta">
-                <span class="meta-item">
-                  <i class="el-icon-user"></i>
-                  {{ data.assigneeName || '鏈垎閰�' }}
-                </span>
-                <span class="meta-item">
-                  <i class="el-icon-calendar"></i>
-                  {{ formatDateRange(data.startDate, data.endDate) }}
-                </span>
-              </div>
-            </div>
-
-            <!-- 浠诲姟杩涘害鏉� -->
-            <div v-if="data.type === 'task'" class="task-progress">
-              <el-progress :percentage="data.progress || 0" :stroke-width="4" :show-text="false" />
-            </div>
-
-            <!-- 鎿嶄綔鎸夐挳 -->
-            <div class="node-actions">
-              <el-button
-                v-if="data.type === 'task'"
-                type="text"
-                size="small"
-                icon="Edit"
-                @click.stop="handleEditTask(data)"
-                v-hasPermi="['oaSystem:task:edit']"
-              />
-              <el-button
-                v-if="data.type === 'phase'"
-                type="text"
-                size="small"
-                icon="Plus"
-                @click.stop="handleAddTaskUnderPhase(data)"
-                v-hasPermi="['oaSystem:task:add']"
-              />
-              <el-button
-                type="text"
-                size="small"
-                icon="Delete"
-                @click.stop="handleDeleteNode(data)"
-                v-hasPermi="['oaSystem:task:remove']"
-              />
-            </div>
-          </div>
-        </template>
-      </el-tree>
-    </div>
-
-    <!-- 鍙抽敭鑿滃崟 -->
-    <div v-if="showContextMenu" :style="contextMenuStyle" class="context-menu">
-      <el-menu @select="handleContextMenuSelect">
-        <el-menu-item v-if="selectedNode.type === 'task'" index="edit">缂栬緫浠诲姟</el-menu-item>
-        <el-menu-item v-if="selectedNode.type === 'phase'" index="addTask">娣诲姞瀛愪换鍔�</el-menu-item>
-        <el-menu-item index="delete">鍒犻櫎</el-menu-item>
-        <el-menu-item index="expandAll">灞曞紑鍏ㄩ儴</el-menu-item>
-        <el-menu-item index="collapseAll">鏀惰捣鍏ㄩ儴</el-menu-item>
-      </el-menu>
-    </div>
-
-    <!-- 浠诲姟琛ㄥ崟瀵硅瘽妗� -->
-    <el-dialog :title="dialogTitle" v-model="dialogOpen" width="600px" append-to-body>
-      <el-form ref="taskFormRef" :model="taskForm" :rules="taskRules" label-width="80px">
-        <el-form-item label="浠诲姟鍚嶇О" prop="taskName">
-          <el-input v-model="taskForm.taskName" placeholder="璇疯緭鍏ヤ换鍔″悕绉�" />
-        </el-form-item>
-        <el-form-item label="璐熻矗浜�" prop="assigneeId">
-          <el-input v-model="taskForm.assigneeId" placeholder="璇疯緭鍏ヨ礋璐d汉ID" />
-        </el-form-item>
-        <el-form-item label="寮�濮嬫棩鏈�" prop="startDate">
-          <el-date-picker
-            v-model="taskForm.startDate"
-            type="date"
-            placeholder="閫夋嫨寮�濮嬫棩鏈�"
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="缁撴潫鏃ユ湡" prop="endDate">
-          <el-date-picker
-            v-model="taskForm.endDate"
-            type="date"
-            placeholder="閫夋嫨缁撴潫鏃ユ湡"
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="浼樺厛绾�" prop="priority">
-          <el-select v-model="taskForm.priority" placeholder="閫夋嫨浼樺厛绾�">
-            <el-option label="浣�" value="low" />
-            <el-option label="涓�" value="medium" />
-            <el-option label="楂�" value="high" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="杩涘害" prop="progress">
-          <el-input-number v-model="taskForm.progress" :min="0" :max="100" style="width: 100%" />
-        </el-form-item>
-        <el-form-item label="鎻忚堪" prop="description">
-          <el-input v-model="taskForm.description" type="textarea" placeholder="璇疯緭鍏ヤ换鍔℃弿杩�" />
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitTaskForm">纭畾</el-button>
-          <el-button @click="dialogOpen = false">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup>
-import { ref, reactive, computed, watch, onMounted } from 'vue';
-import { ElMessage, ElMessageBox, ElMenu, ElMenuItem } from 'element-plus';
-// import { getProject, addTask, updateTask, deleteTask, deletePhase } from '@/api/oaSystem/projectManagement';
-
-const props = defineProps({
-  projectId: {
-    type: String,
-    required: true
-  }
-});
-
-const emit = defineEmits(['refresh']);
-
-// 缁勪欢鐘舵��
-const loading = ref(false);
-const treeRef = ref();
-const showContextMenu = ref(false);
-const contextMenuStyle = ref({});
-const selectedNode = ref({});
-const showFilter = ref(false);
-const dialogOpen = ref(false);
-const dialogTitle = ref('');
-const taskFormRef = ref();
-
-// 绛涢�夊弬鏁�
-const filterParams = reactive({
-  status: '',
-  assignee: ''
-});
-
-// 浠诲姟琛ㄥ崟鏁版嵁
-const taskForm = reactive({
-  taskId: undefined,
-  taskName: '',
-  description: '',
-  startDate: '',
-  endDate: '',
-  assigneeId: '',
-  assigneeName: '',
-  status: 'notStarted',
-  progress: 0,
-  priority: 'medium',
-  phaseId: '',
-  projectId: props.projectId
-});
-
-// 琛ㄥ崟楠岃瘉瑙勫垯
-const taskRules = {
-  taskName: [
-    { required: true, message: '浠诲姟鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' },
-    { min: 2, max: 50, message: '浠诲姟鍚嶇О闀垮害鍦� 2 鍒� 50 涓瓧绗�', trigger: 'blur' }
-  ],
-  startDate: [
-    { required: true, message: '寮�濮嬫棩鏈熶笉鑳戒负绌�', trigger: 'change' }
-  ],
-  endDate: [
-    { required: true, message: '缁撴潫鏃ユ湡涓嶈兘涓虹┖', trigger: 'change' }
-  ],
-  assigneeId: [
-    { required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }
-  ],
-  progress: [
-    { required: true, message: '杩涘害涓嶈兘涓虹┖', trigger: 'blur' },
-    { type: 'number', min: 0, max: 100, message: '杩涘害蹇呴』鍦� 0 鍒� 100 涔嬮棿', trigger: 'blur' }
-  ]
-};
-
-// 浠诲姟鏍戞暟鎹�
-const rawTaskTreeData = ref([]);
-
-// 妯℃嫙浠诲姟鏁版嵁
-const mockTaskData = {
-  'PRJ2023001': [
-    {
-      phaseId: 'PHASE001',
-      phaseName: '闇�姹傚垎鏋�',
-      startDate: '2023-11-01',
-      endDate: '2023-11-15',
-      status: 'completed',
-      tasks: [
-        {
-          taskId: 'TASK001',
-          taskName: '闇�姹傝皟鐮�',
-          description: '璋冪爺鐢ㄦ埛闇�姹傚拰涓氬姟娴佺▼',
-          startDate: '2023-11-01',
-          endDate: '2023-11-05',
-          assigneeId: 'USER001',
-          assigneeName: '寮犱笁',
-          status: 'completed',
-          progress: 100,
-          priority: 'medium'
-        },
-        {
-          taskId: 'TASK002',
-          taskName: '闇�姹傛枃妗g紪鍐�',
-          description: '缂栧啓璇︾粏鐨勯渶姹傝鏍艰鏄庝功',
-          startDate: '2023-11-06',
-          endDate: '2023-11-15',
-          assigneeId: 'USER002',
-          assigneeName: '鏉庡洓',
-          status: 'completed',
-          progress: 100,
-          priority: 'high'
-        }
-      ]
-    },
-    {
-      phaseId: 'PHASE002',
-      phaseName: '绯荤粺璁捐',
-      startDate: '2023-11-16',
-      endDate: '2023-12-10',
-      status: 'completed',
-      tasks: [
-        {
-          taskId: 'TASK003',
-          taskName: '绯荤粺鏋舵瀯璁捐',
-          description: '璁捐绯荤粺鏁翠綋鏋舵瀯',
-          startDate: '2023-11-16',
-          endDate: '2023-11-25',
-          assigneeId: 'USER003',
-          assigneeName: '鐜嬩簲',
-          status: 'completed',
-          progress: 100,
-          priority: 'high'
-        },
-        {
-          taskId: 'TASK004',
-          taskName: '鏁版嵁搴撹璁�',
-          description: '璁捐鏁版嵁搴撹〃缁撴瀯鍜屽叧绯�',
-          startDate: '2023-11-26',
-          endDate: '2023-12-10',
-          assigneeId: 'USER004',
-          assigneeName: '璧靛叚',
-          status: 'completed',
-          progress: 100,
-          priority: 'medium'
-        }
-      ]
-    },
-    {
-      phaseId: 'PHASE003',
-      phaseName: '寮�鍙戝疄鐜�',
-      startDate: '2023-12-11',
-      endDate: '2024-01-31',
-      status: 'inProgress',
-      tasks: [
-        {
-          taskId: 'TASK005',
-          taskName: '鍓嶇寮�鍙�',
-          description: '寮�鍙戠敤鎴风晫闈㈠拰浜や簰閫昏緫',
-          startDate: '2023-12-11',
-          endDate: '2024-01-15',
-          assigneeId: 'USER005',
-          assigneeName: '閽变竷',
-          status: 'inProgress',
-          progress: 70,
-          priority: 'high'
-        },
-        {
-          taskId: 'TASK006',
-          taskName: '鍚庣寮�鍙�',
-          description: '寮�鍙戜笟鍔¢�昏緫鍜孉PI鎺ュ彛',
-          startDate: '2023-12-11',
-          endDate: '2024-01-20',
-          assigneeId: 'USER006',
-          assigneeName: '瀛欏叓',
-          status: 'inProgress',
-          progress: 60,
-          priority: 'high'
-        }
-      ]
-    }
-  ],
-  // 榛樿鏁版嵁
-  default: [
-    {
-      phaseId: 'PHASE_DEFAULT1',
-      phaseName: '鍑嗗闃舵',
-      startDate: '2023-01-01',
-      endDate: '2023-03-31',
-      status: 'completed',
-      tasks: [
-        {
-          taskId: 'TASK_DEFAULT1',
-          taskName: '椤圭洰鍚姩',
-          description: '鍙紑椤圭洰鍚姩浼氳',
-          startDate: '2023-01-01',
-          endDate: '2023-01-05',
-          assigneeId: 'USER_DEFAULT1',
-          assigneeName: '璐熻矗浜篈',
-          status: 'completed',
-          progress: 100,
-          priority: 'high'
-        }
-      ]
-    },
-    {
-      phaseId: 'PHASE_DEFAULT2',
-      phaseName: '鎵ц闃舵',
-      startDate: '2023-04-01',
-      endDate: '2023-09-30',
-      status: 'inProgress',
-      tasks: [
-        {
-          taskId: 'TASK_DEFAULT2',
-          taskName: '鏍稿績鍔熻兘寮�鍙�',
-          description: '寮�鍙戠郴缁熸牳蹇冨姛鑳芥ā鍧�',
-          startDate: '2023-04-01',
-          endDate: '2023-06-30',
-          assigneeId: 'USER_DEFAULT2',
-          assigneeName: '璐熻矗浜築',
-          status: 'inProgress',
-          progress: 50,
-          priority: 'high'
-        }
-      ]
-    }
-  ]
-};
-
-const taskTreeData = computed(() => {
-  // 搴旂敤绛涢�夋潯浠�
-  if (!showFilter.value || (!filterParams.status && !filterParams.assignee)) {
-    return rawTaskTreeData.value;
-  }
-
-  // 娣辨嫹璐濆師濮嬫暟鎹互閬垮厤淇敼
-  const filteredData = JSON.parse(JSON.stringify(rawTaskTreeData.value));
-  
-  // 閫掑綊绛涢�夎妭鐐�
-  const filterNodes = (nodes) => {
-    const result = [];
-    
-    nodes.forEach(node => {
-      // 瀵逛簬闃舵鑺傜偣锛屾鏌ュ叾瀛愪换鍔℃槸鍚︾鍚堢瓫閫夋潯浠�
-      if (node.type === 'phase' && node.children) {
-        const filteredChildren = filterNodes(node.children);
-        if (filteredChildren.length > 0) {
-          // 淇濈暀鑷冲皯鏈変竴涓瓙浠诲姟绗﹀悎鏉′欢鐨勯樁娈�
-          node.children = filteredChildren;
-          result.push(node);
-        }
-      }
-      // 瀵逛簬浠诲姟鑺傜偣锛岀洿鎺ュ簲鐢ㄧ瓫閫夋潯浠�
-      else if (node.type === 'task') {
-        const statusMatch = !filterParams.status || node.status === filterParams.status;
-        const assigneeMatch = !filterParams.assignee || 
-          (node.assigneeName && node.assigneeName.includes(filterParams.assignee));
-        
-        if (statusMatch && assigneeMatch) {
-          result.push(node);
-        }
-      }
-    });
-    
-    return result;
-  };
-  
-  return filterNodes(filteredData);
-});
-
-// 鏍戣妭鐐归厤缃�
-const defaultProps = {
-  children: 'children',
-  label: (data) => {
-    if (data.type === 'phase') {
-      return `${data.phaseName}`;
-    } else {
-      return `${data.taskName}`;
-    }
-  }
-};
-
-// 鍔犺浇浠诲姟鏍戞暟鎹�
-const loadTaskTree = async () => {
-  loading.value = true;
-  // try {
-  //   const { data } = await getProject(props.projectId);
-  //   rawTaskTreeData.value = buildTaskTree(data.phases || []);
-  // } catch (error) {
-  //   ElMessage.error('鍔犺浇浠诲姟鏍戝け璐�');
-  //   console.error('鍔犺浇浠诲姟鏍戝け璐�:', error);
-  // } finally {
-  //   loading.value = false;
-  // }
-  try {
-    // 妯℃嫙缃戠粶寤惰繜
-    await new Promise(resolve => setTimeout(resolve, 500));
-    
-    // 浣跨敤妯℃嫙鏁版嵁鏇夸唬API璇锋眰
-    const phases = mockTaskData[props.projectId] || mockTaskData.default;
-    rawTaskTreeData.value = buildTaskTree(phases);
-  } catch (error) {
-    ElMessage.error('鍔犺浇浠诲姟鏍戝け璐�');
-    console.error('鍔犺浇浠诲姟鏍戝け璐�:', error);
-  } finally {
-    loading.value = false;
-  }
-};
-
-// 鏋勫缓浠诲姟鏍�
-const buildTaskTree = (phases) => {
-  return phases.map(phase => ({
-    nodeId: phase.phaseId,
-    phaseId: phase.phaseId,
-    phaseName: phase.phaseName,
-    type: 'phase',
-    children: (phase.tasks || []).map(task => ({
-      nodeId: task.taskId,
-      taskId: task.taskId,
-      taskName: task.taskName,
-      description: task.description,
-      startDate: task.startDate,
-      endDate: task.endDate,
-      assigneeId: task.assigneeId,
-      assigneeName: task.assigneeName,
-      status: task.status,
-      progress: task.progress,
-      priority: task.priority,
-      phaseId: task.phaseId,
-      projectId: props.projectId,
-      type: 'task'
-    }))
-  }));
-};
-
-// 鏍煎紡鍖栨棩鏈熻寖鍥�
-const formatDateRange = (startDate, endDate) => {
-  if (!startDate || !endDate) return '';
-  return `${startDate} - ${endDate}`;
-};
-
-// 鍒锋柊鏍�
-const refreshTree = () => {
-  loadTaskTree();
-  // 閫氱煡鐖剁粍浠跺埛鏂版暟鎹�
-  emit('refresh');
-};
-
-// 鍒囨崲绛涢�夐潰鏉�
-const toggleFilter = () => {
-  showFilter.value = !showFilter.value;
-};
-
-// 搴旂敤绛涢��
-const filterTree = () => {
-  // 绛涢�夐�昏緫宸茬粡鍦╟omputed涓疄鐜�
-};
-
-// 閲嶇疆绛涢��
-const resetFilter = () => {
-  filterParams.status = '';
-  filterParams.assignee = '';
-};
-
-// 澶勭悊鑺傜偣鐐瑰嚮
-const handleNodeClick = (data, node) => {
-  // 鍒囨崲灞曞紑/鏀惰捣鐘舵��
-  if (data.type === 'phase') {
-    node.expanded = !node.expanded;
-  }
-};
-
-// 澶勭悊鍙抽敭鑿滃崟
-const handleContextMenu = (event, data) => {
-  event.preventDefault();
-  selectedNode.value = data;
-  contextMenuStyle.value = {
-    position: 'fixed',
-    left: `${event.clientX}px`,
-    top: `${event.clientY}px`,
-    zIndex: 1000
-  };
-  showContextMenu.value = true;
-};
-
-// 澶勭悊鍙抽敭鑿滃崟閫夋嫨
-const handleContextMenuSelect = (index) => {
-  showContextMenu.value = false;
-  switch (index) {
-    case 'edit':
-      if (selectedNode.value.type === 'task') {
-        handleEditTask(selectedNode.value);
-      }
-      break;
-    case 'addTask':
-      if (selectedNode.value.type === 'phase') {
-        handleAddTaskUnderPhase(selectedNode.value);
-      }
-      break;
-    case 'delete':
-      handleDeleteNode(selectedNode.value);
-      break;
-    case 'expandAll':
-      treeRef.value?.expandAll();
-      break;
-    case 'collapseAll':
-      treeRef.value?.collapseAll();
-      break;
-  }
-};
-
-// 娣诲姞浠诲姟
-const handleAddTask = () => {
-  resetTaskForm();
-  dialogTitle.value = '娣诲姞浠诲姟';
-  dialogOpen.value = true;
-};
-
-// 鍦ㄦ寚瀹氶樁娈典笅娣诲姞浠诲姟
-const handleAddTaskUnderPhase = (phase) => {
-  resetTaskForm();
-  taskForm.phaseId = phase.phaseId;
-  dialogTitle.value = '娣诲姞瀛愪换鍔�';
-  dialogOpen.value = true;
-};
-
-// 缂栬緫浠诲姟
-const handleEditTask = (task) => {
-  resetTaskForm();
-  Object.assign(taskForm, { ...task });
-  dialogTitle.value = '缂栬緫浠诲姟';
-  dialogOpen.value = true;
-};
-
-// 鍒犻櫎鑺傜偣
-const handleDeleteNode = async (node) => {
-  const confirmMessage = node.type === 'phase' 
-    ? `纭畾瑕佸垹闄ら樁娈� "${node.phaseName}" 鍙婂叾鎵�鏈夊瓙浠诲姟鍚楋紵` 
-    : `纭畾瑕佸垹闄や换鍔� "${node.taskName}" 鍚楋紵`;
-  
-  await ElMessageBox.confirm(confirmMessage, '纭鎿嶄綔', {
-    confirmButtonText: '纭畾',
-    cancelButtonText: '鍙栨秷',
-    type: 'warning'
-  }).catch(() => {
-    throw new Error('鍙栨秷鍒犻櫎');
-  });
-  
-  try {
-    if (node.type === 'phase') {
-      await deletePhase(node.phaseId);
-    } else {
-      await deleteTask(node.taskId);
-    }
-    ElMessage.success('鍒犻櫎鎴愬姛');
-    refreshTree();
-  } catch (error) {
-    if (error.message !== '鍙栨秷鍒犻櫎') {
-      ElMessage.error('鍒犻櫎澶辫触');
-      console.error('鍒犻櫎澶辫触:', error);
-    }
-  }
-};
-
-// 閲嶇疆浠诲姟琛ㄥ崟
-const resetTaskForm = () => {
-  taskForm.taskId = undefined;
-  taskForm.taskName = '';
-  taskForm.description = '';
-  taskForm.startDate = '';
-  taskForm.endDate = '';
-  taskForm.assigneeId = '';
-  taskForm.assigneeName = '';
-  taskForm.status = 'notStarted';
-  taskForm.progress = 0;
-  taskForm.priority = 'medium';
-  taskForm.phaseId = '';
-  taskForm.projectId = props.projectId;
-  
-  if (taskFormRef.value) {
-    taskFormRef.value.resetFields();
-  }
-};
-
-// 鎻愪氦浠诲姟琛ㄥ崟
-const submitTaskForm = async () => {
-  try {
-    await taskFormRef.value.validate();
-    
-    if (taskForm.taskId) {
-      await updateTask(taskForm);
-      ElMessage.success('淇敼浠诲姟鎴愬姛');
-    } else {
-      await addTask(taskForm);
-      ElMessage.success('娣诲姞浠诲姟鎴愬姛');
-    }
-    
-    dialogOpen.value = false;
-    refreshTree();
-  } catch (error) {
-    console.error('鎻愪氦琛ㄥ崟澶辫触:', error);
-  }
-};
-
-// 鐐瑰嚮鍏朵粬鍖哄煙鍏抽棴鍙抽敭鑿滃崟
-document.addEventListener('click', () => {
-  if (showContextMenu.value) {
-    showContextMenu.value = false;
-  }
-});
-
-// 鐩戝惉椤圭洰ID鍙樺寲
-watch(() => props.projectId, (newProjectId) => {
-  if (newProjectId) {
-    loadTaskTree();
-  }
-});
-
-// 鍒濆鍖�
-onMounted(() => {
-  loadTaskTree();
-});
-</script>
-
-<style scoped>
-.task-tree-container {
-  padding: 10px;
-}
-
-.tree-actions {
-  display: flex;
-  gap: 10px;
-  align-items: center;
-}
-
-.filter-section {
-  background: #f5f7fa;
-  padding: 10px;
-  border-radius: 4px;
-}
-
-.tree-content {
-  background: #fff;
-  border: 1px solid #ebeef5;
-  border-radius: 4px;
-  padding: 10px;
-  max-height: 600px;
-  overflow-y: auto;
-}
-
-.tree-node-content {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  padding: 5px 0;
-  min-height: 40px;
-}
-
-.phase-node {
-  font-weight: bold;
-  color: #409eff;
-}
-
-.task-node {
-  color: #606266;
-}
-
-.node-icon {
-  display: flex;
-  align-items: center;
-  width: 20px;
-}
-
-.node-info {
-  flex: 1;
-  min-width: 0;
-}
-
-.node-title {
-  font-weight: 500;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  margin-bottom: 2px;
-}
-
-.overdue-title {
-  color: #f56c6c;
-  font-weight: bold;
-}
-
-.priority-tag {
-  background: #f56c6c;
-  color: white;
-  font-size: 10px;
-  padding: 1px 4px;
-  border-radius: 2px;
-  margin-left: 5px;
-}
-
-.priority-tag.medium {
-  background: #e6a23c;
-}
-
-.node-description {
-  font-size: 12px;
-  color: #909399;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-.task-meta {
-  display: flex;
-  gap: 15px;
-  font-size: 12px;
-  color: #909399;
-  margin-top: 2px;
-}
-
-.meta-item {
-  display: flex;
-  align-items: center;
-  gap: 3px;
-}
-
-.task-progress {
-  width: 120px;
-  margin: 0 10px;
-}
-
-.node-actions {
-  display: flex;
-  gap: 5px;
-  opacity: 0;
-  transition: opacity 0.3s;
-}
-
-.tree-node-content:hover .node-actions {
-  opacity: 1;
-}
-
-.context-menu {
-  background: white;
-  border: 1px solid #ebeef5;
-  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-  border-radius: 4px;
-}
-
-.context-menu .el-menu {
-  min-width: 120px;
-  border: none;
-}
-
-.context-menu .el-menu-item {
-  padding: 0 15px;
-  height: 36px;
-  line-height: 36px;
-}
-
-.context-menu .el-menu-item:hover {
-  background-color: #f5f7fa;
-}
-
-.text-gray-400 {
-  color: #c0c4cc;
-}
-</style>
\ No newline at end of file
diff --git a/src/views/oaSystem/projectManagement/index.vue b/src/views/oaSystem/projectManagement/index.vue
deleted file mode 100644
index 79fbe7f..0000000
--- a/src/views/oaSystem/projectManagement/index.vue
+++ /dev/null
@@ -1,481 +0,0 @@
-<template>
-  <div class="app-container">
-    <!-- 椤堕儴鎼滅储鍜屾搷浣滄爮 -->
-    <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="80px">
-      <el-form-item label="椤圭洰鍚嶇О" prop="projectName">
-        <el-input
-          v-model="queryParams.projectName"
-          placeholder="璇疯緭鍏ラ」鐩悕绉�"
-          clearable
-          style="width: 240px"
-          @keyup.enter="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="璐熻矗浜�" prop="managerName">
-        <el-input
-          v-model="queryParams.managerName"
-          placeholder="璇疯緭鍏ヨ礋璐d汉濮撳悕"
-          clearable
-          style="width: 240px"
-          @keyup.enter="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="鐘舵��" prop="status">
-        <el-select
-          v-model="queryParams.status"
-          placeholder="椤圭洰鐘舵��"
-          clearable
-          style="width: 150px"
-        >
-          <el-option label="瑙勫垝涓�" value="planning" />
-          <el-option label="杩涜涓�" value="inProgress" />
-          <el-option label="宸插畬鎴�" value="completed" />
-          <el-option label="宸叉殏鍋�" value="paused" />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
-        <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
-      </el-form-item>
-    </el-form>
-
-    <!-- 宸ュ叿鏍� -->
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="Plus"
-          @click="handleAdd"
-          v-hasPermi="['oaSystem:project:add']"
-        >鏂板椤圭洰</el-button>
-      </el-col>
-      <!-- <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="Edit"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['oaSystem:project:edit']"
-        >缂栬緫椤圭洰</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="Delete"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['oaSystem:project:remove']"
-        >鍒犻櫎椤圭洰</el-button>
-      </el-col> -->
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="Download"
-          @click="handleExport"
-          v-hasPermi="['oaSystem:project:export']"
-        >瀵煎嚭椤圭洰</el-button>
-      </el-col>
-    </el-row>
-
-    <!-- 椤圭洰鍒楄〃琛ㄦ牸 -->
-    <el-table
-      v-loading="loading"
-      :data="projectList"
-      @selection-change="handleSelectionChange"
-    >
-      <el-table-column type="selection" width="50" align="center" />
-      <el-table-column
-        label="椤圭洰缂栧彿"
-        align="center"
-        prop="projectId"
-        width="100"
-      />
-      <el-table-column
-        label="椤圭洰鍚嶇О"
-        align="center"
-        prop="projectName"
-        :show-overflow-tooltip="true"
-      />
-      <el-table-column
-        label="璐熻矗浜�"
-        align="center"
-        prop="managerName"
-      />
-      <el-table-column
-        label="寮�濮嬫棩鏈�"
-        align="center"
-        prop="startDate"
-        width="120"
-      />
-      <el-table-column
-        label="缁撴潫鏃ユ湡"
-        align="center"
-        prop="endDate"
-        width="120"
-      />
-      <el-table-column
-        label="鐘舵��"
-        align="center"
-        prop="status"
-        width="90"
-      >
-        <template #default="scope">
-          <el-tag :type="getStatusType(scope.row.status)">{{ getStatusText(scope.row.status) }}</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column
-        label="瀹屾垚搴�"
-        align="center"
-        prop="completionRate"
-        width="100"
-      >
-        <template #default="scope">
-          <el-progress :percentage="scope.row.completionRate" :stroke-width="6" />
-        </template>
-      </el-table-column>
-      <el-table-column
-        label="鎿嶄綔"
-        align="center"
-        width="180"
-        class-name="small-padding fixed-width"
-      >
-        <template #default="scope">
-          <el-button
-            link
-            type="primary"
-            icon="Search"
-            @click="handleView(scope.row)"
-            v-hasPermi="['oaSystem:project:query']"
-          >璇︽儏</el-button>
-          <el-button
-            link
-            type="primary"
-            icon="Edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['oaSystem:project:edit']"
-          >缂栬緫</el-button>
-          <el-button
-            link
-            type="danger"
-            icon="Delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['oaSystem:project:remove']"
-          >鍒犻櫎</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <!-- 鍒嗛〉缁勪欢 -->
-    <pagination
-      v-show="total > 0"
-      :total="total"
-      v-model:page="queryParams.pageNum"
-      v-model:limit="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 椤圭洰琛ㄥ崟瀵硅瘽妗� -->
-    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
-      <project-form
-        ref="projectFormRef"
-        :form="form"
-        :rules="rules"
-        :visible="open"
-      />
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭畾</el-button>
-          <el-button @click="cancel">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup>
-import { ref, reactive, computed, onMounted } from 'vue';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import Pagination from '@/components/Pagination';
-import ProjectForm from './components/projectForm.vue';
-import { useRouter } from 'vue-router';
-const { proxy } = getCurrentInstance();
-// 瀵煎叆椤圭洰绠$悊API鎺ュ彛
-import { listProject, addProject, updateProject, delProject, exportProject } from '@/api/oaSystem/projectManagement';
-// import { listUser } from '@/api/system/user'; // 瀵煎叆鐢ㄦ埛鍒楄〃API鎺ュ彛
-
-// 鍒涘缓router瀹炰緥
-const router = useRouter();
-
-// 琛ㄦ牸鏁版嵁
-const projectList = ref([]);
-const loading = ref(true);
-const total = ref(0);
-const queryParams = reactive({
-  pageNum: 1,
-  pageSize: 10,
-  projectName: '',
-  managerName: '',
-  status: ''
-});
-
-// 琛ㄥ崟鏁版嵁
-const form = reactive({
-  projectId: undefined,
-  projectName: '',
-  description: '',
-  startDate: '',
-  endDate: '',
-  managerId: '',
-  managerName: '',
-  status: 'planning',
-  completionRate: 0
-});
-
-// 琛ㄥ崟鏍¢獙瑙勫垯
-const rules = {
-  projectName: [
-    { required: true, message: '椤圭洰鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' },
-    { min: 2, max: 50, message: '椤圭洰鍚嶇О闀垮害鍦� 2 鍒� 50 涓瓧绗�', trigger: 'blur' }
-  ],
-  startDate: [
-    { required: true, message: '寮�濮嬫棩鏈熶笉鑳戒负绌�', trigger: 'change' }
-  ],
-  endDate: [
-    { required: true, message: '缁撴潫鏃ユ湡涓嶈兘涓虹┖', trigger: 'change' }
-  ],
-  managerId: [
-    { required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }
-  ]
-};
-
-// 瀵硅瘽妗嗙姸鎬�
-const open = ref(false);
-const title = ref('');
-const projectFormRef = ref();
-const queryRef = ref();
-
-// 閫変腑鐘舵��
-const multiple = computed(() => {
-  return selectedRowKeys.value.length === 0;
-});
-const single = computed(() => {
-  return selectedRowKeys.value.length !== 1;
-});
-const selectedRowKeys = ref([]);
-
-// 鑾峰彇椤圭洰鍒楄〃
-const getList = async () => {
-  loading.value = true;
-    try {
-    const { data } = await listProject(queryParams);
-    projectList.value = data.records;
-    total.value = data.total;
-  } catch (error) {
-    ElMessage.error('鑾峰彇椤圭洰鍒楄〃澶辫触');
-    console.error('鑾峰彇椤圭洰鍒楄〃澶辫触:', error);
-  } finally {
-    loading.value = false;
-  }
-};
-
-// 鎼滅储
-const handleQuery = () => {
-  queryParams.pageNum = 1;
-  getList();
-};
-
-// 閲嶇疆
-const resetQuery = () => {
-  if (queryRef.value) {
-    queryRef.value.resetFields();
-  }
-  handleQuery();
-};
-
-// 閫変腑琛屽彉鍖�
-const handleSelectionChange = (selection) => {
-  selectedRowKeys.value = selection.map(item => item.projectId);
-};
-
-// 鏂板椤圭洰 
-const handleAdd = () => {
-  resetForm();
-  open.value = true;
-  title.value = '鏂板椤圭洰';
-};
-
-// 缂栬緫椤圭洰 
-const handleUpdate = async (row) => {
-  resetForm();
-  const projectId = row.projectId || selectedRowKeys.value[0];
-    try {
-    // const { data } = await getProject(projectId);
-    Object.assign(form, row);
-    open.value = true;
-    title.value = '缂栬緫椤圭洰';
-  } catch (error) {
-    ElMessage.error('鑾峰彇椤圭洰璇︽儏澶辫触');
-    console.error('鑾峰彇椤圭洰璇︽儏澶辫触:', error);
-  }
-};
-
-// 鍒犻櫎椤圭洰
-const handleDelete = async (row) => {
-  // const projectIds = row.projectId ? [row.projectId] : selectedRowKeys.value;
-  const projectNames = row.projectName ? [row.projectName] : 
-    projectList.value.filter(item => projectIds.includes(item.projectId)).map(item => item.projectName);
-  
-  const confirmMessage = `纭畾瑕佸垹闄ら」鐩� "${projectNames.join('銆�')}" 鍚楋紵`;
-  await ElMessageBox.confirm(confirmMessage, '纭鎿嶄綔', {
-    confirmButtonText: '纭畾',
-    cancelButtonText: '鍙栨秷',
-    type: 'warning'
-  }).catch(() => {
-    throw new Error('鍙栨秷鍒犻櫎');
-  });
-  
-  try {
-    // if (projectIds.length === 1) {
-      await delProject(row.projectId);
-    // } else {
-    //   await delProjectBatch(projectIds);
-    // }
-    ElMessage.success('鍒犻櫎鎴愬姛');
-    getList();
-  } catch (error) {
-    if (error.message !== '鍙栨秷鍒犻櫎') {
-      ElMessage.error('鍒犻櫎澶辫触');
-      console.error('鍒犻櫎椤圭洰澶辫触:', error);
-    }
-  }
-  // try {
-  //   await ElMessageBox.confirm(confirmMessage, '纭鎿嶄綔', {
-  //     confirmButtonText: '纭畾',
-  //     cancelButtonText: '鍙栨秷',
-  //     type: 'warning'
-  //   });
-    
-  //   // 妯℃嫙缃戠粶寤惰繜
-  //   await new Promise(resolve => setTimeout(resolve, 300));
-   
-    
-  //   ElMessage.success('鍒犻櫎鎴愬姛');
-  //   getList();
-  // } catch (error) {
-  //   if (error !== 'cancel') {
-  //     console.error('鍒犻櫎椤圭洰澶辫触:', error);
-  //   }
-  // }
-};
-
-// 鏌ョ湅椤圭洰璇︽儏
-const handleView = (row) => {
-  const projectId = row.projectId;
-  // 璺宠浆鍒伴」鐩鎯呴〉闈�
-  router.push({
-    path: `/oaSystem/projectManagement/projectDetail/${projectId}`,
-    query: { projectName: row.projectName }
-  });
-};
-
-// 瀵煎嚭椤圭洰
-const handleExport = async () => {
-    let ids = [];
-    if (selectedRowKeys.value.length > 0) {
-      ids = selectedRowKeys.value; // 瀵煎嚭閫変腑鐨勯」鐩�
-    } else {
-      ids = projectList.value.map(item => item.projectId); // 瀵煎嚭鎵�鏈夐」鐩�
-    }
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
-    .then(() => {
-      proxy.download(`/oA/project/export/${ids.join(',')}`, {}, "椤圭洰鏁版嵁.xlsx");
-      ElMessage.success("瀵煎嚭鎴愬姛");
-      ids = [];
-    })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
-    });
-};
-// 鎻愪氦琛ㄥ崟
-const submitForm = async () => {
-  try {
-    await projectFormRef.value.validate();
-
-    if (form.projectId) {
-      await updateProject(form);
-      ElMessage.success('淇敼椤圭洰鎴愬姛');
-    } else {
-      console.log("form",form);
-      await addProject(form);
-      ElMessage.success('鏂板椤圭洰鎴愬姛');
-    }
-    open.value = false;
-    getList();
-  } catch (error) {
-    console.error('鎻愪氦琛ㄥ崟澶辫触:', error);
-  }
-};
-
-// 鍙栨秷
-const cancel = () => {
-  open.value = false;
-  resetForm();
-};
-
-// 閲嶇疆琛ㄥ崟
-const resetForm = () => {
-  form.projectId = undefined;
-  form.projectName = '';
-  form.description = '';
-  form.startDate = '';
-  form.endDate = '';
-  form.managerId = '';
-  form.managerName = '';
-  form.status = 'planning';
-  form.completionRate = 0;
-  if (projectFormRef.value) {
-    projectFormRef.value.resetFields();
-  }
-};
-
-// 鑾峰彇鐘舵�佹爣绛剧被鍨�
-const getStatusType = (status) => {
-  const statusTypeMap = {
-    planning: 'info',
-    inProgress: 'primary',
-    completed: 'success',
-    paused: 'warning'
-  };
-  return statusTypeMap[status] || 'default';
-};
-
-// 鑾峰彇鐘舵�佹枃鏈�
-const getStatusText = (status) => {
-  const statusTextMap = {
-    planning: '瑙勫垝涓�',
-    inProgress: '杩涜涓�',
-    completed: '宸插畬鎴�',
-    paused: '宸叉殏鍋�'
-  };
-  return statusTextMap[status] || status;
-};
-
-// 鍒濆鍖�
-onMounted(() => {
-  getList();
-});
-</script>
-
-<style scoped>
-.app-container {
-  padding: 20px;
-}
-</style>
\ No newline at end of file
diff --git a/src/views/oaSystem/projectManagement/projectDetail.vue b/src/views/oaSystem/projectManagement/projectDetail.vue
deleted file mode 100644
index 578f76e..0000000
--- a/src/views/oaSystem/projectManagement/projectDetail.vue
+++ /dev/null
@@ -1,565 +0,0 @@
-// ... existing code ...
-<template>
-  <div class="app-container">
-    <!-- 椤圭洰鍩烘湰淇℃伅 -->
-    <el-card class="mb20">
-      <template #header>
-        <div class="card-header">
-          <span>椤圭洰鍩烘湰淇℃伅</span>
-        </div>
-      </template>
-      <el-descriptions :column="2" border>
-        <el-descriptions-item label="椤圭洰鍚嶇О">{{ projectInfo.projectName }}</el-descriptions-item>
-        <el-descriptions-item label="椤圭洰璐熻矗浜�">{{ projectInfo.managerName }}</el-descriptions-item>
-        <el-descriptions-item label="寮�濮嬫棩鏈�">{{ projectInfo.startDate }}</el-descriptions-item>
-        <el-descriptions-item label="缁撴潫鏃ユ湡">{{ projectInfo.endDate }}</el-descriptions-item>
-        <el-descriptions-item label="椤圭洰鐘舵��">
-          <el-tag :type="getStatusType(projectInfo.status)">{{ getStatusText(projectInfo.status) }}</el-tag>
-        </el-descriptions-item>
-        <el-descriptions-item label="瀹屾垚搴�">
-          <el-progress :percentage="projectInfo.completionRate" :stroke-width="6" />
-        </el-descriptions-item>
-        <el-descriptions-item label="椤圭洰鎻忚堪" :span="2">{{ projectInfo.description || '-' }}</el-descriptions-item>
-      </el-descriptions>
-    </el-card>
-
-    <!-- 椤圭洰杩涘害姒傝 -->
-    <el-card class="mb20">
-      <template #header>
-        <div class="card-header">
-          <span>椤圭洰杩涘害姒傝</span>
-        </div>
-      </template>
-      <el-row :gutter="20">
-        <el-col :span="6">
-          <div class="progress-item">
-            <div class="progress-title">鎬讳綋杩涘害</div>
-            <div class="progress-number">{{ projectInfo.completionRate }}%</div>
-          </div>
-        </el-col>
-        <el-col :span="6">
-          <div class="progress-item">
-            <div class="progress-title">闃舵鎬绘暟</div>
-            <div class="progress-number">{{ statistics.totalPhases }}</div>
-          </div>
-        </el-col>
-        <el-col :span="6">
-          <div class="progress-item">
-            <div class="progress-title">浠诲姟鎬绘暟</div>
-            <div class="progress-number">{{ statistics.totalTasks }}</div>
-          </div>
-        </el-col>
-        <el-col :span="6">
-          <div class="progress-item">
-            <div class="progress-title">宸插畬鎴愪换鍔�</div>
-            <div class="progress-number">{{ statistics.completedTasks }}</div>
-          </div>
-        </el-col>
-      </el-row>
-    </el-card>
-
-    <!-- 闃舵鍜屼换鍔$鐞� -->
-    <!-- <el-card class="mb20">
-      <template #header>
-        <div class="card-header">
-          <span>椤圭洰浠诲姟缁撴瀯</span>
-          <el-button type="primary" size="small" @click="handleAddPhase">娣诲姞闃舵</el-button>
-        </div>
-      </template>
-      <task-tree :project-id="projectId" @refresh="getProjectDetail" />
-    </el-card> -->
-
-    <!-- 閲岀▼纰戠鐞� -->
-    <el-card class="mb20">
-      <template #header>
-        <div class="card-header">
-          <span>椤圭洰闃舵閲岀▼纰�</span>
-          <el-button type="primary" size="small" @click="handleAddMilestone">娣诲姞閲岀▼纰�</el-button>
-        </div>
-      </template>
-      <milestone-list :project-id="projectId" @refresh="getProjectDetail" :key="`milestone-${refreshProjectId}`"/>
-    </el-card>
-
-    <!-- 闃舵鐩爣绠$悊 -->
-    <el-card>
-      <template #header>
-        <div class="card-header">
-          <span>闃舵浠诲姟</span>
-          <el-button type="primary" size="small" @click="handleAddPhaseGoal">娣诲姞闃舵鐩爣</el-button>
-        </div>
-      </template>
-      <phase-goal-list :project-id="projectId" @refresh="getProjectDetail" @editGoal="handleEditPhaseGoal" :key="`phaseGoal-${refreshProjectId}`"/>
-    </el-card>
-
-    <!-- 閲岀▼纰戠鐞嗗脊妗� -->  
-    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
-      <el-form :model="form" ref="formRef" label-width="100px">
-    <el-form-item label="椤圭洰闃舵鍚嶇О" prop="phaseName">
-      <el-input
-        v-model="form.phaseName"
-        placeholder="璇疯緭鍏ラ」鐩樁娈靛悕绉�"
-        maxlength="50"
-      />
-    </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-radio-group v-model="form.status">
-        <el-radio label="notStarted">鏈紑濮�</el-radio>
-        <el-radio label="completed">宸插畬鎴�</el-radio>
-        <el-radio label="delayed">宸插欢杩�</el-radio>
-      </el-radio-group>
-    </el-form-item>
-  </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭畾</el-button>
-          <el-button @click="cancel">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-
-    <!-- 闃舵浠诲姟绠$悊寮规 -->
-    <el-dialog :title="goalTitle" v-model="goalOpen" width="600px" append-to-body>
-      <el-form :model="goalForm" ref="goalFormRef" label-width="100px">
-        <el-form-item label="鎵�灞為樁娈�" prop="phaseId">
-          <el-select v-model="goalForm.phaseId" placeholder="璇烽�夋嫨鎵�灞為樁娈�">
-            <el-option
-              v-for="phase in phaseList"
-              :key="phase.phaseId"
-              :label="phase.phaseName"
-              :value="phase.phaseId"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="鐩爣鍚嶇О" prop="taskName">
-          <el-input
-            v-model="goalForm.taskName"
-            placeholder="璇疯緭鍏ョ洰鏍囧悕绉�"
-            maxlength="50"
-          />
-        </el-form-item>
-        <el-form-item label="鐩爣鍊�" prop="targetValue">
-          <el-input-number
-            v-model="goalForm.targetValue"
-            :min="0"
-            :precision="2"
-            placeholder="璇疯緭鍏ョ洰鏍囧��"
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="褰撳墠鍊�" prop="currentValue">
-          <el-input-number
-            v-model="goalForm.currentValue"
-            :min="0"
-            :precision="2"
-            placeholder="璇疯緭鍏ュ綋鍓嶅��"
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="鍗曚綅" prop="unit">
-          <el-input
-            v-model="goalForm.unit"
-            placeholder="璇疯緭鍏ュ崟浣�"
-            maxlength="10"
-          />
-        </el-form-item>
-        <el-form-item label="浠诲姟瀹屾垚鏃ユ湡" prop="targetDate">
-          <el-date-picker
-            v-model="goalForm.targetDate"
-            type="date"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            placeholder="閫夋嫨鐩爣鏃ユ湡"
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="寮�濮嬫棩鏈�" prop="startDate">
-          <el-date-picker
-            v-model="goalForm.startDate"
-            type="date"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            placeholder="閫夋嫨鐩爣鏃ユ湡"
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="缁撴潫鏃ユ湡" prop="endDate">
-          <el-date-picker
-            v-model="goalForm.endDate"
-            type="date"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            placeholder="閫夋嫨鐩爣鏃ユ湡"
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="鐘舵��" prop="status">
-          <el-select v-model="goalForm.status" placeholder="璇烽�夋嫨鐘舵��">
-            <el-option label="鏈紑濮�" value="notStarted" />
-            <el-option label="杩涜涓�" value="inProgress" />
-            <el-option label="宸插畬鎴�" value="completed" />
-            <el-option label="宸插欢杩�" value="delayed" />
-          </el-select>
-        </el-form-item>
-        <!-- <el-form-item label="瀹屾垚搴�" prop="completionRate">
-          <el-input-number
-            v-model="goalForm.completionRate"
-            :min="0"
-            :max="100"
-            :precision="2"
-            placeholder="璇疯緭鍏ュ畬鎴愬害"
-            style="width: 100%"
-          />
-        </el-form-item> -->
-      </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitGoalForm">纭畾</el-button>
-          <el-button @click="cancelGoal">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup>
-import { ref, reactive, onMounted, watch } from 'vue';
-import { useRoute, useRouter } from 'vue-router';
-import { ElMessage } from 'element-plus';
-import TaskTree from './components/taskTree.vue';
-import MilestoneList from './components/milestoneList.vue';
-import ProjectForm from './components/projectForm.vue';
-import PhaseGoalList from './components/phaseGoalList.vue';
-import { getProject, addProjectPhase, listProjectPhase, addProjectTask, updateProjectTask } from '@/api/oaSystem/projectManagement';
-
-const route = useRoute();
-const router = useRouter();
-const open = ref(false);
-const title = ref('');
-const projectFormRef = ref();
-const formRef = ref();
-// 椤圭洰ID
-// 鍦ㄥ叾浠杛ef瀹氫箟闄勮繎娣诲姞
-const refreshProjectId = ref(0);
-
-const projectId = ref(route.params.projectId);
-
-// 椤圭洰淇℃伅
-const projectInfo = reactive({
-  projectId: '',
-  projectName: '',
-  description: '',
-  startDate: '',
-  endDate: '',
-  managerId: '',
-  managerName: '',
-  status: 'planning',
-  completionRate: 0
-});
-
-// 缁熻淇℃伅
-const statistics = reactive({
-  totalPhases: 0,
-  totalTasks: 0,
-  completedTasks: 0
-});
-const form = reactive({
-  phaseId: '',
-  phaseName: '',
-  startDate: '',
-  endDate: '',
-  status: 'planning',
-  oaProjectId: projectId.value,
-})
-
-// 闃舵鐩爣鐩稿叧
-const goalOpen = ref(false);
-const goalTitle = ref('');
-const goalFormRef = ref();
-const phaseList = ref([]);
-const goalForm = reactive({
-  taskId: '',
-  phaseId: '',
-  taskName: '',
-  targetValue: 100,
-  currentValue: 0,
-  unit: '%',
-  targetDate: '',
-  startDate: '',
-  endDate: '',
-  status: 'notStarted',
-  completionRate: 0
-});
-
-// 鑾峰彇椤圭洰璇︽儏
-const getProjectDetail = async () => {
-  try {
-    getProject().then((res)=>{
-      console.log("椤圭洰璇︽儏",res)
-      const projectData = res.data[projectId.value];
-      // 鏇存柊椤圭洰淇℃伅
-      Object.assign(projectInfo, projectData);
-      
-      // 鏇存柊缁熻淇℃伅
-      updateStatistics(projectData);
-
-      // 寮哄埗鏇存柊DOM浠ョ‘淇濆瓙缁勪欢鑳芥纭埛鏂�
-      // 杩欓噷閫氳繃瑙﹀彂refreshProjectId浜嬩欢鏉ュ己鍒跺埛鏂板瓙缁勪欢
-      refreshProjectId.value++;
-    })
-  } catch (error) {
-    ElMessage.error('鑾峰彇椤圭洰璇︽儏澶辫触');
-    console.error('鑾峰彇椤圭洰璇︽儏澶辫触:', error);
-  }
-};
-
-// 鏇存柊缁熻淇℃伅
-const updateStatistics = (projectData) => {
-  // 杩欓噷鍋囪projectData涓寘鍚簡缁熻淇℃伅
-  // 濡傛灉娌℃湁锛岄渶瑕佸崟鐙姹傜粺璁℃暟鎹�
-  statistics.totalPhases = projectData.phases ? projectData.phases.length : 0;
-  statistics.totalTasks = projectData.tasks ? projectData.tasks.length : 0;
-  statistics.completedTasks = projectData.tasks ? 
-    projectData.tasks.filter(task => task.status === 'completed').length : 0;
-};
-
-// 鑾峰彇椤圭洰闃舵鍒楄〃
-const getPhaseList = async () => {
-  try {
-    const { data } = await listProjectPhase(projectId.value);
-    phaseList.value = data.rows || data;
-  } catch (error) {
-    ElMessage.error('鑾峰彇椤圭洰闃舵鍒楄〃澶辫触');
-    console.error('鑾峰彇椤圭洰闃舵鍒楄〃澶辫触:', error);
-  }
-};
-
-// 璁$畻瀹屾垚搴�
-const calculateCompletionRate = () => {
-  if (goalForm.targetValue > 0) {
-    goalForm.completionRate = Math.min(Math.round((goalForm.currentValue / goalForm.targetValue) * 100), 100);
-  } else {
-    goalForm.completionRate = 0;
-  }
-};
-
-// 娣诲姞闃舵
-const handleAddPhase = () => {
-  // resetForm();
-  ElMessage.info('娣诲姞闃舵鍔熻兘寰呭疄鐜�');
-};
-
-// 娣诲姞閲岀▼纰�
-const handleAddMilestone = () => {
-  resetForm();
-  open.value = true;
-  title.value = '鏂板椤圭洰闃舵';
-};
-
-// 娣诲姞闃舵浠诲姟
-const handleAddPhaseGoal = () => {
-  goalForm.taskId = '';
-  goalForm.phaseId = '';
-  goalForm.taskName = '';
-  goalForm.targetValue = 0;
-  goalForm.currentValue = 0;
-  goalForm.unit = '%';
-  goalForm.targetDate = '';
-  goalForm.startDate = '';
-  goalForm.endDate = '';
-  goalForm.status = 'notStarted';
-  goalForm.completionRate = 0;
-  if (goalFormRef.value) {
-    goalFormRef.value.resetFields();
-  }
-  getPhaseList();
-  goalTitle.value = '鏂板闃舵鐩爣';
-  goalOpen.value = true;
-};
-
-// 鎻愪氦琛ㄥ崟
-const submitForm = async () => {
-  try {
-    await formRef.value.validate();
-
-    if (form.phaseId) {
-      // await updateProject(form);
-      // ElMessage.success('淇敼椤圭洰闃舵鎴愬姛');
-    } else {
-      console.log("form",form);
-      await addProjectPhase(form);
-      ElMessage.success('鏂板椤圭洰闃舵鎴愬姛');
-      getProjectDetail();
-    }
-    open.value = false;
-  } catch (error) {
-    console.error('鎻愪氦琛ㄥ崟澶辫触:', error);
-  }
-};
-
-// 鎻愪氦闃舵浠诲姟琛ㄥ崟
-const submitGoalForm = async () => {
-  try {
-    await goalFormRef.value.validate();
-    calculateCompletionRate();
-    
-    const goalData = {
-      ...goalForm,
-      oaProjectId: projectId.value
-    };
-    
-    if (goalForm.taskId) {
-      await updateProjectTask(goalData);
-      ElMessage.success('淇敼闃舵鐩爣鎴愬姛');
-
-    } else {
-      await addProjectTask(goalData);
-      ElMessage.success('鏂板闃舵鐩爣鎴愬姛');
-      
-    }
-    // 璋冪敤getProjectDetail鍒锋柊鎵�鏈夌浉鍏虫暟鎹�
-    getProjectDetail();
-    goalOpen.value = false;
-
-  } catch (error) {
-    console.error('鎻愪氦闃舵鐩爣琛ㄥ崟澶辫触:', error);
-  }
-};
-
-// 閲嶇疆閲岀▼纰戣〃鍗�
-const resetForm = () => {
-  form.phaseId = '';
-  form.phaseName = '';
-  form.startDate = '';
-  form.endDate = '';
-  form.status = 'planning';
-  form.oaProjectId = projectId.value;
-  if (formRef.value) {
-    formRef.value.resetFields();
-  }
-};
-
-// 鍙栨秷闃舵浠诲姟鎿嶄綔
-const cancelGoal = () => {
-  goalOpen.value = false;
-};
-
-// 鍙栨秷鎿嶄綔
-const cancel = () => {
-  open.value = false;
-};
-// 缂栬緫闃舵浠诲姟
-const handleEditPhaseGoal = async (goal) => {
-  // 澶嶅埗鐩爣鏁版嵁鍒拌〃鍗�
-  Object.assign(goalForm, goal);
-  
-  // 鑾峰彇椤圭洰闃舵鍒楄〃
-  await getPhaseList();
-  
-  // 鎵撳紑缂栬緫寮圭獥
-  goalTitle.value = '缂栬緫闃舵鐩爣';
-  goalOpen.value = true;
-};
-// 鑾峰彇鐘舵�佹爣绛剧被鍨�
-const getStatusType = (status) => {
-  const statusTypeMap = {
-    planning: 'info',
-    inProgress: 'primary',
-    completed: 'success',
-    paused: 'warning'
-  };
-  return statusTypeMap[status] || 'default';
-};
-
-// 鑾峰彇鐘舵�佹枃鏈�
-const getStatusText = (status) => {
-  const statusTextMap = {
-    planning: '瑙勫垝涓�',
-    inProgress: '杩涜涓�',
-    completed: '宸插畬鎴�',
-    paused: '宸叉殏鍋�'
-  };
-  return statusTextMap[status] || status;
-};
-
-// 鐩戝惉璺敱鍙傛暟鍙樺寲
-watch(() => route.params.projectId, (newProjectId) => {
-  // console.log('璺敱鍙傛暟鍙樺寲:', projectId);
-  if (newProjectId) {
-    projectId.value = newProjectId;
-    getProjectDetail();
-  }
-});
-
-// 鐩戝惉褰撳墠鍊煎拰鐩爣鍊煎彉鍖栵紝閲嶆柊璁$畻瀹屾垚搴�
-watch(() => [goalForm.currentValue, goalForm.targetValue], () => {
-  calculateCompletionRate();
-});
-
-// 鍒濆鍖�
-onMounted(() => {
-  if (projectId.value) {
-    getProjectDetail();
-  }
-});
-</script>
-
-<style scoped>
-.app-container {
-  padding: 20px;
-}
-
-.card-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.progress-item {
-  text-align: center;
-  padding: 20px;
-  background-color: #f5f7fa;
-  border-radius: 8px;
-}
-
-.progress-title {
-  font-size: 14px;
-  color: #606266;
-  margin-bottom: 10px;
-}
-
-.progress-number {
-  font-size: 24px;
-  font-weight: bold;
-  color: #409eff;
-}
-
-.mb20 {
-  margin-bottom: 20px;
-}
-</style>

--
Gitblit v1.9.3