import type { Almanac, ZiweiChart, DailyFortune } from '../algorithms/types' import type { SearchTemplate, SearchRequest } from '../types/search' import { storage } from '../utils/storage' export interface ReportTemplate { id: string name: string description: string sections: TemplateSection[] } export interface TemplateSection { id: string title: string type: 'almanac' | 'ziwei' | 'fortune' | 'text' visible: boolean order: number } export interface GeneratedReport { templateId: string generatedAt: string sections: GeneratedSection[] } export interface GeneratedSection { id: string title: string type: string content: string } const DEFAULT_TEMPLATES: ReportTemplate[] = [ { id: 'daily-brief', name: '每日简报', description: '包含今日黄历和运势概要', sections: [ { id: 'almanac', title: '今日黄历', type: 'almanac', visible: true, order: 1 }, { id: 'fortune', title: '今日运势', type: 'fortune', visible: true, order: 2 }, ], }, { id: 'full-report', name: '完整报告', description: '包含黄历、紫微盘和运势详情', sections: [ { id: 'almanac', title: '今日黄历', type: 'almanac', visible: true, order: 1 }, { id: 'ziwei', title: '紫微斗数', type: 'ziwei', visible: true, order: 2 }, { id: 'fortune', title: '运势详情', type: 'fortune', visible: true, order: 3 }, ], }, { id: 'ziwei-only', name: '紫微专报', description: '仅包含紫微斗数排盘分析', sections: [ { id: 'ziwei', title: '紫微斗数', type: 'ziwei', visible: true, order: 1 }, ], }, ] const DEFAULT_SEARCH_TEMPLATES: SearchTemplate[] = [ { id: 'wedding', name: '嫁娶吉日', description: '查找适合嫁娶的黄道吉日', category: '婚嫁', condition: { conditions: [ { id: '1', type: 'suitable', items: ['嫁娶', '纳采', '订盟'], operator: 'and', exclude: false }, ], days: 90, sortBy: 'date', sortOrder: 'asc', }, }, { id: 'moving', name: '搬家吉日', description: '查找适合搬家的好日子', category: '居住', condition: { conditions: [ { id: '1', type: 'suitable', items: ['移徙', '入宅'], operator: 'or', exclude: false }, { id: '2', type: 'unsuitable', items: ['破土', '安葬'], operator: 'or', exclude: true }, ], days: 60, sortBy: 'date', sortOrder: 'asc', }, }, { id: 'business', name: '开市吉日', description: '查找适合开市交易的吉日', category: '商业', condition: { conditions: [ { id: '1', type: 'suitable', items: ['开市', '交易', '立券', '纳财'], operator: 'or', exclude: false }, ], days: 30, sortBy: 'date', sortOrder: 'asc', }, }, { id: 'travel', name: '出行吉日', description: '查找适合出行的安全日子', category: '出行', condition: { conditions: [ { id: '1', type: 'suitable', items: ['出行'], operator: 'and', exclude: false }, { id: '2', type: 'unsuitable', items: ['嫁娶', '安葬'], operator: 'or', exclude: true }, ], days: 30, sortBy: 'date', sortOrder: 'asc', }, }, { id: 'pray', name: '祈福吉日', description: '查找适合祈福祭祀的日子', category: '祭祀', condition: { conditions: [ { id: '1', type: 'suitable', items: ['祭祀', '祈福'], operator: 'or', exclude: false }, ], days: 30, sortBy: 'date', sortOrder: 'asc', }, }, { id: 'construction', name: '修造吉日', description: '查找适合修造动土的日子', category: '建筑', condition: { conditions: [ { id: '1', type: 'suitable', items: ['修造', '动土'], operator: 'or', exclude: false }, ], days: 60, sortBy: 'date', sortOrder: 'asc', }, }, ] export class TemplateService { private templatesKey = 'report_templates' private searchTemplatesKey = 'search_templates' private cachedSearchTemplates: SearchTemplate[] | null = null getSearchTemplates(): SearchTemplate[] { if (this.cachedSearchTemplates) return this.cachedSearchTemplates const stored = storage.get(this.searchTemplatesKey) this.cachedSearchTemplates = stored && stored.length > 0 ? stored : DEFAULT_SEARCH_TEMPLATES return this.cachedSearchTemplates } getCategories(): string[] { const templates = this.getSearchTemplates() const categories = new Set(templates.map(t => t.category)) return Array.from(categories) } getTemplatesByCategory(category: string): SearchTemplate[] { return this.getSearchTemplates().filter(t => t.category === category) } searchTemplates(keyword: string): SearchTemplate[] { const lower = keyword.toLowerCase() return this.getSearchTemplates().filter( t => t.name.toLowerCase().includes(lower) || t.description.toLowerCase().includes(lower), ) } async getTemplates(): Promise { const stored = storage.get(this.templatesKey) if (stored && stored.length > 0) return stored return DEFAULT_TEMPLATES } async getTemplateById(id: string): Promise { const templates = await this.getTemplates() return templates.find(t => t.id === id) ?? null } async saveTemplate(template: ReportTemplate): Promise { const templates = [...(await this.getTemplates())] const index = templates.findIndex(t => t.id === template.id) if (index >= 0) { templates[index] = template } else { templates.push(template) } storage.set(this.templatesKey, templates) } async deleteTemplate(id: string): Promise { const templates = [...(await this.getTemplates())] const index = templates.findIndex(t => t.id === id) if (index < 0) return false templates.splice(index, 1) storage.set(this.templatesKey, templates) return true } async generateReport( templateId: string, data: { almanac?: Almanac; chart?: ZiweiChart; fortune?: DailyFortune }, ): Promise { const template = await this.getTemplateById(templateId) if (!template) return null const sections: GeneratedSection[] = template.sections .filter(s => s.visible) .sort((a, b) => a.order - b.order) .map(s => ({ id: s.id, title: s.title, type: s.type, content: this.renderSection(s.type, data), })) return { templateId, generatedAt: new Date().toISOString(), sections, } } private renderSection( type: string, data: { almanac?: Almanac; chart?: ZiweiChart; fortune?: DailyFortune }, ): string { switch (type) { case 'almanac': return data.almanac ? this.renderAlmanac(data.almanac) : '暂无黄历数据' case 'ziwei': return data.chart ? this.renderZiwei(data.chart) : '暂无紫微数据' case 'fortune': return data.fortune ? this.renderFortune(data.fortune) : '暂无运势数据' case 'text': return '' default: return '' } } private renderAlmanac(almanac: Almanac): string { const parts: string[] = [] parts.push(`日期:${almanac.solarDate}`) parts.push(`宜:${almanac.suitable.join('、')}`) parts.push(`忌:${almanac.unsuitable.join('、')}`) parts.push(`建除:${almanac.jianChu}`) parts.push(`星神:${almanac.starGod}`) return parts.join('\n') } private renderZiwei(chart: ZiweiChart): string { const parts: string[] = [] parts.push(chart.summary ?? '') if (chart.sanFangSiZheng) { parts.push(`三方得分:${chart.sanFangSiZheng.sanFangScore}`) parts.push(`四正得分:${chart.sanFangSiZheng.siZhengScore}`) } return parts.join('\n') } private renderFortune(fortune: DailyFortune): string { const parts: string[] = [] parts.push(`综合评分:${fortune.overallScore}`) if (fortune.careerAdvice) parts.push(`事业:${fortune.careerAdvice}`) if (fortune.wealthAdvice) parts.push(`财运:${fortune.wealthAdvice}`) if (fortune.relationshipAdvice) parts.push(`感情:${fortune.relationshipAdvice}`) if (fortune.healthAdvice) parts.push(`健康:${fortune.healthAdvice}`) return parts.join('\n') } } const templateService = new TemplateService() export default templateService