feat: 初始化项目结构并添加核心功能模块
- 新增文档模板和导航结构 - 实现服务器基础API路由和控制器 - 添加扩展插件配置和前端框架 - 引入多租户和权限管理模块 - 集成日志和数据库配置 - 添加核心业务模型和类型定义
This commit is contained in:
118
server/src/services/PriorityTicketService.ts
Normal file
118
server/src/services/PriorityTicketService.ts
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user