hookehuyr

feat(打卡): 添加计数打卡类型功能

在打卡详情页新增计数打卡类型相关UI和逻辑
- 添加计数对象选择组件
- 添加计数次数调整组件
- 实现新增计数对象功能
- 通过路由参数传递打卡类型
...@@ -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 }
......