399 lines
11 KiB
Vue
399 lines
11 KiB
Vue
|
|
<template>
|
||
|
|
<page-meta :page-style="$theme.pageStyle">
|
||
|
|
<navigation-bar :front-color="$theme.navColor" :background-color="$theme.navBgColor" />
|
||
|
|
</page-meta>
|
||
|
|
<view class="my-recruitment min-h-full pb-[env(safe-area-inset-bottom)]">
|
||
|
|
<view class="px-[30rpx] py-[20rpx]">
|
||
|
|
<view class="filter-bar flex items-center justify-between">
|
||
|
|
<view class="filter-item" @click="showTimeFilter = true">
|
||
|
|
<text :class="timeFilter ? 'text-blue-500' : 'text-gray-600'">
|
||
|
|
{{ timeFilterText }}
|
||
|
|
</text>
|
||
|
|
<u-icon
|
||
|
|
name="arrow-down"
|
||
|
|
size="24"
|
||
|
|
:color="timeFilter ? '#3B82F6' : '#999'"
|
||
|
|
></u-icon>
|
||
|
|
</view>
|
||
|
|
<view class="filter-item" @click="showRegionFilter = true">
|
||
|
|
<text :class="regionFilter ? 'text-blue-500' : 'text-gray-600'">
|
||
|
|
{{ regionFilterText }}
|
||
|
|
</text>
|
||
|
|
<u-icon
|
||
|
|
name="arrow-down"
|
||
|
|
size="24"
|
||
|
|
:color="regionFilter ? '#3B82F6' : '#999'"
|
||
|
|
></u-icon>
|
||
|
|
</view>
|
||
|
|
<view class="filter-item" @click="toggleSort">
|
||
|
|
<text :class="sortBy ? 'text-blue-500' : 'text-gray-600'">
|
||
|
|
{{ sortText }}
|
||
|
|
</text>
|
||
|
|
<u-icon
|
||
|
|
:name="sortOrder === 'desc' ? 'arrow-down' : 'arrow-up'"
|
||
|
|
size="24"
|
||
|
|
:color="sortBy ? '#3B82F6' : '#999'"
|
||
|
|
></u-icon>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
<view class="px-[30rpx]">
|
||
|
|
<view class="text-sm text-gray-500 mb-[20rpx]"> 共 {{ total }} 条记录 </view>
|
||
|
|
|
||
|
|
<view v-if="loading" class="flex justify-center py-[100rpx]">
|
||
|
|
<u-loading mode="circle"></u-loading>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
<view
|
||
|
|
v-else-if="list.length === 0"
|
||
|
|
class="empty-state flex flex-col items-center py-[100rpx]"
|
||
|
|
>
|
||
|
|
<u-icon name="inbox" size="120" color="#E5E7EB"></u-icon>
|
||
|
|
<view class="text-gray-400 mt-[30rpx]">暂无招生数据</view>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
<view v-else class="list">
|
||
|
|
<view
|
||
|
|
v-for="(item, index) in list"
|
||
|
|
:key="index"
|
||
|
|
class="list-item bg-white rounded-lg p-[30rpx] mb-[20rpx]"
|
||
|
|
>
|
||
|
|
<view class="flex items-center justify-between mb-[20rpx]">
|
||
|
|
<view class="flex items-center">
|
||
|
|
<view
|
||
|
|
class="avatar bg-blue-100 text-blue-500 w-[80rpx] h-[80rpx] rounded-full flex items-center justify-center text-xl font-medium"
|
||
|
|
>
|
||
|
|
{{ item.name ? item.name.charAt(0) : '?' }}
|
||
|
|
</view>
|
||
|
|
<view class="ml-[20rpx]">
|
||
|
|
<view class="text-lg font-medium">{{ item.name }}</view>
|
||
|
|
<view class="text-sm text-gray-500 mt-[5rpx]">{{
|
||
|
|
item.gender === 1 ? '男' : '女'
|
||
|
|
}}</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
<view class="text-right">
|
||
|
|
<view class="text-sm text-gray-500">{{ item.majorName }}</view>
|
||
|
|
<view class="text-xs text-gray-400 mt-[5rpx]">{{
|
||
|
|
item.createTime
|
||
|
|
}}</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
<view class="info-grid grid grid-cols-2 gap-[20rpx]">
|
||
|
|
<view class="info-item">
|
||
|
|
<view class="text-xs text-gray-400">身份证号</view>
|
||
|
|
<view class="text-sm mt-[5rpx]">{{ formatIdCard(item.idCard) }}</view>
|
||
|
|
</view>
|
||
|
|
<view class="info-item">
|
||
|
|
<view class="text-xs text-gray-400">毕业学校</view>
|
||
|
|
<view class="text-sm mt-[5rpx]">{{ item.previousSchool }}</view>
|
||
|
|
</view>
|
||
|
|
<view class="info-item">
|
||
|
|
<view class="text-xs text-gray-400">中考成绩</view>
|
||
|
|
<view class="text-sm mt-[5rpx]">{{ item.highSchoolScore }}分</view>
|
||
|
|
</view>
|
||
|
|
<view class="info-item">
|
||
|
|
<view class="text-xs text-gray-400">身高/体重</view>
|
||
|
|
<view class="text-sm mt-[5rpx]"
|
||
|
|
>{{ item.height }}cm / {{ item.weight }}kg</view
|
||
|
|
>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
<view class="status-bar mt-[20rpx] flex items-center justify-between">
|
||
|
|
<view class="flex items-center">
|
||
|
|
<view class="status-dot" :class="getStatusClass(item.status)"></view>
|
||
|
|
<view
|
||
|
|
class="text-sm ml-[10rpx]"
|
||
|
|
:class="getStatusTextClass(item.status)"
|
||
|
|
>
|
||
|
|
{{ getStatusText(item.status) }}
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
<view class="text-xs text-gray-400"> 鞋码: {{ item.shoeSize }} </view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
<u-action-sheet
|
||
|
|
v-model="showTimeFilter"
|
||
|
|
:list="timeFilterList"
|
||
|
|
@click="handleTimeFilter"
|
||
|
|
></u-action-sheet>
|
||
|
|
<u-action-sheet
|
||
|
|
v-model="showRegionFilter"
|
||
|
|
:list="regionFilterList"
|
||
|
|
@click="handleRegionFilter"
|
||
|
|
></u-action-sheet>
|
||
|
|
</view>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { ref, onMounted, computed } from 'vue'
|
||
|
|
import { onLoad } from '@dcloudio/uni-app'
|
||
|
|
import { getRecruitmentList } from '@/api/app'
|
||
|
|
import { useUserStore } from '@/stores/user'
|
||
|
|
import { storeToRefs } from 'pinia'
|
||
|
|
|
||
|
|
const userStore = useUserStore()
|
||
|
|
const { userInfo } = storeToRefs(userStore)
|
||
|
|
|
||
|
|
const list = ref<any[]>([])
|
||
|
|
const loading = ref(false)
|
||
|
|
const total = ref(0)
|
||
|
|
|
||
|
|
const showTimeFilter = ref(false)
|
||
|
|
const showRegionFilter = ref(false)
|
||
|
|
const timeFilter = ref('')
|
||
|
|
const regionFilter = ref('')
|
||
|
|
const sortBy = ref('createTime')
|
||
|
|
const sortOrder = ref<'asc' | 'desc'>('desc')
|
||
|
|
|
||
|
|
const timeFilterText = computed(() => {
|
||
|
|
const map: Record<string, string> = {
|
||
|
|
'': '全部时间',
|
||
|
|
today: '今天',
|
||
|
|
week: '本周',
|
||
|
|
month: '本月',
|
||
|
|
year: '今年'
|
||
|
|
}
|
||
|
|
return map[timeFilter.value] || '全部时间'
|
||
|
|
})
|
||
|
|
|
||
|
|
const regionFilterText = computed(() => {
|
||
|
|
const map: Record<string, string> = {
|
||
|
|
'': '全部地区',
|
||
|
|
north: '北部地区',
|
||
|
|
south: '南部地区',
|
||
|
|
east: '东部地区',
|
||
|
|
west: '西部地区'
|
||
|
|
}
|
||
|
|
return map[regionFilter.value] || '全部地区'
|
||
|
|
})
|
||
|
|
|
||
|
|
const sortText = computed(() => {
|
||
|
|
const map: Record<string, string> = {
|
||
|
|
createTime: '时间',
|
||
|
|
highSchoolScore: '成绩',
|
||
|
|
height: '身高'
|
||
|
|
}
|
||
|
|
return map[sortBy.value] || '排序'
|
||
|
|
})
|
||
|
|
|
||
|
|
const timeFilterList = [
|
||
|
|
{ text: '全部时间' },
|
||
|
|
{ text: '今天' },
|
||
|
|
{ text: '本周' },
|
||
|
|
{ text: '本月' },
|
||
|
|
{ text: '今年' }
|
||
|
|
]
|
||
|
|
|
||
|
|
const regionFilterList = [
|
||
|
|
{ text: '全部地区' },
|
||
|
|
{ text: '北部地区' },
|
||
|
|
{ text: '南部地区' },
|
||
|
|
{ text: '东部地区' },
|
||
|
|
{ text: '西部地区' }
|
||
|
|
]
|
||
|
|
|
||
|
|
const formatIdCard = (idCard: string) => {
|
||
|
|
if (!idCard) return ''
|
||
|
|
return idCard.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2')
|
||
|
|
}
|
||
|
|
|
||
|
|
const getStatusClass = (status: number) => {
|
||
|
|
const map: Record<number, string> = {
|
||
|
|
0: 'status-pending',
|
||
|
|
1: 'status-approved',
|
||
|
|
2: 'status-rejected'
|
||
|
|
}
|
||
|
|
return map[status] || 'status-pending'
|
||
|
|
}
|
||
|
|
|
||
|
|
const getStatusTextClass = (status: number) => {
|
||
|
|
const map: Record<number, string> = {
|
||
|
|
0: 'text-yellow-500',
|
||
|
|
1: 'text-green-500',
|
||
|
|
2: 'text-red-500'
|
||
|
|
}
|
||
|
|
return map[status] || 'text-yellow-500'
|
||
|
|
}
|
||
|
|
|
||
|
|
const getStatusText = (status: number) => {
|
||
|
|
const map: Record<number, string> = {
|
||
|
|
0: '待审核',
|
||
|
|
1: '已通过',
|
||
|
|
2: '已拒绝'
|
||
|
|
}
|
||
|
|
return map[status] || '待审核'
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleTimeFilter = (index: number) => {
|
||
|
|
const valueMap = ['', 'today', 'week', 'month', 'year']
|
||
|
|
timeFilter.value = valueMap[index] || ''
|
||
|
|
loadList()
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleRegionFilter = (index: number) => {
|
||
|
|
const valueMap = ['', 'north', 'south', 'east', 'west']
|
||
|
|
regionFilter.value = valueMap[index] || ''
|
||
|
|
loadList()
|
||
|
|
}
|
||
|
|
|
||
|
|
const toggleSort = () => {
|
||
|
|
if (sortBy.value === 'createTime') {
|
||
|
|
sortBy.value = 'highSchoolScore'
|
||
|
|
} else if (sortBy.value === 'highSchoolScore') {
|
||
|
|
sortBy.value = 'height'
|
||
|
|
} else {
|
||
|
|
sortBy.value = 'createTime'
|
||
|
|
}
|
||
|
|
loadList()
|
||
|
|
}
|
||
|
|
|
||
|
|
const loadList = async () => {
|
||
|
|
if (!userInfo.value || !userInfo.value.teacherId) {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
loading.value = true
|
||
|
|
try {
|
||
|
|
const res = await getRecruitmentList({
|
||
|
|
teacherId: userInfo.value.teacherId,
|
||
|
|
timeFilter: timeFilter.value,
|
||
|
|
regionFilter: regionFilter.value,
|
||
|
|
sortBy: sortBy.value,
|
||
|
|
sortOrder: sortOrder.value
|
||
|
|
})
|
||
|
|
|
||
|
|
if (res.code === 1 && res.data) {
|
||
|
|
list.value = res.data.list || []
|
||
|
|
total.value = res.data.total || 0
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取招生列表失败:', error)
|
||
|
|
uni.$u.toast('获取数据失败')
|
||
|
|
} finally {
|
||
|
|
loading.value = false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
onMounted(() => {
|
||
|
|
loadList()
|
||
|
|
})
|
||
|
|
|
||
|
|
onLoad(() => {
|
||
|
|
loadList()
|
||
|
|
})
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss" scoped>
|
||
|
|
.my-recruitment {
|
||
|
|
background-color: #f5f5f5;
|
||
|
|
min-height: 100vh;
|
||
|
|
}
|
||
|
|
|
||
|
|
.filter-bar {
|
||
|
|
background: white;
|
||
|
|
padding: 20rpx;
|
||
|
|
border-radius: 12rpx;
|
||
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||
|
|
}
|
||
|
|
|
||
|
|
.filter-item {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 8rpx;
|
||
|
|
font-size: 28rpx;
|
||
|
|
padding: 10rpx 20rpx;
|
||
|
|
border-radius: 8rpx;
|
||
|
|
transition: all 0.2s ease;
|
||
|
|
|
||
|
|
&:active {
|
||
|
|
background: #f5f5f5;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.list-item {
|
||
|
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||
|
|
}
|
||
|
|
|
||
|
|
.avatar {
|
||
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.info-grid {
|
||
|
|
padding: 20rpx 0;
|
||
|
|
border-top: 1rpx solid #f0f0f0;
|
||
|
|
border-bottom: 1rpx solid #f0f0f0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.info-item {
|
||
|
|
margin-bottom: 10rpx;
|
||
|
|
|
||
|
|
&:last-child {
|
||
|
|
margin-bottom: 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.status-bar {
|
||
|
|
padding-top: 10rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
.status-dot {
|
||
|
|
width: 16rpx;
|
||
|
|
height: 16rpx;
|
||
|
|
border-radius: 50%;
|
||
|
|
|
||
|
|
&.status-pending {
|
||
|
|
background-color: #f59e0b;
|
||
|
|
}
|
||
|
|
|
||
|
|
&.status-approved {
|
||
|
|
background-color: #10b981;
|
||
|
|
}
|
||
|
|
|
||
|
|
&.status-rejected {
|
||
|
|
background-color: #ef4444;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.empty-state {
|
||
|
|
background: white;
|
||
|
|
border-radius: 12rpx;
|
||
|
|
margin-top: 20rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
.text-blue-500 {
|
||
|
|
color: #3b82f6;
|
||
|
|
}
|
||
|
|
|
||
|
|
.text-gray-600 {
|
||
|
|
color: #666;
|
||
|
|
}
|
||
|
|
|
||
|
|
.text-gray-400 {
|
||
|
|
color: #999;
|
||
|
|
}
|
||
|
|
|
||
|
|
.text-gray-500 {
|
||
|
|
color: #888;
|
||
|
|
}
|
||
|
|
|
||
|
|
.text-yellow-500 {
|
||
|
|
color: #f59e0b;
|
||
|
|
}
|
||
|
|
|
||
|
|
.text-green-500 {
|
||
|
|
color: #10b981;
|
||
|
|
}
|
||
|
|
|
||
|
|
.text-red-500 {
|
||
|
|
color: #ef4444;
|
||
|
|
}
|
||
|
|
</style>
|