yanghao 1 неделя назад
Родитель
Сommit
257a697a64
2 измененных файлов с 192 добавлено и 157 удалено
  1. 11 0
      src/styles/var.css
  2. 181 157
      src/views/researchProject/breakdown/index.vue

+ 11 - 0
src/styles/var.css

@@ -55,6 +55,17 @@
   --transition-time-02: 0.2s;
 }
 
+:root {
+  --el-color-primary: #1060ff !important;
+  --el-color-primary-light-3: #4a8aff;
+  --el-color-primary-light-5: #7aaaff;
+  --el-color-primary-light-7: #aacaff;
+  --el-color-primary-light-8: #c2daff;
+  --el-color-primary-light-9: #e3edff;
+  --el-color-primary-dark-2: #0d4fd6;
+  --el-border-radius-base: 4px !important; /* 把默认的基础圆角改成 8px */
+}
+
 .dark {
   --app-content-bg-color: var(--el-bg-color);
 }

+ 181 - 157
src/views/researchProject/breakdown/index.vue

@@ -27,133 +27,44 @@
   </ContentWrap>
 
   <ContentWrap style="border: none">
-    <zm-table
-      v-loading="loading"
-      :data="projectList"
-      row-key="id"
-      highlight-current-row
-      class="project-table"
-      @current-change="selectProject"
-    >
-      <zm-table-column label="项目名称" prop="projectName" min-width="280" show-overflow-tooltip />
-      <zm-table-column label="项目负责人" prop="projectLeader" width="140" />
-      <zm-table-column label="项目类型" prop="projectType" min-width="180">
+    <zm-table v-loading="loading" :data="projectList" row-key="id">
+      <zm-table-column label="项目名称" prop="projectName" min-width="240" show-overflow-tooltip />
+      <zm-table-column label="项目负责人" prop="projectLeader" width="120" />
+      <zm-table-column label="项目类型" prop="projectType" min-width="160">
         <template #default="{ row }">
           <dict-tag :type="DICT_TYPE.PROJECT_TYPE" :value="row.projectType" />
         </template>
       </zm-table-column>
-      <zm-table-column label="生效日期" prop="projectDate" width="160">
+      <zm-table-column label="生效日期" prop="projectDate" width="120">
         <template #default="{ row }">{{ formatDate(row.projectDate) }}</template>
       </zm-table-column>
       <zm-table-column label="任务数" prop="taskTotal" width="90" align="center" />
-      <zm-table-column label="操作" width="120" fixed="right" align="center">
-        <template #default="{ row }">
-          <el-button link type="primary" @click="selectProject(row)">分解任务</el-button>
-        </template>
-      </zm-table-column>
-    </zm-table>
-    <Pagination
-      v-model:page="queryParams.pageNo"
-      v-model:limit="queryParams.pageSize"
-      :total="total"
-      @pagination="getProjectList"
-    />
-  </ContentWrap>
-
-  <ContentWrap style="border: none" v-if="selectedProject" class="task-panel">
-    <div class="task-heading">
-      <div>
-        <div class="task-title-row">
-          <h3>{{ selectedProject.projectName }}</h3>
-          <el-tag type="success" size="small">已生效</el-tag>
-        </div>
-        <span>
-          项目负责人:{{ selectedProject.projectLeader }} · 已分解
-          {{ selectedProject.taskTotal || 0 }} 个任务
-        </span>
-      </div>
-      <el-button type="primary" @click="openTaskForm()" v-hasPermi="['rd:project-task:create']">
-        <Icon icon="ep:plus" /> 新增一级任务
-      </el-button>
-    </div>
-
-    <el-empty v-if="!taskTree.length" description="暂未分解任务">
-      <el-button type="primary" @click="openTaskForm()">
-        <Icon icon="ep:plus" /> 新增一级任务
-      </el-button>
-    </el-empty>
-    <zm-table
-      v-else
-      :data="taskTree"
-      row-key="id"
-      default-expand-all
-      border
-      :tree-props="{ children: 'children' }"
-    >
-      <zm-table-column label="任务名称" min-width="250">
-        <template #default="{ row }">
-          <div class="task-name">
-            <span>{{ row.taskName }}</span>
-            <el-tag v-if="row.level === 3" type="info" effect="plain" size="small">末级</el-tag>
-          </div>
-        </template>
-      </zm-table-column>
-      <zm-table-column label="开始时间" prop="planStartTime" width="130" />
-      <zm-table-column label="结束时间" prop="planEndTime" width="130" />
-      <zm-table-column label="责任人" prop="ownerName" width="120" />
-      <zm-table-column label="优先级" width="100" align="center">
-        <template #default="{ row }">
-          <el-tag :type="priorityTagType(row.priority)">
-            {{ priorityLabel(row.priority) }}
-          </el-tag>
-        </template>
-      </zm-table-column>
-      <zm-table-column label="进度" width="120" align="center">
-        <template #default="{ row }">
-          <el-progress
-            :percentage="row.progress || 0"
-            :status="row.status === 3 ? 'exception' : row.status === 2 ? 'success' : ''"
-            :stroke-width="8"
-          />
-        </template>
-      </zm-table-column>
-      <zm-table-column label="任务描述" prop="taskDesc" min-width="220" show-overflow-tooltip />
-      <zm-table-column label="操作" width="240" fixed="right" align="center">
+      <zm-table-column label="操作" width="200" fixed="right" align="center">
         <template #default="{ row }">
           <el-button
