hookehuyr

feat(checkin): 添加编辑打卡时合并附件类型的功能

在编辑打卡记录时,合并attachment_type和file_type数组以适配前后打卡类型不一致的情况
...@@ -20,15 +20,9 @@ ...@@ -20,15 +20,9 @@
20 <div class="section-content"> 20 <div class="section-content">
21 <!-- 文本输入区域 --> 21 <!-- 文本输入区域 -->
22 <div class="text-input-area"> 22 <div class="text-input-area">
23 - <van-field 23 + <van-field v-model="message" rows="6" autosize type="textarea"
24 - v-model="message"
25 - rows="6"
26 - autosize
27 - type="textarea"
28 :placeholder="activeType === 'text' ? '请输入打卡留言,至少需要10个字符' : '请输入打卡留言(可选)'" 24 :placeholder="activeType === 'text' ? '请输入打卡留言,至少需要10个字符' : '请输入打卡留言(可选)'"
29 - :maxlength="activeType === 'text' ? 500 : 200" 25 + :maxlength="activeType === 'text' ? 500 : 200" show-word-limit />
30 - show-word-limit
31 - />
32 </div> 26 </div>
33 27
34 <!-- 打卡类型选项卡 --> 28 <!-- 打卡类型选项卡 -->
...@@ -36,19 +30,12 @@ ...@@ -36,19 +30,12 @@
36 <div class="tabs-header"> 30 <div class="tabs-header">
37 <div class="tab-title">选择打卡类型</div> 31 <div class="tab-title">选择打卡类型</div>
38 <div class="tabs-nav"> 32 <div class="tabs-nav">
39 - <div 33 + <div v-for="option in attachmentTypeOptions" :key="option.key"
40 - v-for="option in attachmentTypeOptions" 34 + @click="!isEditMode ? switchType(option.key) : null" :class="['tab-item', {
41 - :key="option.key"
42 - @click="!isEditMode ? switchType(option.key) : null"
43 - :class="['tab-item', {
44 active: activeType === option.key, 35 active: activeType === option.key,
45 disabled: isEditMode && activeType !== option.key 36 disabled: isEditMode && activeType !== option.key
46 - }]" 37 + }]">
47 - > 38 + <van-icon :name="getIconName(option.key)" size="1.2rem" />
48 - <van-icon
49 - :name="getIconName(option.key)"
50 - size="1.2rem"
51 - />
52 <span class="tab-text">{{ option.value }}</span> 39 <span class="tab-text">{{ option.value }}</span>
53 </div> 40 </div>
54 </div> 41 </div>
...@@ -56,19 +43,10 @@ ...@@ -56,19 +43,10 @@
56 43
57 <!-- 文件上传区域 --> 44 <!-- 文件上传区域 -->
58 <div v-if="activeType !== 'text'" class="upload-area"> 45 <div v-if="activeType !== 'text'" class="upload-area">
59 - <van-uploader 46 + <van-uploader v-model="fileList" :max-count="maxCount" :max-size="20 * 1024 * 1024"
60 - v-model="fileList" 47 + :before-read="beforeRead" :after-read="afterRead" @delete="onDelete"
61 - :max-count="maxCount" 48 + @click-preview="onClickPreview" multiple :accept="getAcceptType()" result-type="file"
62 - :max-size="20 * 1024 * 1024" 49 + :deletable="false" />
63 - :before-read="beforeRead"
64 - :after-read="afterRead"
65 - @delete="onDelete"
66 - @click-preview="onClickPreview"
67 - multiple
68 - :accept="getAcceptType()"
69 - result-type="file"
70 - :deletable="false"
71 - />
72 50
73 <!-- 文件列表显示 --> 51 <!-- 文件列表显示 -->
74 <div v-if="fileList.length > 0" class="file-list"> 52 <div v-if="fileList.length > 0" class="file-list">
...@@ -78,12 +56,7 @@ ...@@ -78,12 +56,7 @@
78 <span class="file-name">{{ item.name || item.file?.name }}</span> 56 <span class="file-name">{{ item.name || item.file?.name }}</span>
79 <span class="file-status" :class="item.status">{{ item.message }}</span> 57 <span class="file-status" :class="item.status">{{ item.message }}</span>
80 </div> 58 </div>
81 - <van-icon 59 + <van-icon name="clear" size="1rem" @click="delItem(item)" class="delete-icon" />
82 - name="clear"
83 - size="1rem"
84 - @click="delItem(item)"
85 - class="delete-icon"
86 - />
87 </div> 60 </div>
88 </div> 61 </div>
89 62
...@@ -98,14 +71,8 @@ ...@@ -98,14 +71,8 @@
98 71
99 <!-- 提交按钮 --> 72 <!-- 提交按钮 -->
100 <div v-if="!taskDetail.is_finish || route.query.status === 'edit'" class="submit-area"> 73 <div v-if="!taskDetail.is_finish || route.query.status === 'edit'" class="submit-area">
101 - <van-button 74 + <van-button type="primary" block size="large" :loading="uploading" :disabled="!canSubmit"
102 - type="primary" 75 + @click="onSubmit">
103 - block
104 - size="large"
105 - :loading="uploading"
106 - :disabled="!canSubmit"
107 - @click="onSubmit"
108 - >
109 {{ route.query.status === 'edit' ? '保存修改' : '提交打卡' }} 76 {{ route.query.status === 'edit' ? '保存修改' : '提交打卡' }}
110 </van-button> 77 </van-button>
111 </div> 78 </div>
...@@ -119,41 +86,24 @@ ...@@ -119,41 +86,24 @@
119 </van-overlay> 86 </van-overlay>
120 87
121 <!-- 音频播放器弹窗 --> 88 <!-- 音频播放器弹窗 -->
122 - <van-popup 89 + <van-popup v-model:show="audioShow" position="bottom" round closeable :style="{ height: '60%', width: '100%' }">
123 - v-model:show="audioShow"
124 - position="bottom"
125 - round
126 - closeable
127 - :style="{ height: '60%', width: '100%' }"
128 - >
129 <div class="p-4"> 90 <div class="p-4">
130 <h3 class="text-lg font-medium mb-4 text-center">{{ audioTitle }}</h3> 91 <h3 class="text-lg font-medium mb-4 text-center">{{ audioTitle }}</h3>
131 - <AudioPlayer 92 + <AudioPlayer v-if="audioShow && audioUrl" :songs="[{ title: audioTitle, url: audioUrl }]"
132 - v-if="audioShow && audioUrl" 93 + class="w-full" />
133 - :songs="[{ title: audioTitle, url: audioUrl }]"
134 - class="w-full"
135 - />
136 </div> 94 </div>
137 </van-popup> 95 </van-popup>
138 96
139 <!-- 视频播放器弹窗 --> 97 <!-- 视频播放器弹窗 -->
140 - <van-popup 98 + <van-popup v-model:show="videoShow" position="center" round closeable
141 - v-model:show="videoShow" 99 + :style="{ width: '95%', maxHeight: '80vh' }" @close="stopVideoPlay">
142 - position="center"
143 - round
144 - closeable
145 - :style="{ width: '95%', maxHeight: '80vh' }"
146 - @close="stopVideoPlay"
147 - >
148 <div class="p-4"> 100 <div class="p-4">
149 <h3 class="text-lg font-medium mb-4 text-center">视频预览</h3> 101 <h3 class="text-lg font-medium mb-4 text-center">视频预览</h3>
150 <div class="relative w-full bg-black rounded-lg overflow-hidden" style="aspect-ratio: 16/9;"> 102 <div class="relative w-full bg-black rounded-lg overflow-hidden" style="aspect-ratio: 16/9;">
151 <!-- 视频封面 --> 103 <!-- 视频封面 -->
152 - <div 104 + <div v-show="!isVideoPlaying"
153 - v-show="!isVideoPlaying"
154 class="absolute inset-0 flex items-center justify-center cursor-pointer" 105 class="absolute inset-0 flex items-center justify-center cursor-pointer"
155 - @click="startVideoPlay" 106 + @click="startVideoPlay">
156 - >
157 <img :src="videoCover || 'https://cdn.ipadbiz.cn/mlaj/images/cover_video_2.png'" 107 <img :src="videoCover || 'https://cdn.ipadbiz.cn/mlaj/images/cover_video_2.png'"
158 :alt="videoTitle" class="w-full h-full object-cover" /> 108 :alt="videoTitle" class="w-full h-full object-cover" />
159 <div class="absolute inset-0 flex items-center justify-center bg-black/20"> 109 <div class="absolute inset-0 flex items-center justify-center bg-black/20">
...@@ -164,34 +114,23 @@ ...@@ -164,34 +114,23 @@
164 </div> 114 </div>
165 </div> 115 </div>
166 <!-- 视频播放器 --> 116 <!-- 视频播放器 -->
167 - <VideoPlayer 117 + <VideoPlayer v-show="isVideoPlaying" ref="videoPlayerRef" :video-url="videoUrl"
168 - v-show="isVideoPlaying" 118 + :video-id="videoTitle" :autoplay="false" class="w-full h-full" @play="handleVideoPlay"
169 - ref="videoPlayerRef" 119 + @pause="handleVideoPause" />
170 - :video-url="videoUrl"
171 - :video-id="videoTitle"
172 - :autoplay="false"
173 - class="w-full h-full"
174 - @play="handleVideoPlay"
175 - @pause="handleVideoPause"
176 - />
177 </div> 120 </div>
178 </div> 121 </div>
179 </van-popup> 122 </van-popup>
180 123
181 <!-- 图片预览弹窗 --> 124 <!-- 图片预览弹窗 -->
182 - <van-image-preview 125 + <van-image-preview v-model:show="imageShow" :images="imageList" :start-position="imageIndex"
183 - v-model:show="imageShow" 126 + :show-index="true" />
184 - :images="imageList"
185 - :start-position="imageIndex"
186 - :show-index="true"
187 - />
188 </div> 127 </div>
189 </template> 128 </template>
190 129
191 <script setup> 130 <script setup>
192 import { ref, computed, onMounted, nextTick } from 'vue' 131 import { ref, computed, onMounted, nextTick } from 'vue'
193 import { useRoute, useRouter } from 'vue-router' 132 import { useRoute, useRouter } from 'vue-router'
194 -import { getTaskDetailAPI } from "@/api/checkin" 133 +import { getTaskDetailAPI, getUploadTaskInfoAPI } from "@/api/checkin"
195 import { getTeacherFindSettingsAPI } from '@/api/teacher' 134 import { getTeacherFindSettingsAPI } from '@/api/teacher'
196 import { useTitle } from '@vueuse/core' 135 import { useTitle } from '@vueuse/core'
197 import { useCheckin } from '@/composables/useCheckin' 136 import { useCheckin } from '@/composables/useCheckin'
...@@ -325,6 +264,16 @@ const getTaskDetail = async (month) => { ...@@ -325,6 +264,16 @@ const getTaskDetail = async (month) => {
325 'video': '视频' 264 'video': '视频'
326 } 265 }
327 266
267 + // attachment_type 和 file_type 合并成一个数组 合并以后的数组,就是学员编辑的时候,可以使用的类型
268 + // 主要是适配先前打卡类型和后期打卡类型不一致的情况
269 + if (route.query.status === 'edit') {
270 + const info = await getUploadTaskInfoAPI({ i: route.query.post_id });
271 + if (info.code) {
272 + // 合并 attachment_type 和 file_type 数组, 里面数据需要去重复
273 + data.attachment_type = [...new Set([...data.attachment_type, info.data.file_type])];
274 + }
275 + }
276 +
328 // 如果是数组格式,转换为对象格式 277 // 如果是数组格式,转换为对象格式
329 if (Array.isArray(data.attachment_type)) { 278 if (Array.isArray(data.attachment_type)) {
330 attachmentTypeOptions.value = data.attachment_type.map(key => ({ 279 attachmentTypeOptions.value = data.attachment_type.map(key => ({
......