153 lines
4.5 KiB
TypeScript
153 lines
4.5 KiB
TypeScript
/**
|
|
* templateStore.ts - 模板存储管理模块
|
|
*
|
|
* 本模块负责从后端加载模板配置,并支持本地覆盖功能
|
|
* 模板存储在 /public/templates 目录下,通过 fetch API 加载
|
|
*
|
|
* 主要功能:
|
|
* - 加载模板索引列表
|
|
* - 根据 ID 或元数据加载单个模板
|
|
* - 从本地存储读取/保存模板覆盖
|
|
* - 检查模板是否有本地覆盖
|
|
*/
|
|
|
|
import type { Template, TemplateMeta } from '../types'
|
|
|
|
/**
|
|
* 本地存储中覆盖模板的前缀
|
|
* 完整 key 格式:mope_template_override:{template_id}
|
|
*/
|
|
const OVERRIDE_PREFIX = 'mope_template_override:'
|
|
|
|
/**
|
|
* 深度克隆对象
|
|
* 使用 JSON 序列化/反序列化实现
|
|
* 注意:这会丢失 undefined、正则、函数等特殊类型
|
|
*
|
|
* @param value - 需要克隆的值
|
|
* @returns 克隆后的新值
|
|
*/
|
|
export function clone<T>(value: T): T {
|
|
return JSON.parse(JSON.stringify(value))
|
|
}
|
|
|
|
/**
|
|
* 加载模板索引列表
|
|
* 从 http://ch1.b.uat.4.cn/zncmweb/templates/index.json 获取所有可用模板的元数据
|
|
*
|
|
* @returns 模板元数据数组
|
|
* @throws 如果请求失败或响应非 OK,抛出错误
|
|
*/
|
|
export async function loadTemplateIndex(): Promise<TemplateMeta[]> {
|
|
const response = await fetch('https://ch1.b.uat.4.cn/zncmweb/templates/index.json')
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
const data = await response.json()
|
|
return (data.templates || []) as TemplateMeta[]
|
|
}
|
|
|
|
/**
|
|
* 根据元数据或 ID 加载模板
|
|
* 如果本地有覆盖,返回覆盖版本
|
|
*
|
|
* @param metaOrId - 模板元数据对象或模板 ID 字符串
|
|
* @returns 模板对象
|
|
* @throws 如果请求失败或响应非 OK,抛出错误
|
|
*/
|
|
export async function loadTemplateByMeta(metaOrId: TemplateMeta | string): Promise<Template> {
|
|
// 提取模板 ID
|
|
const templateId = typeof metaOrId === 'string'
|
|
? metaOrId
|
|
: metaOrId?.template_id
|
|
|
|
// 确定请求的 URL
|
|
const file = typeof metaOrId === 'string'
|
|
? `/templates/${templateId}.json`
|
|
: (metaOrId as TemplateMeta)?.file
|
|
|
|
const response = await fetch(file || `/templates/${templateId}.json`)
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
|
|
const template = await response.json() as Template
|
|
|
|
// 检查是否有本地覆盖
|
|
const override = getTemplateOverride(template.template_id || templateId || '')
|
|
|
|
// 如果有覆盖,返回覆盖版本
|
|
return override ? clone(override) : template
|
|
}
|
|
|
|
/**
|
|
* 加载原始模板(忽略本地覆盖)
|
|
* 用于在用户重置模板时恢复到原始状态
|
|
*
|
|
* @param metaOrId - 模板元数据对象或模板 ID 字符串
|
|
* @returns 原始模板对象
|
|
* @throws 如果请求失败或响应非 OK,抛出错误
|
|
*/
|
|
export async function loadOriginalTemplate(metaOrId: TemplateMeta | string): Promise<Template> {
|
|
// 提取模板 ID
|
|
const templateId = typeof metaOrId === 'string'
|
|
? metaOrId
|
|
: metaOrId?.template_id
|
|
|
|
// 确定请求的 URL
|
|
const file = typeof metaOrId === 'string'
|
|
? `/templates/${templateId}.json`
|
|
: (metaOrId as TemplateMeta)?.file
|
|
|
|
const response = await fetch(file || `/templates/${templateId}.json`)
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
|
|
return response.json() as Promise<Template>
|
|
}
|
|
|
|
/**
|
|
* 从本地存储获取模板覆盖
|
|
*
|
|
* @param templateId - 模板 ID
|
|
* @returns 覆盖的模板对象,如果没有覆盖则返回 null
|
|
*/
|
|
export function getTemplateOverride(templateId: string): Template | null {
|
|
if (!templateId) return null
|
|
try {
|
|
const raw = localStorage.getItem(`${OVERRIDE_PREFIX}${templateId}`)
|
|
return raw ? JSON.parse(raw) : null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查指定模板是否有本地覆盖
|
|
*
|
|
* @param templateId - 模板 ID
|
|
* @returns 如果有覆盖返回 true,否则返回 false
|
|
*/
|
|
export function hasTemplateOverride(templateId: string): boolean {
|
|
return Boolean(getTemplateOverride(templateId))
|
|
}
|
|
|
|
/**
|
|
* 保存模板覆盖到本地存储
|
|
*
|
|
* @param templateId - 模板 ID
|
|
* @param template - 要保存的模板对象
|
|
* @throws 如果 templateId 为空,抛出错误
|
|
*/
|
|
export function saveTemplateOverride(templateId: string, template: Template): void {
|
|
if (!templateId) throw new Error('缺少 template_id')
|
|
localStorage.setItem(
|
|
`${OVERRIDE_PREFIX}${templateId}`,
|
|
JSON.stringify(template)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* 清除指定模板的本地覆盖
|
|
*
|
|
* @param templateId - 模板 ID
|
|
*/
|
|
export function clearTemplateOverride(templateId: string): void {
|
|
if (!templateId) return
|
|
localStorage.removeItem(`${OVERRIDE_PREFIX}${templateId}`)
|
|
} |