bug修复 #62

Merged
hnu202326010204 merged 20 commits from develop into main 2 days ago

5
.gitignore vendored

@ -1,11 +1,6 @@
# Python 编译缓存
__pycache__/
# 图片文件
*.png
*.jpg
*.jpeg
# 数据文件
*.csv

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

@ -13,8 +13,8 @@
### 2.1 测试对象
- 项目名称MuseGuard - 基于对抗性扰动的多风格图像生成防护系统
- 测试版本v1.0 (develop 分支最新代码)
- 测试范围:后端 API 服务Flask 应用
- 测试版本v1.0 (main 分支最新代码)
- 测试范围:Web 应用整体功能(前端 + 后端
### 2.2 项目背景
@ -35,8 +35,8 @@
### 2.4 测试时间
- 测试开始时间2026年1月6
- 测试结束时间2026年1月6
- 测试开始时间2026年1月4
- 测试结束时间2026年1月7
- 测试执行耗时68.09秒
---
@ -47,13 +47,16 @@
| 项目 | 配置 |
|------|------|
| 操作系统 | Windows |
| 平台 | win32 |
| 处理器 | 本地开发环境 |
| 内存 | 本地开发环境 |
| 云服务平台 | AutoDL |
| 操作系统 | Linux (Ubuntu) |
| GPU | NVIDIA GPU (CUDA 支持) |
| 处理器 | 云服务器 CPU |
| 内存 | 云服务器配置 |
### 3.2 软件环境
#### 3.2.1 后端环境
| 软件 | 版本 |
|------|------|
| Python | 3.11.14 |
@ -64,16 +67,28 @@
| Redis | 5.0.1 |
| RQ (任务队列) | 1.16.2 |
#### 3.2.2 前端环境
| 软件 | 版本 |
|------|------|
| Vue.js | 3.x |
| Vite | 构建工具 |
| Three.js | 3D 渲染 |
| Element Plus / 自定义组件 | UI 框架 |
### 3.3 测试工具
| 工具 | 版本 | 用途 |
|------|------|------|
| pytest | 9.0.2 | 测试框架 |
| pytest | 9.0.2 | 后端测试框架 |
| pytest-cov | 7.0.0 | 代码覆盖率统计 |
| pytest-flask | 1.3.0 | Flask 测试支持 |
| hypothesis | 6.148.7 | 基于属性的测试 |
| factory-boy | 3.3.1 | 测试数据工厂 |
| faker | 38.2.0 | 假数据生成 |
| Postman | 1.2.0 | API 测试支持 |
| 手工测试 | - | 前端功能与交互测试 |
| Chrome DevTools | - | 前端调试与性能分析 |
### 3.4 测试方法
@ -92,6 +107,11 @@
- 使用 Hypothesis 库进行属性测试
- 自动生成测试数据验证系统属性
4. **前端功能测试Frontend Testing**
- 手工测试前端页面交互和用户体验
- 验证页面组件、状态管理、路由跳转等功能
- 检查边界条件和异常场景处理
---
## 第四章 测试结果与分析
@ -143,7 +163,7 @@
| 中 (Medium) | 次要功能异常、有替代方案 | 计划修复 |
| 低 (Low) | 界面问题、文案错误、建议优化 | 可延后修复 |
#### 4.2.2 已解决 Bug 列表
#### 4.2.2 已解决 Bug 列表(后端)
| Bug ID | 等级 | 模块 | 描述 | 状态 |
|--------|------|------|------|------|
@ -151,17 +171,93 @@
| BUG-002 | 中 | Task | 任务状态更新异常 | ✅ 已解决 |
| BUG-003 | 低 | Image | 图片上传格式校验 | ✅ 已解决 |
#### 4.2.3 待解决 Bug 列表
#### 4.2.3 待解决 Bug 列表(后端)
| Bug ID | 等级 | 模块 | 描述 | 状态 |
|--------|------|------|------|------|
| - | - | - | 无待解决 Bug | - |
#### 4.2.4 Bug 分析
#### 4.2.4 前端 Bug 列表
本次前端测试共发现 10 个问题,按优先级分类如下:
**P0 - 高危问题**
| Bug ID | 等级 | 模块 | 描述 | 位置 | 状态 |
|--------|------|------|------|------|------|
| FE-002 | 高 | 管理员功能 | 管理员可删除自己账号,导致应用状态异常 | Page5/SubpageContainer.vue | ✅ 已解决 |
| FE-005 | 高 | 任务历史 | 列表页删除后分页"空窗",当前页无数据时未自动跳转 | Page4/Page4.vue | ✅ 已解决 |
| FE-006 | 高 | 组件 | 图片预览组件内存泄漏风险,路由跳转时 Blob URL 未清理 | ImagePreviewModal.vue | ✅ 已解决 |
**P1 - 体验问题**
| Bug ID | 等级 | 模块 | 描述 | 位置 | 状态 |
|--------|------|------|------|------|------|
| FE-001 | 中 | 任务历史 | 搜索后分页未重置,过滤结果可能显示为空 | Page4/Page4.vue | ✅ 已解决 |
| FE-003 | 中 | 图片上传 | 文件上传逻辑覆盖而非追加,多次选择文件会丢失之前的选择 | UniversalMode.vue / QuickMode.vue | ✅ 已解决 |
| FE-004 | 中 | 图片上传 | 文件大小超限时清空所有已选文件,体验不佳 | UniversalMode.vue | ✅ 已解决 |
| FE-008 | 中 | 管理员功能 | 管理员后台双重滚动条sticky header 可能失效 | Page5/SubpageContainer.vue | ✅ 已解决 |
**P2 - 优化建议**
| Bug ID | 等级 | 模块 | 描述 | 位置 | 状态 |
|--------|------|------|------|------|------|
| FE-007 | 低 | 组件 | 3D 轨迹图窗口调整变形,未响应窗口大小变化 | ThreeDTrajectoryModal.vue | ✅ 已解决 |
| FE-009 | 低 | 管理员功能 | VIP 生成数量输入框限制不严,未校验上限 | Page5/SubpageContainer.vue | ✅ 已解决 |
| FE-010 | 低 | 登录页 | WebGL 不支持时的白屏,缺少降级处理 | GridDistortion.vue | ✅ 已解决 |
#### 4.2.5 前端 Bug 详细说明
**FE-001 搜索后分页未重置**
- 问题:在任务历史页面,当用户在第 2 页或更后页时输入搜索关键字,过滤后的结果可能只有 1 页,但 currentPage 仍保持在之前的页码,导致列表显示为空
- 建议:监听 searchKeyword 和 selectedTaskType 的变化,一旦变化强制将 currentPage 重置为 1
本次测试未发现严重或高优先级的待解决 Bug系统整体运行稳定。
**FE-002 管理员可删除自己**
- 问题:在用户管理列表中,管理员可以点击自己账号行的"删除"按钮会导致应用状态异常Token 失效但页面未跳转)
- 建议:在渲染列表时判断 user_id 是否为当前用户,如果是则隐藏删除按钮或禁用该操作
#### 4.2.5 警告信息分析
**FE-003 文件上传逻辑覆盖而非追加**
- 问题:用户选择了 2 张图后再次选择第 3 张图,前 2 张图会被覆盖,不符合"追加"预期
- 建议:将新文件 push 到数组中,或在 UI 上明确提示是"替换"操作
**FE-004 文件大小超限体验不佳**
- 问题:当总文件大小超过 15MB 限制时,会清空所有已选文件,用户体验差
- 建议:超限时只拒绝当前添加的文件,保留之前合法的文件
**FE-005 列表页删除后分页"空窗"**
- 问题:删除当前页最后一条数据后,页面显示"暂无符合条件的任务",用户需手动点上一页
- 建议:删除成功后判断当前页是否还有数据,若无则自动跳转到上一页
**FE-006 图片预览组件内存泄漏风险**
- 问题:使用 URL.createObjectURL 创建的 Blob URL 在组件销毁时可能未被清理
- 建议:添加 onUnmounted 生命周期钩子,在组件销毁时显式调用 clearBlobs()
**FE-007 3D 轨迹图窗口调整变形**
- 问题Three.js 初始化后,改变浏览器窗口大小时 Canvas 不会自动调整,导致画面变形
- 建议:引入 ResizeObserver 或监听 window.resize更新 camera 和 renderer
**FE-008 管理员后台双重滚动条**
- 问题kt-modal-body 和 kt-table-wrapper 都设置了 overflow-y: auto可能出现嵌套滚动条
- 建议:移除 kt-modal-body 的 overflow-y让 kt-table-wrapper 独立滚动
**FE-009 VIP 生成数量输入框限制不严**
- 问题:虽然 HTML 属性有 min/max但用户可通过键盘输入超出范围的值JS 逻辑未校验上限
- 建议:在 JS 逻辑中补充 if (count > 10) 的校验
**FE-010 WebGL 不支持时的白屏**
- 问题:登录页背景依赖 WebGL在不支持的设备上可能导致页面不可读
- 建议:设置默认背景图片或渐变色作为 Fallback或捕获 WebGL 错误进行降级处理
#### 4.2.6 Bug 分析
**后端测试**:本次后端测试未发现严重或高优先级的待解决 Bug系统整体运行稳定。
**前端测试**:共发现 10 个问题,已全部修复:
- P0 高危问题 3 个:管理员自删除、分页空窗、内存泄漏 ✅ 已解决
- P1 体验问题 4 个:搜索分页、文件上传、双重滚动条 ✅ 已解决
- P2 优化建议 3 个3D 渲染、输入校验、WebGL 降级 ✅ 已解决
#### 4.2.7 警告信息分析
测试过程中发现部分 SQLAlchemy 2.0 兼容性警告:
@ -196,11 +292,12 @@ LegacyAPIWarning: The Query.get() method is considered legacy as of the 1.x seri
| 集成测试 - Auth API | 11 | 11 | 0 | 100% |
| 集成测试 - Image API | 14 | 14 | 0 | 100% |
| 集成测试 - Task API | 22 | 22 | 0 | 100% |
| **总计** | **149** | **149** | **0** | **100%** |
| 前端功能测试 | 10 | 10 | 0 | 100% |
| **总计** | **159** | **159** | **0** | **100%** |
#### 4.3.3 测试结论
所有测试用例均通过,系统功能完整、运行稳定。
后端所有 149 个测试用例均通过,前端发现的 10 个问题已全部修复。系统功能完整、运行稳定。
---
@ -211,8 +308,9 @@ LegacyAPIWarning: The Query.get() method is considered legacy as of the 1.x seri
| 质量维度 | 评估结果 | 说明 |
|----------|----------|------|
| 功能完整性 | 优秀 | 所有核心功能均已实现并通过测试验证 |
| 代码覆盖率 | 良好 | 整体覆盖率 70%,核心模块覆盖充分 |
| 稳定性 | 优秀 | 100% 测试通过率,系统运行稳定 |
| 代码覆盖率 | 良好 | 后端整体覆盖率 70%,核心模块覆盖充分 |
| 后端稳定性 | 优秀 | 后端 100% 测试通过率,系统运行稳定 |
| 前端稳定性 | 优秀 | 发现的 10 个问题已全部修复 |
| 可维护性 | 良好 | 代码结构清晰,采用分层架构 |
| 安全性 | 良好 | 密码复杂度验证、JWT 认证等安全机制完善 |
@ -242,8 +340,8 @@ LegacyAPIWarning: The Query.get() method is considered legacy as of the 1.x seri
经过本次系统测试MuseGuard 系统整体质量状况优秀:
1. **功能验证**:系统核心功能(用户认证、任务管理、图片处理、管理员功能)均已实现并通过测试验证
2. **测试通过率**149 个测试用例全部通过,通过率达 100%
1. **后端功能验证**:系统核心功能(用户认证、任务管理、图片处理、管理员功能)均已实现并通过测试验证149 个测试用例全部通过
2. **前端功能验证**:前端测试发现的 10 个问题已全部修复,系统运行稳定
3. **代码质量**:采用分层架构设计,代码结构清晰,便于维护和扩展
4. **安全性**新增密码复杂度验证JWT 认证机制完善
@ -331,6 +429,17 @@ LegacyAPIWarning: The Query.get() method is considered legacy as of the 1.x seri
| ADMIN-005 | 删除用户 | 删除指定用户 | ✅ 通过 |
| ADMIN-006 | 系统统计 | 聚合统计平台数据 | ✅ 通过 |
### I. 前端功能测试
| 功能编号 | 功能名称 | 功能描述 | 测试状态 |
|----------|----------|----------|----------|
| FE-PAGE1 | 图片上传 | 通用模式/快速模式图片上传 | ✅ 通过 |
| FE-PAGE4 | 任务历史 | 任务列表搜索、分页、删除 | ✅ 通过 |
| FE-PAGE5 | 管理员后台 | 用户管理、VIP 码生成 | ✅ 通过 |
| FE-COMP1 | 图片预览 | 图片预览模态框 | ✅ 通过 |
| FE-COMP2 | 3D 轨迹图 | Three.js 3D 可视化 | ✅ 通过 |
| FE-LOGIN | 登录页 | WebGL 背景渲染 | ✅ 通过 |
---
**报告编制**:自动化测试系统

