zhangwencui
6 天以前 5333935ae59999c47653122a669f4326f0173c1c
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"
      <el-timeline-item v-for="milestone in milestoneList"
        :key="milestone.phaseId"
        :timestamp="milestone.endDate"
      >
                        :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"
    <el-dialog v-model="dialogVisible"
      :title="'编辑里程碑: ' + (form.phaseName || '')"
      width="600px"
      :close-on-click-modal="false"
    >
      <el-form
        ref="formRef"
               :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="请输入里程碑名称" />
               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"
            <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%"
          />
                              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"
            <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%"
          />
                              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-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,40 +97,43 @@
</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
  }
      required: true,
    },
});
const emit = defineEmits(['refresh']);
  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
    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' }
      { required: true, message: "请输入里程碑名称", trigger: "blur" },
      { min: 2, max: 50, message: "长度在 2 到 50 个字符", trigger: "blur" },
  ],
  status: [
    { required: true, message: '请选择状态', trigger: 'change' }
  ]
    status: [{ required: true, message: "请选择状态", trigger: "change" }],
};
// 获取里程碑列表
@@ -136,15 +143,15 @@
      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);
      ElMessage.error("获取里程碑列表失败");
      console.error("获取里程碑列表失败:", error);
  }
};
// 编辑里程碑
const handleEdit = (milestone) => {
  const handleEdit = milestone => {
  // 复制里程碑数据到表单
  Object.assign(form, {
    phaseId: milestone.phaseId,
@@ -152,7 +159,7 @@
    description: milestone.description,
    endDate: milestone.endDate,
    status: milestone.status,
    projectId: props.projectId
      projectId: props.projectId,
  });
  dialogVisible.value = true;
};
@@ -166,32 +173,32 @@
    const res = await updateProjectPhase(form);
    
    if (res.code === 200) {
      ElMessage.success('里程碑编辑成功');
        ElMessage.success("里程碑编辑成功");
      dialogVisible.value = false;
      getMilestoneList(); // 刷新列表
      emit('refresh'); // 通知父组件刷新
        emit("refresh"); // 通知父组件刷新
    } else {
      ElMessage.error(res.msg || '里程碑编辑失败');
        ElMessage.error(res.msg || "里程碑编辑失败");
    }
  } catch (error) {
    if (error.name === 'ValidationError') {
      if (error.name === "ValidationError") {
      // 表单验证失败,Element Plus会自动提示
      return;
    }
    ElMessage.error('里程碑编辑失败');
    console.error('编辑里程碑失败:', error);
      ElMessage.error("里程碑编辑失败");
      console.error("编辑里程碑失败:", error);
  }
};
// 删除里程碑
const handleDelete = (milestone) => {
  const handleDelete = milestone => {
  ElMessageBox.confirm(
    `确定要删除里程碑 "${milestone.phaseName}" 吗?删除后将无法恢复。`,
    '删除确认',
      "删除确认",
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
    }
  )
    .then(async () => {
@@ -200,49 +207,52 @@
        const res = await delProjectPhase(milestone.phaseId);
        
        if (res.code === 200) {
          ElMessage.success('里程碑删除成功');
            ElMessage.success("里程碑删除成功");
          getMilestoneList(); // 刷新列表
          emit('refresh'); // 通知父组件刷新
            emit("refresh"); // 通知父组件刷新
        } else {
          ElMessage.error(res.msg || '里程碑删除失败');
            ElMessage.error(res.msg || "里程碑删除失败");
        }
      } catch (error) {
        ElMessage.error('里程碑删除失败');
        console.error('删除里程碑失败:', error);
          ElMessage.error("里程碑删除失败");
          console.error("删除里程碑失败:", error);
      }
    })
    .catch(() => {
      // 用户取消删除
      ElMessage.info('已取消删除');
        ElMessage.info("已取消删除");
    });
};
// 获取状态标签类型
const getStatusType = (status) => {
  const getStatusType = status => {
  const statusTypeMap = {
    notStarted: 'info',
    completed: 'success',
    delayed: 'danger'
      notStarted: "info",
      completed: "success",
      delayed: "danger",
  };
  return statusTypeMap[status] || 'default';
    return statusTypeMap[status] || "default";
};
// 获取状态文本
const getStatusText = (status) => {
  const getStatusText = status => {
  const statusTextMap = {
    notStarted: '未开始',
    completed: '已完成',
    delayed: '已延迟'
      notStarted: "未开始",
      completed: "已完成",
      delayed: "已延迟",
  };
  return statusTextMap[status] || status;
};
// 监听项目ID变化
watch(() => props.projectId, () => {
  watch(
    () => props.projectId,
    () => {
  if (props.projectId) {
    getMilestoneList();
  }
});
    }
  );
// 初始化
onMounted(() => {