-            v-if="row.level < 3"
             link
             type="primary"
             v-hasPermi="['rd:project-task:create']"
             @click="openTaskForm(row)"
           >
-            新增子任务
-          </el-button>
-          <el-button v-else link type="info" disabled>不可再分解</el-button>
-          <el-button
-            link
-            type="primary"
-            v-hasPermi="['rd:project-task:update']"
-            @click="openTaskForm(row, true)"
-          >
-            编辑
-          </el-button>
-          <el-button
-            link
-            type="danger"
-            v-hasPermi="['rd:project-task:delete']"
-            @click="removeTask(row)"
-          >
-            删除
+            <Icon icon="ep:plus" /> 新增任务
           </el-button>
+          <el-button link type="primary" @click="openTaskDrawer(row)">查看任务</el-button>
         </template>
       </zm-table-column>
     </zm-table>
+    <Pagination
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      :total="total"
+      @pagination="getProjectList"
+    />
   </ContentWrap>
 
+  <!-- 新增/编辑任务弹窗 -->
   <el-dialog v-model="taskDialogVisible" :title="taskDialogTitle" width="720px" destroy-on-close>
     <el-alert v-if="parentTask" type="info" :closable="false" class="parent-alert">
-      当前父任务:{{ parentTask.taskName }}(已有子任务 {{ parentTask.children?.length || 0 }} 个)
+      当前父任务:{{ parentTask.taskName }}
     </el-alert>
     <el-form ref="taskFormRef" :model="taskForm" :rules="taskRules" label-width="auto">
       <el-form-item label="任务名称" prop="taskName">
@@ -220,6 +131,105 @@
       <el-button type="primary" :loading="submitLoading" @click="submitTask">保存任务</el-button>
     </template>
   </el-dialog>
