|
|
@@ -1,5 +1,42 @@
|
|
|
import { groupBy } from '@/tools';
|
|
|
|
|
|
+/**
|
|
|
+ * 单个检测维度:业务侧用 `key` 关联字段,展示与字典匹配用 `dimension`(与 JSON 中 `dimension` 一致)。
|
|
|
+ */
|
|
|
+export interface AnnotatorScope {
|
|
|
+ /** 字段标识,如 `tongueColor` */
|
|
|
+ key: string;
|
|
|
+ /** 与 `annotator.json` 行内 `dimension` 一致,如「舌色」 */
|
|
|
+ dimension: string;
|
|
|
+}
|
|
|
+
|
|
|
+export const tongueScopes: readonly AnnotatorScope[] = [
|
|
|
+ { key: 'tongueColor', dimension: '舌色' },
|
|
|
+ { key: 'tongueCoatingColor', dimension: '苔色' },
|
|
|
+ { key: 'tongueShape', dimension: '舌形' },
|
|
|
+ { key: 'tongueCoating', dimension: '苔质' },
|
|
|
+ { key: 'bodyFluid', dimension: '津液' },
|
|
|
+ { key: 'sublingualVein', dimension: '舌下' },
|
|
|
+];
|
|
|
+
|
|
|
+export const faceScopes: readonly AnnotatorScope[] = [
|
|
|
+ { key: 'faceColor', dimension: '面色' },
|
|
|
+ { key: 'mainColor', dimension: '主色' },
|
|
|
+ { key: 'shine', dimension: '光泽' },
|
|
|
+ { key: 'blackEye', dimension: '黑眼圈' },
|
|
|
+ // { key: 'leftBlackEye', dimension: '左黑眼圈' },
|
|
|
+ // { key: 'rightBlackEye', dimension: '右黑眼圈' },
|
|
|
+ { key: 'lipColor', dimension: '唇色' },
|
|
|
+ { key: 'eyeContact', dimension: '眼神' },
|
|
|
+ { key: 'eyeColor', dimension: '目色' },
|
|
|
+ // { key: 'leftEyeColor', dimension: '左目色' },
|
|
|
+ // { key: 'rightEyeColor', dimension: '右目色' },
|
|
|
+ { key: 'hecticCheek', dimension: '两颧红' },
|
|
|
+ { key: 'noseFold', dimension: '鼻褶' },
|
|
|
+ { key: 'cyanGlabella', dimension: '眉间/鼻柱青色' },
|
|
|
+ { key: 'faceSkinDefects', dimension: '面部皮损' },
|
|
|
+];
|
|
|
+
|
|
|
export function fromAnalysisModel(mode: 'tongue' | 'face', data: Record<string, any>): AnalysisModel;
|
|
|
export function fromAnalysisModel(mode: 'pulse', data: Record<string, any>): PulseAnalysisModel;
|
|
|
export function fromAnalysisModel(mode: 'alcohol', data: Record<string, any>): AlcoholAnalysisModel;
|
|
|
@@ -41,17 +78,27 @@ export interface AlcoholAnalysisModel {
|
|
|
export interface AnalysisModel {
|
|
|
table: {
|
|
|
columns: string[];
|
|
|
- data: { exception: boolean; invalid?: boolean; columns: string[] }[];
|
|
|
+ data: { key: string; exception: boolean; invalid?: boolean; columns: string[] }[];
|
|
|
};
|
|
|
exception: AnalysisException[];
|
|
|
exceptionGroup: {
|
|
|
key: string;
|
|
|
- exception: AnalysisException[]
|
|
|
+ exception: AnalysisException[];
|
|
|
}[];
|
|
|
cover: string[];
|
|
|
result: string;
|
|
|
}
|
|
|
|
|
|
+export interface AnalysisData {
|
|
|
+ standardValue: string;
|
|
|
+ actualList: {
|
|
|
+ actualValue: string;
|
|
|
+ contrast: 's' | string;
|
|
|
+ splitImage?: string | null;
|
|
|
+ attrs: string[] | null;
|
|
|
+ }[];
|
|
|
+}
|
|
|
+
|
|
|
export interface AnalysisException {
|
|
|
title: string;
|
|
|
cover?: string;
|
|
|
@@ -87,7 +134,12 @@ function fromPulseAnalysisModel(data: Record<string, any>): PulseAnalysisModel {
|
|
|
}
|
|
|
|
|
|
function fromAlcoholAnalysisModel(data: Record<string, any>): AlcoholAnalysisModel {
|
|
|
- const volume: [number, number] = data?.alcoholCapacity?.match(/(\d+)/g)?.slice(0, 2)?.filter(Boolean)?.map((v: string) => +v) ?? [];
|
|
|
+ const volume: [number, number] =
|
|
|
+ data?.alcoholCapacity
|
|
|
+ ?.match(/(\d+)/g)
|
|
|
+ ?.slice(0, 2)
|
|
|
+ ?.filter(Boolean)
|
|
|
+ ?.map((v: string) => +v) ?? [];
|
|
|
return {
|
|
|
condition: data?.alcoholCondition,
|
|
|
description: data?.alcoholCapacity,
|
|
|
@@ -97,20 +149,13 @@ function fromAlcoholAnalysisModel(data: Record<string, any>): AlcoholAnalysisMod
|
|
|
|
|
|
function fromTongueAnalysisModel(data: Record<string, any>): AnalysisModel {
|
|
|
const exception: AnalysisException[] = [];
|
|
|
- const fromTongueException = fromAnalysisException(exception);
|
|
|
- const c1 = data?.upImg ?? data?.tongueImgUrl;
|
|
|
- const c2 = data?.downImg ?? data?.tongueBackImgUrl;
|
|
|
+ const fromTongueException = fromAnalysisException(exception).bind(null, data);
|
|
|
+ const c1 = fromPictureAnnotator(data?.upImg) ?? data?.tongueImgUrl;
|
|
|
+ const c2 = fromPictureAnnotator(data?.downImg) ?? data?.tongueBackImgUrl;
|
|
|
return {
|
|
|
table: {
|
|
|
columns: ['舌象维度', '检测结果', '标准值'],
|
|
|
- data: [
|
|
|
- fromTongueException(data?.tongueColor, '舌色'),
|
|
|
- fromTongueException(data?.tongueCoatingColor, '苔色'),
|
|
|
- fromTongueException(data?.tongueShape, '舌形'),
|
|
|
- fromTongueException(data?.tongueCoating, '苔质'),
|
|
|
- fromTongueException(data?.bodyFluid, '津液'),
|
|
|
- fromTongueException(data?.sublingualVein, '舌下'),
|
|
|
- ],
|
|
|
+ data: tongueScopes.map(({ key, dimension }) => fromTongueException(key, dimension)),
|
|
|
},
|
|
|
exception,
|
|
|
exceptionGroup: [],
|
|
|
@@ -124,30 +169,14 @@ function fromTongueAnalysisModel(data: Record<string, any>): AnalysisModel {
|
|
|
|
|
|
function fromFaceAnalysisModel(data: Record<string, any>): AnalysisModel {
|
|
|
const exception: AnalysisException[] = [];
|
|
|
- const fromFaceException = fromAnalysisException(exception, (label, value) => `${label}${value}`);
|
|
|
- const c1 = data?.faceImg ?? data?.faceImgUrl;
|
|
|
- const c2 = data?.faceLeft ?? data?.faceLeftImgUrl;
|
|
|
- const c3 = data?.faceRight ?? data?.faceRightImgUrl;
|
|
|
+ const fromFaceException = fromAnalysisException(exception, (label, value) => `${label}${value}`).bind(null, data);
|
|
|
+ const c1 = fromPictureAnnotator(data?.faceImg) ?? data?.faceImgUrl;
|
|
|
+ const c2 = fromPictureAnnotator(data?.faceLeft) ?? data?.faceLeftImgUrl;
|
|
|
+ const c3 = fromPictureAnnotator(data?.faceRight) ?? data?.faceRightImgUrl;
|
|
|
return {
|
|
|
table: {
|
|
|
columns: ['面象维度', '检测结果', '标准值'],
|
|
|
- data: [
|
|
|
- fromFaceException(data?.faceColor, '面色'),
|
|
|
- fromFaceException(data?.mainColor, '主色'),
|
|
|
- fromFaceException(data?.shine, '光泽'),
|
|
|
- fromFaceException(data?.blackEye, '黑眼圈'),
|
|
|
- // fromFaceException(data?.leftBlackEye, '左黑眼圈'),
|
|
|
- // fromFaceException(data?.rightBlackEye, '右黑眼圈'),
|
|
|
- fromFaceException(data?.lipColor, '唇色'),
|
|
|
- fromFaceException(data?.eyeContact, '眼神'),
|
|
|
- fromFaceException(data?.eyeColor, '目色'),
|
|
|
- // fromFaceException(data?.leftEyeColor, '左目色'),
|
|
|
- // fromFaceException(data?.rightEyeColor, '右目色'),
|
|
|
- fromFaceException(data?.hecticCheek, '两颧红'),
|
|
|
- fromFaceException(data?.noseFold, '鼻褶'),
|
|
|
- fromFaceException(data?.cyanGlabella, '眉间/鼻柱青色'),
|
|
|
- fromFaceException(data?.faceSkinDefects, '面部皮损'),
|
|
|
- ],
|
|
|
+ data: faceScopes.map(({ key, dimension }) => fromFaceException(key, dimension)),
|
|
|
},
|
|
|
exception,
|
|
|
exceptionGroup: [],
|
|
|
@@ -161,19 +190,24 @@ function fromFaceAnalysisModel(data: Record<string, any>): AnalysisModel {
|
|
|
}
|
|
|
|
|
|
function fromAnalysisException(exception: AnalysisException[], $title = (label: string, value: string) => value) {
|
|
|
- return function (data: { actualList?: Record<string, any>[]; standardValue?: string }, label: string) {
|
|
|
+ const getTitle = (label: string, value: string) => {
|
|
|
+ if (value.startsWith(label)) label = '';
|
|
|
+ return $title(label, value);
|
|
|
+ }
|
|
|
+ return function (data: Record<string, any>, key: string, label: string) {
|
|
|
+ const value = data?.[key] as { actualList?: Record<string, any>[]; standardValue?: string };
|
|
|
let is = false;
|
|
|
let invalid = false;
|
|
|
- const values =
|
|
|
- data?.actualList?.map((item) => {
|
|
|
+ const values = value?.actualList?.map((item) => {
|
|
|
let title: string = item?.actualValue ?? '';
|
|
|
const suffix = item?.contrast ?? 's';
|
|
|
- if (title.endsWith('不符合检测要求')) { invalid = true; }
|
|
|
- else if (suffix !== 's') {
|
|
|
+ if (title.endsWith('不符合检测要求')) {
|
|
|
+ invalid = true;
|
|
|
+ } else if (suffix !== 's') {
|
|
|
if (suffix !== 'r') title += ` (${suffix || ''}) `;
|
|
|
is = true;
|
|
|
exception.push({
|
|
|
- title: $title(label, title),
|
|
|
+ title: getTitle(label, title),
|
|
|
cover: item.splitImage,
|
|
|
descriptions: [
|
|
|
item.features ? { label: '【特征】', value: item.features } : null,
|
|
|
@@ -185,8 +219,12 @@ function fromAnalysisException(exception: AnalysisException[], $title = (label:
|
|
|
return title;
|
|
|
}) ?? [];
|
|
|
return {
|
|
|
- exception: is, invalid,
|
|
|
- columns: [label, values.join('<br>'), data?.standardValue ?? '']
|
|
|
- }
|
|
|
+ key, exception: is, invalid,
|
|
|
+ columns: [label, values.join('<br>'), value?.standardValue ?? ''],
|
|
|
+ };
|
|
|
};
|
|
|
}
|
|
|
+
|
|
|
+function fromPictureAnnotator(value?: string | { object?: { src?: string } }) {
|
|
|
+ return typeof value === 'string' ? value : value?.object?.src;
|
|
|
+}
|