1027 lines
33 KiB
Vue
1027 lines
33 KiB
Vue
<template>
|
||
<view class="work-study-container">
|
||
<!-- 顶部导航 -->
|
||
<u-navbar title="勤工俭学" :border-bottom="false" bg-color="#0051d9" title-color="#fff">
|
||
<view slot="left" @click="goBack">
|
||
<u-icon name="arrow-left" color="#fff" size="22"></u-icon>
|
||
</view>
|
||
</u-navbar>
|
||
|
||
<!-- 搜索栏 -->
|
||
<view class="search-container">
|
||
<u-search
|
||
v-model="searchKeyword"
|
||
placeholder="搜索岗位名称或联系老师"
|
||
:show-action="false"
|
||
@search="handleSearch"
|
||
@custom="handleSearch"
|
||
bg-color="#f5f6fa"
|
||
shape="round"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 标签页 -->
|
||
<view class="tabs-container">
|
||
<u-tabs
|
||
:list="tabsList"
|
||
:current="currentTab"
|
||
@change="onTabChange"
|
||
active-color="#1890ff"
|
||
inactive-color="#999"
|
||
bar-width="40"
|
||
bar-height="4"
|
||
font-size="30"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 岗位列表 -->
|
||
<view class="list-container" v-if="currentTab === 0">
|
||
<!-- 筛选条件 -->
|
||
<view class="filter-bar" v-if="showFilter">
|
||
<view class="filter-item">
|
||
<view @click="showScopePicker = true">
|
||
<u-input
|
||
v-model="scopeText"
|
||
placeholder="选择发布范围"
|
||
readonly
|
||
border="surround"
|
||
suffix-icon="arrow-down"
|
||
/>
|
||
</view>
|
||
</view>
|
||
<view class="filter-item">
|
||
<view @click="showStatusPicker = true">
|
||
<u-input
|
||
v-model="statusText"
|
||
placeholder="选择岗位状态"
|
||
readonly
|
||
border="surround"
|
||
suffix-icon="arrow-down"
|
||
/>
|
||
</view>
|
||
</view>
|
||
<view class="filter-actions">
|
||
<u-button type="primary" size="small" @click="handleFilter" :loading="loading">
|
||
筛选
|
||
</u-button>
|
||
<u-button
|
||
type="default"
|
||
size="small"
|
||
@click="resetFilter"
|
||
style="margin-left: 10rpx"
|
||
>
|
||
重置
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 筛选按钮 -->
|
||
<view class="action-bar">
|
||
<u-button
|
||
type="default"
|
||
size="small"
|
||
:icon="showFilter ? 'arrow-up' : 'arrow-down'"
|
||
@click="showFilter = !showFilter"
|
||
>
|
||
{{ showFilter ? '收起筛选' : '展开筛选' }}
|
||
</u-button>
|
||
<u-button
|
||
type="primary"
|
||
size="small"
|
||
icon="reload"
|
||
@click="refreshData"
|
||
:loading="refreshing"
|
||
>
|
||
刷新
|
||
</u-button>
|
||
</view>
|
||
|
||
<!-- 岗位卡片列表 -->
|
||
<view class="list-content" v-if="positionList.length > 0">
|
||
<view
|
||
class="position-card"
|
||
v-for="item in positionList"
|
||
:key="item.id"
|
||
@click="handleViewDetail(item)"
|
||
>
|
||
<!-- 卡片头部 -->
|
||
<view class="card-header">
|
||
<view class="position-info">
|
||
<view class="position-name">{{ item.positionName }}</view>
|
||
<view class="position-type">
|
||
{{ item.positionScopeName || '未设置' }}
|
||
</view>
|
||
</view>
|
||
<view class="status-badge">
|
||
<u-tag
|
||
:text="item.statusName || '未知'"
|
||
:type="getStatusType(item.status)"
|
||
size="mini"
|
||
shape="circle"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 岗位信息 -->
|
||
<view class="card-content">
|
||
<view class="info-row">
|
||
<u-icon name="account" size="18" color="#666" />
|
||
<text class="info-text">需求人数:{{ item.requiredCount }}人</text>
|
||
<text class="info-text current-count">
|
||
已招录:{{ item.currentCount || 0 }}人
|
||
</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<u-icon name="clock" size="18" color="#666" />
|
||
<text class="info-text">工作时间:{{ item.workTime }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<u-icon name="map" size="18" color="#666" />
|
||
<text class="info-text">联系老师:{{ item.contactTeacher }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<u-icon name="phone" size="18" color="#666" />
|
||
<text class="info-text">联系电话:{{ item.contactPhone }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<u-icon name="calendar" size="18" color="#666" />
|
||
<text class="info-text">
|
||
有效期:{{ item.startDate }} 至 {{ item.endDate }}
|
||
</text>
|
||
</view>
|
||
<!-- 申请状态信息 -->
|
||
<view class="info-row" v-if="getPositionApplicationStatus(item)">
|
||
<u-icon name="checkmark-circle" size="18" color="#1890ff" />
|
||
<text class="info-text" style="color: #1890ff">
|
||
我的申请:{{ getPositionApplicationStatus(item) }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮 -->
|
||
<view class="card-actions">
|
||
<u-button
|
||
type="default"
|
||
size="small"
|
||
@click.stop="handleViewDetail($event, item)"
|
||
>
|
||
查看详情
|
||
</u-button>
|
||
<u-button
|
||
type="primary"
|
||
size="small"
|
||
@click.stop="handleApply($event, item)"
|
||
:disabled="!canApply(item)"
|
||
style="margin-left: 20rpx"
|
||
>
|
||
{{ getApplyButtonText(item) }}
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view class="empty-state" v-else-if="!loading">
|
||
<u-empty text="暂无岗位信息" icon="search" :show="true" />
|
||
</view>
|
||
|
||
<!-- 加载更多 -->
|
||
<view class="load-more" v-if="hasMore && positionList.length > 0">
|
||
<u-loadmore :status="loadMoreStatus" :load-text="loadText" @loadmore="loadMore" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 我的申请列表 -->
|
||
<view class="list-container" v-if="currentTab === 1">
|
||
<view class="list-content" v-if="applicationList.length > 0">
|
||
<view
|
||
class="application-card"
|
||
v-for="item in applicationList"
|
||
:key="item.id"
|
||
@click="handleViewApplication(item)"
|
||
>
|
||
<!-- 申请信息 -->
|
||
<view class="card-header">
|
||
<view class="application-info">
|
||
<view class="position-name">{{ item.positionName }}</view>
|
||
<view class="apply-time">申请时间:{{ item.createTime }}</view>
|
||
</view>
|
||
<view class="status-badge">
|
||
<u-tag
|
||
:text="getApplicationStatusText(item)"
|
||
:type="getApplicationStatusType(item)"
|
||
size="mini"
|
||
shape="circle"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 申请状态 -->
|
||
<view class="card-content">
|
||
<view class="info-row">
|
||
<u-icon name="file-text" size="18" color="#666" />
|
||
<text class="info-text">
|
||
申请状态:{{ getApplicationStatusText(item) }}
|
||
</text>
|
||
</view>
|
||
<view class="info-row" v-if="item.collegeReviewStatus">
|
||
<u-icon name="checkmark-circle" size="18" color="#666" />
|
||
<text class="info-text">
|
||
学院审核:{{ getReviewStatusText(item.collegeReviewStatus) }}
|
||
</text>
|
||
</view>
|
||
<view class="info-row" v-if="item.finalReviewStatus">
|
||
<u-icon name="checkmark-circle" size="18" color="#666" />
|
||
<text class="info-text">
|
||
学生处审核:{{ getReviewStatusText(item.finalReviewStatus) }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮 -->
|
||
<view class="card-actions">
|
||
<u-button
|
||
type="default"
|
||
size="small"
|
||
@click.stop="handleViewApplication($event, item)"
|
||
>
|
||
查看详情
|
||
</u-button>
|
||
<u-button
|
||
type="warning"
|
||
size="small"
|
||
@click.stop="handleCancelApplication($event, item)"
|
||
v-if="canCancelApplication(item)"
|
||
style="margin-left: 20rpx"
|
||
>
|
||
撤销申请
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view class="empty-state" v-else-if="!loading">
|
||
<u-empty text="暂无申请记录" icon="file-text" :show="true" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 发布范围选择器 -->
|
||
<u-picker
|
||
:show="showScopePicker"
|
||
:columns="scopeOptions"
|
||
keyName="label"
|
||
@confirm="onScopeConfirm"
|
||
@cancel="showScopePicker = false"
|
||
/>
|
||
|
||
<!-- 状态选择器 -->
|
||
<u-picker
|
||
:show="showStatusPicker"
|
||
:columns="statusOptions"
|
||
keyName="label"
|
||
@confirm="onStatusConfirm"
|
||
@cancel="showStatusPicker = false"
|
||
/>
|
||
|
||
<!-- 加载状态 -->
|
||
<u-loading-page :loading="loading" loading-text="加载中..." />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
getAvailablePositions,
|
||
getMyApplications,
|
||
cancelApplication,
|
||
getCurrentStudentInfo,
|
||
getStudentApplicationStatusList,
|
||
} from '@/api/workStudy.js';
|
||
|
||
export default {
|
||
name: 'WorkStudyIndex',
|
||
data() {
|
||
return {
|
||
// 搜索关键词
|
||
searchKeyword: '',
|
||
|
||
// 标签页
|
||
currentTab: 0, // 确保是数字类型
|
||
tabsList: [{ name: '可申请岗位' }, { name: '我的申请' }],
|
||
|
||
// 筛选条件
|
||
showFilter: false,
|
||
showScopePicker: false,
|
||
showStatusPicker: false,
|
||
scopeText: '',
|
||
statusText: '',
|
||
|
||
// 选择器选项
|
||
scopeOptions: [
|
||
[
|
||
{ label: '全部', value: '' },
|
||
{ label: '本学院', value: 'COLLEGE' },
|
||
{ label: '全校', value: 'UNIVERSITY' },
|
||
],
|
||
],
|
||
statusOptions: [
|
||
[
|
||
{ label: '全部', value: '' },
|
||
{ label: '已发布', value: 'PUBLISHED' },
|
||
{ label: '招录中', value: 'RECRUITING' },
|
||
{ label: '已暂停', value: 'SUSPENDED' },
|
||
],
|
||
],
|
||
|
||
// 查询参数
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
positionName: '',
|
||
positionScope: '',
|
||
status: '',
|
||
},
|
||
|
||
// 列表数据
|
||
positionList: [],
|
||
applicationList: [],
|
||
|
||
// 分页状态
|
||
hasMore: true,
|
||
loadMoreStatus: 'loadmore',
|
||
loadText: {
|
||
loadmore: '点击或上拉加载更多',
|
||
loading: '正在加载...',
|
||
nomore: '没有更多了',
|
||
},
|
||
|
||
// 加载状态
|
||
loading: false,
|
||
refreshing: false,
|
||
|
||
// 用户信息
|
||
studentInfo: null,
|
||
|
||
// 学生申请状态列表(用于判断申请状态)
|
||
studentApplications: [],
|
||
};
|
||
},
|
||
|
||
onLoad() {
|
||
// 确保currentTab是数字类型
|
||
this.currentTab = Number(this.currentTab);
|
||
this.initData();
|
||
},
|
||
|
||
onReady() {
|
||
// 页面渲染完成后再次确保数据类型正确
|
||
this.$nextTick(() => {
|
||
this.currentTab = Number(this.currentTab);
|
||
});
|
||
},
|
||
|
||
onShow() {
|
||
// 如果是从申请页面返回,刷新数据
|
||
if (this.currentTab === 1) {
|
||
this.loadMyApplications(true);
|
||
}
|
||
},
|
||
|
||
// 下拉刷新
|
||
onPullDownRefresh() {
|
||
this.refreshData();
|
||
},
|
||
|
||
// 上拉加载更多
|
||
onReachBottom() {
|
||
if (this.currentTab === 0 && this.hasMore && !this.loading) {
|
||
this.loadMore();
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// 返回上一页
|
||
goBack() {
|
||
uni.navigateBack();
|
||
},
|
||
|
||
// 初始化数据
|
||
async initData() {
|
||
try {
|
||
// 获取学生信息
|
||
await this.loadStudentInfo();
|
||
// 获取学生申请状态列表
|
||
await this.loadStudentApplications();
|
||
// 加载岗位列表
|
||
await this.loadPositionList(true);
|
||
} catch (error) {
|
||
console.error('初始化数据失败:', error);
|
||
uni.showToast({
|
||
title: '加载数据失败',
|
||
icon: 'none',
|
||
});
|
||
}
|
||
},
|
||
|
||
// 获取学生信息
|
||
async loadStudentInfo() {
|
||
try {
|
||
const response = await getCurrentStudentInfo();
|
||
if (response.code === 200) {
|
||
this.studentInfo = response.data;
|
||
}
|
||
} catch (error) {
|
||
console.error('获取学生信息失败:', error);
|
||
}
|
||
},
|
||
|
||
// 加载学生申请状态列表
|
||
async loadStudentApplications() {
|
||
try {
|
||
const response = await getStudentApplicationStatusList();
|
||
if (response.code === 200) {
|
||
this.studentApplications = response.data || [];
|
||
}
|
||
} catch (error) {
|
||
console.error('获取申请状态失败:', error);
|
||
}
|
||
},
|
||
|
||
// 加载岗位列表
|
||
async loadPositionList(reset = false) {
|
||
if (this.loading) return;
|
||
|
||
if (reset) {
|
||
this.queryParams.pageNum = 1;
|
||
this.positionList = [];
|
||
this.hasMore = true;
|
||
}
|
||
|
||
this.loading = true;
|
||
this.loadMoreStatus = 'loading';
|
||
|
||
try {
|
||
const response = await getAvailablePositions(this.queryParams);
|
||
|
||
if (response.code === 200) {
|
||
const newList = response.rows || [];
|
||
|
||
if (reset) {
|
||
this.positionList = newList;
|
||
} else {
|
||
this.positionList = [...this.positionList, ...newList];
|
||
}
|
||
|
||
// 检查是否还有更多数据
|
||
if (newList.length < this.queryParams.pageSize) {
|
||
this.hasMore = false;
|
||
this.loadMoreStatus = 'nomore';
|
||
} else {
|
||
this.loadMoreStatus = 'loadmore';
|
||
}
|
||
} else {
|
||
throw new Error(response.msg || '获取岗位列表失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('加载岗位列表失败:', error);
|
||
uni.showToast({
|
||
title: error.message || '加载失败',
|
||
icon: 'none',
|
||
});
|
||
this.loadMoreStatus = 'loadmore';
|
||
} finally {
|
||
this.loading = false;
|
||
uni.stopPullDownRefresh();
|
||
}
|
||
},
|
||
|
||
// 加载我的申请列表
|
||
async loadMyApplications(reset = false) {
|
||
if (this.loading) return;
|
||
|
||
this.loading = true;
|
||
|
||
try {
|
||
const response = await getMyApplications();
|
||
|
||
if (response.code === 200) {
|
||
this.applicationList = response.data || [];
|
||
} else {
|
||
throw new Error(response.msg || '获取申请列表失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('加载申请列表失败:', error);
|
||
uni.showToast({
|
||
title: error.message || '加载失败',
|
||
icon: 'none',
|
||
});
|
||
} finally {
|
||
this.loading = false;
|
||
uni.stopPullDownRefresh();
|
||
}
|
||
},
|
||
|
||
// 标签页切换
|
||
onTabChange(index) {
|
||
// 确保index是数字类型
|
||
const tabIndex = typeof index === 'object' ? index.index : index;
|
||
this.currentTab = Number(tabIndex);
|
||
|
||
// 延迟执行,确保DOM渲染完成
|
||
this.$nextTick(() => {
|
||
if (this.currentTab === 0) {
|
||
this.loadPositionList(true);
|
||
} else if (this.currentTab === 1) {
|
||
this.loadMyApplications(true);
|
||
}
|
||
});
|
||
},
|
||
|
||
// 搜索
|
||
handleSearch() {
|
||
this.queryParams.positionName = this.searchKeyword;
|
||
this.loadPositionList(true);
|
||
},
|
||
|
||
// 筛选
|
||
handleFilter() {
|
||
this.loadPositionList(true);
|
||
},
|
||
|
||
// 重置筛选
|
||
resetFilter() {
|
||
this.queryParams.positionScope = '';
|
||
this.queryParams.status = '';
|
||
this.scopeText = '';
|
||
this.statusText = '';
|
||
this.searchKeyword = '';
|
||
this.queryParams.positionName = '';
|
||
this.loadPositionList(true);
|
||
},
|
||
|
||
// 刷新数据
|
||
async refreshData() {
|
||
this.refreshing = true;
|
||
try {
|
||
// 同时刷新学生申请状态
|
||
await this.loadStudentApplications();
|
||
|
||
if (this.currentTab === 0) {
|
||
await this.loadPositionList(true);
|
||
} else {
|
||
await this.loadMyApplications(true);
|
||
}
|
||
} catch (error) {
|
||
console.error('刷新数据失败:', error);
|
||
} finally {
|
||
this.refreshing = false;
|
||
}
|
||
},
|
||
|
||
// 加载更多
|
||
loadMore() {
|
||
if (!this.hasMore || this.loading) return;
|
||
|
||
this.queryParams.pageNum++;
|
||
this.loadPositionList(false);
|
||
},
|
||
|
||
// 查看岗位详情
|
||
handleViewDetail(event, item) {
|
||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
|
||
if (!item && typeof event === 'object' && event.id) {
|
||
item = event;
|
||
}
|
||
uni.navigateTo({
|
||
url: `/pages/workStudy/detail?id=${item.id}`,
|
||
});
|
||
},
|
||
|
||
// 申请岗位(参考web端实现)
|
||
handleApply(event, position) {
|
||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是position
|
||
if (!position && typeof event === 'object' && event.id) {
|
||
position = event;
|
||
}
|
||
|
||
const application = this.studentApplications.find(
|
||
(app) => app.positionId === position.id,
|
||
);
|
||
|
||
// 如果已有申请且状态为已提交或审核中,跳转到申请管理页面
|
||
if (
|
||
application &&
|
||
['submitted', 'college_reviewing', 'final_reviewing'].includes(application.status)
|
||
) {
|
||
uni.switchTab({
|
||
url: '/pages/workStudy/index',
|
||
});
|
||
// 切换到"我的申请"标签页
|
||
this.currentTab = 1;
|
||
this.onTabChange(1);
|
||
return;
|
||
}
|
||
|
||
// 如果已录用,不允许操作
|
||
if (application && application.status === 'approved') {
|
||
uni.showToast({
|
||
title: '您已被该岗位录用',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!this.canApply(position)) {
|
||
uni.showToast({
|
||
title: '该岗位当前不可申请',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
uni.navigateTo({
|
||
url: `/pages/workStudy/apply?positionId=${position.id}`,
|
||
});
|
||
},
|
||
|
||
// 查看申请详情
|
||
handleViewApplication(event, item) {
|
||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
|
||
if (!item && typeof event === 'object' && event.id) {
|
||
item = event;
|
||
}
|
||
uni.navigateTo({
|
||
url: `/pages/workStudy/applicationDetail?id=${item.id}`,
|
||
});
|
||
},
|
||
|
||
// 撤销申请
|
||
async handleCancelApplication(event, item) {
|
||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
|
||
if (!item && typeof event === 'object' && event.id) {
|
||
item = event;
|
||
}
|
||
try {
|
||
const { confirm } = await uni.showModal({
|
||
title: '确认撤销',
|
||
content: '确定要撤销此申请吗?',
|
||
showCancel: true,
|
||
});
|
||
|
||
if (!confirm) return; // 用户取消
|
||
|
||
const response = await cancelApplication(item.id);
|
||
if (response.code === 200) {
|
||
uni.showToast({
|
||
title: '撤销成功',
|
||
icon: 'success',
|
||
});
|
||
this.loadMyApplications(true);
|
||
} else {
|
||
throw new Error(response.msg || '撤销失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('撤销申请失败:', error);
|
||
uni.showToast({
|
||
title: error.message || '撤销失败',
|
||
icon: 'none',
|
||
});
|
||
}
|
||
},
|
||
|
||
// 发布范围选择确认
|
||
onScopeConfirm(e) {
|
||
const index = e.indexs[0];
|
||
const selected = this.scopeOptions[0][index];
|
||
this.queryParams.positionScope = selected.value;
|
||
this.scopeText = selected.label;
|
||
this.showScopePicker = false;
|
||
},
|
||
|
||
// 状态选择确认
|
||
onStatusConfirm(e) {
|
||
const index = e.indexs[0];
|
||
const selected = this.statusOptions[0][index];
|
||
this.queryParams.status = selected.value;
|
||
this.statusText = selected.label;
|
||
this.showStatusPicker = false;
|
||
},
|
||
|
||
// 获取状态类型
|
||
getStatusType(status) {
|
||
const typeMap = {
|
||
DRAFT: 'info',
|
||
PUBLISHED: 'warning',
|
||
RECRUITING: 'success',
|
||
FULL: 'primary',
|
||
EXPIRED: 'error',
|
||
SUSPENDED: 'warning',
|
||
CANCELLED: 'error',
|
||
};
|
||
return typeMap[status] || 'default';
|
||
},
|
||
|
||
// 判断是否可以申请(完全参考web端实现)
|
||
canApply(position) {
|
||
const application = this.studentApplications.find(
|
||
(app) => app.positionId === position.id,
|
||
);
|
||
|
||
// 如果已录用,禁用按钮
|
||
if (application && application.status === 'approved') {
|
||
return false;
|
||
}
|
||
|
||
// 检查岗位状态
|
||
if (!['PUBLISHED', 'RECRUITING'].includes(position.status || '')) {
|
||
return false;
|
||
}
|
||
|
||
// 检查是否还有空缺
|
||
const current = position.currentCount || 0;
|
||
const required = position.requiredCount || 0;
|
||
if (current >= required) {
|
||
return false;
|
||
}
|
||
|
||
// 检查有效期
|
||
if (position.endDate) {
|
||
const endDate = new Date(position.endDate);
|
||
if (endDate < new Date()) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
// 获取申请按钮文字(参考web端实现8种状态)
|
||
getApplyButtonText(position) {
|
||
const application = this.studentApplications.find(
|
||
(app) => app.positionId === position.id,
|
||
);
|
||
|
||
// 如果已录用
|
||
if (application && application.status === 'approved') {
|
||
return '申请已通过';
|
||
}
|
||
|
||
// 如果有申请且状态为审核中
|
||
if (
|
||
application &&
|
||
['submitted', 'college_reviewing', 'final_reviewing'].includes(application.status)
|
||
) {
|
||
return '申请审核中';
|
||
}
|
||
|
||
// 如果被拒绝
|
||
if (application && application.status === 'rejected') {
|
||
return '重新申请';
|
||
}
|
||
|
||
// 检查岗位状态
|
||
if (!['PUBLISHED', 'RECRUITING'].includes(position.status || '')) {
|
||
if (position.status === 'EXPIRED') {
|
||
return '岗位已过期';
|
||
} else if (position.status === 'SUSPENDED') {
|
||
return '岗位已暂停';
|
||
} else if (position.status === 'CANCELLED') {
|
||
return '岗位已取消';
|
||
} else {
|
||
return '暂不可申请';
|
||
}
|
||
}
|
||
|
||
// 检查是否还有空缺
|
||
const current = position.currentCount || 0;
|
||
const required = position.requiredCount || 0;
|
||
if (current >= required) {
|
||
return '岗位已满员';
|
||
}
|
||
|
||
// 检查有效期
|
||
if (position.endDate) {
|
||
const endDate = new Date(position.endDate);
|
||
if (endDate < new Date()) {
|
||
return '岗位已过期';
|
||
}
|
||
}
|
||
|
||
// 默认可申请
|
||
return '申请此岗位';
|
||
},
|
||
|
||
// 获取申请状态文字(与web端保持一致)
|
||
getApplicationStatusText(item) {
|
||
if (!item) return '未申请';
|
||
|
||
// 支持两种格式:web端的小写格式和移动端的大写格式
|
||
const status = item.status ? item.status.toLowerCase() : '';
|
||
|
||
switch (status) {
|
||
case 'submitted':
|
||
case 'SUBMITTED':
|
||
return '已提交';
|
||
case 'college_reviewing':
|
||
case 'COLLEGE_REVIEWING':
|
||
return '学院审核中';
|
||
case 'final_reviewing':
|
||
case 'FINAL_REVIEWING':
|
||
return '学生处审核中';
|
||
case 'approved':
|
||
case 'FINAL_APPROVED':
|
||
return '审核通过';
|
||
case 'rejected':
|
||
case 'FINAL_REJECTED':
|
||
return '审核不通过';
|
||
case 'cancelled':
|
||
case 'CANCELLED':
|
||
return '已撤销';
|
||
case 'draft':
|
||
case 'DRAFT':
|
||
return '草稿';
|
||
default:
|
||
return '未知状态';
|
||
}
|
||
},
|
||
|
||
// 获取申请状态类型(与web端保持一致)
|
||
getApplicationStatusType(item) {
|
||
if (!item) return 'default';
|
||
|
||
// 支持两种格式:web端的小写格式和移动端的大写格式
|
||
const status = item.status ? item.status.toLowerCase() : '';
|
||
|
||
const typeMap = {
|
||
draft: 'info',
|
||
submitted: 'warning',
|
||
college_reviewing: 'warning',
|
||
final_reviewing: 'warning',
|
||
approved: 'success',
|
||
rejected: 'error',
|
||
cancelled: 'info',
|
||
};
|
||
return typeMap[status] || 'default';
|
||
},
|
||
|
||
// 获取审核状态文字
|
||
getReviewStatusText(status) {
|
||
const statusMap = {
|
||
PENDING: '待审核',
|
||
APPROVED: '通过',
|
||
REJECTED: '未通过',
|
||
};
|
||
return statusMap[status] || '未知';
|
||
},
|
||
|
||
// 判断是否可以撤销申请(与web端保持一致)
|
||
canCancelApplication(item) {
|
||
if (!item) return false;
|
||
|
||
// 支持两种格式:web端的小写格式和移动端的大写格式
|
||
const status = item.status ? item.status.toLowerCase() : '';
|
||
return (
|
||
['draft', 'submitted', 'college_reviewing'].includes(status) ||
|
||
['DRAFT', 'SUBMITTED', 'COLLEGE_REVIEWING'].includes(item.status)
|
||
);
|
||
},
|
||
|
||
// 获取岗位的申请状态(用于在岗位卡片中显示)
|
||
getPositionApplicationStatus(position) {
|
||
const application = this.studentApplications.find(
|
||
(app) => app.positionId === position.id,
|
||
);
|
||
if (!application) return null;
|
||
|
||
return this.getApplicationStatusText(application);
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.work-study-container {
|
||
min-height: 100vh;
|
||
background-color: #f5f6fa;
|
||
}
|
||
|
||
.search-container {
|
||
padding: 20rpx;
|
||
background-color: #fff;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.tabs-container {
|
||
background-color: #fff;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.filter-bar {
|
||
background-color: #fff;
|
||
padding: 20rpx;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.filter-item {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.filter-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.action-bar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 20rpx;
|
||
background-color: #fff;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.list-container {
|
||
flex: 1;
|
||
}
|
||
|
||
.list-content {
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.position-card,
|
||
.application-card {
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
margin-bottom: 20rpx;
|
||
padding: 24rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.position-info,
|
||
.application-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.position-name {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #303133;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.position-type,
|
||
.apply-time {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.status-badge {
|
||
margin-left: 20rpx;
|
||
}
|
||
|
||
.card-content {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.info-text {
|
||
font-size: 28rpx;
|
||
color: #606266;
|
||
margin-left: 12rpx;
|
||
flex: 1;
|
||
}
|
||
|
||
.current-count {
|
||
margin-left: 20rpx;
|
||
color: #0051d9;
|
||
}
|
||
|
||
.card-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
border-top: 1rpx solid #eee;
|
||
padding-top: 20rpx;
|
||
}
|
||
|
||
.empty-state {
|
||
padding: 80rpx 20rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.load-more {
|
||
padding: 20rpx;
|
||
}
|
||
</style>
|