Industrial-image-management.../src/views/task/task-approval/TaskApproval.vue

350 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<GiPageLayout>
<div class="task-approval-page">
<div class="page-header">
<h2>任务审批</h2>
<p class="page-description">审批转交的任务</p>
</div>
<!-- 状态汇总改为左边文字右边数字布局 -->
<div class="status-summary">
<div
class="status-item pending"
@click="activeTab = 'pending'"
:class="{ active: activeTab === 'pending' }"
>
<span class="status-text">待审批</span>
<span class="count">{{ pendingCount }}</span>
</div>
<div
class="status-item approved"
@click="activeTab = 'approved'"
:class="{ active: activeTab === 'approved' }"
>
<span class="status-text">已通过</span>
<span class="count">{{ approvedCount }}</span>
</div>
<div
class="status-item rejected"
@click="activeTab = 'rejected'"
:class="{ active: activeTab === 'rejected' }"
>
<span class="status-text">已拒绝</span>
<span class="count">{{ rejectedCount }}</span>
</div>
</div>
<div class="content">
<div class="task-list">
<!-- 根据激活的标签渲染对应状态的任务 -->
<div
class="task-item"
v-for="task in filteredTasks"
:key="task.id"
>
<div class="task-header">
<h3>{{ task.title }}</h3>
<span
class="task-status"
:class="task.status"
>
{{
task.status === 'pending' ? '待审批' :
task.status === 'approved' ? '已通过' : '已拒绝'
}}
</span>
</div>
<p class="task-description">{{ task.description }}</p>
<div class="transfer-info">
<div class="info-item">
<span class="label">转交人:</span>
<span>{{ task.from }}</span>
</div>
<div class="info-item">
<span class="label">接收人:</span>
<span>{{ task.to }}</span>
</div>
<div class="info-item">
<span class="label">部门:</span>
<span>{{ task.department }}</span>
</div>
<div class="info-item">
<span class="label">转交日期:</span>
<span>{{ task.transferDate }}</span>
</div>
<div class="info-item">
<span class="label">转交原因:</span>
<span>{{ task.reason }}</span>
</div>
</div>
<div class="action-buttons" v-if="task.status === 'pending'">
<button class="approve-btn" @click="handleApprove(task.id)">通过</button>
<button class="reject-btn" @click="handleReject(task.id)">拒绝</button>
</div>
</div>
</div>
</div>
</div>
</GiPageLayout>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
// 模拟所有任务数据
const allTasks = ref([
{
id: '1',
title: '前端页面重构',
description: '重构用户管理页面优化交互体验',
from: '张三',
to: '李四',
department: '前端开发部',
transferDate: '2025-08-10',
reason: '原负责人工作负荷过大',
status: 'pending'
},
{
id: '2',
title: 'API接口开发',
description: '开发用户管理相关API接口',
from: '王五',
to: '赵六',
department: '后端开发部',
transferDate: '2025-08-11',
reason: '技术栈更匹配',
status: 'pending'
},
{
id: '3',
title: '数据库设计',
description: '设计用户管理模块的数据库表结构',
from: '钱七',
to: '孙八',
department: '数据库组',
transferDate: '2025-08-12',
reason: '专业领域更对口',
status: 'pending'
}
]);
// 激活的标签默认待审批
const activeTab = ref('pending');
// 计算各状态任务数量
const pendingCount = computed(() => allTasks.value.filter(t => t.status === 'pending').length);
const approvedCount = computed(() => allTasks.value.filter(t => t.status === 'approved').length);
const rejectedCount = computed(() => allTasks.value.filter(t => t.status === 'rejected').length);
// 根据激活标签筛选任务
const filteredTasks = computed(() => {
return allTasks.value.filter(task => task.status === activeTab.value);
});
// 审批操作
const handleApprove = (taskId: string) => {
const task = allTasks.value.find(t => t.id === taskId);
if (task) {
task.status = 'approved';
}
};
// 拒绝操作
const handleReject = (taskId: string) => {
const task = allTasks.value.find(t => t.id === taskId);
if (task) {
task.status = 'rejected';
}
};
</script>
<style scoped>
.task-approval-page {
height: 100%;
padding: 20px;
display: flex;
flex-direction: column;
}
.page-header {
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid #f0f0f0;
}
.page-description {
color: #666;
margin-top: 8px;
font-size: 14px;
}
/* 状态汇总区域 */
.status-summary {
display: flex;
gap: 20px;
margin-bottom: 24px;
}
.status-item {
flex: 1;
display: flex;
justify-content: space-between; /* 让文字居左、数字居右 */
align-items: center;
padding: 16px;
border-radius: 8px;
cursor: pointer; /* 鼠标悬浮变手型,提示可点击 */
transition: all 0.2s ease;
border-top: 4px solid transparent; /* 预留顶部边框位置 */
}
/* 待审批状态样式 */
.status-item.pending {
border-top-color: #f59e0b;
background-color: rgba(245, 158, 11, 0.1); /* 浅橙色背景 */
}
.status-item.pending .count {
color: #f59e0b;
}
/* 已通过状态样式 */
.status-item.approved {
border-top-color: #10b981;
background-color: rgba(16, 185, 129, 0.1); /* 浅绿色背景 */
}
.status-item.approved .count {
color: #10b981;
}
/* 已拒绝状态样式 */
.status-item.rejected {
border-top-color: #ef4444;
background-color: rgba(239, 68, 68, 0.1); /* 浅红色背景 */
}
.status-item.rejected .count {
color: #ef4444;
}
/* 状态文字样式 */
.status-text {
font-size: 14px;
color: #333;
}
/* 数字样式 */
.count {
font-size: 20px;
font-weight: bold;
}
/* 激活态样式(可选,点击后高亮) */
.status-item.active {
transform: scale(1.02);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.content {
flex: 1;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
padding: 20px;
overflow: auto;
}
.task-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.task-item {
padding: 16px;
border: 1px solid #e5e7eb;
border-radius: 8px;
background-color: #fff;
}
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.task-header h3 {
margin: 0;
font-size: 16px;
color: #1f2937;
}
.task-status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.task-status.pending {
background-color: #fef3c7;
color: #92400e;
}
.task-status.approved {
background-color: #d1fae5;
color: #065f46;
}
.task-status.rejected {
background-color: #fee2e2;
color: #991b1b;
}
.task-description {
margin: 0 0 12px 0;
color: #6b7280;
font-size: 14px;
}
.transfer-info {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-bottom: 16px;
}
.info-item {
display: flex;
gap: 8px;
font-size: 14px;
}
.info-item .label {
color: #6b7280;
}
.action-buttons {
display: flex;
gap: 8px;
justify-content: flex-end;
}
.approve-btn, .reject-btn {
padding: 6px 12px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
}
.approve-btn {
background-color: #10b981;
color: white;
border: none;
}
.reject-btn {
background-color: #ef4444;
color: white;
border: none;
}
</style>