feat(签到): 添加多附件功能开关
添加环境变量 VITE_CHECKIN_MULTI_ATTACHMENT 控制是否开启多附件功能。 当开关关闭时,混合类型附件提交会提示“请分别提交”。 当开关开启时,允许混合类型附件提交,并使用新的接口字段。 更新测试用例以覆盖开关开启和关闭的场景。
Showing
3 changed files
with
60 additions
and
12 deletions
| 1 | import { describe, expect, it, vi, beforeEach } from 'vitest' | 1 | import { describe, expect, it, vi, beforeEach } from 'vitest' |
| 2 | 2 | ||
| 3 | +let mock_query = {} | ||
| 4 | + | ||
| 3 | vi.mock('vue-router', () => { | 5 | vi.mock('vue-router', () => { |
| 4 | const router = { | 6 | const router = { |
| 5 | push: vi.fn(), | 7 | push: vi.fn(), |
| ... | @@ -7,7 +9,7 @@ vi.mock('vue-router', () => { | ... | @@ -7,7 +9,7 @@ vi.mock('vue-router', () => { |
| 7 | } | 9 | } |
| 8 | return { | 10 | return { |
| 9 | useRoute: () => ({ | 11 | useRoute: () => ({ |
| 10 | - query: {} | 12 | + query: mock_query |
| 11 | }), | 13 | }), |
| 12 | useRouter: () => router | 14 | useRouter: () => router |
| 13 | } | 15 | } |
| ... | @@ -58,6 +60,7 @@ import { addUploadTaskAPI } from '@/api/checkin' | ... | @@ -58,6 +60,7 @@ import { addUploadTaskAPI } from '@/api/checkin' |
| 58 | describe('useCheckin 上传大小限制', () => { | 60 | describe('useCheckin 上传大小限制', () => { |
| 59 | beforeEach(() => { | 61 | beforeEach(() => { |
| 60 | vi.clearAllMocks() | 62 | vi.clearAllMocks() |
| 63 | + mock_query = { enable_multi: '0' } | ||
| 61 | if (!globalThis.sessionStorage) { | 64 | if (!globalThis.sessionStorage) { |
| 62 | let store = {} | 65 | let store = {} |
| 63 | globalThis.sessionStorage = { | 66 | globalThis.sessionStorage = { |
| ... | @@ -136,6 +139,7 @@ describe('useCheckin 上传大小限制', () => { | ... | @@ -136,6 +139,7 @@ describe('useCheckin 上传大小限制', () => { |
| 136 | describe('useCheckin 提交兼容', () => { | 139 | describe('useCheckin 提交兼容', () => { |
| 137 | beforeEach(() => { | 140 | beforeEach(() => { |
| 138 | vi.clearAllMocks() | 141 | vi.clearAllMocks() |
| 142 | + mock_query = { enable_multi: '0' } | ||
| 139 | if (globalThis.sessionStorage?.clear) sessionStorage.clear() | 143 | if (globalThis.sessionStorage?.clear) sessionStorage.clear() |
| 140 | }) | 144 | }) |
| 141 | 145 | ||
| ... | @@ -156,13 +160,31 @@ describe('useCheckin 提交兼容', () => { | ... | @@ -156,13 +160,31 @@ describe('useCheckin 提交兼容', () => { |
| 156 | 160 | ||
| 157 | expect(addUploadTaskAPI).toHaveBeenCalledTimes(2) | 161 | expect(addUploadTaskAPI).toHaveBeenCalledTimes(2) |
| 158 | expect(addUploadTaskAPI.mock.calls[0][0]).toHaveProperty('files') | 162 | expect(addUploadTaskAPI.mock.calls[0][0]).toHaveProperty('files') |
| 163 | + expect(addUploadTaskAPI.mock.calls[0][0]).toHaveProperty('meta_id') | ||
| 159 | expect(addUploadTaskAPI.mock.calls[1][0]).toHaveProperty('meta_id') | 164 | expect(addUploadTaskAPI.mock.calls[1][0]).toHaveProperty('meta_id') |
| 160 | expect(addUploadTaskAPI.mock.calls[1][0]).not.toHaveProperty('files') | 165 | expect(addUploadTaskAPI.mock.calls[1][0]).not.toHaveProperty('files') |
| 161 | expect(showToast).toHaveBeenCalledWith('提交成功') | 166 | expect(showToast).toHaveBeenCalledWith('提交成功') |
| 162 | }) | 167 | }) |
| 163 | 168 | ||
| 164 | it('混合附件且新结构失败时会提示分别提交', async () => { | 169 | it('混合附件且新结构失败时会提示分别提交', async () => { |
| 165 | - addUploadTaskAPI.mockResolvedValueOnce({ code: 0, msg: '参数错误' }) | 170 | + const { activeType, fileList, message, onSubmit } = useCheckin() |
| 171 | + | ||
| 172 | + activeType.value = 'image' | ||
| 173 | + message.value = '随便写点内容' | ||
| 174 | + fileList.value = [ | ||
| 175 | + { status: 'done', meta_id: 11, file_type: 'image' }, | ||
| 176 | + { status: 'done', meta_id: 12, file_type: 'audio' }, | ||
| 177 | + ] | ||
| 178 | + | ||
| 179 | + await onSubmit({ subtask_id: 's1' }) | ||
| 180 | + | ||
| 181 | + expect(addUploadTaskAPI).toHaveBeenCalledTimes(0) | ||
| 182 | + expect(showToast).toHaveBeenCalledWith('当前接口暂不支持多类型附件,请分别提交') | ||
| 183 | + }) | ||
| 184 | + | ||
| 185 | + it('开启多附件开关时允许 mixed files 提交', async () => { | ||
| 186 | + mock_query = { enable_multi: '1' } | ||
| 187 | + addUploadTaskAPI.mockResolvedValueOnce({ code: 1, data: { id: 1 } }) | ||
| 166 | 188 | ||
| 167 | const { activeType, fileList, message, onSubmit } = useCheckin() | 189 | const { activeType, fileList, message, onSubmit } = useCheckin() |
| 168 | 190 | ||
| ... | @@ -176,6 +198,9 @@ describe('useCheckin 提交兼容', () => { | ... | @@ -176,6 +198,9 @@ describe('useCheckin 提交兼容', () => { |
| 176 | await onSubmit({ subtask_id: 's1' }) | 198 | await onSubmit({ subtask_id: 's1' }) |
| 177 | 199 | ||
| 178 | expect(addUploadTaskAPI).toHaveBeenCalledTimes(1) | 200 | expect(addUploadTaskAPI).toHaveBeenCalledTimes(1) |
| 179 | - expect(showToast).toHaveBeenCalledWith('当前接口暂不支持多类型附件,请分别提交') | 201 | + expect(addUploadTaskAPI.mock.calls[0][0]).toHaveProperty('files') |
| 202 | + expect(addUploadTaskAPI.mock.calls[0][0]).not.toHaveProperty('meta_id') | ||
| 203 | + expect(addUploadTaskAPI.mock.calls[0][0]).toHaveProperty('file_type', 'mixed') | ||
| 204 | + expect(showToast).toHaveBeenCalledWith('提交成功') | ||
| 180 | }) | 205 | }) |
| 181 | }) | 206 | }) | ... | ... |
| ... | @@ -23,6 +23,16 @@ export function useCheckin() { | ... | @@ -23,6 +23,16 @@ export function useCheckin() { |
| 23 | const router = useRouter() | 23 | const router = useRouter() |
| 24 | const { currentUser } = useAuth() | 24 | const { currentUser } = useAuth() |
| 25 | 25 | ||
| 26 | + // TAG: 多附件功能开关 | ||
| 27 | + const multiAttachmentEnabled = computed(() => { | ||
| 28 | + const query_value = String(route?.query?.enable_multi ?? '') | ||
| 29 | + if (query_value === '1') return true | ||
| 30 | + if (query_value === '0') return false | ||
| 31 | + | ||
| 32 | + const fromEnv = String(import.meta.env.VITE_CHECKIN_MULTI_ATTACHMENT || '') === '1' | ||
| 33 | + return fromEnv | ||
| 34 | + }) | ||
| 35 | + | ||
| 26 | // ==================== 状态定义 ==================== | 36 | // ==================== 状态定义 ==================== |
| 27 | 37 | ||
| 28 | /** @type {import('vue').Ref<boolean>} 上传中状态 */ | 38 | /** @type {import('vue').Ref<boolean>} 上传中状态 */ |
| ... | @@ -470,19 +480,25 @@ export function useCheckin() { | ... | @@ -470,19 +480,25 @@ export function useCheckin() { |
| 470 | if (files.length === 0 && activeType.value === 'text') { | 480 | if (files.length === 0 && activeType.value === 'text') { |
| 471 | submitData.file_type = 'text' | 481 | submitData.file_type = 'text' |
| 472 | } else if (files.length > 0) { | 482 | } else if (files.length > 0) { |
| 483 | + const types = new Set(files.map(f => f.file_type).filter(Boolean)) | ||
| 484 | + const hasMixedTypes = types.size > 1 | ||
| 485 | + console.warn(multiAttachmentEnabled.value); | ||
| 486 | + if (hasMixedTypes && !multiAttachmentEnabled.value) { | ||
| 487 | + showToast('当前接口暂不支持多类型附件,请分别提交') | ||
| 488 | + return | ||
| 489 | + } | ||
| 490 | + | ||
| 473 | // 如果有文件,file_type 可能是 'mixed' 或者取第一个文件的类型作为主类型 | 491 | // 如果有文件,file_type 可能是 'mixed' 或者取第一个文件的类型作为主类型 |
| 474 | // 这里暂时保留 file_type 字段以防后端必须校验,取第一个文件的类型,或者传 'mixed' | 492 | // 这里暂时保留 file_type 字段以防后端必须校验,取第一个文件的类型,或者传 'mixed' |
| 475 | // 如果后端已更新为只看 files 数组,则此字段可能无效 | 493 | // 如果后端已更新为只看 files 数组,则此字段可能无效 |
| 476 | - const types = new Set(files.map(f => f.file_type)) | 494 | + submitData.file_type = hasMixedTypes ? 'mixed' : files[0].file_type |
| 477 | - if (types.size > 1) { | 495 | + |
| 478 | - submitData.file_type = 'mixed' // 假设后端支持 mixed | 496 | + if (!multiAttachmentEnabled.value) { |
| 479 | - } else { | 497 | + submitData.meta_id = files.map(f => f.meta_id) |
| 480 | - submitData.file_type = files[0].file_type | ||
| 481 | } | 498 | } |
| 482 | } | 499 | } |
| 483 | 500 | ||
| 484 | - // 如果有文件,添加文件ID (为了兼容可能还在用 meta_id 的旧接口逻辑,如果确定废弃可删除) | 501 | + // 说明:submitData.meta_id 为旧接口兜底字段,后端完全支持 files 后再移除 |
| 485 | - // submitData.meta_id = files.map(f => f.meta_id) | ||
| 486 | 502 | ||
| 487 | let result | 503 | let result |
| 488 | if (route.query.status === 'edit') { | 504 | if (route.query.status === 'edit') { |
| ... | @@ -491,7 +507,7 @@ export function useCheckin() { | ... | @@ -491,7 +507,7 @@ export function useCheckin() { |
| 491 | i: route.query.post_id, | 507 | i: route.query.post_id, |
| 492 | subtask_id: submitData.subtask_id || route.query.subtask_id, | 508 | subtask_id: submitData.subtask_id || route.query.subtask_id, |
| 493 | note: submitData.note, | 509 | note: submitData.note, |
| 494 | - // meta_id: submitData.meta_id, | 510 | + ...(submitData.meta_id ? { meta_id: submitData.meta_id } : {}), |
| 495 | files: submitData.files, | 511 | files: submitData.files, |
| 496 | file_type: submitData.file_type, | 512 | file_type: submitData.file_type, |
| 497 | } | 513 | } |
| ... | @@ -515,7 +531,11 @@ export function useCheckin() { | ... | @@ -515,7 +531,11 @@ export function useCheckin() { |
| 515 | const hasMixedTypes = types.size > 1 | 531 | const hasMixedTypes = types.size > 1 |
| 516 | 532 | ||
| 517 | if (hasMixedTypes) { | 533 | if (hasMixedTypes) { |
| 518 | - showToast('当前接口暂不支持多类型附件,请分别提交') | 534 | + if (!multiAttachmentEnabled.value) { |
| 535 | + showToast('当前接口暂不支持多类型附件,请分别提交') | ||
| 536 | + return | ||
| 537 | + } | ||
| 538 | + showToast(result?.msg || '提交失败,请重试') | ||
| 519 | return | 539 | return |
| 520 | } | 540 | } |
| 521 | 541 | ... | ... |
-
Please register or login to post a comment