Files
DataMate/frontend/src/pages/TaskCoordination/components/AssignmentLogDrawer.tsx
Jerry Yan 71f8f7d1c3 feat: 实现任务拆分和分配功能
## 功能概述
实现完整的任务拆分、分配和进度跟踪功能,支持将任务拆分为子任务并分配给不同用户。

## Phase 1: 数据库层
- 新增 t_task_meta 表(任务元数据协调表)
- 新增 t_task_assignment_log 表(分配日志表)
- 新增 3 个权限条目(read/write/assign)
- 新增 SQLAlchemy ORM 模型

## Phase 2: 后端 API (Java)
- 新增 task-coordination-service 模块(32 个文件)
- 实现 11 个 API 端点:
  - 任务查询(列表、子任务、我的任务)
  - 任务拆分(支持 4 种策略)
  - 任务分配(单个、批量、重新分配、撤回)
  - 进度管理(查询、更新、聚合)
  - 分配日志
- 集成权限控制和路由规则

## Phase 3: 前端 UI (React + TypeScript)
- 新增 10 个文件(模型、API、组件、页面)
- 实现 5 个核心组件:
  - SplitTaskDialog - 任务拆分对话框
  - AssignTaskDialog - 任务分配对话框
  - BatchAssignDialog - 批量分配对话框
  - TaskProgressPanel - 进度面板
  - AssignmentLogDrawer - 分配记录
- 实现 2 个页面:
  - TaskCoordination - 任务管理主页
  - MyTasks - 我的任务页面
- 集成侧边栏菜单和路由

## 问题修复
- 修复 getMyTasks 分页参数缺失
- 修复子任务 assignee 信息缺失(批量查询优化)
- 修复 proportion 精度计算(余量分配)

## 技术亮点
- 零侵入设计:通过独立协调表实现,不修改现有模块
- 批量查询优化:避免 N+1 查询问题
- 4 种拆分策略:按比例/数量/文件/手动
- 进度自动聚合:子任务更新自动聚合到父任务
- 权限细粒度控制:read/write/assign 三级权限

## 验证
- Maven 编译: 零错误
- TypeScript 编译: 零错误
- Vite 生产构建: 成功
2026-02-09 00:42:34 +08:00

95 lines
2.8 KiB
TypeScript

import { useEffect, useState } from "react";
import { Drawer, Table, Tag, Spin, Timeline, App } from "antd";
import { TaskAssignmentLogDto } from "../taskCoordination.model";
import { getAssignmentLogsUsingGet } from "../taskCoordination.api";
import { AssignmentActionMap } from "../taskCoordination.const";
interface AssignmentLogDrawerProps {
open: boolean;
taskId: string | null;
taskName?: string;
onClose: () => void;
}
const actionColorMap: Record<string, string> = {
ASSIGN: "blue",
REASSIGN: "orange",
REVOKE: "red",
};
export default function AssignmentLogDrawer({
open,
taskId,
taskName,
onClose,
}: AssignmentLogDrawerProps) {
const { message } = App.useApp();
const [loading, setLoading] = useState(false);
const [logs, setLogs] = useState<TaskAssignmentLogDto[]>([]);
useEffect(() => {
if (!open || !taskId) return;
setLoading(true);
getAssignmentLogsUsingGet(taskId)
.then((res: any) => {
setLogs(res?.data ?? []);
})
.catch(() => {
message.error("加载分配记录失败");
})
.finally(() => {
setLoading(false);
});
}, [open, taskId, message]);
return (
<Drawer
title={`分配记录:${taskName || ""}`}
open={open}
onClose={onClose}
width={520}
>
<Spin spinning={loading}>
{logs.length === 0 && !loading ? (
<div className="text-center text-gray-400 py-8"></div>
) : (
<Timeline
items={logs.map((log) => ({
color: actionColorMap[log.action] || "gray",
children: (
<div className="pb-2">
<div className="flex items-center gap-2 mb-1">
<Tag
color={actionColorMap[log.action] || "default"}
>
{AssignmentActionMap[log.action] || log.action}
</Tag>
<span className="text-sm text-gray-500">
{log.createdAt}
</span>
</div>
<div className="text-sm">
<span className="text-gray-500"></span>
{log.operatorName || "-"}
{log.userName && (
<>
<span className="text-gray-500 ml-3"></span>
{log.userName}
</>
)}
</div>
{log.remark && (
<div className="text-sm text-gray-500 mt-1">
{log.remark}
</div>
)}
</div>
),
}))}
/>
)}
</Spin>
</Drawer>
);
}