外包风险评估系统:领域引擎+前端+服务端持久化与生产部署

- 确定性领域引擎(分类/评分/分级/红线/费用/裁决)+LLM(通义千问)语言理解
- 6步评估向导、服务端草稿持久化(跨设备/编辑草稿保护)
- 工作流(草稿→风控→管理层)、RBAC、报告导出、校准、客户/费率/红线/最低工资管理
- 专业图标体系替换全部emoji、看板美化
- 生产化:API_BASE可配置(同源反代)、auth密钥惰性读取修复RBAC
- 444单测+204前端测试+51 e2e
This commit is contained in:
freedakgmail
2026-06-13 01:06:39 +08:00
commit c670b9e454
404 changed files with 61820 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
/**
* 分行业知识库存储:按行业标识分区存储五类内容并校验完备性(Req 14.1, 14.4)。
*
* - 按行业标识分区存储 Indicator、权重模板、Redline、典型案例、追问话术五类内容(Req 14.1)。
* - 新增分区缺任一类内容时拒绝创建、抛出指明缺失类别的校验错误,
* 且保持已有分区不变(Req 14.4{@link IncompletePartitionError})。
*/
import type { Industry } from '../domain/common.js';
import type { IndustryPartition, KnowledgeBase } from '../domain/knowledge.js';
import { findMissingCategories } from './category.js';
import { IncompletePartitionError } from './errors.js';
/** 规范化行业标识用于分区键匹配(首尾空白不敏感)。 */
function normalizeIndustryId(industryId: Industry): string {
return industryId.trim();
}
/**
* 分行业知识库存储(Knowledge_BaseReq 14.1, 14.4)。
*
* 以行业标识为键登记 {@link IndustryPartition};新增分区前强制完备性校验,
* 校验不通过则拒绝并保持已有分区不变。
*/
export class KnowledgeBaseStore {
/** 以规范化行业标识为键的分区表。 */
private readonly partitions = new Map<string, IndustryPartition>();
/**
* @param initial 初始登记的行业分区集合(默认空)。
* @throws {IncompletePartitionError} 当任一初始分区缺少五类必备内容时。
*/
constructor(initial: readonly IndustryPartition[] = []) {
for (const partition of initial) {
this.addPartition(partition);
}
}
/**
* 新增一个行业分区(Req 14.1, 14.4)。
*
* 先做五类内容完备性校验:缺任一类则拒绝创建、抛出
* {@link IncompletePartitionError}(指明缺失类别),且不修改任何已有分区。
* 校验通过后按行业标识登记该分区(同一行业再次新增将覆盖其内容)。
*
* @throws {IncompletePartitionError} 当该分区缺少五类必备内容中的任一类时。
*/
addPartition(partition: IndustryPartition): void {
const missing = findMissingCategories(partition);
if (missing.length > 0) {
// 校验失败:拒绝创建,不改动 this.partitions(保持已有分区不变)。
throw new IncompletePartitionError(partition.industryId, missing);
}
this.partitions.set(normalizeIndustryId(partition.industryId), partition);
}
/**
* 判断是否存在与给定行业标识匹配的分区。
*/
has(industryId: Industry): boolean {
return this.partitions.has(normalizeIndustryId(industryId));
}
/**
* 按行业标识获取分区;不存在时返回 undefined。
*/
get(industryId: Industry): IndustryPartition | undefined {
return this.partitions.get(normalizeIndustryId(industryId));
}
/** 已登记分区数量。 */
get size(): number {
return this.partitions.size;
}
/**
* 导出当前知识库的不可变快照(Req 14.1)。
*/
snapshot(): KnowledgeBase {
return { partitions: [...this.partitions.values()] };
}
}