|
|
@@ -4,7 +4,12 @@ import type {
|
|
|
} from '#/request/schema/audit-record';
|
|
|
|
|
|
import { z } from '#/adapter/form';
|
|
|
-import { decodeList } from '#/request/schema';
|
|
|
+import {
|
|
|
+ decodeList,
|
|
|
+ decodeZeroFlag,
|
|
|
+ encodeZeroFlag,
|
|
|
+ encodeZeroFlagOptional,
|
|
|
+} from '#/request/schema';
|
|
|
import { decodeAuditRecord } from '#/request/schema/audit-record';
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
@@ -15,6 +20,21 @@ export type VideoCategory = 'clinical_skill' | 'clinical_teaching' | 'theory';
|
|
|
|
|
|
export type VideoSortType = 'latest' | 'popular';
|
|
|
|
|
|
+/** 后端 `type` 字段,对应字典:智慧传承系统-视频类型 */
|
|
|
+export type VideoTypeDTO = '0' | '1' | '2';
|
|
|
+
|
|
|
+const VIDEO_TYPE_TO_DTO: Record<VideoCategory, VideoTypeDTO> = {
|
|
|
+ clinical_skill: '0',
|
|
|
+ clinical_teaching: '1',
|
|
|
+ theory: '2',
|
|
|
+};
|
|
|
+
|
|
|
+const VIDEO_TYPE_FROM_DTO: Record<VideoTypeDTO, VideoCategory> = {
|
|
|
+ '0': 'clinical_skill',
|
|
|
+ '1': 'clinical_teaching',
|
|
|
+ '2': 'theory',
|
|
|
+};
|
|
|
+
|
|
|
export const VIDEO_CATEGORY_OPTIONS = [
|
|
|
{ label: '临床技能', value: 'clinical_skill' },
|
|
|
{ label: '临床教学', value: 'clinical_teaching' },
|
|
|
@@ -30,28 +50,49 @@ export function getVideoCategoryLabel(category?: VideoCategory) {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+export function decodeVideoType(type?: number | string): VideoCategory {
|
|
|
+ const normalized = type?.toString();
|
|
|
+ if (normalized === '0' || normalized === '1' || normalized === '2') {
|
|
|
+ return VIDEO_TYPE_FROM_DTO[normalized];
|
|
|
+ }
|
|
|
+ return 'clinical_skill';
|
|
|
+}
|
|
|
+
|
|
|
+function encodeVideoType(category: VideoCategory): VideoTypeDTO {
|
|
|
+ return VIDEO_TYPE_TO_DTO[category];
|
|
|
+}
|
|
|
+
|
|
|
// ---------------------------------------------------------------------------
|
|
|
// DTO
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
+/** 视频讲解 DTO,对应 `OutcomeVideoExplainDetail` */
|
|
|
export interface VideoDTO extends AuditRecordDTO {
|
|
|
id?: number | string;
|
|
|
+ status?: string;
|
|
|
+ remark?: string;
|
|
|
personalStudioId?: number | string;
|
|
|
- videoName?: string;
|
|
|
- speakerName?: string;
|
|
|
- category?: VideoCategory;
|
|
|
+ fileUrl?: string;
|
|
|
+ downloadCount?: number;
|
|
|
+ browseCount?: number;
|
|
|
+ commentCount?: number;
|
|
|
+ praiseCount?: number;
|
|
|
+ name?: string;
|
|
|
+ explainer?: string;
|
|
|
+ /** 视频类型,详见字典:智慧传承系统-视频类型 */
|
|
|
+ type?: string | VideoTypeDTO;
|
|
|
+ outcomeMedicalCasesId?: number | string;
|
|
|
videoUrl?: string;
|
|
|
videoFirstUrl?: string;
|
|
|
duration?: string;
|
|
|
- viewCount?: number;
|
|
|
- status?: boolean;
|
|
|
}
|
|
|
|
|
|
export interface VideoQueryDTO {
|
|
|
mixture?: string;
|
|
|
personalStudioId?: number | string;
|
|
|
- category?: VideoCategory;
|
|
|
- sortType?: VideoSortType;
|
|
|
+ type?: string | VideoTypeDTO;
|
|
|
+ status?: string;
|
|
|
+ isOrderByBrowseCount?: boolean;
|
|
|
pageNum?: number;
|
|
|
pageSize?: number;
|
|
|
}
|
|
|
@@ -80,6 +121,7 @@ export interface VideoQueryVO {
|
|
|
workroomId?: string;
|
|
|
category?: VideoCategory;
|
|
|
sortType?: VideoSortType;
|
|
|
+ status?: boolean;
|
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
@@ -106,37 +148,49 @@ export function decodeVideo(dto: VideoDTO): VideoVO {
|
|
|
...decodeAuditRecord(dto),
|
|
|
id: dto.id?.toString(),
|
|
|
workroomId: dto.personalStudioId?.toString() ?? '',
|
|
|
- name: dto.videoName ?? '',
|
|
|
- speaker: dto.speakerName,
|
|
|
- category: dto.category ?? 'clinical_skill',
|
|
|
+ name: dto.name ?? '',
|
|
|
+ speaker: dto.explainer,
|
|
|
+ category: decodeVideoType(dto.type),
|
|
|
videoUrl: dto.videoUrl,
|
|
|
thumbnailUrl: dto.videoFirstUrl,
|
|
|
duration: dto.duration,
|
|
|
- viewCount: dto.viewCount ?? 0,
|
|
|
- status: dto.status ?? true,
|
|
|
+ viewCount: dto.browseCount ?? 0,
|
|
|
+ status: decodeZeroFlag(dto.status),
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-export function encodeVideoQuery(query: Partial<VideoQueryVO>): VideoQueryDTO {
|
|
|
+function encodeBrowseCountSort(sortType?: VideoSortType): boolean | undefined {
|
|
|
+ if (sortType === 'popular') return true;
|
|
|
+ if (sortType === 'latest') return false;
|
|
|
+ return undefined;
|
|
|
+}
|
|
|
+
|
|
|
+export function encodeVideoQuery(
|
|
|
+ query: Partial<Record<string, unknown> & VideoQueryVO>,
|
|
|
+): VideoQueryDTO {
|
|
|
return {
|
|
|
- mixture: query.keyword,
|
|
|
+ mixture: query.keyword || undefined,
|
|
|
personalStudioId: query.workroomId,
|
|
|
- category: query.category,
|
|
|
- sortType: query.sortType,
|
|
|
+ type: query.category ? encodeVideoType(query.category) : undefined,
|
|
|
+ status: encodeZeroFlagOptional(query.status),
|
|
|
+ isOrderByBrowseCount: encodeBrowseCountSort(query.sortType),
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function encodeVideo(vo: VideoSubmitVO): VideoDTO {
|
|
|
+ const videoUrl = vo.videoUrl ?? '';
|
|
|
+
|
|
|
return {
|
|
|
id: vo.id,
|
|
|
personalStudioId: vo.workroomId,
|
|
|
- videoName: vo.name,
|
|
|
- speakerName: vo.speaker,
|
|
|
- category: vo.category,
|
|
|
- videoUrl: vo.videoUrl,
|
|
|
- videoFirstUrl: vo.thumbnailUrl,
|
|
|
- duration: vo.duration,
|
|
|
- status: vo.status,
|
|
|
+ fileUrl: videoUrl,
|
|
|
+ name: vo.name,
|
|
|
+ explainer: vo.speaker,
|
|
|
+ type: encodeVideoType(vo.category),
|
|
|
+ videoUrl,
|
|
|
+ videoFirstUrl: vo.thumbnailUrl ?? '',
|
|
|
+ duration: vo.duration ?? '',
|
|
|
+ status: encodeZeroFlag(vo.status),
|
|
|
};
|
|
|
}
|
|
|
|