feat: 添加流水线任务子任务处理人展开显示功能
- 在任务卡片中添加展开/折叠功能,显示每个子任务的详细处理人信息 - 支持显示子任务编号、处理人姓名和状态 - 更新TaskCard组件和TaskHall页面,添加相应的样式和交互逻辑
This commit is contained in:
parent
75a0783379
commit
744ac08a91
@ -52,7 +52,25 @@
|
||||
</div>
|
||||
<div v-if="showReceiver" class="info-item">
|
||||
<span class="label">{{ receiverLabel }}</span>
|
||||
<span class="value">{{ task.receiverName || '--' }}</span>
|
||||
<span class="value">
|
||||
<span>{{ task.receiverName || '--' }}</span>
|
||||
<span v-if="task.isPipeline === 1 && task.subTasks && task.subTasks.length > 0"
|
||||
class="expand-subtasks"
|
||||
@click.stop="toggleSubtasks">
|
||||
<Icon :name="showSubtasks ? 'arrowUp' : 'arrowDown'" size="xs" style="margin-left: 4px; cursor: pointer;" />
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 流水线任务子任务详细信息(可展开) -->
|
||||
<div v-if="showReceiver && task.isPipeline === 1 && task.subTasks && task.subTasks.length > 0 && showSubtasks"
|
||||
class="subtasks-detail">
|
||||
<div v-for="(subTask, index) in task.subTasks" :key="subTask.id || index" class="subtask-item">
|
||||
<span class="subtask-label">{{ subTask.itemNo || `子任务${index + 1}` }}:</span>
|
||||
<span class="subtask-receiver">{{ subTask.receiverName || '待接单' }}</span>
|
||||
<span :class="['subtask-status', getSubTaskStatusClass(subTask.status)]">
|
||||
{{ getSubTaskStatusText(subTask.status) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="task.brandName" class="detail-item">
|
||||
<span class="icon">
|
||||
@ -133,12 +151,19 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import Icon from './Icon.vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
|
||||
interface TaskItem {
|
||||
id?: number
|
||||
itemNo?: string
|
||||
receiverName?: string
|
||||
status: string
|
||||
}
|
||||
|
||||
interface Task {
|
||||
id: number
|
||||
taskNo: string
|
||||
@ -161,6 +186,8 @@ interface Task {
|
||||
deadline?: string
|
||||
completeTime?: string
|
||||
submitTime?: string
|
||||
isPipeline?: number
|
||||
subTasks?: TaskItem[]
|
||||
}
|
||||
|
||||
interface Props {
|
||||
@ -179,6 +206,11 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
defineEmits(['click'])
|
||||
|
||||
const configStore = useConfigStore()
|
||||
const showSubtasks = ref(false)
|
||||
|
||||
const toggleSubtasks = () => {
|
||||
showSubtasks.value = !showSubtasks.value
|
||||
}
|
||||
|
||||
// 状态相关计算属性
|
||||
const statusClass = computed(() => {
|
||||
@ -278,6 +310,30 @@ const handleCopyTaskNo = async (taskNo: string) => {
|
||||
document.body.removeChild(textarea)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取子任务状态文本
|
||||
const getSubTaskStatusText = (status: string) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
'locked': '已锁定',
|
||||
'pending': '待接单',
|
||||
'in_progress': '进行中',
|
||||
'completed': '已完成',
|
||||
'rejected': '已驳回'
|
||||
}
|
||||
return statusMap[status] || status
|
||||
}
|
||||
|
||||
// 获取子任务状态样式类
|
||||
const getSubTaskStatusClass = (status: string) => {
|
||||
const classMap: Record<string, string> = {
|
||||
'locked': 'status-locked',
|
||||
'pending': 'status-pending',
|
||||
'in_progress': 'status-in-progress',
|
||||
'completed': 'status-completed',
|
||||
'rejected': 'status-rejected'
|
||||
}
|
||||
return classMap[status] || ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -340,6 +396,9 @@ const handleCopyTaskNo = async (taskNo: string) => {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: $text-primary;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
&.text-brand {
|
||||
color: #31f08b;
|
||||
@ -362,6 +421,19 @@ const handleCopyTaskNo = async (taskNo: string) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.expand-subtasks {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
color: #31f08b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -402,6 +474,66 @@ const handleCopyTaskNo = async (taskNo: string) => {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.subtasks-detail {
|
||||
margin-top: $space-xs;
|
||||
padding: $space-sm;
|
||||
background: rgba(49, 240, 139, 0.05);
|
||||
border-radius: $radius-sm;
|
||||
border: 1px solid rgba(49, 240, 139, 0.1);
|
||||
|
||||
.subtask-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-xs;
|
||||
font-size: 12px;
|
||||
padding: 4px 0;
|
||||
color: $text-secondary;
|
||||
|
||||
.subtask-label {
|
||||
color: $text-primary;
|
||||
font-weight: 500;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.subtask-receiver {
|
||||
color: $text-primary;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.subtask-status {
|
||||
padding: 2px 8px;
|
||||
border-radius: $radius-sm;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
|
||||
&.status-completed {
|
||||
background: rgba(49, 240, 139, 0.2);
|
||||
color: #31f08b;
|
||||
}
|
||||
|
||||
&.status-in-progress {
|
||||
background: rgba(59, 130, 246, 0.2);
|
||||
color: #3B82F6;
|
||||
}
|
||||
|
||||
&.status-pending {
|
||||
background: rgba(156, 163, 175, 0.2);
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
&.status-locked {
|
||||
background: rgba(107, 114, 128, 0.2);
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
color: #EF4444;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.task-progress {
|
||||
|
||||
@ -1715,7 +1715,27 @@
|
||||
<span class="icon">
|
||||
<Icon name="user" size="sm" color="#31f08b" />
|
||||
</span>
|
||||
<span>处理人: {{ task.receiverName || '待接单' }}</span>
|
||||
<span>
|
||||
处理人: {{ task.receiverName || '待接单' }}
|
||||
<span
|
||||
v-if="task.isPipeline === 1 && task.subTasks && task.subTasks.length > 0 && task.id"
|
||||
class="expand-subtasks"
|
||||
@click.stop="toggleTaskSubtasks(task.id!)"
|
||||
>
|
||||
<Icon :name="expandedTaskSubtasks[task.id!] ? 'arrowUp' : 'arrowDown'" size="xs" style="margin-left: 4px; cursor: pointer;" />
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 流水线任务子任务详细信息(可展开) -->
|
||||
<div v-if="task.isPipeline === 1 && task.subTasks && task.subTasks.length > 0 && task.id && expandedTaskSubtasks[task.id]"
|
||||
class="subtasks-detail">
|
||||
<div v-for="(subTask, index) in task.subTasks" :key="subTask.id || index" class="subtask-item">
|
||||
<span class="subtask-label">{{ getSubTaskLabel(subTask, index) }}:</span>
|
||||
<span class="subtask-receiver">{{ subTask.receiverName || '待接单' }}</span>
|
||||
<span :class="['subtask-status', getSubTaskStatusClass(subTask.status)]">
|
||||
{{ getSubTaskStatusText(subTask.status) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="task.brandName" class="detail-item">
|
||||
<span class="icon">
|
||||
@ -2842,11 +2862,20 @@ const getSubTaskLabel = (subTask: any, index: number) => {
|
||||
}
|
||||
|
||||
const getSubTaskStatusText = (status: string | undefined) => {
|
||||
switch (status) {
|
||||
case 'completed': return '已完成'
|
||||
case 'in_progress': return '进行中'
|
||||
default: return '待接单'
|
||||
const statusMap: Record<string, string> = {
|
||||
'locked': '已锁定',
|
||||
'pending': '待接单',
|
||||
'in_progress': '进行中',
|
||||
'completed': '已完成',
|
||||
'rejected': '已驳回'
|
||||
}
|
||||
return statusMap[status || ''] || status || '未知'
|
||||
}
|
||||
|
||||
// 展开/折叠任务子任务详情
|
||||
const expandedTaskSubtasks = ref<Record<number, boolean>>({})
|
||||
const toggleTaskSubtasks = (taskId: number) => {
|
||||
expandedTaskSubtasks.value[taskId] = !expandedTaskSubtasks.value[taskId]
|
||||
}
|
||||
|
||||
// 判断任务是否有子任务在进行中
|
||||
@ -6631,6 +6660,83 @@ onUnmounted(() => {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
// 展开/折叠图标
|
||||
.expand-subtasks {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
margin-left: 4px;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
color: #31f08b;
|
||||
}
|
||||
}
|
||||
|
||||
// 子任务详情展开样式
|
||||
.subtasks-detail {
|
||||
grid-column: 1 / -1;
|
||||
margin-top: $space-xs;
|
||||
padding: $space-sm;
|
||||
background: rgba(49, 240, 139, 0.05);
|
||||
border-radius: $radius-sm;
|
||||
border: 1px solid rgba(49, 240, 139, 0.1);
|
||||
|
||||
.subtask-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-sm;
|
||||
font-size: 12px;
|
||||
padding: 4px 0;
|
||||
color: $text-secondary;
|
||||
|
||||
.subtask-label {
|
||||
color: $text-primary;
|
||||
font-weight: 500;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.subtask-receiver {
|
||||
color: $text-primary;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.subtask-status {
|
||||
padding: 2px 8px;
|
||||
border-radius: $radius-sm;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
|
||||
&.status-completed {
|
||||
background: rgba(49, 240, 139, 0.2);
|
||||
color: #31f08b;
|
||||
}
|
||||
|
||||
&.status-in-progress {
|
||||
background: rgba(59, 130, 246, 0.2);
|
||||
color: #3B82F6;
|
||||
}
|
||||
|
||||
&.status-pending {
|
||||
background: rgba(156, 163, 175, 0.2);
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
&.status-locked {
|
||||
background: rgba(107, 114, 128, 0.2);
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
color: #EF4444;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 审批弹窗暗黑主题适配 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user