Register 直播切片 as a video-only material type. Upload and edit flows collect required title, live date (defaults to today), optional host with user link, and live platform presets. Persist the fields on Material and skip SPU formatting for free-text titles.
98 lines
2.8 KiB
TypeScript
98 lines
2.8 KiB
TypeScript
/**
|
||
* 直播切片素材:类型判断、平台预置与字段校验
|
||
*/
|
||
|
||
import { LIVE_CLIP_VIDEO_TYPE } from './video-material-types'
|
||
|
||
export { LIVE_CLIP_VIDEO_TYPE }
|
||
|
||
export const LIVE_CLIP_PLATFORMS = [
|
||
'抖音',
|
||
'快手',
|
||
'视频号',
|
||
'淘宝直播',
|
||
'B站',
|
||
] as const
|
||
|
||
export type LiveClipPlatform = (typeof LIVE_CLIP_PLATFORMS)[number]
|
||
|
||
export function isLiveClipType(materialType?: string | null): boolean {
|
||
return (materialType || '').trim() === LIVE_CLIP_VIDEO_TYPE
|
||
}
|
||
|
||
export function isLiveClipPlatform(value?: string | null): value is LiveClipPlatform {
|
||
return LIVE_CLIP_PLATFORMS.includes((value || '') as LiveClipPlatform)
|
||
}
|
||
|
||
/** 上传日期当天(本地日历日,YYYY-MM-DD) */
|
||
export function getDefaultLiveDate(now: Date = new Date()): string {
|
||
const y = now.getFullYear()
|
||
const m = String(now.getMonth() + 1).padStart(2, '0')
|
||
const d = String(now.getDate()).padStart(2, '0')
|
||
return `${y}-${m}-${d}`
|
||
}
|
||
|
||
export function parseLiveDate(value?: string | null): Date | null {
|
||
const trimmed = (value || '').trim()
|
||
if (!trimmed) return null
|
||
if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return null
|
||
const [y, m, d] = trimmed.split('-').map(Number)
|
||
const date = new Date(y, m - 1, d)
|
||
if (
|
||
date.getFullYear() !== y ||
|
||
date.getMonth() !== m - 1 ||
|
||
date.getDate() !== d
|
||
) {
|
||
return null
|
||
}
|
||
// 存库用 UTC 当天 0 点,避免时区偏移串日
|
||
return new Date(Date.UTC(y, m - 1, d))
|
||
}
|
||
|
||
export function formatLiveDate(value?: Date | string | null): string {
|
||
if (!value) return ''
|
||
const date = value instanceof Date ? value : new Date(value)
|
||
if (Number.isNaN(date.getTime())) return ''
|
||
const y = date.getUTCFullYear()
|
||
const m = String(date.getUTCMonth() + 1).padStart(2, '0')
|
||
const d = String(date.getUTCDate()).padStart(2, '0')
|
||
return `${y}-${m}-${d}`
|
||
}
|
||
|
||
export interface LiveClipFieldInput {
|
||
title?: string | null
|
||
liveDate?: string | null
|
||
liveHost?: string | null
|
||
liveHostUserId?: string | null
|
||
livePlatform?: string | null
|
||
}
|
||
|
||
export interface LiveClipFieldError {
|
||
field: 'title' | 'liveDate' | 'livePlatform'
|
||
message: string
|
||
}
|
||
|
||
export function validateLiveClipFields(input: LiveClipFieldInput): LiveClipFieldError[] {
|
||
const errors: LiveClipFieldError[] = []
|
||
const title = (input.title || '').trim()
|
||
if (!title) {
|
||
errors.push({ field: 'title', message: '请填写标题' })
|
||
} else if (title.length > 100) {
|
||
errors.push({ field: 'title', message: '标题不能超过 100 个字符' })
|
||
}
|
||
|
||
const liveDateRaw = (input.liveDate || '').trim()
|
||
if (liveDateRaw) {
|
||
if (!parseLiveDate(liveDateRaw)) {
|
||
errors.push({ field: 'liveDate', message: '直播日期格式无效' })
|
||
}
|
||
}
|
||
|
||
const platform = (input.livePlatform || '').trim()
|
||
if (platform && !isLiveClipPlatform(platform)) {
|
||
errors.push({ field: 'livePlatform', message: '请选择有效的直播平台' })
|
||
}
|
||
|
||
return errors
|
||
}
|