2025-09-15 22:40:32 +08:00

326 lines
7.9 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>
<view class="approval-progress">
<view class="progress-title">
<text class="applicant-name">审批进度</text>
</view>
<view class="divider"></view>
<view class="progress-list" v-if="approvalList.length > 0">
<view class="progress-item" v-for="(approver, index) in approvalList" :key="index">
<view class="progress-item-row">
<view class="item-avatar">
<image
:src="approver.avatar || '/static/base/home/11222.png'"
class="w-full h-full"
></image>
</view>
<view class="item-middle">
<text class="item-name">{{ approver.userName }}</text>
<text class="item-detail">{{ getSpTypeText(approver.spType) }}</text>
</view>
<view class="item-right">
<text class="item-time" v-if="approver.approveTime">{{ formatTime(approver.approveTime) }}</text>
<text class="item-status" :class="getStatusClass(approver.approveStatus)">
{{ getStatusText(approver.spType, approver.approveStatus) }}
</text>
</view>
</view>
<view class="progress-item-line" v-if="index < approvalList.length - 1"></view>
</view>
</view>
<view class="empty-state" v-else>
<view class="empty-icon">
<uni-icons type="info" size="40" color="#999"></uni-icons>
</view>
<view class="empty-text">暂无审批进度信息</view>
<view class="empty-subtext">可能审批流程尚未启动或数据加载失败</view>
<view class="retry-button" @click="loadApprovalProcess" v-if="hasError">
<text class="retry-text">重新加载</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import dayjs from "dayjs";
import { getByYwIdAndYwTypeApi } from "@/api/base/lcglSpApi";
// 接收外部传入属性
const props = withDefaults(defineProps<{
ywId: string,
ywType: string,
showSqr: boolean,
showSpr: boolean,
showCsr: boolean,
}>(), {
ywId: '',
ywType: '',
showSqr: true,
showSpr: true,
showCsr: false
});
// 审批流程数据
const approvalList = ref<any[]>([]);
// 错误状态标识
const hasError = ref(false);
// 获取审批流程
const loadApprovalProcess = async () => {
if (!props.ywId || !props.ywType) return;
try {
// 重置错误状态
hasError.value = false;
// 调用后端API获取审批流程数据
const res = await getByYwIdAndYwTypeApi(props.ywId, props.ywType);
approvalList.value = [];
if (res.resultCode === 1 && res.result) {
// 转换为前端显示格式后端已按sort字段排序
const list = res.result.map((item: any) => ({
userName: item.userName || getDefaultUserName(item.spType),
spType: item.spType,
approveStatus: item.approveStatus,
approveTime: item.approveTime,
approveRemark: item.approveRemark,
avatar: item.avatar || '/static/base/home/11222.png'
}));
for (let item of list) {
if ((item.spType === 'SQ' && !props.showSqr)
|| (item.spType === 'SP' && !props.showSpr)
|| (item.spType === 'CC' && !props.showCsr)) {
continue;
}
approvalList.value.push(item);
}
} else {
hasError.value = true;
}
} catch (error) {
console.error('获取审批流程失败:', error);
approvalList.value = [];
hasError.value = true;
}
};
// 获取默认用户名
const getDefaultUserName = (spType: string) => {
switch (spType) {
case 'SQ': return '申请人';
case 'SP': return '审批人';
case 'CC': return '抄送人';
case 'DK': return '代课老师';
case 'JWC': return '教科处';
default: return '未知';
}
};
// 获取审批类型文本
const getSpTypeText = (spType: string) => {
switch (spType) {
case 'SQ': return '申请人';
case 'SP': return '审批人';
case 'CC': return '抄送人';
case 'DK': return '代课老师';
case 'JWC': return '教科处';
default: return '';
}
};
// 获取状态文本
const getStatusText = (spType: string, status: string) => {
switch (status) {
case 'apply': return '已申请';
case 'pending': return spType === 'CC' ? '待抄送' : '待处理';
case 'approved': return spType === 'CC' ? '已抄送' : '已同意';
case 'rejected': return '已拒绝';
case 'cc_sent': return '已抄送';
default: return '未知';
}
};
// 获取状态样式类
const getStatusClass = (status: string) => {
switch (status) {
case 'pending': return 'status-pending';
case 'approved': return 'status-approved';
case 'rejected': return 'status-rejected';
case 'cc_sent': return 'status-cc';
default: return '';
}
};
// 格式化时间
const formatTime = (time: string | Date) => {
if (!time) return '';
return dayjs(time).format('YYYY-MM-DD HH:mm');
};
// 监听ywId变化
watch(() => props.ywId, (newVal) => {
if (newVal) {
loadApprovalProcess();
}
});
// 初始化
if (props.ywId) {
loadApprovalProcess();
}
</script>
<style lang="scss" scoped>
.approval-progress {
margin: 15px;
background-color: #fff;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
.progress-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
.applicant-name {
font-size: 16px;
font-weight: bold;
color: #333;
}
}
.divider {
height: 1px;
background-color: #eee;
margin-bottom: 15px;
}
.progress-list {
display: flex;
flex-direction: column;
.progress-item {
position: relative;
.progress-item-row {
display: flex;
align-items: center;
padding: 10px 0;
.item-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 12px;
flex-shrink: 0;
}
.item-middle {
flex: 1;
display: flex;
flex-direction: column;
.item-name {
font-size: 14px;
color: #333;
font-weight: 500;
margin-bottom: 4px;
}
.item-detail {
font-size: 12px;
color: #999;
}
}
.item-right {
display: flex;
flex-direction: column;
align-items: flex-end;
.item-time {
font-size: 12px;
color: #999;
margin-bottom: 4px;
}
.item-status {
font-size: 12px;
padding: 2px 8px;
border-radius: 10px;
&.status-pending {
background-color: #fff7e6;
color: #fa8c16;
}
&.status-approved {
background-color: #f6ffed;
color: #52c41a;
}
&.status-rejected {
background-color: #fff2f0;
color: #ff4d4f;
}
&.status-cc {
background-color: #f0f5ff;
color: #1890ff;
}
}
}
}
.progress-item-line {
height: 20px;
width: 2px;
background-color: #e8e8e8;
margin-left: 19px;
margin-top: -10px;
margin-bottom: -10px;
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
.empty-icon {
margin-bottom: 16px;
}
.empty-text {
font-size: 16px;
color: #333;
margin-bottom: 8px;
font-weight: 500;
}
.empty-subtext {
font-size: 14px;
color: #999;
margin-bottom: 20px;
text-align: center;
}
.retry-button {
padding: 8px 24px;
background-color: #007AFF;
border-radius: 4px;
cursor: pointer;
.retry-text {
color: #FFFFFF;
font-size: 14px;
}
}
}
}
</style>