Some checks failed
CI Check / check (push) Has been cancelled
- 创建统一的Modal组件,采用Apple风格设计 - 实现毛玻璃效果、圆角、动画和细边框描边 - 修复弹窗打开时背景滚动问题 - 修复分类管理中重复卡片和数组字符串显示问题 - 优化选项解析逻辑,添加去重和过滤机制
128 lines
3.8 KiB
TypeScript
128 lines
3.8 KiB
TypeScript
/**
|
|
* 分类字段配置工具方法
|
|
* 用于读取/写入系统设置中「哪些字段需要同步到分类管理」的配置
|
|
*/
|
|
|
|
import { prisma } from '@/lib/prisma'
|
|
import { STANDARD_FIELDS } from './upload-template-presets'
|
|
import { ensureSystemSettingsOptionalColumns } from './system-settings-columns'
|
|
|
|
export const DEFAULT_MANAGED_CATEGORY_FIELDS = [
|
|
'categoryName',
|
|
'sceneName',
|
|
'platformName',
|
|
'renderer',
|
|
] as const
|
|
|
|
type CategorySettingsRow = {
|
|
id: string
|
|
categoryManagedFields: string | null
|
|
}
|
|
|
|
type CategoryFieldOption = {
|
|
key: string
|
|
label: string
|
|
type: string
|
|
source: 'standard' | 'custom'
|
|
}
|
|
|
|
const dedupeKeys = (keys: string[]) => Array.from(new Set(keys.filter(Boolean)))
|
|
|
|
function parseStoredFields(value?: string | null): string[] | null {
|
|
if (!value) return null
|
|
try {
|
|
const parsed = JSON.parse(value)
|
|
if (Array.isArray(parsed)) {
|
|
return dedupeKeys(parsed.map((item) => (typeof item === 'string' ? item : '')).filter(Boolean))
|
|
}
|
|
} catch {
|
|
return null
|
|
}
|
|
return null
|
|
}
|
|
|
|
async function ensureSystemSettingsId(): Promise<CategorySettingsRow> {
|
|
const existing = (await prisma.systemSettings.findFirst()) as unknown as CategorySettingsRow | null
|
|
if (existing) {
|
|
return existing
|
|
}
|
|
const created = (await prisma.systemSettings.create({ data: {} })) as unknown as CategorySettingsRow
|
|
return created
|
|
}
|
|
|
|
export async function getManagedCategoryFields(): Promise<string[]> {
|
|
await ensureSystemSettingsOptionalColumns()
|
|
const settings = (await prisma.systemSettings.findFirst()) as unknown as CategorySettingsRow | null
|
|
const availableKeys = new Set((await getAvailableCategoryFields()).map(field => field.key))
|
|
|
|
const coerceToAvailable = (keys: string[] | null | undefined) => {
|
|
if (!keys) return null
|
|
const filtered = keys.filter((key) => availableKeys.has(key))
|
|
return filtered
|
|
}
|
|
|
|
const parsed = parseStoredFields(settings?.categoryManagedFields)
|
|
const filteredParsed = coerceToAvailable(parsed)
|
|
if (filteredParsed && filteredParsed.length > 0) {
|
|
if (!parsed || filteredParsed.length !== parsed.length) {
|
|
await saveManagedCategoryFields(filteredParsed)
|
|
}
|
|
return filteredParsed
|
|
}
|
|
|
|
const filteredDefaults = DEFAULT_MANAGED_CATEGORY_FIELDS.filter((key) => availableKeys.has(key))
|
|
await saveManagedCategoryFields(filteredDefaults)
|
|
return filteredDefaults
|
|
}
|
|
|
|
export async function saveManagedCategoryFields(fieldKeys: string[]) {
|
|
await ensureSystemSettingsOptionalColumns()
|
|
const unique = dedupeKeys(fieldKeys)
|
|
const payload = JSON.stringify(unique)
|
|
const settings = await ensureSystemSettingsId()
|
|
await prisma.systemSettings.update({
|
|
where: { id: settings.id },
|
|
// Prisma 类型缓存未及时刷新,临时使用 any 以避免阻塞,可在下一次 generate 后移除
|
|
data: { categoryManagedFields: payload } as any,
|
|
})
|
|
return unique
|
|
}
|
|
|
|
export async function getAvailableCategoryFields(): Promise<CategoryFieldOption[]> {
|
|
await ensureSystemSettingsOptionalColumns()
|
|
const fieldMap = new Map<string, CategoryFieldOption>()
|
|
|
|
Object.values(STANDARD_FIELDS).forEach((field) => {
|
|
if (field.type === 'select') {
|
|
fieldMap.set(field.key, {
|
|
key: field.key,
|
|
label: field.label,
|
|
type: field.type,
|
|
source: 'standard',
|
|
})
|
|
}
|
|
})
|
|
|
|
const customFields = await prisma.uploadField.findMany({
|
|
where: { type: 'select' },
|
|
select: { key: true, label: true },
|
|
distinct: ['key'],
|
|
orderBy: { key: 'asc' },
|
|
})
|
|
|
|
customFields.forEach((field) => {
|
|
if (!field.key) return
|
|
if (!fieldMap.has(field.key)) {
|
|
fieldMap.set(field.key, {
|
|
key: field.key,
|
|
label: field.label || field.key,
|
|
type: 'select',
|
|
source: 'custom',
|
|
})
|
|
}
|
|
})
|
|
|
|
return Array.from(fieldMap.values()).sort((a, b) => a.key.localeCompare(b.key))
|
|
}
|
|
|