hookehuyr

feat(打卡): 拆分音视频上传组件并实现打卡功能

将原有的file.vue拆分为独立的video.vue和audio.vue组件
添加打卡相关API接口并实现提交功能
更新打卡页面路由和类型选择逻辑
实现打卡动态列表的数据获取和展示
/*
* @Date: 2025-06-06 09:26:16
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-06 15:05:19
* @LastEditTime: 2025-06-06 16:19:13
* @FilePath: /mlaj/src/api/checkin.js
* @Description: 签到模块相关接口
*/
......@@ -11,6 +11,8 @@ const Api = {
GET_TASK_LIST: '/srv/?a=task&t=my_list',
GET_TASK_DETAIL: '/srv/?a=task&t=detail',
TASK_CHECKIN: '/srv/?a=checkin&t=checkin',
TASK_UPLOAD_ADD: '/srv/?a=checkin&t=upload_add',
TASK_UPLOAD_LIST: '/srv/?a=checkin&t=upload_list',
}
/**
......@@ -35,3 +37,25 @@ export const getTaskDetailAPI = (params) => fn(fetch.get(Api.GET_TASK_DETAIL, p
* @returns
*/
export const checkinTaskAPI = (params) => fn(fetch.post(Api.TASK_CHECKIN, params))
/**
* @description: 新增上传打卡
* @param task_id 上传作业ID
* @param note 打卡文字
* @param meta_id[] 附件ID列表
* @param file_type 上传附件的类型 image=上传图片,video=视频,audio=音频
* @returns
*/
export const addUploadTaskAPI = (params) => fn(fetch.post(Api.TASK_UPLOAD_ADD, params))
/**
* @description: 获取打卡动态列表
* @param task_id 上传作业ID
* @param date 日期
* @param keyword 搜索
* @param order_by_time asc=正序,desc=倒序。默认为倒序
* @param limit
* @param offset
* @returns
*/
export const getUploadTaskListAPI = (params) => fn(fetch.post(Api.TASK_UPLOAD_LIST, params))
......
/*
* @Date: 2025-03-21 13:28:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-06 14:35:56
* @LastEditTime: 2025-06-06 15:45:36
* @FilePath: /mlaj/src/router/checkin.js
* @Description: 文件描述
*/
......@@ -61,11 +61,20 @@ export default [
}
},
{
path: '/checkin/file',
name: 'FileCheckIn',
component: () => import('@/views/checkin/upload/file.vue'),
path: '/checkin/video',
name: 'VideoCheckIn',
component: () => import('@root/src/views/checkin/upload/video.vue'),
meta: {
title: '打卡视频/音频',
title: '打卡视频',
requiresAuth: true
}
},
{
path: '/checkin/audio',
name: 'AudioCheckIn',
component: () => import('@root/src/views/checkin/upload/audio.vue'),
meta: {
title: '打卡音频',
requiresAuth: true
}
},
......
<!--
* @Date: 2025-05-29 15:34:17
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-06 14:33:04
* @LastEditTime: 2025-06-06 17:07:25
* @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue
* @Description: 文件描述
-->
......@@ -40,25 +40,26 @@
<van-progress :percentage="progress2" color="#4caf50" :show-pivot="false" />
</div> -->
<div style="padding: 0.75rem 1rem;">
<van-image round width="2.8rem" height="2.8rem" src="https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg"
<van-image round width="2.8rem" height="2.8rem" :src="item ? item : 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'" fit="contain"
v-for="(item, index) in teamAvatars" :key="index"
:style="{ marginLeft: index > 0 ? '-0.5rem' : '', border: '2px solid #FFF' }" />
:style="{ marginLeft: index > 0 ? '-0.5rem' : '', border: '2px solid #eff6ff', background: '#fff' }" />
</div>
</div>
</div>
<div v-if="!taskDetail.is_gray" class="text-wrapper">
<!-- <div v-if="!taskDetail.is_gray" class="text-wrapper"> -->
<div v-if="taskDetail.is_gray" class="text-wrapper">
<div class="text-header">打卡类型</div>
<div class="upload-wrapper">
<div @click="goToCheckinImagePage" class="upload-boxer">
<div><van-icon name="photo" size="2.5rem" /></div>
<div style="font-size: 0.85rem;">图文打卡</div>
</div>
<div @click="goToCheckinFilePage('video')" class="upload-boxer">
<div @click="goToCheckinVideoPage()" class="upload-boxer">
<div><van-icon name="video" size="2.5rem" /></div>
<div style="font-size: 0.85rem;">视频打卡</div>
</div>
<div @click="goToCheckinFilePage('audio')" class="upload-boxer">
<div @click="goToCheckinAudioPage()" class="upload-boxer">
<div><van-icon name="music" size="2.5rem" /></div>
<div style="font-size: 0.85rem;">音频打卡</div>
</div>
......@@ -67,11 +68,11 @@
<div class="text-wrapper">
<div class="text-header">打卡动态</div>
<div class="post-card" v-for="post in mockPosts" :key="post.id">
<div class="post-card" v-for="post in checkinDataList" :key="post.id">
<div class="post-header">
<van-row>
<van-col span="4">
<van-image round width="2.5rem" height="2.5rem" :src="post.user.avatar" />
<van-image round width="2.5rem" height="2.5rem" :src="post.user.avatar" fit="cover" />
</van-col>
<van-col span="17">
<div class="user-info">
......@@ -98,13 +99,13 @@
<div v-for="(v, idx) in post.videoList" :key="idx">
<!-- 视频封面和播放按钮 -->
<div v-if="v.video && !v.isPlaying" class="relative w-full rounded-lg overflow-hidden" style="aspect-ratio: 16/9; margin-bottom: 1rem;">
<img :src="v.videoCover || 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg'"
<img :src="v.videoCover || 'https://cdn.ipadbiz.cn/mlaj/images/cover_video_1.png'"
:alt="v.content" class="w-full h-full object-cover" />
<div class="absolute inset-0 flex items-center justify-center cursor-pointer bg-black/20"
@click="startPlay(v)">
<div
class="w-16 h-16 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors">
<van-icon name="play-circle-o" class="text-white" size="30" />
<van-icon name="play-circle-o" class="text-white" size="40" />
</div>
</div>
</div>
......@@ -163,7 +164,7 @@ import AudioPlayer from "@/components/ui/AudioPlayer.vue";
import { useTitle } from '@vueuse/core';
import dayjs from 'dayjs';
import { getTaskDetailAPI } from "@/api/checkin";
import { getTaskDetailAPI, getUploadTaskListAPI } from "@/api/checkin";
const route = useRoute()
const router = useRouter()
......@@ -200,10 +201,10 @@ onBeforeUnmount(() => {
* @param {Object} post - 要播放视频的帖子对象
*/
const startPlay = (post) => {
// 确保mockPosts.value是一个数组
if (mockPosts.value) {
// 确保checkinDataList.value是一个数组
if (checkinDataList.value) {
// 先暂停所有其他视频
mockPosts.value.forEach(p => {
checkinDataList.value.forEach(p => {
p.videoList.forEach(v => {
if (v.id !== post.id) {
v.isPlaying = false;
......@@ -251,7 +252,7 @@ const stopOtherVideos = (currentPlayer, currentPost) => {
}
// 更新其他帖子的播放状态
mockPosts.value.forEach(p => {
checkinDataList.value.forEach(p => {
p.videoList.forEach(v => {
if (v.id !== currentPost.id) {
v.isPlaying = false;
......@@ -281,7 +282,7 @@ const stopOtherAudio = (currentPlayer, currentPost) => {
});
}
// 更新其他帖子的播放状态
mockPosts.value.forEach(post => {
checkinDataList.value.forEach(post => {
if (post.id!== currentPost.id) {
post.isPlaying = false;
}
......@@ -300,7 +301,7 @@ const stopAllAudio = () => {
}
});
// 更新所有帖子的播放状态
mockPosts.value.forEach(post => {
checkinDataList.value.forEach(post => {
if (post.audio.length) {
post.isPlaying = false;
}
......@@ -315,7 +316,7 @@ const stopAllVideos = () => {
if (!videoPlayers.value) return;
// 更新所有帖子的播放状态
mockPosts.value.forEach(p => {
checkinDataList.value.forEach(p => {
p.videoList.forEach(v => {
v.isPlaying = false;
});
......@@ -338,9 +339,7 @@ const mockPosts = ref([
'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg',
'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg',
],
video: '',
videoList: [],
videoCover: '',
isPlaying: false,
audio: [],
likes: 12,
......@@ -367,7 +366,6 @@ const mockPosts = ref([
videoCover: '',
isPlaying: false,
}],
videoCover: '',
isPlaying: false,
audio: [],
likes: 12,
......@@ -382,9 +380,7 @@ const mockPosts = ref([
},
content: '今天完成了React基础课程的学习,收获满满!',
images: [],
video: '',
videoList: [],
videoCover: '',
isPlaying: false,
audio: [
{
......@@ -412,7 +408,6 @@ const mockPosts = ref([
},
content: '今天完成了React基础课程的学习,收获满满!',
images: [],
video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
videoList: [{
id: 3,
video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
......@@ -424,7 +419,6 @@ const mockPosts = ref([
videoCover: '',
isPlaying: false,
}],
videoCover: '',
isPlaying: false,
audio: [],
likes: 12,
......@@ -439,9 +433,7 @@ const mockPosts = ref([
},
content: '今天完成了React基础课程的学习,收获满满!',
images: [],
video: '',
videoList: [],
videoCover: '',
isPlaying: false,
audio: [
{
......@@ -461,7 +453,7 @@ const themeVars = {
}
const progress1 = ref(0);
const progress2 = ref(76);
// const progress2 = ref(76);
const teamAvatars = ref([])
......@@ -485,7 +477,7 @@ const formatter = (day) => {
const month = day.date.getMonth() + 1;
const date = day.date.getDate();
let checkin_days = [1, 2];
let checkin_days = myCheckinDates.value;
if (month === 6) {
if (checkin_days.includes(date)) {
......@@ -511,10 +503,32 @@ const onClickSubtitle = (evt) => {
}
const goToCheckinImagePage = () => {
router.push('/checkin/image');
router.push({
path: '/checkin/image',
query: {
id: route.query.id,
type: 'image'
}
})
}
const goToCheckinFilePage = (type) => {
router.push('/checkin/file?type=' + type);
const goToCheckinVideoPage = (type) => {
router.push({
path: '/checkin/video',
query: {
id: route.query.id,
type: 'video',
}
})
}
const goToCheckinAudioPage = (type) => {
router.push({
path: '/checkin/audio',
query: {
id: route.query.id,
type: 'audio',
}
})
}
const handLike = (post) => {
......@@ -522,15 +536,22 @@ const handLike = (post) => {
// TODO: 调用接口
}
const editCheckin = () => {
let type = 'image';
const editCheckin = (type) => {
if (type === 'image') {
router.push({
path: '/checkin/image',
query: {
id: route.query.id,
type,
}
})
} else {
router.push({
path: '/checkin/file',
query: {
id: route.query.id,
type,
}
})
}
}
......@@ -554,14 +575,73 @@ const delCheckin = () => {
}
const taskDetail = ref({});
const myCheckinDates = ref([]);
const checkinDataList = ref([]);
onMounted(async () => {
const { code, data } = await getTaskDetailAPI({ id: route.query.id, month: dayjs().format('YYYY-MM') });
const { code, data } = await getTaskDetailAPI({ i: route.query.id, month: dayjs().format('YYYY-MM') });
if (code) {
console.warn(data);
taskDetail.value = data;
progress1.value = (data.checkin_number/data.target_number)*100 ;
teamAvatars.value = data.checkin_avatars;
// 获取当前用户的打卡日期
myCheckinDates.value = data.my_checkin_dates;
// 把['2025-06-06'] 转化为 [6] 只取日期去掉0
myCheckinDates.value = myCheckinDates.value.map(date => {
return dayjs(date).date();
})
}
// 获取打卡动态列表
const task_list = await getUploadTaskListAPI({ task_id: route.query.id, date: dayjs().format('YYYY-MM-DD'), limit: 999 });
if (task_list.code) {
console.warn(task_list.data?.checkin_list);
// 整理数据结构
task_list.data?.checkin_list.forEach((item, index) => {
let images = [];
let audio = [];
let videoList = [];
if (item.file_type === 'image') {
images = item.files.map(file => {
return file.value;
});
} else if (item.file_type === 'video') {
videoList = item.files.map(file => {
return {
id: file.meta_id,
video: file.value,
videoCover: file.cover,
isPlaying: false,
}
})
} else if (item.file_type === 'audio') {
audio = item.files.map(file => {
return {
title: file.title ? file.title : '打卡音频',
artist: file.artist ? file.artist : '',
url: file.value,
cover: file.cover ? file.cover : '',
}
})
}
checkinDataList.value.push({
id: item.id,
task_id: item.task_id,
user: {
name: item.username,
avatar: item.avatar,
time: item.created_time_desc,
},
content: item.note,
images,
videoList,
audio,
isPlaying: false,
likes: item.like_count,
is_liked: item.is_like,
is_my: item.is_my,
})
})
}
})
</script>
......
<!--
* @Date: 2025-06-03 09:41:41
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-06 15:51:31
* @FilePath: /mlaj/src/views/checkin/upload/audio.vue
* @Description: 音视频文件上传组件
-->
<template>
<div class="checkin-upload-file p-4">
<!-- 文件上传区域 -->
<div class="mb-4">
<van-uploader
v-model="fileList"
:max-count="max_count"
:max-size="20 * 1024 * 1024"
:before-read="beforeRead"
:after-read="afterRead"
@delete="onDelete"
multiple
accept="audio/*"
result-type="file"
upload-icon="plus"
>
<template #upload-text>
<!-- :accept="route.query.type === 'video' ? 'video/*' : 'audio/*'" -->
<div class="text-center">
<van-icon name="plus" size="24" />
<div class="mt-1 text-sm text-gray-600">上传文件</div>
</div>
</template>
</van-uploader>
<div class="mt-2 text-xs text-gray-500">最多上传{{ max_count }}个文件,每个不超过20M</div>
<div class="mt-2 text-xs text-gray-500">上传类型:&nbsp;音频文件</div>
</div>
<!-- 文字留言区域 -->
<div class="mb-4 border">
<van-field
v-model="message"
rows="4"
autosize
type="textarea"
placeholder="请输入打卡留言"
/>
</div>
<!-- 提交按钮 -->
<div class="fixed bottom-0 left-0 right-0 p-4 bg-white">
<van-button
type="primary"
block
:loading="uploading"
:disabled="!canSubmit"
@click="onSubmit"
>
提交
</van-button>
</div>
<!-- 上传加载遮罩 -->
<van-overlay :show="loading">
<div class="wrapper" @click.stop>
<van-loading vertical color="#FFFFFF">上传中...</van-loading>
</div>
</van-overlay>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showToast, showLoadingToast } from 'vant'
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from '@/api/common'
import { addUploadTaskAPI } from "@/api/checkin";
import BMF from 'browser-md5-file'
import _ from 'lodash'
import { useTitle } from '@vueuse/core';
import { useAuth } from '@/contexts/auth'
const route = useRoute()
const router = useRouter()
const { currentUser } = useAuth()
useTitle(route.meta.title);
const max_count = ref(5);
// 文件列表
const fileList = ref([])
// 留言内容
const message = ref('')
// 上传状态
const uploading = ref(false)
// 上传loading
const loading = ref(false)
// 是否可以提交
const canSubmit = computed(() => {
return fileList.value.length > 0 && message.value.trim() !== ''
})
// 文件校验
const beforeRead = (file) => {
let flag = true
if (Array.isArray(file)) {
// 多个文件
const invalidTypes = file.filter(item => {
const fileType = item.type.toLowerCase();
return !fileType.startsWith('audio/');
})
if (invalidTypes.length) {
flag = false
showToast('请上传音频文件')
}
if (fileList.value.length + file.length > max_count.value) {
flag = false
showToast(`最大上传数量为${max_count.value}个`)
}
} else {
const fileType = file.type.toLowerCase();
if (!fileType.startsWith('audio/')) {
showToast('请上传音频文件')
flag = false
}
if (fileList.value.length + 1 > max_count.value) {
flag = false
showToast(`最大上传数量为${max_count.value}个`)
}
if ((file.size / 1024 / 1024).toFixed(2) > 20) {
flag = false
showToast('最大文件体积为20MB')
}
}
return flag
}
// 获取文件MD5
const getFileMD5 = (file) => {
return new Promise((resolve, reject) => {
const bmf = new BMF()
bmf.md5(file, (err, md5) => {
if (err) {
reject(err)
return
}
resolve(md5)
})
})
}
// 上传到七牛云
const uploadToQiniu = async (file, token, fileName) => {
const formData = new FormData()
formData.append('file', file)
formData.append('token', token)
formData.append('key', fileName)
const config = {
headers: { 'Content-Type': 'multipart/form-data' }
}
// 根据协议选择上传地址
const qiniuUploadUrl = window.location.protocol === 'https:'
? 'https://up.qbox.me'
: 'http://upload.qiniu.com'
return await qiniuUploadAPI(qiniuUploadUrl, formData, config)
}
// 处理单个文件上传
const handleUpload = async (file) => {
loading.value = true
try {
// 获取MD5值
const md5 = await getFileMD5(file.file)
// 获取七牛token
const tokenResult = await qiniuTokenAPI({
name: file.file.name,
hash: md5
})
// 文件已存在,直接返回
if (tokenResult.data) {
return tokenResult.data
}
// 新文件上传
if (tokenResult.token) {
const suffix = /.[^.]+$/.exec(file.file.name) || ''
const fileName = `mlaj/upload/checkin/${currentUser.value.mobile}/file/${md5}${suffix}`
const { filekey } = await uploadToQiniu(
file.file,
tokenResult.token,
fileName
)
if (filekey) {
// 保存文件信息
const { data } = await saveFileAPI({
name: file.file.name,
filekey,
hash: md5
})
return data
}
}
return null
} catch (error) {
console.error('Upload error:', error)
return null
} finally {
loading.value = false
}
}
// 文件读取后的处理
const afterRead = async (file) => {
if (Array.isArray(file)) {
// 多文件上传
for (const item of file) {
item.status = 'uploading'
item.message = '上传中...'
const result = await handleUpload(item)
if (result) {
item.status = 'done'
item.message = '上传成功'
item.url = result.url
item.meta_id = result.meta_id
} else {
item.status = 'failed'
item.message = '上传失败'
showToast('上传失败,请重试')
}
}
} else {
// 单文件上传
file.status = 'uploading'
file.message = '上传中...'
const result = await handleUpload(file)
if (result) {
file.status = 'done'
file.message = '上传成功'
file.url = result.url
file.meta_id = result.meta_id
} else {
file.status = 'failed'
file.message = '上传失败'
showToast('上传失败,请重试')
}
}
}
// 删除文件
const onDelete = (file) => {
const index = fileList.value.indexOf(file)
if (index !== -1) {
fileList.value.splice(index, 1)
}
}
// 提交表单
const onSubmit = async () => {
if (uploading.value) return
// 检查是否所有文件都上传完成
const hasUploadingFiles = fileList.value.some(file => file.status === 'uploading')
if (hasUploadingFiles) {
showToast('请等待所有文件上传完成')
return
}
uploading.value = true
const toast = showLoadingToast({
message: '提交中...',
forbidClick: true,
})
try {
// 调用提交打卡接口
const { code, data } = await addUploadTaskAPI({
task_id: route.query.id,
note: message.value,
meta_id: fileList.value.map(item => item.meta_id),
file_type: route.query.type,
});
if (code) {
showToast('提交成功')
router.back()
}
} catch (error) {
showToast('提交失败,请重试')
} finally {
toast.close()
uploading.value = false
}
}
</script>
<style lang="less" scoped>
.checkin-upload-file {
min-height: 100vh;
padding-bottom: 80px;
}
.wrapper {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
</style>
......@@ -56,6 +56,7 @@ import { ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showToast, showLoadingToast } from 'vant'
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from '@/api/common'
import { addUploadTaskAPI } from "@/api/checkin";
import BMF from 'browser-md5-file'
import _ from 'lodash'
import { useTitle } from '@vueuse/core';
......@@ -274,11 +275,17 @@ const onSubmit = async () => {
})
try {
// TODO: 调用提交打卡接口
await new Promise(resolve => setTimeout(resolve, 1000))
console.warn('提交打卡接口', fileList.value, message.value);
showToast('提交成功')
router.back()
// 调用提交打卡接口
const { code, data } = await addUploadTaskAPI({
task_id: route.query.id,
note: message.value,
meta_id: fileList.value.map(item => item.meta_id),
file_type: route.query.type,
});
if (code) {
showToast('提交成功')
router.back()
}
} catch (error) {
showToast('提交失败,请重试')
} finally {
......
<!--
* @Date: 2025-06-03 09:41:41
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-06 14:38:20
* @FilePath: /mlaj/src/views/checkin/upload/file.vue
* @LastEditTime: 2025-06-06 15:49:37
* @FilePath: /mlaj/src/views/checkin/upload/video.vue
* @Description: 音视频文件上传组件
-->
<template>
......@@ -17,11 +17,12 @@
:after-read="afterRead"
@delete="onDelete"
multiple
:accept="route.query.type === 'video' ? 'video/*' : 'audio/*'"
accept="video/*"
result-type="file"
upload-icon="plus"
>
<template #upload-text>
<!-- :accept="route.query.type === 'video' ? 'video/*' : 'audio/*'" -->
<div class="text-center">
<van-icon name="plus" size="24" />
<div class="mt-1 text-sm text-gray-600">上传文件</div>
......@@ -29,7 +30,7 @@
</template>
</van-uploader>
<div class="mt-2 text-xs text-gray-500">最多上传{{ max_count }}个文件,每个不超过20M</div>
<div class="mt-2 text-xs text-gray-500">上传类型:&nbsp;{{ route.query.type === 'video' ? "视频文件" : '音频文件' }}</div>
<div class="mt-2 text-xs text-gray-500">上传类型:&nbsp;视频文件</div>
</div>
<!-- 文字留言区域 -->
......@@ -70,6 +71,7 @@ import { ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showToast, showLoadingToast } from 'vant'
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from '@/api/common'
import { addUploadTaskAPI } from "@/api/checkin";
import BMF from 'browser-md5-file'
import _ from 'lodash'
import { useTitle } from '@vueuse/core';
......@@ -104,11 +106,11 @@ const beforeRead = (file) => {
// 多个文件
const invalidTypes = file.filter(item => {
const fileType = item.type.toLowerCase();
return !fileType.startsWith('audio/') && !fileType.startsWith('video/');
return !fileType.startsWith('video/');
})
if (invalidTypes.length) {
flag = false
showToast('请上传音频或视频文件')
showToast('请上传视频文件')
}
if (fileList.value.length + file.length > max_count.value) {
flag = false
......@@ -116,8 +118,8 @@ const beforeRead = (file) => {
}
} else {
const fileType = file.type.toLowerCase();
if (!fileType.startsWith('audio/') && !fileType.startsWith('video/')) {
showToast('请上传音频或视频文件')
if (!fileType.startsWith('video/')) {
showToast('请上传视频文件')
flag = false
}
if (fileList.value.length + 1 > max_count.value) {
......@@ -276,10 +278,17 @@ const onSubmit = async () => {
})
try {
// TODO: 调用提交打卡接口
await new Promise(resolve => setTimeout(resolve, 1000))
showToast('提交成功')
router.back()
// 调用提交打卡接口
const { code, data } = await addUploadTaskAPI({
task_id: route.query.id,
note: message.value,
meta_id: fileList.value.map(item => item.meta_id),
file_type: route.query.type,
});
if (code) {
showToast('提交成功')
router.back()
}
} catch (error) {
showToast('提交失败,请重试')
} finally {
......