Files
zhxg_app/pages/finance/special/index.vue

689 lines
16 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="special-aid">
<!-- 申请列表 -->
<view class="app-container">
<!-- 数据列表滚动容器 -->
<scroll-view class="list-container" id="list-container" scroll-y @scrolltolower="handleLoadMore"
lower-threshold="50" enhanced :show-scrollbar="false">
<!-- 初始加载状态 -->
<uni-load-more :status="loading ? 'loading' : 'done'" v-if="loading" class="loading-wrap"></uni-load-more>
<!-- 空数据状态 -->
<view class="empty-state" v-if="!loading && !hasData">
<uni-icons type="empty" size="80" color="#c0c4cc"></uni-icons>
<text class="empty-text">暂无特殊困难资助申请数据</text>
<text class="empty-tip" v-if="roleGroup.includes('学生')">点击右下角"+"按钮提交新申请</text>
</view>
<!-- 数据列表 -->
<view class="card-list" v-if="!loading && hasData">
<view class="apply-card" v-for="(item, index) in validDataList" :key="index" hover-class="card-hover"
:hover-stop-propagation="true">
<!-- 卡片头部 -->
<view class="card-header">
<view class="apply-no">
<text class="label-text">学年</text>
<text class="no-text">{{ getSafeValue(item, 'stuYearName', '无') }}</text>
</view>
<view class="status-wrap">
<view class="status-label" :class="getStatusClass(item)">
{{ getStatusText(item) }}
</view>
</view>
</view>
<!-- 卡片主体折叠面板 -->
<uni-collapse accordion v-model="item.activeCollapse">
<uni-collapse-item title="基本信息" name="basic" class="collapse-item">
<view class="info-grid">
<view class="info-item"><text class="label">学号</text><text
class="value">{{ getSafeValue(item, 'stuNo', '-') }}</text></view>
<view class="info-item"><text class="label">姓名</text><text
class="value">{{ getSafeValue(item, 'stuName', '-') }}</text></view>
<view class="info-item"><text class="label">学院</text><text
class="value">{{ getSafeValue(item, 'deptName', '-') }}</text></view>
<view class="info-item"><text class="label">班级</text><text
class="value">{{ getSafeValue(item, 'className', '-') }}</text></view>
</view>
</uni-collapse-item>
<uni-collapse-item title="申请信息" name="apply" class="collapse-item">
<view class="info-form">
<view class="form-item"><text class="label">困难类型</text><text
class="value">{{ getSafeValue(item, 'hardCondition', '-') }}</text></view>
<!-- <view class="form-item"><text class="label">申请金额</text><text
class="value">{{ getSafeValue(item, 'yearMoney', '-') }} </text></view> -->
<view class="form-item"><text class="label">困难原因</text><text
class="value">{{ getSafeValue(item, 'applyReason', '-') }}</text></view>
</view>
</uni-collapse-item>
<uni-collapse-item title="审核意见" name="approval" class="collapse-item">
<view class="approval-list">
<view class="approval-item">
<text class="approval-node">辅导员审核意见</text>
<text class="approval-result" :class="getReviewClass(item, 'fdyCmt')">
{{ getReviewDetailText(item, 'fdyCmt') }}
</text>
</view>
<view class="approval-item">
<text class="approval-node">学院审核意见</text>
<text class="approval-result" :class="getReviewClass(item, 'deptCmt')">
{{ getReviewDetailText(item, 'deptCmt') }}
</text>
</view>
<view class="approval-item">
<text class="approval-node">学校审核意见</text>
<text class="approval-result" :class="getReviewClass(item, 'xgCmt')">
{{ getReviewDetailText(item, 'xgCmt') }}
</text>
</view>
</view>
</uni-collapse-item>
</uni-collapse>
<!-- 卡片操作区 -->
<view class="card-actions">
<view>
<uni-button type="text" size="mini" @click="detail(item, '修改')"
v-if="item.applyStatus == '10'">
<uni-icons type="refresh" size="14" class="mr-5"></uni-icons>重新提交
</uni-button>
<uni-button type="text" size="mini" @click="detail(item, '修改')"
v-if="item.applyStatus == '1'">
<uni-icons type="edit" size="14" class="mr-5"></uni-icons>修改
</uni-button>
<uni-button type="text" size="mini" @click="handleDelete(item)"
v-if="item.applyStatus == '1'">
<uni-icons type="close" size="14" class="mr-5"></uni-icons>取消申请
</uni-button>
</view>
<view>
<uni-button type="text" size="mini" @click="detail(item, '详情')" class="detail-btn"
:disabled="!getSafeValue(item, 'id')">
<uni-icons type="eye" size="14" class="mr-5"></uni-icons>查看
</uni-button>
</view>
</view>
</view>
</view>
<!-- 加载更多状态 -->
<view class="load-more-wrap" v-if="hasData">
<uni-load-more :status="loadingMore ? 'loading' : (hasMore ? 'more' : 'nomore')"
:content-text="loadMoreText"></uni-load-more>
</view>
</scroll-view>
</view>
<!-- 添加申请按钮 -->
<view class="add" @click="applySpecial" v-if="roleGroup.includes('学生')">{{ '+' }}</view>
</view>
</template>
<script>
import { listOwn, delApply, reApply } from '@/api/finance/special';
import { getUserProfile } from '@/api/system/user';
export default {
name: "SpecialAidList",
data() {
return {
// 加载状态
loading: true,
loadingMore: false,
hasMore: true,
// 总数据量
totalCount: 0,
// 原始数据
specialApplyList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 5
},
// 用户角色
roleGroup: '',
user: {},
// 加载更多文本
loadMoreText: {
contentdown: '上拉加载更多',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了'
}
};
},
computed: {
// 过滤后的有效数据列表
validDataList() {
return this.specialApplyList.filter(item => {
return item !== null && item !== undefined && typeof item === 'object';
}).map(item => {
if (!item.hasOwnProperty('activeCollapse')) {
item.activeCollapse = 'basic';
}
return item;
});
},
// 是否有有效数据
hasData() {
return this.validDataList.length > 0;
}
},
onShow() {
this.getUser();
},
methods: {
/** 安全取值方法 */
getSafeValue(obj, key, defaultValue = '') {
if (!obj || typeof obj !== 'object') return defaultValue;
return obj[key] !== undefined && obj[key] !== null ? obj[key] : defaultValue;
},
/** 获取状态样式类 */
getStatusClass(item) {
const status = this.getSafeValue(item, 'applyStatus');
const typeMap = {
'1': 'status-warning',
'2': 'status-success',
'3': 'status-success',
'4': 'status-success',
'5': 'status-success',
'10': 'status-error'
};
return typeMap[status] || 'status-default';
},
/** 获取状态文本 */
getStatusText(item) {
const status = this.getSafeValue(item, 'applyStatus');
const statusMap = {
'1': '待审核',
'2': '辅导员审核通过',
'3': '学院审核通过',
'4': '学校审核通过',
'5': '审核通过',
'10': '已驳回'
};
return statusMap[status] || '未知状态';
},
/** 获取审核意见样式类 */
getReviewClass(item, type = 'fdyCmt') {
const reviewResult = this.getSafeValue(item, type);
if (!reviewResult) return 'status-default';
return 'status-success';
},
/** 获取详细审核意见文本 */
getReviewDetailText(item, type = 'fdyCmt') {
const reviewResult = this.getSafeValue(item, type);
if (!reviewResult) return '未审核';
return reviewResult;
},
/** 时间格式化 */
parseTime(time, format = '{y}-{m}-{d}') {
if (!time) return '';
try {
const date = new Date(time);
if (isNaN(date.getTime())) return '';
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return format.replace('{y}', year).replace('{m}', month).replace('{d}', day);
} catch (error) {
return '';
}
},
/** 查询数据 */
getList(isRefresh = false) {
if (isRefresh) {
this.loading = true;
this.hasMore = true;
this.queryParams.pageNum = 1;
this.specialApplyList = [];
} else {
this.loadingMore = true;
}
listOwn(this.queryParams).then(response => {
const res = response || {};
const newData = Array.isArray(res.rows) ? res.rows : [];
this.totalCount = Number(res.total) || 0;
if (isRefresh) {
this.specialApplyList = newData;
} else {
this.specialApplyList = [...this.specialApplyList, ...newData];
}
// 更新状态
this.loading = false;
this.loadingMore = false;
this.hasMore = this.specialApplyList.length < this.totalCount;
}).catch((error) => {
console.error('数据加载失败:', error);
this.loading = false;
this.loadingMore = false;
uni.showToast({
title: '数据加载失败',
icon: 'none'
});
});
},
/** 获取用户信息 */
getUser() {
getUserProfile().then(response => {
const res = response || {};
this.user = res.data || {};
this.roleGroup = res.roleGroup || '';
// 获取申请列表
this.getList(true);
}).catch((error) => {
console.error('用户信息获取失败:', error);
this.loading = false;
uni.showToast({
title: '用户信息加载失败',
icon: 'none'
});
});
},
/** 加载更多 */
handleLoadMore() {
if (this.loadingMore || !this.hasMore) return;
this.queryParams.pageNum += 1;
this.getList(false);
},
/** 查看详情 */
detail(item, text) {
const id = this.getSafeValue(item, 'id');
if (!id) {
uni.showToast({
title: '数据异常,无法查看详情',
icon: 'none'
});
return;
}
// 使用本地存储传递item数据到详情页面避免url长度限制
uni.setStorageSync('specialApplyItem', item);
if (text == '详情') {
uni.navigateTo({
url: `/pages/finance/special/apply?id=${id}&type=detail`
});
} else {
uni.navigateTo({
url: `/pages/finance/special/apply?id=${id}`
});
}
},
/** 删除申请 */
handleDelete(item) {
uni.showModal({
title: '确认删除',
content: '确定要删除该申请吗?',
success: (res) => {
if (res.confirm) {
delApply(item.id).then(() => {
uni.showToast({
title: '删除成功',
icon: 'success'
});
this.getList(true);
}).catch(() => {
uni.showToast({
title: '删除失败',
icon: 'none'
});
});
}
}
});
},
// 跳转到申请页面
applySpecial() {
uni.navigateTo({
url: './apply'
});
},
// 撤回申请
handleRevoke(item) {
uni.showModal({
title: '确认撤回',
content: '确定要撤回该申请吗?',
success: (res) => {
if (res.confirm) {
// 调用撤回接口
reApply(item).then(response => {
const res = response || {};
if (res.code === 200 || res.code === 0) {
uni.showToast({
title: '撤回成功',
icon: 'success'
});
this.getList(true);
} else {
uni.showToast({
title: res.msg || '撤回失败',
icon: 'none'
});
}
}).catch(error => {
console.error('撤回申请失败:', error);
uni.showToast({
title: error.response?.data?.msg || error.message || '撤回失败',
icon: 'none'
});
});
}
}
});
}
}
}
</script>
<style scoped>
.special-aid {
background-color: #F3F4F6;
min-height: 100vh;
padding-bottom: 20rpx;
}
.page-header {
background-color: #4A90E2;
color: white;
padding: 30rpx 20rpx;
text-align: center;
.title {
font-size: 36rpx;
font-weight: bold;
}
}
.app-container {
padding-bottom: 10rpx;
}
.list-container {
width: 100%;
min-height: calc(100vh - 300rpx);
}
.loading-wrap {
padding: 20rpx;
text-align: center;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
color: #c0c4cc;
}
.empty-text {
margin-top: 20rpx;
font-size: 28rpx;
}
.empty-tip {
margin-top: 10rpx;
font-size: 24rpx;
color: #909399;
}
.card-list {
width: 100%;
padding: 5px 15px 0px;
}
.apply-card {
background-color: white;
margin-bottom: 10px;
border-radius: 10px;
overflow: hidden;
}
.card-hover {
opacity: 0.8;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 24rpx;
border-bottom: 1px solid #f0f0f0;
}
.apply-no {
display: flex;
align-items: center;
}
.label-text {
font-size: 26rpx;
color: #606266;
margin-right: 10rpx;
}
.no-text {
font-size: 28rpx;
color: #303133;
font-weight: 500;
}
.status-wrap {
display: flex;
align-items: center;
gap: 10rpx;
}
.status-label {
padding: 4rpx 12rpx;
border-radius: 10rpx;
font-size: 22rpx;
color: white;
}
.status-info {
background-color: #909399;
}
.status-warning {
background-color: #e6a23c;
}
.status-success {
background-color: #67c23a;
}
.status-error {
background-color: #f56c6c;
}
.status-default {
background-color: #909399;
}
.collapse-item {
padding: 0;
}
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15rpx;
padding: 20rpx 24rpx;
}
.info-item {
display: flex;
align-items: center;
}
.info-item .label {
font-size: 26rpx;
color: #606266;
width: 100rpx;
}
.info-item .value {
font-size: 26rpx;
color: #303133;
flex: 1;
}
.info-form {
padding: 20rpx 24rpx;
}
.form-item {
display: flex;
align-items: flex-start;
margin-bottom: 15rpx;
}
.form-item .label {
font-size: 26rpx;
color: #606266;
width: 140rpx;
padding-top: 5rpx;
}
.form-item .value {
font-size: 26rpx;
color: #303133;
flex: 1;
word-break: break-word;
}
.split-text {
margin: 0 10rpx;
color: #909399;
}
.approval-list {
padding: 20rpx 24rpx;
}
.approval-item {
margin-bottom: 15rpx;
}
.approval-item:last-child {
margin-bottom: 0;
}
.approval-node {
font-size: 26rpx;
color: #606266;
margin-right: 10rpx;
}
.approval-result {
font-size: 26rpx;
padding: 4rpx 12rpx;
border-radius: 10rpx;
color: white;
}
.approval-time {
font-size: 24rpx;
color: #909399;
margin-left: 10rpx;
}
.approval-remark {
display: block;
font-size: 24rpx;
color: #606266;
margin-top: 5rpx;
margin-left: 100rpx;
}
.empty-approval {
padding: 20rpx 24rpx;
color: #909399;
font-size: 26rpx;
text-align: center;
}
.card-actions {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 24rpx;
border-top: 1px solid #f0f0f0;
}
.detail-btn {
color: #1890FF;
}
.load-more-wrap {
padding: 20rpx;
text-align: center;
}
.add {
position: fixed;
right: 30rpx;
bottom: 30rpx;
width: 80rpx;
height: 80rpx;
background-color: #1890FF;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 48rpx;
box-shadow: 0 4rpx 20rpx rgba(24, 144, 255, 0.3);
}
.info-area {
margin: 20rpx;
background-color: white;
border-radius: 10rpx;
padding: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.info-header {
margin-bottom: 20rpx;
.info-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
}
.info-content {
.info-text {
display: block;
font-size: 26rpx;
color: #666;
margin-bottom: 15rpx;
line-height: 1.5;
}
}
}
</style>