feat(打卡): 添加计数打卡类型功能
在打卡详情页新增计数打卡类型相关UI和逻辑 - 添加计数对象选择组件 - 添加计数次数调整组件 - 实现新增计数对象功能 - 通过路由参数传递打卡类型
Showing
2 changed files
with
122 additions
and
2 deletions
| ... | @@ -37,6 +37,73 @@ | ... | @@ -37,6 +37,73 @@ |
| 37 | /> | 37 | /> |
| 38 | </van-popup> | 38 | </van-popup> |
| 39 | </div> | 39 | </div> |
| 40 | + <!-- 计数对象 --> | ||
| 41 | + <div v-if="checkinType === 'count'" class="mb-4"> | ||
| 42 | + <div class="flex justify-between items-center mb-2 mx-2"> | ||
| 43 | + <div class="text-sm font-bold text-gray-700">计数对象</div> | ||
| 44 | + <van-button size="small" type="primary" plain icon="plus" @click="showAddTargetDialog = true" class="!h-7">添加</van-button> | ||
| 45 | + </div> | ||
| 46 | + | ||
| 47 | + <div class="bg-gray-50 rounded-lg p-2 max-h-48 overflow-y-auto"> | ||
| 48 | + <van-checkbox-group v-model="selectedTargets"> | ||
| 49 | + <template v-if="targetList.length > 0"> | ||
| 50 | + <div | ||
| 51 | + v-for="(item, index) in targetList" | ||
| 52 | + :key="index" | ||
| 53 | + class="flex items-center justify-between p-3 mb-2 bg-white rounded border border-gray-100 last:mb-0" | ||
| 54 | + @click="toggleTarget(index)" | ||
| 55 | + > | ||
| 56 | + <div class="flex-1"> | ||
| 57 | + <div class="font-medium text-gray-800">{{ item.name }}</div> | ||
| 58 | + <div class="text-xs text-gray-500 mt-0.5">{{ item.city }} | {{ item.school }}</div> | ||
| 59 | + </div> | ||
| 60 | + <van-checkbox | ||
| 61 | + :name="item" | ||
| 62 | + :ref="el => setCheckboxRef(el, index)" | ||
| 63 | + @click.stop | ||
| 64 | + /> | ||
| 65 | + </div> | ||
| 66 | + </template> | ||
| 67 | + <div v-else class="text-center py-4 text-gray-400 text-sm"> | ||
| 68 | + 暂无计数对象,请点击上方添加按钮 | ||
| 69 | + </div> | ||
| 70 | + </van-checkbox-group> | ||
| 71 | + </div> | ||
| 72 | + </div> | ||
| 73 | + | ||
| 74 | + <!-- 计数次数 --> | ||
| 75 | + <div v-if="checkinType === 'count'" class="mb-4 flex items-center justify-between bg-gray-50 p-3 rounded-lg"> | ||
| 76 | + <div class="text-sm font-bold text-gray-700">计数次数</div> | ||
| 77 | + <van-stepper v-model="countValue" min="1" integer input-width="80px" button-size="28px" /> | ||
| 78 | + </div> | ||
| 79 | + | ||
| 80 | + <!-- 新增计数对象弹框 --> | ||
| 81 | + <van-dialog v-model:show="showAddTargetDialog" title="添加计数对象" show-cancel-button confirmButtonColor="#4caf50" @confirm="confirmAddTarget"> | ||
| 82 | + <div class="p-4"> | ||
| 83 | + <van-field | ||
| 84 | + v-model="newTargetForm.name" | ||
| 85 | + label="姓名" | ||
| 86 | + placeholder="请输入姓名" | ||
| 87 | + class="border-b border-gray-100" | ||
| 88 | + /> | ||
| 89 | + <van-field | ||
| 90 | + v-model="newTargetForm.city" | ||
| 91 | + label="城市" | ||
| 92 | + placeholder="请输入所在城市" | ||
| 93 | + class="border-b border-gray-100" | ||
| 94 | + /> | ||
| 95 | + <van-field | ||
| 96 | + v-model="newTargetForm.school" | ||
| 97 | + label="学校" | ||
| 98 | + rows="2" | ||
| 99 | + autosize | ||
| 100 | + type="textarea" | ||
| 101 | + maxlength="50" | ||
| 102 | + placeholder="请输入所在学校" | ||
| 103 | + /> | ||
| 104 | + </div> | ||
| 105 | + </van-dialog> | ||
| 106 | + | ||
| 40 | <!-- 文本输入区域 --> | 107 | <!-- 文本输入区域 --> |
| 41 | <div class="text-input-area"> | 108 | <div class="text-input-area"> |
| 42 | <van-field v-model="message" rows="6" autosize type="textarea" | 109 | <van-field v-model="message" rows="6" autosize type="textarea" |
| ... | @@ -146,7 +213,7 @@ | ... | @@ -146,7 +213,7 @@ |
| 146 | </template> | 213 | </template> |
| 147 | 214 | ||
| 148 | <script setup> | 215 | <script setup> |
| 149 | -import { ref, computed, onMounted, nextTick } from 'vue' | 216 | +import { ref, computed, onMounted, nextTick, reactive } from 'vue' |
| 150 | import { useRoute, useRouter } from 'vue-router' | 217 | import { useRoute, useRouter } from 'vue-router' |
| 151 | import { getTaskDetailAPI, getUploadTaskInfoAPI } from "@/api/checkin" | 218 | import { getTaskDetailAPI, getUploadTaskInfoAPI } from "@/api/checkin" |
| 152 | import { getTeacherFindSettingsAPI } from '@/api/teacher' | 219 | import { getTeacherFindSettingsAPI } from '@/api/teacher' |
| ... | @@ -182,6 +249,9 @@ const { | ... | @@ -182,6 +249,9 @@ const { |
| 182 | // 任务详情数据 | 249 | // 任务详情数据 |
| 183 | const taskDetail = ref({}) | 250 | const taskDetail = ref({}) |
| 184 | 251 | ||
| 252 | +// 打卡类型 | ||
| 253 | +const checkinType = computed(() => route.query.type) | ||
| 254 | + | ||
| 185 | // 作业选择相关 | 255 | // 作业选择相关 |
| 186 | const showTaskPicker = ref(false) | 256 | const showTaskPicker = ref(false) |
| 187 | const selectedTaskText = ref('') | 257 | const selectedTaskText = ref('') |
| ... | @@ -199,6 +269,53 @@ const onConfirmTask = ({ selectedOptions }) => { | ... | @@ -199,6 +269,53 @@ const onConfirmTask = ({ selectedOptions }) => { |
| 199 | showTaskPicker.value = false | 269 | showTaskPicker.value = false |
| 200 | } | 270 | } |
| 201 | 271 | ||
| 272 | +// 计数打卡相关逻辑 | ||
| 273 | +const countValue = ref(1) | ||
| 274 | +const selectedTargets = ref([]) | ||
| 275 | +// Mock 老师数据 | ||
| 276 | +const targetList = ref([ | ||
| 277 | + { name: '张老师', city: '北京', school: '北京大学' }, | ||
| 278 | + { name: '李老师', city: '上海', school: '复旦大学' } | ||
| 279 | +]) | ||
| 280 | +const showAddTargetDialog = ref(false) | ||
| 281 | +const newTargetForm = reactive({ | ||
| 282 | + name: '', | ||
| 283 | + city: '', | ||
| 284 | + school: '' | ||
| 285 | +}) | ||
| 286 | + | ||
| 287 | +const checkboxRefs = ref([]) | ||
| 288 | +const setCheckboxRef = (el, index) => { | ||
| 289 | + if (el) { | ||
| 290 | + checkboxRefs.value[index] = el | ||
| 291 | + } | ||
| 292 | +} | ||
| 293 | + | ||
| 294 | +const toggleTarget = (index) => { | ||
| 295 | + const checkbox = checkboxRefs.value[index] | ||
| 296 | + if (checkbox) { | ||
| 297 | + checkbox.toggle() | ||
| 298 | + } | ||
| 299 | +} | ||
| 300 | + | ||
| 301 | +const confirmAddTarget = () => { | ||
| 302 | + if (!newTargetForm.name || !newTargetForm.city || !newTargetForm.school) { | ||
| 303 | + showToast('请完整填写信息') | ||
| 304 | + return | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + // 打印录入信息 | ||
| 308 | + console.log('新增计数对象信息:', { ...newTargetForm }) | ||
| 309 | + | ||
| 310 | + // 添加到列表 | ||
| 311 | + targetList.value.push({ ...newTargetForm }) | ||
| 312 | + | ||
| 313 | + // 重置表单 | ||
| 314 | + newTargetForm.name = '' | ||
| 315 | + newTargetForm.city = '' | ||
| 316 | + newTargetForm.school = '' | ||
| 317 | +} | ||
| 318 | + | ||
| 202 | // 作品类型选项 | 319 | // 作品类型选项 |
| 203 | const attachmentTypeOptions = ref([]) | 320 | const attachmentTypeOptions = ref([]) |
| 204 | 321 | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-05-29 15:34:17 | 2 | * @Date: 2025-05-29 15:34:17 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-12-10 21:32:42 | 4 | + * @LastEditTime: 2025-12-11 10:32:47 |
| 5 | * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue | 5 | * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| ... | @@ -584,6 +584,8 @@ const handleCheckinTypeClick = (type) => { | ... | @@ -584,6 +584,8 @@ const handleCheckinTypeClick = (type) => { |
| 584 | 584 | ||
| 585 | /** | 585 | /** |
| 586 | * 跳转到打卡详情页面 | 586 | * 跳转到打卡详情页面 |
| 587 | + * taskDetail.task_type: 打卡类型, [upload 上传附件, count 计数] | ||
| 588 | + * 业务逻辑调整, 需要把打卡类型带到下一页判断 | ||
| 587 | */ | 589 | */ |
| 588 | const goToCheckinDetailPage = () => { | 590 | const goToCheckinDetailPage = () => { |
| 589 | const current_date = route.query.date || dayjs().format('YYYY-MM-DD'); | 591 | const current_date = route.query.date || dayjs().format('YYYY-MM-DD'); |
| ... | @@ -593,6 +595,7 @@ const goToCheckinDetailPage = () => { | ... | @@ -593,6 +595,7 @@ const goToCheckinDetailPage = () => { |
| 593 | id: route.query.id, | 595 | id: route.query.id, |
| 594 | date: current_date, | 596 | date: current_date, |
| 595 | is_patch: isPatchCheckin.value ? '1' : '0', | 597 | is_patch: isPatchCheckin.value ? '1' : '0', |
| 598 | + type: taskDetail.value.task_type, | ||
| 596 | } | 599 | } |
| 597 | }) | 600 | }) |
| 598 | } | 601 | } | ... | ... |
-
Please register or login to post a comment