fix: 修复任务详情交付路径显示和部门负责人任务卡片显示问题

1. 交付路径改为下载按钮形式,不再显示完整URL
2. 子任务交付路径也改为下载按钮列表
3. 修复部门负责人切换到接单部门后不显示任务卡片的问题
   - 后端查询时包含指定部门的所有子部门
4. 统一蓝色改为绿色主题
This commit is contained in:
Your Name 2026-01-08 17:40:35 +08:00
parent 03239c27b1
commit a7fce8e618
2 changed files with 105 additions and 38 deletions

View File

@ -80,7 +80,9 @@ public class TaskItemController {
if (isAdmin) {
// 管理员:看到所有进行中的子任务(如果指定了deptId则按部门过滤)
if (deptId != null) {
items = taskItemService.getInProgressItemsByDeptIds(page, pageSize, List.of(deptId), keyword);
// 获取指定部门及其所有子部门
List<Long> deptAndChildIds = getDeptAndChildIds(deptId);
items = taskItemService.getInProgressItemsByDeptIds(page, pageSize, deptAndChildIds, keyword);
} else {
items = taskItemService.getInProgressItems(page, pageSize, null, null, keyword);
}
@ -93,13 +95,20 @@ public class TaskItemController {
// 如果指定了deptId,验证是否在负责的部门列表中
if (deptId != null) {
if (leadingDeptIds.contains(deptId)) {
items = taskItemService.getInProgressItemsByDeptIds(page, pageSize, List.of(deptId), keyword);
// 获取指定部门及其所有子部门
List<Long> deptAndChildIds = getDeptAndChildIds(deptId);
items = taskItemService.getInProgressItemsByDeptIds(page, pageSize, deptAndChildIds, keyword);
} else {
// 无权查看该部门
items = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>();
}
} else {
items = taskItemService.getInProgressItemsByDeptIds(page, pageSize, leadingDeptIds, keyword);
// 获取所有负责部门及其子部门
List<Long> allDeptIds = new java.util.ArrayList<>();
for (Long leadDeptId : leadingDeptIds) {
allDeptIds.addAll(getDeptAndChildIds(leadDeptId));
}
items = taskItemService.getInProgressItemsByDeptIds(page, pageSize, allDeptIds, keyword);
}
} else {
// 普通设计师:只看自己的子任务
@ -142,7 +151,9 @@ public class TaskItemController {
if (isAdmin) {
// 管理员:看到所有已完成的子任务(如果指定了deptId则按部门过滤)
if (deptId != null) {
items = taskItemService.getCompletedItemsByDeptIds(page, pageSize, List.of(deptId), keyword);
// 获取指定部门及其所有子部门
List<Long> deptAndChildIds = getDeptAndChildIds(deptId);
items = taskItemService.getCompletedItemsByDeptIds(page, pageSize, deptAndChildIds, keyword);
} else {
items = taskItemService.getCompletedItems(page, pageSize, null, null, keyword);
}
@ -155,12 +166,19 @@ public class TaskItemController {
// 如果指定了deptId,验证是否在负责的部门列表中
if (deptId != null) {
if (leadingDeptIds.contains(deptId)) {
items = taskItemService.getCompletedItemsByDeptIds(page, pageSize, List.of(deptId), keyword);
// 获取指定部门及其所有子部门
List<Long> deptAndChildIds = getDeptAndChildIds(deptId);
items = taskItemService.getCompletedItemsByDeptIds(page, pageSize, deptAndChildIds, keyword);
} else {
items = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>();
}
} else {
items = taskItemService.getCompletedItemsByDeptIds(page, pageSize, leadingDeptIds, keyword);
// 获取所有负责部门及其子部门
List<Long> allDeptIds = new java.util.ArrayList<>();
for (Long leadDeptId : leadingDeptIds) {
allDeptIds.addAll(getDeptAndChildIds(leadDeptId));
}
items = taskItemService.getCompletedItemsByDeptIds(page, pageSize, allDeptIds, keyword);
}
} else {
// 普通设计师:只看自己的子任务
@ -377,4 +395,33 @@ public class TaskItemController {
log.info("最终返回 {} 个待审核子任务组", allGroups.size());
return Result.success(allGroups);
}
/**
* 获取指定部门及其所有子部门的ID列表
*/
private List<Long> getDeptAndChildIds(Long deptId) {
List<Long> result = new java.util.ArrayList<>();
result.add(deptId);
// 递归查询所有子部门
collectChildDeptIds(deptId, result);
return result;
}
/**
* 递归收集所有子部门ID
*/
private void collectChildDeptIds(Long parentId, List<Long> result) {
List<com.designhub.entity.Department> children = departmentMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.designhub.entity.Department>()
.eq(com.designhub.entity.Department::getParentId, parentId)
.eq(com.designhub.entity.Department::getStatus, 1)
);
for (com.designhub.entity.Department child : children) {
result.add(child.getId());
collectChildDeptIds(child.getId(), result);
}
}
}

View File

@ -221,7 +221,7 @@
<h3 class="task-title">{{ task.title }}</h3>
<div class="task-badges">
<span v-if="task.isSubTask" class="badge badge-subtask">
<Icon name="layers" size="sm" color="#1890ff" style="margin-right: 4px; vertical-align: middle;" />
<Icon name="layers" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
子任务
</span>
<span v-if="isNewTask(task)" class="badge badge-new">
@ -902,11 +902,11 @@
<h3 class="task-title">{{ task.title }}</h3>
<div class="task-badges">
<span v-if="task.isSubTask" class="badge badge-subtask">
<Icon name="layers" size="sm" color="#1890ff" style="margin-right: 4px; vertical-align: middle;" />
<Icon name="layers" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
子任务
</span>
<span v-if="task.releaseType === 'assigned'" class="badge badge-assigned">
<Icon name="target" size="sm" color="#1890ff" style="margin-right: 4px; vertical-align: middle;" />
<Icon name="target" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
指定
</span>
<span class="badge badge-in-progress">
@ -1620,7 +1620,7 @@
{{ getTaskStatusText(task.status, task) }}
</span>
<span v-if="task.releaseType === 'assigned'" class="badge badge-assigned">
<Icon name="target" size="sm" color="#1890ff" style="margin-right: 4px; vertical-align: middle;" />
<Icon name="target" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
指定
</span>
<span v-if="task.isUrgent" class="badge badge-urgent">
@ -2069,13 +2069,14 @@
交付路径
</h4>
<div class="delivery-path">
<a v-if="selectedTask.deliveryPath.startsWith('http')"
:href="selectedTask.deliveryPath"
target="_blank"
class="delivery-link">
<Icon name="external-link" size="sm" style="margin-right: 4px;" />
{{ selectedTask.deliveryPath }}
</a>
<a-button
v-if="selectedTask.deliveryPath.startsWith('http')"
type="primary"
size="small"
@click="openDeliveryPath(selectedTask.deliveryPath)">
<Icon name="download" size="sm" style="margin-right: 4px;" />
下载素材
</a-button>
<p v-else class="delivery-text">{{ selectedTask.deliveryPath }}</p>
</div>
</div>
@ -2173,10 +2174,14 @@
</h4>
<div class="delivery-paths-list">
<div v-for="(path, index) in selectedTask.allDeliveryPaths" :key="index" class="delivery-path-item">
<a v-if="isUrl(path)" :href="extractUrl(path)" target="_blank" class="delivery-link">
<Icon name="link" size="sm" style="margin-right: 4px;" />
{{ path }}
</a>
<a-button
v-if="isUrl(path)"
type="primary"
size="small"
@click="openDeliveryPath(extractUrl(path))">
<Icon name="download" size="sm" style="margin-right: 4px;" />
{{ extractLabel(path) }}
</a-button>
<span v-else class="delivery-text">{{ path }}</span>
</div>
</div>
@ -4895,6 +4900,21 @@ const extractUrl = (str: string) => {
return urlMatch ? urlMatch[0] : str
}
// 从子任务交付路径提取标签(例如 "【TASK...】https://..." -> "下载 TASK...")
const extractLabel = (str: string) => {
// 尝试提取【】中的内容作为标签
const labelMatch = str.match(/【([^】]+)】/)
if (labelMatch) {
return `下载 ${labelMatch[1]}`
}
return '下载素材'
}
// 打开交付路径
const openDeliveryPath = (url: string) => {
window.open(url, '_blank')
}
// 监听配置更新事件
const handleConfigUpdate = async (event: CustomEvent) => {
console.log('配置已更新,刷新配置数据:', event.detail)
@ -5587,9 +5607,9 @@ onUnmounted(() => {
}
.badge-subtask {
background: rgba(24, 144, 255, 0.1);
border: 1px solid rgba(24, 144, 255, 0.3);
color: #1890ff;
background: rgba(49, 240, 139, 0.1);
border: 1px solid rgba(49, 240, 139, 0.3);
color: #31f08b;
}
.badge-new {
@ -5611,9 +5631,9 @@ onUnmounted(() => {
}
.badge-assigned {
background: rgba(24, 144, 255, 0.1);
border: 1px solid rgba(24, 144, 255, 0.2);
color: #1890ff;
background: rgba(49, 240, 139, 0.1);
border: 1px solid rgba(49, 240, 139, 0.2);
color: #31f08b;
}
// 待填写ID状态样式 - 醒目警告色
@ -5948,8 +5968,8 @@ onUnmounted(() => {
}
&.in-progress {
background: rgba(24, 144, 255, 0.1);
color: #1890ff;
background: rgba(49, 240, 139, 0.1);
color: #31f08b;
}
&.pending {
@ -6058,17 +6078,17 @@ onUnmounted(() => {
// 进行中状态
&.in-progress {
.node-dot {
background: #1890ff;
border-color: #1890ff;
box-shadow: 0 0 10px rgba(24, 144, 255, 0.6);
background: #31f08b;
border-color: #31f08b;
box-shadow: 0 0 10px rgba(49, 240, 139, 0.6);
animation: pulse 1.5s ease-in-out infinite;
}
.node-label {
color: #1890ff;
color: #31f08b;
font-weight: 600;
}
.node-status {
color: #1890ff;
color: #31f08b;
}
}
@ -6250,12 +6270,12 @@ onUnmounted(() => {
flex-wrap: wrap;
.prev-assets-btn {
background: rgba(24, 144, 255, 0.1);
border-color: #1890ff;
color: #1890ff;
background: rgba(49, 240, 139, 0.1);
border-color: #31f08b;
color: #31f08b;
&:hover {
background: rgba(24, 144, 255, 0.2);
background: rgba(49, 240, 139, 0.2);
}
}
margin-top: $space-md;