|
|
@@ -0,0 +1,744 @@
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, computed, watch, onMounted } from 'vue'
|
|
|
+import { showToast, showConfirmDialog } from 'vant'
|
|
|
+import TopNavBar from '@/business/top-nav-bar.vue'
|
|
|
+import { getStudentDetail, getStudentLeaveApplication, applyForResumption, withdrawApplication } from '@/services/student-prosthetics'
|
|
|
+import utils from '@/utils/utils'
|
|
|
+
|
|
|
+// 学生数据
|
|
|
+const students = ref([
|
|
|
+ {
|
|
|
+ id: 'ec03f17b3474469f99cf7039bb11e688',
|
|
|
+ name: '张三',
|
|
|
+ gradeClass: '',
|
|
|
+ schoolName: '',
|
|
|
+ studentNo: '',
|
|
|
+ studentStatusStr: '', // 状态:'在校' 或 '休学中'
|
|
|
+ applying: false, // 是否正在申请
|
|
|
+ applyStatusStr: '', // 申请状态
|
|
|
+ leaveType: null, // 申请类型:'1 休学' 或 '2 复学'
|
|
|
+ certNo: null // 存证id
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'e909040887a644a4b1b7bf2f0d6e9460',
|
|
|
+ name: '李四',
|
|
|
+ studentId: '',
|
|
|
+ gradeClass: '',
|
|
|
+ schoolName: '',
|
|
|
+ studentNo: '',
|
|
|
+ studentStatusStr: '休学中',
|
|
|
+ applying: false,
|
|
|
+ applyStatusStr: '',
|
|
|
+ leaveType: 1,
|
|
|
+ certNo: 'LV202401150001'
|
|
|
+ },
|
|
|
+ // {
|
|
|
+ // id: 3,
|
|
|
+ // name: '张小刚',
|
|
|
+ // studentId: '2023030303',
|
|
|
+ // gradeClass: '初三·2班',
|
|
|
+ // schoolName: '太原市第五中学',
|
|
|
+ // studentNo: '123',
|
|
|
+ // studentStatusStr: '在校',
|
|
|
+ // applying: true,
|
|
|
+ // applyStatusStr: '审批中', // 申请状态
|
|
|
+ // leaveType: 1,
|
|
|
+ // certNo: null
|
|
|
+ // }
|
|
|
+])
|
|
|
+
|
|
|
+// 当前选中的学生
|
|
|
+const selectedStudent = ref(null)
|
|
|
+
|
|
|
+
|
|
|
+// 申请表单数据
|
|
|
+const formData = reactive({
|
|
|
+ leaveType: 1, // 1'休学' 或 2'复学'
|
|
|
+ diseaseDiagnosis: '',
|
|
|
+ expectedStartDate: '',
|
|
|
+ expectedEndDate: '',
|
|
|
+ auditOpinion: '',
|
|
|
+ stdLeaveAttachments: []
|
|
|
+})
|
|
|
+
|
|
|
+// 期限描述
|
|
|
+const periodDescription = computed(() => {
|
|
|
+ if (!formData.expectedStartDate || !formData.expectedEndDate) return ''
|
|
|
+
|
|
|
+ const start = new Date(formData.expectedStartDate)
|
|
|
+ const end = new Date(formData.expectedEndDate)
|
|
|
+
|
|
|
+ const days = Math.ceil((end - start) / (1000 * 60 * 60 * 24))
|
|
|
+
|
|
|
+ return `共${days}天`
|
|
|
+})
|
|
|
+
|
|
|
+// 方法:选择学生
|
|
|
+const selectStudent = (student) => {
|
|
|
+ if (student.applying) {
|
|
|
+ showToast('该学生有正在审批中的申请,请等待审批完成')
|
|
|
+ }
|
|
|
+ selectedStudent.value = student
|
|
|
+ // 重置表单
|
|
|
+ resetForm()
|
|
|
+}
|
|
|
+
|
|
|
+// 重置表单
|
|
|
+const resetForm = () => {
|
|
|
+ if (selectedStudent.value) {
|
|
|
+ if (selectedStudent.value.studentStatusStr === '休学中') {
|
|
|
+ formData.leaveType = 2
|
|
|
+ } else {
|
|
|
+ formData.leaveType = 1
|
|
|
+ }
|
|
|
+ formData.diseaseDiagnosis = ''
|
|
|
+ formData.expectedStartDate = ''
|
|
|
+ formData.expectedEndDate = ''
|
|
|
+ formData.auditOpinion = ''
|
|
|
+ formData.stdLeaveAttachments = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 查看存证
|
|
|
+const viewEvidence = (student) => {
|
|
|
+ localStorage.setItem('studentInfo', JSON.stringify(student))
|
|
|
+ uni.navigateTo({
|
|
|
+ url: `/modules/common/student-prosthetics/certificate`
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 查看审批进度
|
|
|
+const viewProgress = (student) => {
|
|
|
+ localStorage.setItem('studentInfo', JSON.stringify(student))
|
|
|
+ uni.navigateTo({
|
|
|
+ url: `/modules/common/student-prosthetics/approval-progress`
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const showDialog = ref(false)
|
|
|
+const auditOpinion = ref('')
|
|
|
+// 撤回申请
|
|
|
+const withdrawApply = () => {
|
|
|
+ if (!selectedStudent.value?.applying) return
|
|
|
+ auditOpinion.value = ''
|
|
|
+ showDialog.value = true
|
|
|
+}
|
|
|
+const handleConfirm = async () => {
|
|
|
+ if (!auditOpinion.value.trim()) {
|
|
|
+ showToast('请输入撤回原因')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await showConfirmDialog({
|
|
|
+ title: '确认撤回',
|
|
|
+ message: '确定要撤回申请吗?撤回后需要重新提交'
|
|
|
+ })
|
|
|
+ withdrawApplication({
|
|
|
+ auditOpinion: auditOpinion.value,
|
|
|
+ auditorId: selectedStudent.value.applicantId,
|
|
|
+ auditorName: selectedStudent.value.applicantName,
|
|
|
+ }).then(res => {
|
|
|
+ if (res.success) {
|
|
|
+ showToast('撤回成功')
|
|
|
+ init(0)
|
|
|
+ init(1)
|
|
|
+ selectedStudent.value = null
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ // 用户取消
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 提交申请
|
|
|
+const submitApply = async () => {
|
|
|
+ // 表单验证
|
|
|
+ if (!formData.diseaseDiagnosis.trim()) {
|
|
|
+ showToast('请输入诊断记录')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!formData.expectedStartDate) {
|
|
|
+ showToast('请选择开始日期')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!formData.expectedEndDate) {
|
|
|
+ showToast('请选择结束日期')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!formData.auditOpinion.trim()) {
|
|
|
+ showToast('请输入申请原因')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!formData.stdLeaveAttachments || !formData.stdLeaveAttachments.length) {
|
|
|
+ showToast('请上传证明材料')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let params = {
|
|
|
+ studentId: selectedStudent.value.id,
|
|
|
+ studentName: selectedStudent.value.name,
|
|
|
+ applicantId: "02e168c19b7c456eafeb647853a079ae",
|
|
|
+ applicantName: "15296619861",
|
|
|
+ ...formData
|
|
|
+ }
|
|
|
+
|
|
|
+ params.expectedStartDate = params.expectedStartDate + ' 00:00:00'
|
|
|
+ params.expectedEndDate = params.expectedEndDate + ' 00:00:00'
|
|
|
+
|
|
|
+ if (params.stdLeaveAttachments && params.stdLeaveAttachments.length) {
|
|
|
+ params.stdLeaveAttachments = params.stdLeaveAttachments.map(item => {
|
|
|
+ return {
|
|
|
+ fileName: item.fileName,
|
|
|
+ fileUrl: item.fileUrl,
|
|
|
+ fileType: item.fileType
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ applyForResumption(params).then(res => {
|
|
|
+ if (res.success) {
|
|
|
+ showToast('提交成功,等待审批')
|
|
|
+ init(0)
|
|
|
+ init(1)
|
|
|
+ selectedStudent.value = null
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 上传文件
|
|
|
+const afterRead = async (file) => {
|
|
|
+ let files = []
|
|
|
+ if (Array.isArray(file)) {
|
|
|
+ files = file
|
|
|
+ } else {
|
|
|
+ files = [file]
|
|
|
+ }
|
|
|
+ console.log('afterRead', files)
|
|
|
+ const res = await utils.transferOssUrl(files) || []
|
|
|
+ formData.stdLeaveAttachments = formData.stdLeaveAttachments.map(item => {
|
|
|
+ if (item.file) {
|
|
|
+ const index = res.findIndex(file => file.objectUrl === item.objectUrl)
|
|
|
+ if (index !== -1) {
|
|
|
+ return res[index]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return item
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 删除文件
|
|
|
+const removeFile = () => { }
|
|
|
+
|
|
|
+// 日期选择器相关
|
|
|
+const showStartDatePicker = ref(false)
|
|
|
+const showEndDatePicker = ref(false)
|
|
|
+
|
|
|
+const onStartDateConfirm = ({ selectedValues }) => {
|
|
|
+ formData.expectedStartDate = selectedValues.join('-')
|
|
|
+ showStartDatePicker.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const onEndDateConfirm = ({ selectedValues }) => {
|
|
|
+ formData.expectedEndDate = selectedValues.join('-')
|
|
|
+ showEndDatePicker.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const getStudentDetailFun = (id) => {
|
|
|
+ return new Promise(async (resolve, reject) => {
|
|
|
+ const res1 = await getStudentDetail({ id })
|
|
|
+ const res2 = await getStudentLeaveApplication({ studentId: id })
|
|
|
+ if (res1.success && res2.success) {
|
|
|
+ const res1Info = res1.info || {}
|
|
|
+ const res2Info = res2.info || {}
|
|
|
+ resolve({
|
|
|
+ success: res1.success && res2.success,
|
|
|
+ info: {
|
|
|
+ res1: {
|
|
|
+ id: res1Info.id,
|
|
|
+ name: res1Info.name,
|
|
|
+ gradeClass: res1Info.gradeClass,
|
|
|
+ schoolName: res1Info.schoolName,
|
|
|
+ studentNo: res1Info.studentNo,
|
|
|
+ },
|
|
|
+ res2: {
|
|
|
+ studentStatusStr: res2Info.studentStatusStr || '在校', // 状态:'在校' 或 '休学中'
|
|
|
+ applying: res2Info.applyStatusStr ? true : false, // 是否正在申请
|
|
|
+ applyStatusStr: res2Info.applyStatusStr, // 申请状态
|
|
|
+ leaveType: res2Info.leaveType, // 申请类型:'1 休学' 或 '2 复学'
|
|
|
+ certNo: res2Info.certNo, // 存证id
|
|
|
+ createdTime: res2Info.createdTime || '', // 申请时间 存证时间
|
|
|
+ details: {
|
|
|
+ diseaseDiagnosis: res2Info.diseaseDiagnosis,
|
|
|
+ expectedStartDate: res2Info.expectedStartDate,
|
|
|
+ expectedEndDate: res2Info.expectedEndDate,
|
|
|
+ auditOpinion: res2Info.auditOpinion
|
|
|
+ },
|
|
|
+ applicationId: res2Info.id,
|
|
|
+ applicantId: res2Info.applicantId,
|
|
|
+ applicantName: res2Info.applicantName,
|
|
|
+ tenantId: res2Info.tenantId
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ reject()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const init = (num = 0) => {
|
|
|
+ const id = students.value[num]?.id
|
|
|
+ getStudentDetailFun(id).then((res) => {
|
|
|
+ if (res.success) {
|
|
|
+ students.value[num] = Object.assign({}, students.value[num], res.info.res1, res.info.res2)
|
|
|
+ // students.value[num].applying = false // 硬编码 需删除
|
|
|
+ // students.value[num].certNo = '100000' // 硬编码 需删除
|
|
|
+ // students.value[num].studentStatusStr = '休学中' // 硬编码 需删除
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ init(0)
|
|
|
+ init(1)
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="apply-page">
|
|
|
+ <TopNavBar></TopNavBar>
|
|
|
+
|
|
|
+ <!-- 选择学生部分 -->
|
|
|
+ <div class="section">
|
|
|
+ <div class="section-title">选择学生</div>
|
|
|
+ <div class="student-list">
|
|
|
+ <div v-for="student in students" :key="student.id" class="student-item"
|
|
|
+ :class="{ active: selectedStudent?.id === student.id }" @click="selectStudent(student)">
|
|
|
+ <div class="student-info">
|
|
|
+ <div class="name-status">
|
|
|
+ <span class="name">{{ student.name }}</span>
|
|
|
+ <span class="status-badge" :class="student.studentStatusStr">
|
|
|
+ {{ student.studentStatusStr }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="class-info">{{ student.gradeClass }}</div>
|
|
|
+
|
|
|
+ <div v-if="student.certNo" class="extra-info">
|
|
|
+ <div class="evidence-id">存证编号:{{ student.certNo }}</div>
|
|
|
+ <van-button v-if="student.studentStatusStr === '休学中'" size="mini" type="primary"
|
|
|
+ @click.stop="viewEvidence(student)">
|
|
|
+ 查看存证
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="student.applying" class="extra-info">
|
|
|
+ <div class="applying-status">{{ student.applyStatusStr }}</div>
|
|
|
+ <van-button size="mini" type="primary" @click.stop="viewProgress(student)">
|
|
|
+ 查看进度
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 学生信息和申请表单(只在选中学生时显示) -->
|
|
|
+ <div v-if="selectedStudent" class="form-container">
|
|
|
+ <!-- 学生信息 -->
|
|
|
+ <div class="section">
|
|
|
+ <div class="section-title">学生信息</div>
|
|
|
+ <div class="info-grid">
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">姓名</div>
|
|
|
+ <div class="info-value">{{ selectedStudent.name }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">学号</div>
|
|
|
+ <div class="info-value">{{ selectedStudent.studentNo }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">所属学校</div>
|
|
|
+ <div class="info-value">{{ selectedStudent.schoolName }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">当前年级</div>
|
|
|
+ <div class="info-value">{{ selectedStudent.gradeClass }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 审批中的提示 -->
|
|
|
+ <div v-if="selectedStudent.applying" class="section warning">
|
|
|
+ <div class="warning-text">
|
|
|
+ 该学生有正在审批中的休学申请,请等待审批完成后再发起新的申请。
|
|
|
+ </div>
|
|
|
+ <div class="apply-info">
|
|
|
+ <div class="apply-row">
|
|
|
+ <div class="apply-label">申请类型</div>
|
|
|
+ <div class="apply-value">{{ selectedStudent.leaveType == 1 ? '休学' : '复学' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="apply-row">
|
|
|
+ <div class="apply-label">提交时间</div>
|
|
|
+ <div class="apply-value">{{ selectedStudent?.createdTime || '' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="apply-row">
|
|
|
+ <div class="apply-label">当前状态</div>
|
|
|
+ <div class="apply-value status-text">{{ selectedStudent.applyStatusStr }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="action-buttons">
|
|
|
+ <van-button type="primary" @click="viewProgress(selectedStudent)">查看审批进度</van-button>
|
|
|
+ <van-button v-if="selectedStudent.leaveType === 1" type="default" @click="withdrawApply">
|
|
|
+ 撤回申请
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 申请表单(只在非审批中状态显示) -->
|
|
|
+ <div v-else class="section">
|
|
|
+ <div class="section-title">申请信息</div>
|
|
|
+
|
|
|
+ <!-- 业务类型 -->
|
|
|
+ <div class="form-group">
|
|
|
+ <div class="form-label">业务类型</div>
|
|
|
+ <div class="radio-group">
|
|
|
+ <van-radio-group v-model="formData.leaveType" direction="horizontal">
|
|
|
+ <van-radio :name="1" :disabled="selectedStudent.studentStatusStr === '休学中'">休学</van-radio>
|
|
|
+ <van-radio :name="2" :disabled="selectedStudent.studentStatusStr !== '休学中'">复学</van-radio>
|
|
|
+ </van-radio-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 诊断记录 -->
|
|
|
+ <div class="form-group">
|
|
|
+ <div class="form-label">诊断记录</div>
|
|
|
+ <van-field v-model="formData.diseaseDiagnosis" type="textarea" placeholder="请输入医院诊断结果" rows="2"
|
|
|
+ maxlength="200" show-word-limit />
|
|
|
+ </div>
|
|
|
+ <van-notice-bar left-icon="info-o" class="tw-mt-[10rpx]">
|
|
|
+ 请务必按照医院诊断证明书上的结论据实填写
|
|
|
+ </van-notice-bar>
|
|
|
+
|
|
|
+ <!-- 开始日期 -->
|
|
|
+ <div class="form-group">
|
|
|
+ <div class="form-label">开始日期</div>
|
|
|
+ <van-field v-model="formData.expectedStartDate" readonly placeholder="请选择开始日期"
|
|
|
+ @click="showStartDatePicker = true" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 结束日期 -->
|
|
|
+ <div class="form-group">
|
|
|
+ <div class="form-label">结束日期</div>
|
|
|
+ <van-field v-model="formData.expectedEndDate" readonly placeholder="请选择结束日期"
|
|
|
+ @click="showEndDatePicker = true" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 期限描述 -->
|
|
|
+ <div class="form-group">
|
|
|
+ <div class="form-label">期限描述</div>
|
|
|
+ <van-field v-model="periodDescription" placeholder="系统将根据起止日期自动计算期限" readonly />
|
|
|
+ </div>
|
|
|
+ <van-notice-bar color="#1989fa" background="#ecf9ff" left-icon="info-o" class="tw-mt-[10rpx]">
|
|
|
+ 系统将根据起止日期自动计算期限
|
|
|
+ </van-notice-bar>
|
|
|
+
|
|
|
+ <!-- 申请原因 -->
|
|
|
+ <div class="form-group">
|
|
|
+ <div class="form-label">申请原因</div>
|
|
|
+ <van-field v-model="formData.auditOpinion" type="textarea" placeholder="请详细说明申请原因" rows="3"
|
|
|
+ maxlength="200" show-word-limit />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 日期选择器 -->
|
|
|
+ <van-popup v-model:show="showStartDatePicker" position="bottom">
|
|
|
+ <van-date-picker title="选择开始日期" @confirm="onStartDateConfirm"
|
|
|
+ @cancel="showStartDatePicker = false" />
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <van-popup v-model:show="showEndDatePicker" position="bottom">
|
|
|
+ <van-date-picker title="选择结束日期" @confirm="onEndDateConfirm" @cancel="showEndDatePicker = false" />
|
|
|
+ </van-popup>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 证明材料 -->
|
|
|
+ <div v-if="!selectedStudent.applying" class="section">
|
|
|
+ <div class="section-title">证明材料</div>
|
|
|
+ <div class="upload-list">
|
|
|
+ <!-- 病历资料 -->
|
|
|
+ <div class="upload-item">
|
|
|
+ <div class="upload-title">医院诊断证明(必传)</div>
|
|
|
+ <div class="upload-title">病历资料(支持多页)</div>
|
|
|
+ <div class="upload-title">家长身份证复印件</div>
|
|
|
+ <van-uploader v-model="formData.stdLeaveAttachments" multiple :max-count="9"
|
|
|
+ :after-read="afterRead" @delete="removeFile" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 提交按钮 -->
|
|
|
+ <div v-if="!selectedStudent.applying" class="submit-section">
|
|
|
+ <van-button type="primary" size="large" @click="submitApply">提交申请</van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <van-dialog v-model:show="showDialog" title="撤回申请原因" showConfirmButton showCancelButton @confirm="handleConfirm">
|
|
|
+ <van-field v-model="auditOpinion" type="textarea" placeholder="请输入撤回申请原因" rows="3" maxlength="200"
|
|
|
+ show-word-limit />
|
|
|
+ </van-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.apply-page {
|
|
|
+ padding: 24rpx;
|
|
|
+ background-color: #f7f8fa;
|
|
|
+ min-height: 100vh;
|
|
|
+ padding-top: 120rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.section {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+
|
|
|
+ &.warning {
|
|
|
+ border-left: 8rpx solid #ff4444;
|
|
|
+ background-color: #fff7f7;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ padding-bottom: 16rpx;
|
|
|
+ border-bottom: 1rpx solid #eee;
|
|
|
+}
|
|
|
+
|
|
|
+.student-list {
|
|
|
+ .student-item {
|
|
|
+ padding: 24rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ border: 2rpx solid #eee;
|
|
|
+ background: #fff;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ border-color: #1989fa;
|
|
|
+ background-color: #f0f9ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .student-info {
|
|
|
+ .name-status {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+
|
|
|
+ .name {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .status-badge {
|
|
|
+ font-size: 24rpx;
|
|
|
+ padding: 4rpx 12rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+
|
|
|
+ &.在校 {
|
|
|
+ background-color: #e8f5e9;
|
|
|
+ color: #4caf50;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.休学中 {
|
|
|
+ background-color: #fff3e0;
|
|
|
+ color: #ff9800;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .class-info {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .extra-info {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 12rpx;
|
|
|
+ padding-top: 12rpx;
|
|
|
+ border-top: 1rpx solid #eee;
|
|
|
+
|
|
|
+ .evidence-id {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #888;
|
|
|
+ }
|
|
|
+
|
|
|
+ .applying-status {
|
|
|
+ font-size: 24rpx;
|
|
|
+ padding: 4rpx 12rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ background-color: #fff3e0;
|
|
|
+ color: #ff9800;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.info-grid {
|
|
|
+ .info-row {
|
|
|
+ display: flex;
|
|
|
+ padding: 16rpx 0;
|
|
|
+ border-bottom: 1rpx solid #f0f0f0;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-label {
|
|
|
+ width: 200rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-value {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.warning-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #ff4444;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+
|
|
|
+.apply-info {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ padding: 16rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+
|
|
|
+ .apply-row {
|
|
|
+ display: flex;
|
|
|
+ padding: 12rpx 0;
|
|
|
+
|
|
|
+ .apply-label {
|
|
|
+ width: 200rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+
|
|
|
+ .apply-value {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+
|
|
|
+ &.status-text {
|
|
|
+ color: #ff9800;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.action-buttons {
|
|
|
+ display: flex;
|
|
|
+ gap: 24rpx;
|
|
|
+
|
|
|
+ .van-button {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.form-container {
|
|
|
+ .form-group {
|
|
|
+ margin-top: 32rpx;
|
|
|
+
|
|
|
+ .form-label {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+
|
|
|
+ .radio-group {
|
|
|
+ .van-radio {
|
|
|
+ margin-right: 48rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.van-field) {
|
|
|
+ background-color: #fafafa;
|
|
|
+ border-radius: 8rpx;
|
|
|
+
|
|
|
+ .van-field__control {
|
|
|
+ font-size: 28rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.upload-list {
|
|
|
+ .upload-item {
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.van-uploader) {
|
|
|
+ .van-uploader__upload {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .van-uploader__preview {
|
|
|
+ margin: 0 16rpx 16rpx 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .van-uploader__preview-image {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.submit-section {
|
|
|
+ margin-top: 48rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+
|
|
|
+ :deep(.van-button) {
|
|
|
+ height: 88rpx;
|
|
|
+ font-size: 32rpx;
|
|
|
+ border-radius: 44rpx;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|