analysis.model.ts 5.8 KB

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