Binary file not shown.

@ -545,12 +545,14 @@ def _save_final_images(
os.makedirs(save_folder, exist_ok=True)
noised_imgs = final_perturbed_images.detach().float().cpu()
img_names = [str(instance_path[0]).split("/")[-1] for instance_path in train_dataset.instance_images_path]
from pathlib import Path
img_names = [Path(instance_path[0]).stem for instance_path in train_dataset.instance_images_path]
for i in range(len(img_names)):
img_pixel = noised_imgs[i]
img_name = img_names[i]
save_path = os.path.join(save_folder, f"final_noise_{img_name}")
save_path = os.path.join(save_folder, f"perturbed_{img_name}.png")
Image.fromarray(
(img_pixel * 127.5 + 128).clamp(0, 255).to(torch.uint8).permute(1, 2, 0).numpy()
).save(save_path)

@ -11,6 +11,7 @@ from torch.utils.data import Dataset
from torchvision import transforms
from tqdm.auto import tqdm
from diffusers import AutoencoderKL
from pathlib import Path
def parse_args(input_args=None):
@ -225,7 +226,8 @@ def main(args):
for i in range(0, len(dataset.instance_images_path)):
img = dataset[i]['pixel_values']
img = to_image(img + attackmodel.delta[i])
img.save(os.path.join(args.output_dir, f"{i}.png"))
original_name = Path(dataset.instance_images_path[i]).stem
img.save(os.path.join(args.output_dir, f"perturbed_{original_name}.png"))
# 分别计算原始图像和中毒(添加扰动)图像在潜空间的分布
clean_embedding = attackmodel(vae, batch['pixel_values'], batch['index'], False)

@ -37,22 +37,21 @@ CUDA_VISIBLE_DEVICES=0 accelerate launch ../finetune_infras/train_db_gen_trace.p
--output_dir=$DREAMBOOTH_OUTPUT_DIR \
--with_prior_preservation \
--train_text_encoder \
--prior_loss_weight=0.4 \
--prior_loss_weight=0.15 \
--instance_prompt="a selfie photo of <sks> person" \
--class_prompt="a selfie photo of person" \
--resolution=512 \
--train_batch_size=1 \
--gradient_accumulation_steps=1 \
--learning_rate=5e-7 \
--lr_scheduler="constant_with_warmup" \
--lr_warmup_steps=50 \
--num_class_images=100 \
--max_train_steps=800 \
--gradient_accumulation_steps=4 \
--learning_rate=1e-6 \
--lr_scheduler="cosine_with_restarts" \
--num_class_images=80 \
--max_train_steps=1200 \
--checkpointing_steps=400 \
--mixed_precision=bf16 \
--prior_generation_precision=bf16 \
--sample_batch_size=5 \
--validation_prompt="a selfie photo of <sks> person, head-and-shoulders, face looking at the camera, Eiffel Tower clearly visible behind, outdoor daytime, realistic" \
--validation_prompt="a selfie photo of <sks> person" \
--num_validation_images=5 \
--validation_num_inference_steps=120 \
--validation_guidance_scale=7.0 \

@ -53,8 +53,8 @@ CUDA_VISIBLE_DEVICES=0 accelerate launch ../finetune_infras/train_lora_gen_trace
--output_dir=$DREAMBOOTH_OUTPUT_DIR \
--validation_image_output_dir=$OUTPUT_INFER_DIR \
--with_prior_preservation --prior_loss_weight=1.0 \
--instance_prompt="a photo of sks person" \
--class_prompt="a photo of person" \
--instance_prompt="a selfie photo of <sks> person" \
--class_prompt="a selfie photo of person" \
--resolution=512 \
--train_batch_size=1 \
--gradient_accumulation_steps=1 \
@ -67,7 +67,7 @@ CUDA_VISIBLE_DEVICES=0 accelerate launch ../finetune_infras/train_lora_gen_trace
--seed=0 \
--mixed_precision=fp16 \
--rank=4 \
--validation_prompt="a photo of sks person" \
--validation_prompt="a selfie photo of <sks> person" \
--num_validation_images 10 \
--positions_save_path="$POSITION_DIR" \
--coords_log_interval 10 \

@ -47,9 +47,9 @@ CUDA_VISIBLE_DEVICES=0 accelerate launch ../finetune_infras/train_ti_gen_trace.p
--instance_data_dir=$INSTANCE_DIR \
--output_dir=$TI_OUTPUT_DIR \
--validation_image_output_dir=$OUTPUT_INFER_DIR \
--placeholder_token="<sks-concept>" \
--placeholder_token="<sks>" \
--initializer_token="person" \
--instance_prompt="a photo of <sks-concept> person" \
--instance_prompt="a selfie photo of <sks> person" \
--resolution=512 \
--train_batch_size=1 \
--gradient_accumulation_steps=1 \
@ -60,7 +60,7 @@ CUDA_VISIBLE_DEVICES=0 accelerate launch ../finetune_infras/train_ti_gen_trace.p
--checkpointing_steps=500 \
--seed=0 \
--mixed_precision=fp16 \
--validation_prompt="a close-up photo of <sks-concept> person" \
--validation_prompt="a selfie photo of <sks> person" \
--num_validation_images 4 \
--validation_epochs 50 \
--coords_save_path="$COORD_DIR" \

@ -318,17 +318,16 @@ class AlgorithmConfig:
'default_params': {
'pretrained_model_name_or_path': MODELS_DIR['model2'],
'with_prior_preservation': True,
'prior_loss_weight': 0.4,
'prior_loss_weight': 0.15,
'instance_prompt': 'a selfie photo of <sks> person',
'class_prompt': 'a selfie photo of person',
'resolution': 512,
'train_batch_size': 1,
'gradient_accumulation_steps': 1,
'gradient_accumulation_steps': 4,
'learning_rate': 1e-6,
'lr_scheduler': 'constant_with_warmup',
'lr_warmup_steps': 50,
'num_class_images': 100,
'max_train_steps': 800,
'lr_scheduler': 'cosine_with_restarts',
'num_class_images': 80,
'max_train_steps': 1200,
'checkpointing_steps': 400,
'center_crop': True,
'mixed_precision': 'bf16',

@ -105,8 +105,8 @@ def init_database():
'data_type_code': 'art',
'instance_prompt': 'a painting in <sks> style',
'class_prompt': 'a painting',
'validation_prompt_prefix_db_lora': '((a painting in <sks> style)), distinct <sks> feature, coherent aesthetic, balanced lighting and color, fine art texture',
'validation_prompt_prefix_ti': 'a painting in <sks> style',
'validation_prompt_prefix_db_lora': 'a painting in strong <sks> style',
'validation_prompt_prefix_ti': 'a painting in strong <sks> style',
'placeholder_token': '<sks>',
'initializer_token': 'style',
'description': '艺术品类型的数据集'

@ -55,7 +55,7 @@ export function getStylePresets() {
/**
* 获取任务日志 (新增)
* 获取任务日志
*/
export function getTaskLogs(taskId) {
return request({ url: `/task/${taskId}/logs`, method: 'get' })
@ -90,7 +90,7 @@ export function submitFinetuneFromUpload(formData) {
}
/**
* 微调: 启动任务 (新增)
* 微调: 启动任务
*/
export function startFinetuneTask(taskId) {
return request({ url: `/task/finetune/${taskId}/start`, method: 'post' })
@ -103,13 +103,6 @@ export function submitEvaluateTask(data) {
return request({ url: '/task/evaluate', method: 'post', data })
}
/**
* 评估: 启动任务 (新增)
*/
export function startEvaluateTask(taskId) {
return request({ url: `/task/evaluate/${taskId}/start`, method: 'post' })
}
/**
* 热力图: 创建任务
*/

@ -14,7 +14,7 @@ const emit = defineEmits(['navigate', 'logout', 'toggle'])
const isDarkMode = ref(true)
const savedState = localStorage.getItem('kt_nav_expanded')
const isExpanded = ref(savedState === 'true' && savedState !== null ? true : false)
const isExpanded = ref(savedState === 'true' && typeof window !== 'undefined' && window.innerWidth > 900)
// DOM Refs
const navButtonRefs = ref([]) // DOM
@ -83,6 +83,19 @@ watch(() => props.currentSection, () => {
// ResizeObserver: window.resize
let resizeObserver = null
// === ===
const handleWindowResize = () => {
// 1. ()
updateHighlightPosition()
// 2. (<=900px)
if (window.innerWidth <= 900 && isExpanded.value) {
isExpanded.value = false
}
}
onMounted(() => {
const savedTheme = localStorage.getItem('theme')
if (savedTheme === 'light') {
@ -105,13 +118,13 @@ onMounted(() => {
resizeObserver.observe(navContainerRef.value)
}
// window resize
window.addEventListener('resize', updateHighlightPosition)
window.addEventListener('resize', handleWindowResize)
})
})
onUnmounted(() => {
if (resizeObserver) resizeObserver.disconnect()
window.removeEventListener('resize', updateHighlightPosition)
window.removeEventListener('resize', handleWindowResize)
})
const handleNavClick = (id) => { emit('navigate', id) }

@ -309,8 +309,9 @@ onMounted(() => {
//
document.addEventListener('visibilitychange', handleVisibilityChange)
const savedNavState = localStorage.getItem('kt_nav_expanded')
if (savedNavState === 'true') {
if (savedNavState === 'true' && window.innerWidth > 900) {
setTimeout(() => {
handleNavToggle(true)
}, 200)

@ -191,7 +191,7 @@ import { useRoute } from 'vue-router'
import TaskSideBar from '@/components/TaskSideBar.vue'
import { useTaskStore } from '@/stores/taskStore'
import { useUserStore } from '@/stores/userStore'
import { submitFinetuneFromPerturbation, submitFinetuneFromUpload, submitEvaluateTask, submitHeatmapTask, startFinetuneTask, startEvaluateTask } from '@/api/task'
import { submitFinetuneFromPerturbation, submitFinetuneFromUpload, submitEvaluateTask, submitHeatmapTask } from '@/api/task'
import { getTaskImages } from '@/api/image'
import { FINETUNE_MAP } from '@/utils/constants'
import modal from '@/utils/modal'
@ -368,10 +368,9 @@ const submitTask = async () => {
taskId = res.task?.task_id || res.job_id
}
if (taskId) {
await startFinetuneTask(taskId)
await modal.showSuccess({
title: '任务提交成功',
message: '微调任务已创建并启动,正在处理中...',
message: '微调任务已创建并自动启动,正在处理中...',
hint: '可在「我的资源」中查看任务进度',
taskInfo: { taskName: formData.value.taskName, taskType }
})
@ -381,13 +380,14 @@ const submitTask = async () => {
if (!formData.value.sourceId) throw new Error('请选择微调任务')
const res = await submitEvaluateTask({ finetune_task_id: formData.value.sourceId, evaluate_name: formData.value.taskName })
taskId = res.task?.task_id || res.job_id
if (taskId) await startEvaluateTask(taskId)
await modal.showSuccess({
title: '任务提交成功',
message: '评估任务已创建并启动,正在处理中...',
hint: '可在「我的资源」中查看任务进度',
taskInfo: { taskName: formData.value.taskName, taskType }
})
if (taskId) {
await modal.showSuccess({
title: '任务提交成功',
message: '评估任务已创建并自动启动,正在处理中...',
hint: '可在「我的资源」中查看任务进度',
taskInfo: { taskName: formData.value.taskName, taskType }
})
}
} else if (subpageType.value === 'heatmap') {
taskType = '热力图分析'
if (!formData.value.sourceId) throw new Error('请选择加噪任务')

@ -59,8 +59,8 @@
<div class="kt-col kt-col--id kt-sortable" @click="handleSort('virtual_id', $event)">
ID <i :class="getSortIcon('virtual_id')" aria-hidden="true"></i>
</div>
<div class="kt-col kt-col--name kt-sortable" @click="handleSort('name', $event)">
任务名称 <i :class="getSortIcon('name')" aria-hidden="true"></i>
<div class="kt-col kt-col--name">
任务名称
</div>
<div class="kt-col kt-col--type kt-sortable" @click="handleSort('task_type', $event)">
类型 <i :class="getSortIcon('task_type')" aria-hidden="true"></i>
@ -135,7 +135,7 @@
</button>
<button
v-if="['pending','waiting','processing','running'].includes(task.status)"
v-if="['pending','waiting'].includes(task.status)"
class="kt-action-btn kt-action-btn--danger"
title="取消任务"
@click="handleCancel(task)"

Loading…
Cancel
Save