461 lines
11 KiB
Vue
461 lines
11 KiB
Vue
<template>
|
||
<view class="main-data-page">
|
||
<!-- 使用子头部组件 -->
|
||
<sub-header
|
||
title="业务审批"
|
||
@goBack="goBack"
|
||
@showMoreOptions="showMoreOptions"
|
||
/>
|
||
<view class="main-container">
|
||
<!-- 审批状态tabs -->
|
||
<view class="approval-tabs">
|
||
<view
|
||
v-for="tab in approvalTabs"
|
||
:key="tab.key"
|
||
class="tab-item"
|
||
:class="{ active: activeTab === tab.key }"
|
||
@click="switchTab(tab.key)"
|
||
>
|
||
{{ tab.label }}
|
||
<view v-if="(tab.key === 'pending' || tab.key === 'all') && tab.count > 0" class="tab-badge">{{ tab.count }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 审批列表 -->
|
||
<view class="approval-list">
|
||
<view
|
||
v-for="item in filteredApprovalList"
|
||
:key="item.id"
|
||
class="approval-item"
|
||
@click="viewDetail(item)"
|
||
>
|
||
<view class="item-header">
|
||
<view class="item-title">{{ item.title }}</view>
|
||
<view class="item-status" :class="item.status">
|
||
{{ getStatusText(item.status) }}
|
||
</view>
|
||
</view>
|
||
<view class="item-content">
|
||
<view class="item-info">
|
||
<text class="info-label">申请人:</text>
|
||
<text class="info-value">{{ item.applicant }}</text>
|
||
</view>
|
||
<view class="item-info">
|
||
<text class="info-label">申请时间:</text>
|
||
<text class="info-value">{{ item.applyTime }}</text>
|
||
</view>
|
||
<view class="item-info">
|
||
<text class="info-label">业务类型:</text>
|
||
<text class="info-value">{{ item.businessType }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="item-footer">
|
||
<view class="priority" :class="item.priority">
|
||
{{ getPriorityText(item.priority) }}
|
||
</view>
|
||
<view class="item-amount" v-if="item.amount">
|
||
金额:{{ item.amount }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view v-if="filteredApprovalList.length === 0" class="empty-state">
|
||
<view class="empty-icon">📋</view>
|
||
<view class="empty-text">暂无{{ getCurrentTabLabel() }}审批</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted } from "vue";
|
||
import SubHeader from "../components/subHeader.vue";
|
||
|
||
// 响应式数据
|
||
const activeTab = ref('all'); // 当前激活的tab
|
||
|
||
// 审批状态tabs配置
|
||
const approvalTabs = ref([
|
||
{ key: 'all', label: '全部', count: 0 },
|
||
{ key: 'pending', label: '待审批', count: 0 },
|
||
{ key: 'approved', label: '已通过', count: 0 },
|
||
{ key: 'rejected', label: '已拒绝', count: 0 }
|
||
]);
|
||
|
||
// 审批列表数据
|
||
const approvalList = ref([
|
||
{
|
||
id: 1,
|
||
title: '港口作业申请',
|
||
status: 'pending',
|
||
applicant: '张三',
|
||
applyTime: '2024-01-15 09:30',
|
||
businessType: '港口作业',
|
||
priority: 'high',
|
||
amount: '¥50,000'
|
||
},
|
||
{
|
||
id: 2,
|
||
title: '设备维修申请',
|
||
status: 'approved',
|
||
applicant: '李四',
|
||
applyTime: '2024-01-14 14:20',
|
||
businessType: '设备维护',
|
||
priority: 'medium',
|
||
amount: '¥15,000'
|
||
},
|
||
{
|
||
id: 3,
|
||
title: '人员调动申请',
|
||
status: 'rejected',
|
||
applicant: '王五',
|
||
applyTime: '2024-01-13 16:45',
|
||
businessType: '人事管理',
|
||
priority: 'low',
|
||
amount: null
|
||
},
|
||
{
|
||
id: 4,
|
||
title: '采购申请',
|
||
status: 'pending',
|
||
applicant: '赵六',
|
||
applyTime: '2024-01-12 11:15',
|
||
businessType: '采购管理',
|
||
priority: 'high',
|
||
amount: '¥80,000'
|
||
},
|
||
{
|
||
id: 5,
|
||
title: '安全培训申请',
|
||
status: 'approved',
|
||
applicant: '钱七',
|
||
applyTime: '2024-01-11 08:30',
|
||
businessType: '培训管理',
|
||
priority: 'medium',
|
||
amount: '¥5,000'
|
||
}
|
||
]);
|
||
|
||
// 计算属性:根据当前tab过滤列表
|
||
const filteredApprovalList = computed(() => {
|
||
let filteredList = [];
|
||
|
||
if (activeTab.value === 'all') {
|
||
filteredList = approvalList.value;
|
||
} else {
|
||
filteredList = approvalList.value.filter(item => item.status === activeTab.value);
|
||
}
|
||
|
||
// 按照状态排序:待审批、已拒绝、已通过
|
||
const statusOrder = ['pending', 'rejected', 'approved'];
|
||
return filteredList.sort((a, b) => {
|
||
const aIndex = statusOrder.indexOf(a.status);
|
||
const bIndex = statusOrder.indexOf(b.status);
|
||
return aIndex - bIndex;
|
||
});
|
||
});
|
||
|
||
// 更新tabs计数
|
||
const updateTabCounts = () => {
|
||
approvalTabs.value.forEach(tab => {
|
||
if (tab.key === 'all') {
|
||
tab.count = approvalList.value.length;
|
||
} else {
|
||
tab.count = approvalList.value.filter(item => item.status === tab.key).length;
|
||
}
|
||
});
|
||
};
|
||
|
||
// 切换tab
|
||
const switchTab = (tabKey) => {
|
||
activeTab.value = tabKey;
|
||
};
|
||
|
||
// 获取状态文本
|
||
const getStatusText = (status) => {
|
||
const statusMap = {
|
||
pending: '待审批',
|
||
approved: '已通过',
|
||
rejected: '已拒绝'
|
||
};
|
||
return statusMap[status] || status;
|
||
};
|
||
|
||
// 获取优先级文本
|
||
const getPriorityText = (priority) => {
|
||
const priorityMap = {
|
||
high: '高',
|
||
medium: '中',
|
||
low: '低'
|
||
};
|
||
return priorityMap[priority] || priority;
|
||
};
|
||
|
||
// 获取当前tab标签
|
||
const getCurrentTabLabel = () => {
|
||
const currentTab = approvalTabs.value.find(tab => tab.key === activeTab.value);
|
||
return currentTab ? currentTab.label : '';
|
||
};
|
||
|
||
// 查看详情
|
||
const viewDetail = (item) => {
|
||
uni.navigateTo({
|
||
url: `/pages/tasks/approvalDetail?id=${item.id}&title=${encodeURIComponent(item.title)}&status=${item.status}&applicant=${encodeURIComponent(item.applicant)}&applyTime=${encodeURIComponent(item.applyTime)}&businessType=${encodeURIComponent(item.businessType)}&priority=${item.priority}&amount=${item.amount ? encodeURIComponent(item.amount) : ''}`
|
||
});
|
||
};
|
||
|
||
// 头部相关方法
|
||
const goBack = () => {
|
||
uni.navigateBack();
|
||
};
|
||
|
||
const showMoreOptions = () => {
|
||
uni.showActionSheet({
|
||
itemList: ["刷新", "返回首页"],
|
||
success: (res) => {
|
||
switch (res.tapIndex) {
|
||
case 0:
|
||
// 刷新数据
|
||
updateTabCounts();
|
||
uni.showToast({ title: "数据已刷新", icon: "success" });
|
||
break;
|
||
case 1:
|
||
uni.reLaunch({
|
||
url: "/pages/index/index",
|
||
});
|
||
uni.showToast({ title: "已返回工作台", icon: "success" });
|
||
break;
|
||
}
|
||
},
|
||
});
|
||
};
|
||
|
||
// 页面加载时处理URL参数
|
||
onMounted(() => {
|
||
const pages = getCurrentPages();
|
||
const currentPage = pages[pages.length - 1];
|
||
const options = currentPage.options;
|
||
|
||
// 如果URL中有activeTab参数,则设置为对应的tab
|
||
if (options.activeTab) {
|
||
activeTab.value = options.activeTab;
|
||
}
|
||
|
||
// 初始化计数
|
||
updateTabCounts();
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
|
||
// 变量定义
|
||
$border-radius: 16rpx;
|
||
$border-radius-small: 12rpx;
|
||
$border-radius-badge: 20rpx;
|
||
$spacing-small: 12rpx;
|
||
$spacing-medium: 20rpx;
|
||
$spacing-large: 30rpx;
|
||
$transition: all 0.3s ease;
|
||
|
||
.main-data-page {
|
||
background: var(--background);
|
||
min-height: 100vh;
|
||
padding-top: calc(var(--status-bar-height) + 88rpx);
|
||
padding-bottom: 40rpx;
|
||
|
||
.main-container {
|
||
padding: 24rpx;
|
||
}
|
||
}
|
||
|
||
// 审批状态tabs
|
||
.approval-tabs {
|
||
display: flex;
|
||
background: var(--surface);
|
||
border-radius: $border-radius;
|
||
margin-bottom: $spacing-large;
|
||
box-shadow: var(--shadow-md);
|
||
border: 1rpx solid var(--border-light);
|
||
overflow: hidden;
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24rpx 16rpx;
|
||
font-size: 28rpx;
|
||
color: var(--text-secondary);
|
||
background: var(--surface);
|
||
transition: $transition;
|
||
position: relative;
|
||
|
||
&.active {
|
||
background: var(--primary-color);
|
||
color: var(--white);
|
||
font-weight: 600;
|
||
|
||
.tab-badge {
|
||
background: rgba(255, 255, 255, 0.3);
|
||
}
|
||
}
|
||
|
||
.tab-badge {
|
||
background: var(--error);
|
||
color: var(--white);
|
||
font-size: 20rpx;
|
||
padding: 4rpx 8rpx;
|
||
border-radius: $border-radius-badge;
|
||
margin-left: 8rpx;
|
||
min-width: 32rpx;
|
||
text-align: center;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 审批列表
|
||
.approval-list {
|
||
.approval-item {
|
||
background: var(--surface);
|
||
border-radius: $border-radius;
|
||
margin-bottom: $spacing-medium;
|
||
padding: $spacing-large;
|
||
box-shadow: var(--shadow);
|
||
border: 1rpx solid var(--border-light);
|
||
transition: $transition;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
box-shadow: var(--shadow-md);
|
||
background: var(--surface-hover);
|
||
}
|
||
|
||
.item-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: $spacing-medium;
|
||
|
||
.item-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: var(--title-color);
|
||
flex: 1;
|
||
margin-right: $spacing-medium;
|
||
}
|
||
|
||
.item-status {
|
||
padding: 8rpx 16rpx;
|
||
border-radius: $border-radius-badge;
|
||
font-size: 24rpx;
|
||
font-weight: 500;
|
||
white-space: nowrap;
|
||
|
||
&.pending {
|
||
background: var(--warning-light);
|
||
color: var(--warning);
|
||
}
|
||
|
||
&.approved {
|
||
background: var(--success-light);
|
||
color: var(--success);
|
||
}
|
||
|
||
&.rejected {
|
||
background: var(--error-light);
|
||
color: var(--error);
|
||
}
|
||
}
|
||
}
|
||
|
||
.item-content {
|
||
margin-bottom: $spacing-medium;
|
||
|
||
.item-info {
|
||
display: flex;
|
||
margin-bottom: $spacing-small;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.info-label {
|
||
font-size: 26rpx;
|
||
color: var(--text-muted);
|
||
width: 140rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.info-value {
|
||
font-size: 26rpx;
|
||
color: var(--text-color);
|
||
flex: 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
.item-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.priority {
|
||
padding: 6rpx 12rpx;
|
||
border-radius: $border-radius-small;
|
||
font-size: 22rpx;
|
||
font-weight: 500;
|
||
|
||
&.high {
|
||
background: var(--error-light);
|
||
color: var(--error);
|
||
}
|
||
|
||
&.medium {
|
||
background: var(--warning-light);
|
||
color: var(--warning);
|
||
}
|
||
|
||
&.low {
|
||
background: var(--success-light);
|
||
color: var(--success);
|
||
}
|
||
}
|
||
|
||
.item-amount {
|
||
font-size: 26rpx;
|
||
color: var(--orange);
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 空状态
|
||
.empty-state {
|
||
text-align: center;
|
||
padding: 120rpx 60rpx;
|
||
|
||
.empty-icon {
|
||
font-size: 120rpx;
|
||
margin-bottom: $spacing-large;
|
||
}
|
||
|
||
.empty-text {
|
||
font-size: 28rpx;
|
||
color: var(--text-muted);
|
||
}
|
||
}
|
||
|
||
// 支持安全区域的设备
|
||
@supports (padding: max(0px)) {
|
||
.main-data-page {
|
||
padding-top: calc(
|
||
var(--status-bar-height) + 88rpx + env(safe-area-inset-top)
|
||
);
|
||
}
|
||
}
|
||
</style>
|