| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- <template>
- <view class="page">
- <van-nav-bar :title="`${grade} ${className}`" left-arrow @click-left="onBack" fixed />
- <view class="search-bar">
- <van-search v-model="searchKeyword" placeholder="搜索学生姓名或身份证号" @input="onSearch" />
- <van-button type="primary" size="small" @click="addStudent" style="width: 120rpx;">新增</van-button>
- </view>
- <view class="tab-bar">
- <van-tabs v-model:active="activeTab" @change="onTabChange">
- <van-tab title="未录入"></van-tab>
- <van-tab title="已录入"></van-tab>
- <van-tab title="全部"></van-tab>
- </van-tabs>
- </view>
- <view class="content">
- <view class="student-card" v-for="student in studentList" :key="student.id" @click="goToVisionInput(student)">
- <view class="card-header">
- <view class="left">
- <view class="name">{{ student.name }}</view>
- <image class="gender-icon" :src="student.gender === '男' ? '/static/images/icon/man.png' : '/static/images/icon/woman.png'" mode="aspectFit"></image>
- </view>
- <view class="status-tag" :class="student.input_status === '未录入' ? 'warning' : ''">{{ student.input_status }}</view>
- </view>
- <view class="card-body">
- <view class="info-row">
- <text class="label">身份证号</text>
- <text class="value">{{ student.id_card }}</text>
- </view>
- </view>
- <view class="divider" v-if="(student.vision_input_user || student.refraction_input_user) && activeTab !== 0"></view>
- <view class="card-footer" v-if="activeTab !== 0">
- <view class="info-row" v-if="student.vision_input_user">
- <text class="label">视力录入医生</text>
- <text class="value">{{ student.vision_input_user }}</text>
- </view>
- <view class="info-row" v-if="student.vision_input_time">
- <text class="label">视力录入时间</text>
- <text class="value">{{ student.vision_input_time }}</text>
- </view>
- <view class="info-row" v-if="student.refraction_input_user">
- <text class="label">屈光度录入医生</text>
- <text class="value">{{ student.refraction_input_user }}</text>
- </view>
- <view class="info-row" v-if="student.refraction_input_time">
- <text class="label">屈光度录入时间</text>
- <text class="value">{{ student.refraction_input_time }}</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script setup>
- import { getIncompleteVisionStudents } from '@/services/common'
- const studentList = ref([])
- const activeTab = ref(0)
- const classId = ref('')
- const className = ref('')
- const grade = ref('')
- const searchKeyword = ref('')
- const schoolName = ref('')
- const userName = ref('')
- const userPhone = ref('')
- const userOrg = ref('')
- let searchTimer = null
- const isEntered = (student) => {
- return student.vision_input_status === 1 && student.refraction_input_status === 1
- }
- const formatTime = (time) => {
- if (!time) return ''
- try {
- const date = new Date(time)
- if (isNaN(date.getTime())) return time
- date.setHours(date.getHours() + 8)
- const year = date.getFullYear()
- const month = String(date.getMonth() + 1).padStart(2, '0')
- const day = String(date.getDate()).padStart(2, '0')
- const hour = String(date.getHours()).padStart(2, '0')
- const minute = String(date.getMinutes()).padStart(2, '0')
- const second = String(date.getSeconds()).padStart(2, '0')
- return `${year}-${month}-${day} ${hour}:${minute}:${second}`
- } catch (e) {
- return time
- }
- }
- const onTabChange = () => {
- fetchStudents()
- }
- const fetchStudents = async () => {
- if (!classId.value) return
-
- try {
- const params = {}
- if (searchKeyword.value) {
- if (/^\d+$/.test(searchKeyword.value)) {
- params.id_card = searchKeyword.value
- } else {
- params.name = searchKeyword.value
- }
- }
-
- if (activeTab.value === 0) {
- params.status = 'incomplete'
- } else if (activeTab.value === 1) {
- params.status = 'complete'
- } else if (activeTab.value === 2) {
- params.status = 'all'
- }
-
- const res = await getIncompleteVisionStudents(classId.value, params)
- if (res && res.code === 200) {
- studentList.value = res.data.list || []
- }
- } catch (error) {
- console.error('获取学生列表失败', error)
- }
- }
- const onSearch = () => {
- if (searchTimer) clearTimeout(searchTimer)
- searchTimer = setTimeout(() => {
- fetchStudents()
- }, 500)
- }
- onLoad(async (options) => {
- classId.value = options.classId || ''
- className.value = options.className || ''
- grade.value = options.grade || ''
- schoolName.value = decodeURIComponent(options.schoolName || '')
- userName.value = decodeURIComponent(options.userName || '')
- userPhone.value = decodeURIComponent(options.userPhone || '')
- userOrg.value = decodeURIComponent(options.userOrg || '')
-
- if (!classId.value) {
- uni.showToast({
- title: '班级信息缺失',
- icon: 'none'
- })
- return
- }
-
- fetchStudents()
- })
- onShow(() => {
- if (classId.value) {
- fetchStudents()
- }
- })
- const addStudent = () => {
- uni.navigateTo({
- url: `/pages/index/add-student?classId=${classId.value}&userName=${encodeURIComponent(userName.value)}&userPhone=${encodeURIComponent(userPhone.value)}`
- })
- }
- const onBack = () => {
- uni.navigateBack()
- }
- const goToVisionInput = (student) => {
- const params = {
- studentId: student.id,
- studentName: student.name,
- studentGender: student.gender,
- studentIdCard: student.id_card,
- classId: classId.value,
- className: className.value,
- grade: grade.value,
- visionDataId: student.vision_data_id || '',
- schoolName: schoolName.value,
- userName: userName.value,
- userPhone: userPhone.value,
- userOrg: userOrg.value,
- visionStatus: student.vision_input_status,
- refractionStatus: student.refraction_input_status
- }
-
- const visionStatus = student.vision_input_status
- const refractionStatus = student.refraction_input_status
-
- if (visionStatus === 1 && refractionStatus === 1) {
- return uni.navigateTo({
- url: `/pages/index/vision-detail?${Object.keys(params).map(k => `${k}=${encodeURIComponent(params[k])}`).join('&')}`
- })
- }
-
- uni.navigateTo({
- url: `/pages/index/select-input-type?${Object.keys(params).map(k => `${k}=${encodeURIComponent(params[k])}`).join('&')}`
- })
- }
- </script>
- <style lang="scss" scoped>
- .page {
- min-height: 100vh;
- background: #f5f5f5;
- }
- .content {
- padding: 20rpx;
- padding-top: calc(20rpx + 46px + 54px + 44px);
- }
- .tab-bar {
- position: fixed;
- top: calc(46px + 54px);
- left: 0;
- right: 0;
- z-index: 999;
- background: #fff;
- }
- .search-bar {
- position: fixed;
- top: 46px;
- left: 0;
- right: 0;
- z-index: 999;
- background: #fff;
- display: flex;
- align-items: center;
- padding: 10rpx 20rpx;
- gap: 10rpx;
- }
- .search-bar :deep(.van-search) {
- flex: 1;
- padding: 0;
- }
- .search-bar :deep(.van-button) {
- flex-shrink: 0;
- }
- .student-card {
- background: #fff;
- border-radius: 20rpx;
- padding: 30rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
- }
- .card-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 20rpx;
- padding-bottom: 20rpx;
- border-bottom: 1rpx solid #f0f0f0;
- }
- .left {
- display: flex;
- align-items: center;
- gap: 20rpx;
- }
- .name {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
- .gender-icon {
- width: 40rpx;
- height: 40rpx;
- }
- .status-tag {
- padding: 8rpx 20rpx;
- border-radius: 30rpx;
- font-size: 24rpx;
- background: #e8f8f5;
- color: #07c160;
- }
- .status-tag.warning {
- background: #fff3e8;
- color: #ff976a;
- }
- .card-body {
- padding-top: 10rpx;
- }
- .divider {
- height: 1rpx;
- background: #f0f0f0;
- margin: 20rpx 0;
- }
- .card-footer {
- padding-top: 10rpx;
- }
- .info-row {
- display: flex;
- align-items: center;
- font-size: 26rpx;
- color: #666;
- margin-bottom: 10rpx;
- justify-content: space-between;
- }
- .info-row:last-child {
- margin-bottom: 0;
- }
- .label {
- color: #999;
- }
- .value {
- color: #333;
- text-align: right;
- }
- </style>
|