Commit 0aa1e88b by luoqi

refactor(cleanup): 删未用导出/导入(审计 A5/A6/A7/A9/A10/A13)

packages/utils: 删 daysBetween/addDays/isoNow/hmacSha256/renderTemplate(+连带 DAY_MS、createHmac import)
packages/types/canonical-codes: 删 isPACDiagnosisCode/isPACTreatmentCategory/isFDIToothPosition 三个未用 type-guard + RecommendationExtractedBy const/type 别名(保留 Schema)
packages/types/enums: 删 SyncResource、PersonaTriggerSource、HostActionKeySchema、AgentKindSchema、RecallFeedbackTag(均零引用;保留各自仍用的 const)
pac-service: 删 sync-incremental.scheduler 未用 CronExpression import、wrap-openapi 未用 SUCCESS_ENVELOPE_NAME、realtime-provider 未用 RealtimeProviderKey

types/utils build + service/web tsc 全通过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parent ed9c1bbe
......@@ -3,8 +3,6 @@
* 对网关暴露同一个 open() 接口:喂音频 → 回吐文字提示。
*/
export type RealtimeProviderKey = 'qwen' | 'gemini';
export interface CoachProxyHandle {
/** 灌一帧 base64 PCM16 16k 音频(provider 内部按"患者停顿"切轮触发) */
appendAudio(base64Frame: string): void;
......
......@@ -5,7 +5,6 @@ type SchemaObject = Exclude<
undefined
>[string];
const SUCCESS_ENVELOPE_NAME = 'ApiSuccessEnvelope';
const ERROR_ENVELOPE_NAME = 'ApiErrorEnvelope';
/**
......
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Cron } from '@nestjs/schedule';
import * as path from 'path';
import { PrismaService } from '../prisma/prisma.service';
import {
......
......@@ -673,13 +673,6 @@ export const PACImageModalitySchema = z.enum(
// Recommendation 提取来源(content.extractedBy)
// =============================================================
export const RecommendationExtractedBy = {
rule: 'rule', // 关键词规则(兜底)
llm: 'llm', // Layer C LLM 抽取
doctor_input: 'doctor_input', // 医生显式录入(host 结构化字段)
} as const;
export type RecommendationExtractedBy =
(typeof RecommendationExtractedBy)[keyof typeof RecommendationExtractedBy];
export const RecommendationExtractedBySchema = z.enum([
'rule',
'llm',
......@@ -687,25 +680,6 @@ export const RecommendationExtractedBySchema = z.enum([
]);
// =============================================================
// 工具:运行时检查 code 是否合法(yaml 校验 / CI 防漂移用)
// =============================================================
export function isPACDiagnosisCode(v: unknown): v is PACDiagnosisCode {
return typeof v === 'string' && v in PACDiagnosisCodes;
}
export function isPACTreatmentCategory(v: unknown): v is PACTreatmentCategory {
return typeof v === 'string' && v in PACTreatmentCategories;
}
export function isFDIToothPosition(v: unknown): v is FDIToothPosition {
return (
typeof v === 'string' &&
(FDI_TOOTH_POSITIONS as readonly string[]).includes(v)
);
}
// =============================================================
// 工具:code → 中文名(单一真理源,前后端共用)
// - 后端拼"自然语言句子"(plan reason / persona description)时用,根上不漏 enum code
// - 前端展示"字段型 enum"(category / status / code 列)时也用,不必接口冗余塞 xxName
......
......@@ -83,19 +83,6 @@ export const HostActionKey = {
CALL_PATIENT: 'CALL_PATIENT', // 拨号
} as const;
export type HostActionKey = (typeof HostActionKey)[keyof typeof HostActionKey];
export const HostActionKeySchema = z.enum([
'VIEW_PATIENT',
'EDIT_PATIENT',
'CREATE_APPOINTMENT',
'VIEW_APPOINTMENT',
'VIEW_ENCOUNTER',
'VIEW_MEDICAL_RECORD',
'VIEW_IMAGE',
'VIEW_PAYMENT',
'ADD_NOTE',
'OPEN_WECOM_CHAT',
'CALL_PATIENT',
]);
/// 标签(中文)+ 占位变量提示(给 admin 配置页显示)
export const HOST_ACTION_META: Record<HostActionKey, { label: string; placeholders: string[] }> = {
......@@ -422,14 +409,6 @@ export const PersonaFeatureKey = {
export type PersonaFeatureKey =
(typeof PersonaFeatureKey)[keyof typeof PersonaFeatureKey];
/// Persona 触发来源
export const PersonaTriggerSource = {
TXN: 'txn', // event-driven(主路径)
MANUAL: 'manual', // admin / API 调试
SCHEDULED: 'scheduled', // 每日 cron 兜底
} as const;
export type PersonaTriggerSource =
(typeof PersonaTriggerSource)[keyof typeof PersonaTriggerSource];
// =============================================================
// FollowupPlan
......@@ -623,7 +602,6 @@ export const RECALL_FEEDBACK_OPTIONS = [
{ value: 'bad_timing', labelZh: '时机不对', hint: '太早 / 太晚' },
{ value: 'not_worth', labelZh: '不值得召', hint: '价值低 / 不是真机会' },
] as const;
export type RecallFeedbackTag = (typeof RECALL_FEEDBACK_OPTIONS)[number]['value'];
export const ExecutionChannel = {
PHONE: 'phone',
......@@ -707,22 +685,6 @@ export const SyncStatus = {
export type SyncStatus = (typeof SyncStatus)[keyof typeof SyncStatus];
export const SyncStatusSchema = z.enum(['running', 'success', 'partial', 'failed']);
/// Pull / Push 资源 — 跟 SubjectType 对齐 + patients + users(host /users:resolve)
export const SyncResource = {
PATIENTS: 'patients',
CONSULTATIONS: 'consultations',
APPOINTMENTS: 'appointments',
VISIT_REGISTRATIONS: 'visit_registrations',
VISIT_RECEPTIONS: 'visit_receptions',
CLINICAL_ENCOUNTERS: 'clinical_encounters',
EMR_DOCUMENTS: 'emr_documents',
CHARGE_ORDERS: 'charge_orders',
PAYMENTS: 'payments',
REFUNDS: 'refunds',
IMAGE_STUDIES: 'image_studies',
USERS: 'users', // host /users:resolve(用于 Plan 分配查客服)
} as const;
export type SyncResource = (typeof SyncResource)[keyof typeof SyncResource];
// =============================================================
// AgentInvocation
......@@ -737,13 +699,6 @@ export const AgentKind = {
PLAN_ANALYSIS: 'plan_analysis', // 将来,Plan 解释
} as const;
export type AgentKind = (typeof AgentKind)[keyof typeof AgentKind];
export const AgentKindSchema = z.enum([
'script',
'summary',
'persona_feature',
'ranking',
'plan_analysis',
]);
/// Agent 调用状态(3 个;流式过程也归 running,流式完成也归 succeeded)
export const AgentStatus = {
......
import { createHash, createHmac, randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
const DAY_MS = 24 * 60 * 60 * 1000;
export function daysBetween(a: Date | string, b: Date | string): number {
const ad = typeof a === 'string' ? new Date(a) : a;
const bd = typeof b === 'string' ? new Date(b) : b;
return Math.floor((bd.getTime() - ad.getTime()) / DAY_MS);
}
export function addDays(date: Date | string, days: number): Date {
const d = typeof date === 'string' ? new Date(date) : new Date(date);
d.setUTCDate(d.getUTCDate() + days);
return d;
}
export function isoNow(): string {
return new Date().toISOString();
}
import { createHash, randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
export function randomCode(bytes = 24): string {
return randomBytes(bytes).toString('base64url');
......@@ -26,10 +8,6 @@ export function sha256(value: string): string {
return createHash('sha256').update(value).digest('hex');
}
export function hmacSha256(secret: string, value: string): string {
return createHmac('sha256', secret).update(value).digest('hex');
}
const SCRYPT_KEYLEN = 64;
export function hashSecret(secret: string): string {
......@@ -57,12 +35,6 @@ export function chunk<T>(arr: T[], size: number): T[][] {
return out;
}
export function renderTemplate(template: string, vars: Record<string, string | number>): string {
return template.replace(/\{(\w+)\}/g, (_, key) =>
vars[key] !== undefined ? String(vars[key]) : `{${key}}`,
);
}
export async function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment