gongxiangp2/lib/live-clip.ts
WuYongJie d8d843e6ad feat: add live clip material type with date host and platform
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.
2026-09-22 18:59:05 +08:00

98 lines
2.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 直播切片素材:类型判断、平台预置与字段校验
*/
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
}