feat: 初始化项目结构并添加核心功能模块

- 新增文档模板和导航结构
- 实现服务器基础API路由和控制器
- 添加扩展插件配置和前端框架
- 引入多租户和权限管理模块
- 集成日志和数据库配置
- 添加核心业务模型和类型定义
This commit is contained in:
2026-03-17 22:07:19 +08:00
parent c0870dce50
commit 136c2fa579
728 changed files with 107690 additions and 5614 deletions

View File

@@ -0,0 +1,118 @@
import db from '../config/database';
import { logger } from '../utils/logger';
import { DecisionExplainabilityEngine } from '../core/ai/DecisionExplainabilityEngine';
export interface TicketSentiment {
ticketId: string;
sentimentScore: number; // 0 (negative) to 1 (positive)
urgency: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
keywords: string[];
}
/**
* [BIZ_OPS_135] 智能工单优先级调度建议 (Support Queue)
* @description 核心逻辑:分析工单内容的情感极性与关键词,自动识别“紧急差评”或“退款威胁”,并建议优先处理。
*/
export class PriorityTicketService {
private static readonly PRIORITY_AUDIT_TABLE = 'cf_ticket_priority_audit';
/**
* 初始化数据库表
*/
static async initTable() {
const hasTable = await db.schema.hasTable(this.PRIORITY_AUDIT_TABLE);
if (!hasTable) {
await db.schema.createTable(this.PRIORITY_AUDIT_TABLE, (table) => {
table.increments('id').primary();
table.string('tenant_id', 64).index();
table.string('ticket_id', 64).index();
table.string('priority_suggested', 16);
table.text('reason');
table.string('status', 32).defaultTo('PENDING_REVIEW');
table.timestamp('created_at').defaultTo(db.fn.now());
});
}
}
/**
* 优先调度工单 (BIZ_OPS_135)
*/
static async prioritizeTickets(tenantId: string): Promise<any> {
logger.info(`[TicketPriority] Analyzing tickets for Tenant: ${tenantId}`);
try {
// 1. 获取该租户下所有未解决的工单 (模拟查询)
const tickets = await db('cf_support_tickets')
.where({ tenant_id: tenantId, status: 'OPEN' })
.limit(50);
const prioritized = [];
for (const ticket of tickets) {
// 2. 情感与关键词分析 (模拟)
const sentiment = await this.analyzeTicketSentiment(ticket.content);
// 3. 优先级策略:情感极低 (< 0.2) 或 包含 "refund", "scam"
let priority: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' = 'LOW';
if (sentiment.sentimentScore < 0.2 || sentiment.keywords.some(k => ['refund', 'scam', 'bad', 'fraud'].includes(k.toLowerCase()))) {
priority = 'CRITICAL';
} else if (sentiment.sentimentScore < 0.5) {
priority = 'HIGH';
}
if (priority === 'CRITICAL' || priority === 'HIGH') {
const reason = `Ticket identified as ${priority} based on negative sentiment (${sentiment.sentimentScore.toFixed(2)}) ` +
`and keywords: [${sentiment.keywords.join(', ')}].`;
// 4. 生成优先处理建议 (Suggestion-First)
const [suggestionId] = await db(this.PRIORITY_AUDIT_TABLE).insert({
tenant_id: tenantId,
ticket_id: ticket.id,
priority_suggested: priority,
reason: reason,
status: 'PENDING_REVIEW',
created_at: new Date()
});
// 5. [UX_XAI_01] 记录决策证据链
await DecisionExplainabilityEngine.logDecision({
tenantId,
module: 'SUPPORT_TICKET',
resourceId: String(suggestionId),
decisionType: 'PRIORITY_SCHEDULING_SUGGESTION',
causalChain: reason,
factors: [
{ name: 'SentimentScore', value: sentiment.sentimentScore, weight: 0.6, impact: 'NEGATIVE' },
{ name: 'KeywordMatch', value: sentiment.keywords.length, weight: 0.4, impact: 'NEGATIVE' }
],
traceId: 'ticket-priority-' + Date.now()
});
prioritized.push({ ticketId: ticket.id, priority, suggestionId });
}
}
return {
success: true,
count: prioritized.length,
prioritized,
status: 'PENDING_REVIEW'
};
} catch (err: any) {
logger.error(`[TicketPriority][WARN] Prioritization failed: ${err.message}`);
return { success: false, error: err.message };
}
}
private static async analyzeTicketSentiment(content: string): Promise<TicketSentiment> {
// 实际业务中应调用 AIService 或专门的情感分析接口
const score = Math.random(); // 模拟得分
const keywords = ['refund', 'wait', 'shipping'].filter(() => Math.random() > 0.5);
return {
ticketId: 'mock',
sentimentScore: score,
urgency: 'MEDIUM',
keywords
};
}
}