analysis.model.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import { groupBy } from '@/tools';
  2. export function fromAnalysisModel(mode: 'tongue' | 'face', data: Record<string, any>): AnalysisModel;
  3. export function fromAnalysisModel(mode: 'pulse', data: Record<string, any>): PulseAnalysisModel;
  4. export function fromAnalysisModel(mode: 'alcohol', data: Record<string, any>): AlcoholAnalysisModel;
  5. export function fromAnalysisModel(
  6. mode: 'tongue' | 'face' | 'pulse' | 'alcohol',
  7. data: Record<string, any>
  8. ): AnalysisModel | AlcoholAnalysisModel | PulseAnalysisModel {
  9. let model: AnalysisModel;
  10. switch (mode) {
  11. case 'tongue':
  12. model = fromTongueAnalysisModel(data);
  13. break;
  14. case 'face':
  15. model = fromFaceAnalysisModel(data);
  16. break;
  17. case 'pulse':
  18. return fromPulseAnalysisModel(data);
  19. case 'alcohol':
  20. return fromAlcoholAnalysisModel(data?.extendFlowData);
  21. }
  22. const group = groupBy<AnalysisException>(model.exception, (item) => item.cover ?? '') ?? {};
  23. model.exceptionGroup = Object.entries(group).map(([key, exception]) => ({ key, exception }));
  24. return model;
  25. }
  26. export interface PulseAnalysisModel extends Pick<Awaited<ReturnType<typeof Bridge.pulse>>, 'measureId' | 'summaryLabel' | 'summaryValue'> {
  27. hand?: number;
  28. results?: string;
  29. url?: string;
  30. }
  31. export interface AlcoholAnalysisModel {
  32. condition: string;
  33. description: string;
  34. volume: [min: number, max?: number];
  35. }
  36. export interface AnalysisModel {
  37. table: {
  38. columns: string[];
  39. data: { exception: boolean; invalid?: boolean; columns: string[] }[];
  40. };
  41. exception: AnalysisException[];
  42. exceptionGroup: {
  43. key: string;
  44. exception: AnalysisException[]
  45. }[];
  46. cover: string[];
  47. result: string;
  48. }
  49. export interface AnalysisException {
  50. title: string;
  51. cover?: string;
  52. description?: string;
  53. descriptions: { label: string; value: string }[];
  54. tags: string[];
  55. }
  56. function fromPulseAnalysisModel(data: Record<string, any>): PulseAnalysisModel {
  57. const pulse = (function (value) {
  58. if (typeof value === 'string')
  59. try {
  60. value = JSON.parse(value);
  61. } catch (e) {}
  62. return typeof value === 'object' ? value : {};
  63. })(data.pulseReport);
  64. const getSummary = (value?: string[]) => (Array.isArray(value) && value.length ? value : void 0);
  65. const summary =
  66. getSummary(pulse?.summary_desc?.summary) ??
  67. getSummary(pulse?.summary_desc?.left?.summary) ??
  68. getSummary(pulse?.summary_desc?.right?.summary) ??
  69. [];
  70. return {
  71. measureId: data?.measureId,
  72. hand: pulse?.hand ?? 0,
  73. summaryValue: pulse?.summary,
  74. summaryLabel: pulse?.summary_desc,
  75. results: summary.join(','),
  76. url: pulse?.url ?? void 0,
  77. };
  78. }
  79. function fromAlcoholAnalysisModel(data: Record<string, any>): AlcoholAnalysisModel {
  80. const volume: [number, number] = data?.alcoholCapacity?.match(/(\d+)/g)?.slice(0, 2)?.filter(Boolean)?.map((v: string) => +v) ?? [];
  81. return {
  82. condition: data?.alcoholCondition,
  83. description: data?.alcoholCapacity,
  84. volume: volume.sort((a, b) => a - b),
  85. };
  86. }
  87. function fromTongueAnalysisModel(data: Record<string, any>): AnalysisModel {
  88. const exception: AnalysisException[] = [];
  89. const fromTongueException = fromAnalysisException(exception);
  90. const c1 = data?.upImg ?? data?.tongueImgUrl;
  91. const c2 = data?.downImg ?? data?.tongueBackImgUrl;
  92. return {
  93. table: {
  94. columns: ['舌象维度', '检测结果', '标准值'],
  95. data: [
  96. fromTongueException(data?.tongueColor, '舌色'),
  97. fromTongueException(data?.tongueCoatingColor, '苔色'),
  98. fromTongueException(data?.tongueShape, '舌形'),
  99. fromTongueException(data?.tongueCoating, '苔质'),
  100. fromTongueException(data?.bodyFluid, '津液'),
  101. fromTongueException(data?.sublingualVein, '舌下'),
  102. ],
  103. },
  104. exception,
  105. exceptionGroup: [],
  106. result: data?.tongueAnalysisResult ?? data?.tongue ?? '',
  107. cover: Object.assign([c1, c2].filter(Boolean), {
  108. ['舌上']: c1,
  109. ['舌下']: c2,
  110. }),
  111. };
  112. }
  113. function fromFaceAnalysisModel(data: Record<string, any>): AnalysisModel {
  114. const exception: AnalysisException[] = [];
  115. const fromFaceException = fromAnalysisException(exception, (label, value) => `${label}${value}`);
  116. const c1 = data?.faceImg ?? data?.faceImgUrl;
  117. const c2 = data?.faceLeft ?? data?.faceLeftImgUrl;
  118. const c3 = data?.faceRight ?? data?.faceRightImgUrl;
  119. return {
  120. table: {
  121. columns: ['面象维度', '检测结果', '标准值'],
  122. data: [
  123. fromFaceException(data?.faceColor, '面色'),
  124. fromFaceException(data?.mainColor, '主色'),
  125. fromFaceException(data?.shine, '光泽'),
  126. fromFaceException(data?.leftBlackEye, '左黑眼圈'),
  127. fromFaceException(data?.rightBlackEye, '右黑眼圈'),
  128. fromFaceException(data?.lipColor, '唇色'),
  129. fromFaceException(data?.eyeContact, '眼神'),
  130. fromFaceException(data?.leftEyeColor, '左目色'),
  131. fromFaceException(data?.rightEyeColor, '右目色'),
  132. fromFaceException(data?.hecticCheek, '两颧红'),
  133. fromFaceException(data?.noseFold, '鼻褶'),
  134. fromFaceException(data?.cyanGlabella, '眉间/鼻柱青色'),
  135. fromFaceException(data?.faceSkinDefects, '面部皮损'),
  136. ],
  137. },
  138. exception,
  139. exceptionGroup: [],
  140. result: data?.faceAnalysisResult ?? data?.face ?? '',
  141. cover: Object.assign([c1, c2, c3].filter(Boolean), {
  142. ['正面']: c1,
  143. ['左面']: c2,
  144. ['右面']: c3,
  145. }),
  146. };
  147. }
  148. function fromAnalysisException(exception: AnalysisException[], $title = (label: string, value: string) => value) {
  149. return function (data: { actualList?: Record<string, any>[]; standardValue?: string }, label: string) {
  150. let is = false;
  151. let invalid = false;
  152. const values =
  153. data?.actualList?.map((item) => {
  154. let title: string = item?.actualValue ?? '';
  155. const suffix = item?.contrast ?? 's';
  156. if (title.endsWith('不符合检测要求')) { invalid = true; }
  157. else if (suffix !== 's') {
  158. if (suffix !== 'r') title += ` (${suffix || ''}) `;
  159. is = true;
  160. exception.push({
  161. title: $title(label, title),
  162. cover: item.splitImage,
  163. descriptions: [
  164. item.features ? { label: '【特征】', value: item.features } : null,
  165. item.clinicalSignificance ? { label: '【临床意义】', value: item.clinicalSignificance } : null,
  166. ].filter((v) => !!v),
  167. tags: item.attrs ?? [],
  168. });
  169. }
  170. return title;
  171. }) ?? [];
  172. return {
  173. exception: is, invalid,
  174. columns: [label, values.join('<br>'), data?.standardValue ?? '']
  175. }
  176. };
  177. }