refactor(project): 重构项目执行模块组件结构和数据管理

- 移除 execution-list-panel.vue 组件并将功能整合到执行区域
- 新增 execution-section.vue 组件替代原有的列表面板
- 将 task-workspace.vue 重命名为 task-workspace-comp.vue 并更新引用
- 引入 useTaskViewContext 组合式 API 进行任务视图上下文管理
- 添加跨执行任务状态统计接口调用和数据处理逻辑
- 重构执行状态筛选和任务创建权限判断逻辑
- 更新执行选择、搜索和重置功能的事件处理方式
- 调整页面布局结构,优化左右分栏的内容组织方式
- 完善执行详情获取和状态操作的业务流程
- 优化执行分配和状态变更的异步处理机制
This commit is contained in:
2026-05-23 14:22:58 +08:00
parent 13b74cfe97
commit e9214137c1
40 changed files with 4432 additions and 1419 deletions

View File

@@ -0,0 +1,112 @@
<script setup lang="ts">
import WorkbenchModuleCard from './workbench-module-card.vue';
defineOptions({ name: 'WorkbenchTeamWorklog' });
interface Props {
editing?: boolean;
collapsed?: boolean;
}
withDefaults(defineProps<Props>(), { editing: false, collapsed: false });
defineEmits<{ (e: 'hide'): void; (e: 'toggle-collapse'): void }>();
interface MemberRow {
name: string;
hours: number;
}
const members: MemberRow[] = [
{ name: '张三', hours: 38 },
{ name: '李四', hours: 42 },
{ name: '王五', hours: 30 },
{ name: '赵六', hours: 48 },
{ name: '钱七', hours: 25 }
];
const maxHours = 48;
const avg = (members.reduce((s, m) => s + m.hours, 0) / members.length).toFixed(1);
const lowest = members.reduce((a, b) => (a.hours < b.hours ? a : b));
const highest = members.reduce((a, b) => (a.hours > b.hours ? a : b));
</script>
<template>
<WorkbenchModuleCard
title="团队工时分布"
icon="mdi:chart-bar"
:editing="editing"
:collapsed="collapsed"
@hide="$emit('hide')"
@toggle-collapse="$emit('toggle-collapse')"
>
<div class="bars">
<div v-for="m in members" :key="m.name" class="bar-col">
<div class="bar-value">{{ m.hours }}h</div>
<div class="bar" :style="{ height: `${(m.hours / maxHours) * 100}%` }" />
</div>
</div>
<div class="bars-x">
<div v-for="m in members" :key="m.name">{{ m.name }}</div>
</div>
<div class="bars-hint">
平均 {{ avg }}h / ·
<span class="text-danger">{{ lowest.name }}</span>
工时偏低 ·
<span class="text-warn">{{ highest.name }}</span>
40h
</div>
</WorkbenchModuleCard>
</template>
<style scoped>
.bars {
display: flex;
align-items: flex-end;
gap: 10px;
height: 120px;
padding: 18px 4px 0;
border-bottom: 1px solid var(--el-border-color-lighter);
}
.bar-col {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
height: 100%;
position: relative;
}
.bar-value {
position: absolute;
top: -16px;
font-size: 10px;
color: var(--el-text-color-secondary);
}
.bar {
width: 100%;
background: linear-gradient(180deg, var(--el-color-primary), var(--el-color-primary-light-7));
border-radius: 4px 4px 0 0;
min-height: 6px;
}
.bars-x {
display: flex;
gap: 10px;
margin-top: 4px;
}
.bars-x div {
flex: 1;
text-align: center;
font-size: 11px;
color: var(--el-text-color-secondary);
}
.bars-hint {
margin-top: 10px;
font-size: 12px;
color: var(--el-text-color-secondary);
}
.text-danger {
color: var(--el-color-danger);
}
.text-warn {
color: var(--el-color-warning);
}
</style>