feat(project): 支持项目初始化任务的异步查询和状态展示
Some checks failed
Lint Code / Lint Code (push) Failing after 23m42s
Some checks failed
Lint Code / Lint Code (push) Failing after 23m42s
- 新增项目初始化任务相关类型定义及接口封装,包括任务列表、任务统计和单个任务状态查询 - 集成 Element Plus 通知组件,增加任务完成和失败时的用户通知提醒 - 在 SSE 状态管理版块添加任务列表状态管理,支持任务状态的动态获取和展示 - 在创建项目向导组件中集成任务列表展示,支持查看任务进度、完成结果及错误信息 - 增加“使用此结果”按钮,允许用户直接应用已完成任务的项目初始化结果 - 对任务列表样式进行设计,区分不同状态的任务视觉效果提升用户体验 - 打开项目创建对话框时自动刷新并加载最新的任务列表数据
This commit is contained in:
@@ -239,3 +239,53 @@ export const confirmProjectInit = (data: ProjectInitResult) => {
|
||||
{ data }
|
||||
);
|
||||
};
|
||||
|
||||
// ==================== 项目初始化任务(SSE) ====================
|
||||
|
||||
/** 项目初始化任务 VO - 根据 OpenAPI 定义 */
|
||||
export type ProjectInitTaskVO = {
|
||||
taskId: string;
|
||||
userId?: number;
|
||||
status: string; // pending, processing, completed, failed
|
||||
statusDesc: string;
|
||||
progress: number;
|
||||
progressMessage: string;
|
||||
originalFilename: string;
|
||||
createTime: string;
|
||||
startTime?: string;
|
||||
completeTime?: string;
|
||||
result?: ProjectInitResult;
|
||||
errorMessage?: string;
|
||||
};
|
||||
|
||||
/** 任务统计信息 */
|
||||
export type TaskStats = {
|
||||
total: number;
|
||||
processing: number;
|
||||
completed: number;
|
||||
failed: number;
|
||||
};
|
||||
|
||||
/** 查询我的任务列表 */
|
||||
export const getMyTasks = () => {
|
||||
return http.request<Result<ProjectInitTaskVO[]>>(
|
||||
"get",
|
||||
"/api/v1/project-init/my-tasks"
|
||||
);
|
||||
};
|
||||
|
||||
/** 查询我的任务统计信息 */
|
||||
export const getMyTaskStats = () => {
|
||||
return http.request<Result<TaskStats>>(
|
||||
"get",
|
||||
"/api/v1/project-init/my-tasks/stats"
|
||||
);
|
||||
};
|
||||
|
||||
/** 查询单个任务状态 */
|
||||
export const getTaskStatus = (taskId: string) => {
|
||||
return http.request<Result<ProjectInitTaskVO>>(
|
||||
"get",
|
||||
`/api/v1/project-init/task/${taskId}`
|
||||
);
|
||||
};
|
||||
|
||||
606
src/api/项目sse.openapi.json
Normal file
606
src/api/项目sse.openapi.json
Normal file
@@ -0,0 +1,606 @@
|
||||
{
|
||||
"openapi": "3.0.1",
|
||||
"info": {
|
||||
"title": "默认模块",
|
||||
"description": "",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"tags": [],
|
||||
"paths": {
|
||||
"/api/v1/project-init/sse/submit-task": {
|
||||
"post": {
|
||||
"summary": "通过 SSE 提交项目初始化任务",
|
||||
"deprecated": false,
|
||||
"description": "使用通用 SSE 通道,通过 userId 推送进度",
|
||||
"tags": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"in": "query",
|
||||
"description": "用户ID",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"description": "",
|
||||
"example": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"multipart/form-data": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"description": "项目资料文件",
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"required": ["file"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BaseResponseMapObject",
|
||||
"description": "提交结果"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": []
|
||||
}
|
||||
},
|
||||
"/api/v1/project-init/my-tasks": {
|
||||
"get": {
|
||||
"summary": "查询我的任务列表",
|
||||
"deprecated": false,
|
||||
"description": "根据当前登录用户的token查询其所有任务",
|
||||
"tags": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"description": "",
|
||||
"example": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BaseResponseListProjectInitTaskVO",
|
||||
"description": "任务列表"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": []
|
||||
}
|
||||
},
|
||||
"/api/v1/project-init/my-tasks/stats": {
|
||||
"get": {
|
||||
"summary": "查询我的任务统计信息",
|
||||
"deprecated": false,
|
||||
"description": "",
|
||||
"tags": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"description": "",
|
||||
"example": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BaseResponseMapObject",
|
||||
"description": "统计信息"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": []
|
||||
}
|
||||
},
|
||||
"/api/v1/project-init/task/{taskId}": {
|
||||
"get": {
|
||||
"summary": "查询单个任务状态",
|
||||
"deprecated": false,
|
||||
"description": "",
|
||||
"tags": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "taskId",
|
||||
"in": "path",
|
||||
"description": "任务ID",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"description": "",
|
||||
"example": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": "Bearer 6bf1de0f-9edf-413f-a98f-1103b8dc30fc"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BaseResponseProjectInitTaskVO",
|
||||
"description": "任务状态"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"ProjectInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_name": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"project_type": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"objectives": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"plan_start_date": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"plan_end_date": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"budget": {
|
||||
"type": "number",
|
||||
"description": ""
|
||||
},
|
||||
"currency": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"MilestoneInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"milestone_name": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"plan_date": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"deliverables": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"owner_role": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"TaskInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task_id": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"task_name": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"parent_task_id": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"plan_start_date": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"plan_end_date": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"estimated_hours": {
|
||||
"type": "integer",
|
||||
"description": ""
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"assignee_role": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"dependencies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": ""
|
||||
},
|
||||
"deliverables": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"BaseResponseMapObject": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"description": ""
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"processing": {
|
||||
"type": "integer"
|
||||
},
|
||||
"completed": {
|
||||
"type": "null"
|
||||
},
|
||||
"failed": {
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"MemberInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"role_code": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"responsibility": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"weekly_hours": {
|
||||
"type": "integer",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"ResourceInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"resource_name": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"resource_type": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"quantity": {
|
||||
"type": "number",
|
||||
"description": ""
|
||||
},
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"unit_price": {
|
||||
"type": "number",
|
||||
"description": ""
|
||||
},
|
||||
"supplier": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"RiskInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"risk_name": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"probability": {
|
||||
"type": "integer",
|
||||
"description": ""
|
||||
},
|
||||
"impact": {
|
||||
"type": "integer",
|
||||
"description": ""
|
||||
},
|
||||
"mitigation_plan": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"TimelineNodeInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"node_name": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"node_type": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"plan_date": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"kb_scope": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"ProjectInitResult": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project": {
|
||||
"$ref": "#/components/schemas/ProjectInfo",
|
||||
"description": "项目基本信息"
|
||||
},
|
||||
"milestones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/MilestoneInfo",
|
||||
"description": "cn.yinlihupo.domain.dto.ProjectInitResult.MilestoneInfo"
|
||||
},
|
||||
"description": "里程碑列表"
|
||||
},
|
||||
"tasks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/TaskInfo",
|
||||
"description": "cn.yinlihupo.domain.dto.ProjectInitResult.TaskInfo"
|
||||
},
|
||||
"description": "任务清单"
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/MemberInfo",
|
||||
"description": "cn.yinlihupo.domain.dto.ProjectInitResult.MemberInfo"
|
||||
},
|
||||
"description": "项目成员"
|
||||
},
|
||||
"resources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ResourceInfo",
|
||||
"description": "cn.yinlihupo.domain.dto.ProjectInitResult.ResourceInfo"
|
||||
},
|
||||
"description": "资源需求"
|
||||
},
|
||||
"risks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/RiskInfo",
|
||||
"description": "cn.yinlihupo.domain.dto.ProjectInitResult.RiskInfo"
|
||||
},
|
||||
"description": "风险识别"
|
||||
},
|
||||
"timeline_nodes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/TimelineNodeInfo",
|
||||
"description": "cn.yinlihupo.domain.dto.ProjectInitResult.TimelineNodeInfo"
|
||||
},
|
||||
"description": "时间节点"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ProjectInitTaskVO": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"description": "任务ID"
|
||||
},
|
||||
"userId": {
|
||||
"type": "integer",
|
||||
"description": "用户ID(任务所属用户)",
|
||||
"format": "int64"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "任务状态: pending-待处理, processing-处理中, completed-已完成, failed-失败"
|
||||
},
|
||||
"statusDesc": {
|
||||
"type": "string",
|
||||
"description": "状态描述"
|
||||
},
|
||||
"progress": {
|
||||
"type": "integer",
|
||||
"description": "当前进度百分比 (0-100)"
|
||||
},
|
||||
"progressMessage": {
|
||||
"type": "string",
|
||||
"description": "进度描述信息"
|
||||
},
|
||||
"originalFilename": {
|
||||
"type": "string",
|
||||
"description": "原始文件名"
|
||||
},
|
||||
"createTime": {
|
||||
"type": "string",
|
||||
"description": "任务创建时间"
|
||||
},
|
||||
"startTime": {
|
||||
"type": "string",
|
||||
"description": "任务开始处理时间"
|
||||
},
|
||||
"completeTime": {
|
||||
"type": "string",
|
||||
"description": "任务完成时间"
|
||||
},
|
||||
"result": {
|
||||
"$ref": "#/components/schemas/ProjectInitResult",
|
||||
"description": "处理结果(仅当status=completed时有值)"
|
||||
},
|
||||
"errorMessage": {
|
||||
"type": "string",
|
||||
"description": "错误信息(仅当status=failed时有值)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BaseResponseListProjectInitTaskVO": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"description": ""
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ProjectInitTaskVO",
|
||||
"description": "项目初始化异步任务VO"
|
||||
},
|
||||
"description": ""
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"BaseResponseProjectInitTaskVO": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"description": ""
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/ProjectInitTaskVO",
|
||||
"description": ""
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"servers": [],
|
||||
"security": []
|
||||
}
|
||||
@@ -2,6 +2,11 @@ import { defineStore } from "pinia";
|
||||
import { ref, computed } from "vue";
|
||||
import { SseClient, type ProjectInitTaskVO } from "@/utils/sse/SseClient";
|
||||
import { store } from "../utils";
|
||||
import {
|
||||
getMyTasks as fetchTasksApi,
|
||||
type ProjectInitTaskVO as ApiTaskVO
|
||||
} from "@/api/project";
|
||||
import { ElNotification } from "element-plus";
|
||||
|
||||
export const useSseStore = defineStore("sse", () => {
|
||||
// State
|
||||
@@ -13,12 +18,20 @@ export const useSseStore = defineStore("sse", () => {
|
||||
"idle" | "submitted" | "processing" | "completed" | "error"
|
||||
>("idle");
|
||||
const errorMessage = ref("");
|
||||
// 我的任务列表
|
||||
const myTasks = ref<ApiTaskVO[]>([]);
|
||||
// 是否有待处理的任务
|
||||
const hasProcessingTask = computed(() =>
|
||||
myTasks.value.some(t => t.status === "processing" || t.status === "pending")
|
||||
);
|
||||
|
||||
// Getters
|
||||
const getIsConnected = computed(() => isConnected.value);
|
||||
const getCurrentTask = computed(() => currentTask.value);
|
||||
const getTaskProgress = computed(() => taskProgress.value);
|
||||
const getTaskStatus = computed(() => taskStatus.value);
|
||||
const getMyTasks = computed(() => myTasks.value);
|
||||
const getHasProcessingTask = computed(() => hasProcessingTask.value);
|
||||
|
||||
// Actions
|
||||
/**
|
||||
@@ -55,6 +68,18 @@ export const useSseStore = defineStore("sse", () => {
|
||||
taskProgress.value = 100;
|
||||
taskStatus.value = "completed";
|
||||
console.log("SSE Store: 任务完成", data.result);
|
||||
|
||||
// 发送通知
|
||||
ElNotification({
|
||||
title: "项目解析完成",
|
||||
message: `文件 "${data.originalFilename}" 已解析完成,请前往新建项目查看预览数据。`,
|
||||
type: "success",
|
||||
duration: 5000,
|
||||
position: "top-right"
|
||||
});
|
||||
|
||||
// 刷新任务列表
|
||||
fetchMyTasks();
|
||||
});
|
||||
|
||||
// 监听任务提交
|
||||
@@ -71,6 +96,18 @@ export const useSseStore = defineStore("sse", () => {
|
||||
taskStatus.value = "error";
|
||||
errorMessage.value = data.error;
|
||||
console.error("SSE Store: 任务错误", data.error);
|
||||
|
||||
// 发送错误通知
|
||||
ElNotification({
|
||||
title: "项目解析失败",
|
||||
message: data.error || "文件解析失败,请重试",
|
||||
type: "error",
|
||||
duration: 5000,
|
||||
position: "top-right"
|
||||
});
|
||||
|
||||
// 刷新任务列表
|
||||
fetchMyTasks();
|
||||
});
|
||||
|
||||
// 监听连接错误
|
||||
@@ -122,6 +159,20 @@ export const useSseStore = defineStore("sse", () => {
|
||||
errorMessage.value = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的任务列表
|
||||
*/
|
||||
async function fetchMyTasks() {
|
||||
try {
|
||||
const { code, data } = await fetchTasksApi();
|
||||
if (code === 200 && data) {
|
||||
myTasks.value = data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取任务列表失败", error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
sseClient,
|
||||
@@ -130,16 +181,20 @@ export const useSseStore = defineStore("sse", () => {
|
||||
taskProgress,
|
||||
taskStatus,
|
||||
errorMessage,
|
||||
myTasks,
|
||||
// Getters
|
||||
getIsConnected,
|
||||
getCurrentTask,
|
||||
getTaskProgress,
|
||||
getTaskStatus,
|
||||
getMyTasks,
|
||||
getHasProcessingTask,
|
||||
// Actions
|
||||
initSse,
|
||||
closeSse,
|
||||
submitProjectInitTask,
|
||||
resetTaskStatus
|
||||
resetTaskStatus,
|
||||
fetchMyTasks
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } from "vue";
|
||||
import { ref, reactive, computed, watch, onMounted } from "vue";
|
||||
import { message } from "@/utils/message";
|
||||
import { confirmProjectInit } from "@/api/project";
|
||||
import { confirmProjectInit, type ProjectInitTaskVO } from "@/api/project";
|
||||
import type { ProjectInitResult } from "@/api/project";
|
||||
import {
|
||||
WizardStep,
|
||||
@@ -16,6 +16,7 @@ import CheckIcon from "~icons/ri/check-line";
|
||||
import DeleteIcon from "~icons/ri/delete-bin-line";
|
||||
import AddIcon from "~icons/ri/add-line";
|
||||
import LoadingIcon from "~icons/ri/loader-4-line";
|
||||
import TimeIcon from "~icons/ri/time-line";
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
@@ -42,6 +43,18 @@ const sseStore = useSseStoreHook();
|
||||
const taskProgress = computed(() => sseStore.taskProgress);
|
||||
const taskStatus = computed(() => sseStore.taskStatus);
|
||||
const currentTask = computed(() => sseStore.currentTask);
|
||||
const myTasks = computed(() => sseStore.getMyTasks);
|
||||
const hasProcessingTask = computed(() => sseStore.getHasProcessingTask);
|
||||
|
||||
// 对话框打开时查询任务列表
|
||||
watch(
|
||||
() => props.visible,
|
||||
visible => {
|
||||
if (visible) {
|
||||
sseStore.fetchMyTasks();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听任务完成
|
||||
watch(
|
||||
@@ -272,6 +285,15 @@ function removeRisk(index: number) {
|
||||
projectData.risks.splice(index, 1);
|
||||
}
|
||||
|
||||
// 使用已完成任务的结果
|
||||
function handleUseTaskResult(task: ProjectInitTaskVO) {
|
||||
if (task.result) {
|
||||
Object.assign(projectData, task.result);
|
||||
currentStep.value = WizardStep.Preview;
|
||||
message("已加载任务结果", { type: "success" });
|
||||
}
|
||||
}
|
||||
|
||||
// 标签输入
|
||||
const tagInput = ref("");
|
||||
function handleTagInput() {
|
||||
@@ -331,6 +353,69 @@ function removeTag(tag: string) {
|
||||
</template>
|
||||
</el-upload>
|
||||
|
||||
<!-- 待处理任务列表 -->
|
||||
<div v-if="myTasks.length > 0" class="task-list-container mt-4">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<el-icon class="text-blue-500">
|
||||
<component :is="useRenderIcon(TimeIcon)" />
|
||||
</el-icon>
|
||||
<span class="text-sm font-medium">我的任务</span>
|
||||
</div>
|
||||
<div class="task-list">
|
||||
<div
|
||||
v-for="task in myTasks"
|
||||
:key="task.taskId"
|
||||
class="task-item"
|
||||
:class="{
|
||||
'task-processing': task.status === 'processing',
|
||||
'task-completed': task.status === 'completed',
|
||||
'task-failed': task.status === 'failed'
|
||||
}"
|
||||
>
|
||||
<div class="task-info">
|
||||
<span class="task-filename">{{ task.originalFilename }}</span>
|
||||
<el-tag
|
||||
:type="
|
||||
task.status === 'completed'
|
||||
? 'success'
|
||||
: task.status === 'processing'
|
||||
? 'warning'
|
||||
: task.status === 'failed'
|
||||
? 'danger'
|
||||
: 'info'
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{ task.statusDesc }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div v-if="task.status === 'processing'" class="task-progress">
|
||||
<el-progress
|
||||
:percentage="task.progress"
|
||||
:stroke-width="4"
|
||||
:show-text="false"
|
||||
/>
|
||||
<span class="text-xs text-gray-500 ml-2"
|
||||
>{{ task.progress }}%</span
|
||||
>
|
||||
</div>
|
||||
<div v-if="task.status === 'completed'" class="task-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
@click="handleUseTaskResult(task)"
|
||||
>
|
||||
使用此结果
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="task.status === 'failed'" class="task-error">
|
||||
<span class="text-xs text-red-500">{{ task.errorMessage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 进度显示 -->
|
||||
<div v-if="uploading" class="progress-container mt-6">
|
||||
<div class="flex-c gap-2 mb-2">
|
||||
@@ -770,6 +855,74 @@ function removeTag(tag: string) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.task-list-container {
|
||||
padding: 12px 16px;
|
||||
background: var(--el-fill-color-lighter);
|
||||
border-radius: 8px;
|
||||
|
||||
.task-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
background: white;
|
||||
border-left: 3px solid var(--el-color-info);
|
||||
border-radius: 6px;
|
||||
|
||||
&.task-processing {
|
||||
background: var(--el-color-warning-light-9);
|
||||
border-left-color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
&.task-completed {
|
||||
border-left-color: var(--el-color-success);
|
||||
}
|
||||
|
||||
&.task-failed {
|
||||
background: var(--el-color-danger-light-9);
|
||||
border-left-color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.task-info {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.task-filename {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.task-progress {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 120px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.task-actions {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.task-error {
|
||||
width: 100%;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
Reference in New Issue
Block a user