feat(web): T-WEB-001 NestJS 骨架 + 连接现有 MySQL 实例

This commit is contained in:
2026-09-14 19:00:55 +08:00
parent 9b8fc6be96
commit bd6cb9fa90
18 changed files with 7763 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
/**
* 跨模块共享枚举。
* 与 contracts/data-models.md 中的枚举**逐字对应**,改动必须同步契约版本。
*/
export enum SourceType {
/** 原创 */
Original = 'original',
/** 已获授权 */
Licensed = 'licensed',
/** Creative Commons */
Cc = 'cc',
/** 公共领域 */
PublicDomain = 'public_domain',
/** 用户上传(需审核) */
UserUpload = 'user_upload',
/** 其他(须在 sourceName 说明) */
Other = 'other',
}
export enum PublishStatus {
Draft = 'draft',
Pending = 'pending',
Published = 'published',
Rejected = 'rejected',
}
export enum MotionFormat {
Bvh = 'bvh',
Fbx = 'fbx',
Gltf = 'gltf',
Glb = 'glb',
KeypointsJson = 'keypoints-json',
}
export enum ModelFormat {
Vrm = 'vrm',
Glb = 'glb',
Gltf = 'gltf',
Fbx = 'fbx',
}
export enum PreprocessState {
None = 'none',
Running = 'running',
Done = 'done',
Failed = 'failed',
}
export enum ReviewAction {
Submit = 'submit',
Approve = 'approve',
Reject = 'reject',
Withdraw = 'withdraw',
}
export enum TargetType {
Song = 'song',
Motion = 'motion',
Model = 'model',
}
export enum AssetKind {
SongAudio = 'song-audio',
SongCover = 'song-cover',
Motion = 'motion',
Model = 'model',
Thumbnail = 'thumbnail',
Keypoints = 'keypoints',
}
export const SOURCE_TYPE_VALUES = Object.values(SourceType) as string[];
export const PUBLISH_STATUS_VALUES = Object.values(PublishStatus) as string[];
export const MOTION_FORMAT_VALUES = Object.values(MotionFormat) as string[];
export const MODEL_FORMAT_VALUES = Object.values(ModelFormat) as string[];
export const TARGET_TYPE_VALUES = Object.values(TargetType) as string[];
/** 允许上传的扩展名 → 动作格式 */
export const MOTION_EXTENSION_MAP: Record<string, MotionFormat> = {
'.bvh': MotionFormat.Bvh,
'.fbx': MotionFormat.Fbx,
'.gltf': MotionFormat.Gltf,
'.glb': MotionFormat.Glb,
'.json': MotionFormat.KeypointsJson,
};
/** 允许上传的扩展名 → 模型格式 */
export const MODEL_EXTENSION_MAP: Record<string, ModelFormat> = {
'.vrm': ModelFormat.Vrm,
'.glb': ModelFormat.Glb,
'.gltf': ModelFormat.Gltf,
'.fbx': ModelFormat.Fbx,
};
export const AUDIO_EXTENSIONS = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.flac'];
export const IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp'];
/**
* 状态机:契约 database.md §状态机。
* key = 当前状态,value = 允许流转到的状态集合。
*/
export const STATUS_TRANSITIONS: Record<PublishStatus, PublishStatus[]> = {
[PublishStatus.Draft]: [PublishStatus.Pending, PublishStatus.Published],
[PublishStatus.Pending]: [PublishStatus.Published, PublishStatus.Rejected, PublishStatus.Draft],
[PublishStatus.Published]: [PublishStatus.Draft, PublishStatus.Rejected],
[PublishStatus.Rejected]: [PublishStatus.Pending, PublishStatus.Draft],
};
export function canTransition(from: PublishStatus, to: PublishStatus): boolean {
return (STATUS_TRANSITIONS[from] ?? []).includes(to);
}
/** 审核动作 → 目标状态 */
export const ACTION_TARGET_STATUS: Record<ReviewAction, PublishStatus> = {
[ReviewAction.Submit]: PublishStatus.Pending,
[ReviewAction.Approve]: PublishStatus.Published,
[ReviewAction.Reject]: PublishStatus.Rejected,
[ReviewAction.Withdraw]: PublishStatus.Draft,
};