+
+  <!-- 查看任务抽屉 -->
+  <el-drawer
+    v-model="drawerVisible"
+    :title="`任务列表:${currentProject?.projectName || ''}`"
+    size="75%"
+    destroy-on-close
+  >
+    <div class="drawer-header">
+      <span
+        >项目负责人:{{ currentProject?.projectLeader }} · 已分解 {{ taskTree.length }} 个任务</span
+      >
+      <el-button
+        type="primary"
+        style="background-color: #1560fc"
+        @click="openTaskForm()"
+        v-hasPermi="['rd:project-task:create']"
+      >
+        <Icon icon="ep:plus" /> 新增一级任务
+      </el-button>
+    </div>
+
+    <el-empty v-if="!taskTree.length" description="暂未分解任务">
+      <el-button type="primary" @click="openTaskForm()">
+        <Icon icon="ep:plus" /> 新增一级任务
+      </el-button>
+    </el-empty>
+
+    <el-table
+      v-else
+      :data="taskTree"
+      row-key="id"
+      default-expand-all
+      :tree-props="{ children: 'children' }"
+      :header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 'none' }"
+    >
+      <el-table-column label="任务名称" min-width="220" class-name="task-name-col">
+        <template #default="{ row }">
+          <!-- 将 div 换成 span,并设为 flex 布局 -->
+          <span class="task-name">
+            <span>{{ row.taskName }}</span>
+            <el-tag v-if="row.level === 3" type="info" effect="plain" size="small">末级</el-tag>
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="开始时间" prop="planStartTime" width="120" />
+      <el-table-column label="结束时间" prop="planEndTime" width="120" />
+      <el-table-column label="责任人" prop="ownerName" width="110" />
+      <el-table-column label="优先级" width="90" align="center">
+        <template #default="{ row }">
+          <el-tag :type="priorityTagType(row.priority)">
+            {{ priorityLabel(row.priority) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="进度" width="180" align="center">
+        <template #default="{ row }">
+          <el-progress
+            :percentage="row.progress || 0"
+            :status="row.status === 3 ? 'exception' : row.status === 2 ? 'success' : ''"
+            :stroke-width="8"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="任务描述" prop="taskDesc" min-width="180" show-overflow-tooltip />
+      <el-table-column label="操作" width="220" fixed="right" align="center">
+        <template #default="{ row }">
+          <el-button
+            v-if="row.level < 3"
+            link
+            style="color: #4b7bb1"
+            type="primary"
+            v-hasPermi="['rd:project-task:create']"
+            @click="openTaskForm(row)"
+          >
+            新增子任务
+          </el-button>
+          <!-- <el-button v-else link type="info" disabled>不可再分解</el-button> -->
+          <el-button
+            link
+            type="primary"
+            v-hasPermi="['rd:project-task:update']"
+            @click="openTaskForm(row, true)"
+            style="color: #4b7bb1"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            v-hasPermi="['rd:project-task:delete']"
+            @click="removeTask(row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </el-drawer>
 </template>
 
 <script setup lang="ts">
@@ -253,7 +263,7 @@ const getProjectList = async () => {
   try {
     const data = await getProjectPage({
       ...queryParams,
-      formalAuditStatus: 2 // ⭐ 只查正式审批通过的
+      formalAuditStatus: 2 // 只查正式审批通过的
     })
     projectList.value = data.list || []
     total.value = data.total || 0
@@ -271,22 +281,23 @@ const resetQuery = () => {
   handleQuery()
 }
 
-// ========== 选中项目 + 任务树 ==========
-const selectedProject = ref<any>(null)
+// ========== 查看任务抽屉 ==========
+const drawerVisible = ref(false)
+const currentProject = ref<any>(null)
 const taskTree = ref<any[]>([])
 
-const selectProject = async (project?: any) => {
-  if (!project) return
-  selectedProject.value = project
+const openTaskDrawer = async (project: any) => {
+  currentProject.value = project
+  drawerVisible.value = true
   await loadTaskTree()
 }
 
 const loadTaskTree = async () => {
-  if (!selectedProject.value?.id) {
+  if (!currentProject.value?.id) {
     taskTree.value = []
     return
   }
-  taskTree.value = await getTaskTreeByProjectId(selectedProject.value.id)
+  taskTree.value = await getTaskTreeByProjectId(currentProject.value.id)
 }
 
 // ========== 任务表单 ==========
@@ -320,13 +331,32 @@ const taskRules: FormRules = {
   taskDesc: [{ required: true, message: '请输入任务描述', trigger: 'blur' }]
 }
 
-const openTaskForm = (task?: any, editing = false) => {
-  if (!selectedProject.value) return
-  editingTask.value = editing ? task : undefined
-  parentTask.value = !editing && task ? task : undefined
-  taskDialogTitle.value = editing ? '编辑任务' : task ? '新增子任务' : '新增一级任务'
+/**
+ * 打开任务表单
+ * - project: 从项目列表点击时传入(新增一级任务)
+ * - task: 从任务树点击"新增子任务"或"编辑"时传入
+ * - editing: 是否编辑模式
+ */
+const openTaskForm = (projectOrTask?: any, editing = false) => {
+  // 场景 1:从项目列表点"新增任务"(projectOrTask 是项目对象)
+  if (projectOrTask && projectOrTask.projectName && !projectOrTask.taskName) {
+    editingTask.value = undefined
+    parentTask.value = undefined
+    taskDialogTitle.value = '新增一级任务'
+    Object.assign(taskForm, createEmptyTask(), {
+      projectId: projectOrTask.id
+    })
+    taskDialogVisible.value = true
+    return
+  }
 
+  // 场景 2:从任务树里点"新增子任务"或"编辑"(projectOrTask 是任务对象)
+  const task = projectOrTask
   if (editing && task) {
+    // 编辑任务
+    editingTask.value = task
+    parentTask.value = undefined
+    taskDialogTitle.value = '编辑任务'
     Object.assign(taskForm, {
       id: task.id,
       projectId: task.projectId,
@@ -340,8 +370,12 @@ const openTaskForm = (task?: any, editing = false) => {
       planEndTime: task.planEndTime
     })
   } else {
+    // 新增子任务
+    editingTask.value = undefined
+    parentTask.value = task || undefined
+    taskDialogTitle.value = task ? '新增子任务' : '新增一级任务'
     Object.assign(taskForm, createEmptyTask(), {
-      projectId: selectedProject.value.id,
+      projectId: currentProject.value?.id || null,
       parentId: task ? task.id : 0
     })
   }
@@ -364,8 +398,11 @@ const submitTask = async () => {
     }
     ElMessage.success(editingTask.value ? '任务已更新' : '任务已添加')
     taskDialogVisible.value = false
-    await loadTaskTree()
-    // 刷新项目列表(任务总数变了)
+    // 如果抽屉是打开的,刷新任务树
+    if (drawerVisible.value) {
+      await loadTaskTree()
+    }
+    // 刷新项目列表(任务数变了)
     await getProjectList()
   } finally {
     submitLoading.value = false
@@ -407,57 +444,44 @@ const formatDate = (dt: string) => {
 }
 
 // ========== 初始化 ==========
-onMounted(async () => {
-  await getProjectList()
-  // 默认选中第一条
-  if (projectList.value.length > 0) {
-    selectProject(projectList.value[0])
-  }
+onMounted(() => {
+  getProjectList()
 })
 </script>
 
 <style scoped lang="scss">
-.task-heading,
-.task-title-row {
+.project-filter {
+  margin-bottom: -15px;
+}
+.task-name {
   display: flex;
   align-items: center;
+  gap: 8px;
 }
-.task-heading {
-  justify-content: space-between;
+.parent-alert {
   margin-bottom: 18px;
 }
-.task-heading h3 {
-  margin: 0;
-  font-size: 18px;
-  color: var(--el-text-color-primary);
+.drawer-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 16px;
 }
-.task-heading span {
-  margin-top: 6px;
+.drawer-header span {
   color: var(--el-text-color-secondary);
   font-size: 13px;
 }
-.task-title-row {
-  gap: 10px;
-}
-.project-filter {
-  margin-bottom: -15px;
-}
-.task-panel {
-  margin-top: 16px;
-}
-.task-name {
+
+/* 让该列的单元格内容变成 flex 布局,使图标和文字在同一行 */
+:deep(.task-name-col .cell) {
   display: flex;
   align-items: center;
-  gap: 8px;
-}
-.parent-alert {
-  margin-bottom: 18px;
 }
-@media (max-width: 900px) {
-  .task-heading {
-    align-items: flex-start;
-    flex-direction: column;
-    gap: 14px;
-  }
+
+/* 任务名称的容器样式 */
+.task-name {
+  display: inline-flex;
+  align-items: center;
+  gap: 8px; /* 给文字和标签之间加点间距 */
 }
 </style>