Explorar el Código

feat: 专家问答水质报警

whh hace 9 meses
padre
commit
2c367b9376

+ 1 - 0
package.json

@@ -31,6 +31,7 @@
     "markdown-it": "^14.1.0",
     "markdown-it-link-attributes": "^4.0.1",
     "markdown-it-math": "^4.1.1",
+    "markdown-it-texmath": "^1.0.0",
     "nprogress": "0.2.0",
     "pinia": "2.1.7",
     "vue": "3.3.9",

+ 1 - 1
src/api/business/record.js

@@ -3,7 +3,7 @@ import request from '@/utils/request'
 // 查询信义大模型问答记录列表
 export function listRecord(query) {
   return request({
-    url: '/business/record/list',
+    url: '/business/chatRecord/list',
     method: 'get',
     params: query
   })

+ 43 - 0
src/api/business/water.js

@@ -0,0 +1,43 @@
+import request from '@/utils/request'
+
+// 报警记录
+export function listWarn(query) {
+  return request({
+    url: '/business/record/list',
+    method: 'get',
+    params: query
+  })
+}
+// 报警记录详情
+export function getWarn(id) {
+  return request({
+    url: '/front/bigModel/warning/qaDetailByWarningId/' + id,
+    method: 'get'
+  })
+}
+
+// 新增信义大模型问答记录
+export function addRecord(data) {
+  return request({
+    url: '/business/record',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改信义大模型问答记录
+export function updateRecord(data) {
+  return request({
+    url: '/business/record',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除信义大模型问答记录
+export function delRecord(id) {
+  return request({
+    url: '/business/record/' + id,
+    method: 'delete'
+  })
+}

+ 172 - 195
src/assets/styles/github-markdown.scss

@@ -1,107 +1,14 @@
-html.dark {
-  .markdown-body {
-    color-scheme: dark;
-    --color-prettylights-syntax-comment: #8b949e;
-    --color-prettylights-syntax-constant: #79c0ff;
-    --color-prettylights-syntax-entity: #d2a8ff;
-    --color-prettylights-syntax-storage-modifier-import: #c9d1d9;
-    --color-prettylights-syntax-entity-tag: #7ee787;
-    --color-prettylights-syntax-keyword: #ff7b72;
-    --color-prettylights-syntax-string: #a5d6ff;
-    --color-prettylights-syntax-variable: #ffa657;
-    --color-prettylights-syntax-brackethighlighter-unmatched: #f85149;
-    --color-prettylights-syntax-invalid-illegal-text: #f0f6fc;
-    --color-prettylights-syntax-invalid-illegal-bg: #8e1519;
-    --color-prettylights-syntax-carriage-return-text: #f0f6fc;
-    --color-prettylights-syntax-carriage-return-bg: #b62324;
-    --color-prettylights-syntax-string-regexp: #7ee787;
-    --color-prettylights-syntax-markup-list: #f2cc60;
-    --color-prettylights-syntax-markup-heading: #1f6feb;
-    --color-prettylights-syntax-markup-italic: #c9d1d9;
-    --color-prettylights-syntax-markup-bold: #c9d1d9;
-    --color-prettylights-syntax-markup-deleted-text: #ffdcd7;
-    --color-prettylights-syntax-markup-deleted-bg: #67060c;
-    --color-prettylights-syntax-markup-inserted-text: #aff5b4;
-    --color-prettylights-syntax-markup-inserted-bg: #033a16;
-    --color-prettylights-syntax-markup-changed-text: #ffdfb6;
-    --color-prettylights-syntax-markup-changed-bg: #5a1e02;
-    --color-prettylights-syntax-markup-ignored-text: #c9d1d9;
-    --color-prettylights-syntax-markup-ignored-bg: #1158c7;
-    --color-prettylights-syntax-meta-diff-range: #d2a8ff;
-    --color-prettylights-syntax-brackethighlighter-angle: #8b949e;
-    --color-prettylights-syntax-sublimelinter-gutter-mark: #484f58;
-    --color-prettylights-syntax-constant-other-reference-link: #a5d6ff;
-    --color-fg-default: #c9d1d9;
-    --color-fg-muted: #8b949e;
-    --color-fg-subtle: #6e7681;
-    --color-canvas-default: #0d1117;
-    --color-canvas-subtle: #161b22;
-    --color-border-default: #30363d;
-    --color-border-muted: #21262d;
-    --color-neutral-muted: rgba(110,118,129,0.4);
-    --color-accent-fg: #58a6ff;
-    --color-accent-emphasis: #1f6feb;
-    --color-attention-subtle: rgba(187,128,9,0.15);
-    --color-danger-fg: #f85149;
-  }
-}
-
-html {
-  .markdown-body {
-    color-scheme: light;
-    --color-prettylights-syntax-comment: #6e7781;
-    --color-prettylights-syntax-constant: #0550ae;
-    --color-prettylights-syntax-entity: #8250df;
-    --color-prettylights-syntax-storage-modifier-import: #24292f;
-    --color-prettylights-syntax-entity-tag: #116329;
-    --color-prettylights-syntax-keyword: #cf222e;
-    --color-prettylights-syntax-string: #0a3069;
-    --color-prettylights-syntax-variable: #953800;
-    --color-prettylights-syntax-brackethighlighter-unmatched: #82071e;
-    --color-prettylights-syntax-invalid-illegal-text: #f6f8fa;
-    --color-prettylights-syntax-invalid-illegal-bg: #82071e;
-    --color-prettylights-syntax-carriage-return-text: #f6f8fa;
-    --color-prettylights-syntax-carriage-return-bg: #cf222e;
-    --color-prettylights-syntax-string-regexp: #116329;
-    --color-prettylights-syntax-markup-list: #3b2300;
-    --color-prettylights-syntax-markup-heading: #0550ae;
-    --color-prettylights-syntax-markup-italic: #24292f;
-    --color-prettylights-syntax-markup-bold: #24292f;
-    --color-prettylights-syntax-markup-deleted-text: #82071e;
-    --color-prettylights-syntax-markup-deleted-bg: #ffebe9;
-    --color-prettylights-syntax-markup-inserted-text: #116329;
-    --color-prettylights-syntax-markup-inserted-bg: #dafbe1;
-    --color-prettylights-syntax-markup-changed-text: #953800;
-    --color-prettylights-syntax-markup-changed-bg: #ffd8b5;
-    --color-prettylights-syntax-markup-ignored-text: #eaeef2;
-    --color-prettylights-syntax-markup-ignored-bg: #0550ae;
-    --color-prettylights-syntax-meta-diff-range: #8250df;
-    --color-prettylights-syntax-brackethighlighter-angle: #57606a;
-    --color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f;
-    --color-prettylights-syntax-constant-other-reference-link: #0a3069;
-    --color-fg-default: #24292f;
-    --color-fg-muted: #57606a;
-    --color-fg-subtle: #6e7781;
-    --color-canvas-default: #ffffff;
-    --color-canvas-subtle: #f6f8fa;
-    --color-border-default: #d0d7de;
-    --color-border-muted: hsla(210,18%,87%,1);
-    --color-neutral-muted: rgba(175,184,193,0.2);
-    --color-accent-fg: #0969da;
-    --color-accent-emphasis: #0969da;
-    --color-attention-subtle: #fff8c5;
-    --color-danger-fg: #cf222e;
-  }
-}
+
+/*light*/
 
 .markdown-body {
   -ms-text-size-adjust: 100%;
   -webkit-text-size-adjust: 100%;
   margin: 0;
-  // color: var(--color-fg-default);
-  background-color: var(--color-canvas-default);
+  color: #1F2328;
+  background-color: #ffffff;
   font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
-  // font-size: 16px;
+  font-size: 16px;
   line-height: 1.5;
   word-wrap: break-word;
 }
@@ -143,19 +50,19 @@ html {
 
 .markdown-body a {
   background-color: transparent;
-  color: var(--color-accent-fg);
+  color: #0969da;
   text-decoration: none;
 }
 
 .markdown-body abbr[title] {
   border-bottom: none;
+  -webkit-text-decoration: underline dotted;
   text-decoration: underline dotted;
 }
 
 .markdown-body b,
 .markdown-body strong {
-  font-size: 15px;
-  font-weight: bold;
+  font-weight: 600;
 }
 
 .markdown-body dfn {
@@ -164,15 +71,15 @@ html {
 
 .markdown-body h1 {
   margin: .67em 0;
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
   padding-bottom: .3em;
   font-size: 2em;
-  border-bottom: 1px solid var(--color-border-muted);
+  border-bottom: 1px solid hsla(210,18%,87%,1);
 }
 
 .markdown-body mark {
-  background-color: var(--color-attention-subtle);
-  color: var(--color-fg-default);
+  background-color: #fff8c5;
+  color: #1F2328;
 }
 
 .markdown-body small {
@@ -196,11 +103,10 @@ html {
 }
 
 .markdown-body img {
-  margin-top: 20px;
   border-style: none;
   max-width: 100%;
   box-sizing: content-box;
-  background-color: var(--color-canvas-default);
+  background-color: #ffffff;
 }
 
 .markdown-body code,
@@ -219,11 +125,11 @@ html {
   box-sizing: content-box;
   overflow: hidden;
   background: transparent;
-  border-bottom: 1px solid var(--color-border-muted);
+  border-bottom: 1px solid hsla(210,18%,87%,1);
   height: .25em;
   padding: 0;
   margin: 24px 0;
-  background-color: var(--color-border-default);
+  background-color: #d0d7de;
   border: 0;
 }
 
@@ -240,6 +146,7 @@ html {
 .markdown-body [type=reset],
 .markdown-body [type=submit] {
   -webkit-appearance: button;
+  appearance: button;
 }
 
 .markdown-body [type=checkbox],
@@ -256,6 +163,7 @@ html {
 .markdown-body [type=search]::-webkit-search-cancel-button,
 .markdown-body [type=search]::-webkit-search-decoration {
   -webkit-appearance: none;
+  appearance: none;
 }
 
 .markdown-body ::-webkit-input-placeholder {
@@ -265,6 +173,7 @@ html {
 
 .markdown-body ::-webkit-file-upload-button {
   -webkit-appearance: button;
+  appearance: button;
   font: inherit;
 }
 
@@ -273,7 +182,7 @@ html {
 }
 
 .markdown-body ::placeholder {
-  color: var(--color-fg-subtle);
+  color: #6e7781;
   opacity: 1;
 }
 
@@ -289,17 +198,14 @@ html {
 }
 
 .markdown-body table {
-  table-layout: fixed;
   width: 100%;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: normal;
-  text-align: center;
-  font-size: 12px;
-  // border-spacing: 0;
-  // border-collapse: collapse;
-  // display: block;
-  // max-width: 100%;
+  table-layout: auto; /* 固定表格布局,便于均分列宽 */
+  border-spacing: 0;
+  border-collapse: collapse;
+  // display: table;
+  // width: max-content;
+  // padding-bottom: 5px;
+  // width: 100%;
   // overflow: auto;
 }
 
@@ -320,7 +226,7 @@ html {
 .markdown-body [role=button]:focus,
 .markdown-body input[type=radio]:focus,
 .markdown-body input[type=checkbox]:focus {
-  outline: 2px solid var(--color-accent-fg);
+  outline: 2px solid #0969da;
   outline-offset: -2px;
   box-shadow: none;
 }
@@ -336,7 +242,7 @@ html {
 .markdown-body [role=button]:focus-visible,
 .markdown-body input[type=radio]:focus-visible,
 .markdown-body input[type=checkbox]:focus-visible {
-  outline: 2px solid var(--color-accent-fg);
+  outline: 2px solid #0969da;
   outline-offset: -2px;
   box-shadow: none;
 }
@@ -355,13 +261,13 @@ html {
   padding: 3px 5px;
   font: 11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
   line-height: 10px;
-  color: var(--color-fg-default);
+  color: #1F2328;
   vertical-align: middle;
-  background-color: var(--color-canvas-subtle);
-  border: solid 1px var(--color-neutral-muted);
-  border-bottom-color: var(--color-neutral-muted);
+  background-color: #f6f8fa;
+  border: solid 1px rgba(175,184,193,0.2);
+  border-bottom-color: rgba(175,184,193,0.2);
   border-radius: 6px;
-  box-shadow: inset 0 -1px 0 var(--color-neutral-muted);
+  box-shadow: inset 0 -1px 0 rgba(175,184,193,0.2);
 }
 
 .markdown-body h1,
@@ -372,36 +278,36 @@ html {
 .markdown-body h6 {
   margin-top: 24px;
   margin-bottom: 16px;
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
   line-height: 1.25;
 }
 
 .markdown-body h2 {
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
   padding-bottom: .3em;
   font-size: 1.5em;
-  border-bottom: 1px solid var(--color-border-muted);
+  border-bottom: 1px solid hsla(210,18%,87%,1);
 }
 
 .markdown-body h3 {
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
   font-size: 1.25em;
 }
 
 .markdown-body h4 {
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
   font-size: 1em;
 }
 
 .markdown-body h5 {
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
   font-size: .875em;
 }
 
 .markdown-body h6 {
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
   font-size: .85em;
-  color: var(--color-fg-muted);
+  color: #656d76;
 }
 
 .markdown-body p {
@@ -412,8 +318,8 @@ html {
 .markdown-body blockquote {
   margin: 0;
   padding: 0 1em;
-  color: var(--color-fg-muted);
-  border-left: .25em solid var(--color-border-default);
+  color: #656d76;
+  border-left: .25em solid #d0d7de;
 }
 
 .markdown-body ul,
@@ -468,6 +374,10 @@ html {
   appearance: none;
 }
 
+.markdown-body .mr-2 {
+  margin-right: 8px !important;
+}
+
 .markdown-body::before {
   display: table;
   content: "";
@@ -493,7 +403,7 @@ html {
 }
 
 .markdown-body .absent {
-  color: var(--color-danger-fg);
+  color: #d1242f;
 }
 
 .markdown-body .anchor {
@@ -512,7 +422,6 @@ html {
 .markdown-body ul,
 .markdown-body ol,
 .markdown-body dl,
-.markdown-body table,
 .markdown-body pre,
 .markdown-body details {
   margin-top: 0;
@@ -533,7 +442,7 @@ html {
 .markdown-body h4 .octicon-link,
 .markdown-body h5 .octicon-link,
 .markdown-body h6 .octicon-link {
-  color: var(--color-fg-default);
+  color: #1F2328;
   vertical-align: middle;
   visibility: hidden;
 }
@@ -602,19 +511,19 @@ html {
   list-style-type: none;
 }
 
-.markdown-body ol[type=a] {
+.markdown-body ol[type="a s"] {
   list-style-type: lower-alpha;
 }
 
-.markdown-body ol[type=A] {
+.markdown-body ol[type="A s"] {
   list-style-type: upper-alpha;
 }
 
-.markdown-body ol[type=i] {
+.markdown-body ol[type="i s"] {
   list-style-type: lower-roman;
 }
 
-.markdown-body ol[type=I] {
+.markdown-body ol[type="I s"] {
   list-style-type: upper-roman;
 }
 
@@ -651,7 +560,7 @@ html {
   margin-top: 16px;
   font-size: 1em;
   font-style: italic;
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
 }
 
 .markdown-body dl dd {
@@ -660,22 +569,27 @@ html {
 }
 
 .markdown-body table th {
-  font-weight: var(--base-text-weight-semibold, 600);
+  font-weight: 600;
 }
 
 .markdown-body table th,
 .markdown-body table td {
-  padding: 6px 6px;
-  border: 1px solid var(--color-border-default);
+  white-space: nowrap;
+  padding: 6px 13px;
+  border: 1px solid #d0d7de;
+}
+
+.markdown-body table td>:last-child {
+  margin-bottom: 0;
 }
 
 .markdown-body table tr {
-  background-color: var(--color-canvas-default);
-  border-top: 1px solid var(--color-border-muted);
+  background-color: #ffffff;
+  border-top: 1px solid hsla(210,18%,87%,1);
 }
 
 .markdown-body table tr:nth-child(2n) {
-  background-color: var(--color-canvas-subtle);
+  background-color: #f6f8fa;
 }
 
 .markdown-body table img {
@@ -708,7 +622,7 @@ html {
   padding: 7px;
   margin: 13px 0 0;
   overflow: hidden;
-  border: 1px solid var(--color-border-default);
+  border: 1px solid #d0d7de;
 }
 
 .markdown-body span.frame span img {
@@ -720,7 +634,7 @@ html {
   display: block;
   padding: 5px 0 0;
   clear: both;
-  color: var(--color-fg-default);
+  color: #1F2328;
 }
 
 .markdown-body span.align-center {
@@ -790,7 +704,7 @@ html {
   margin: 0;
   font-size: 85%;
   white-space: break-spaces;
-  background-color: var(--color-neutral-muted);
+  background-color: rgba(175,184,193,0.2);
   border-radius: 6px;
 }
 
@@ -831,11 +745,12 @@ html {
 
 .markdown-body .highlight pre,
 .markdown-body pre {
-  padding: 16px;
+  padding: 0 16px;
   overflow: auto;
   font-size: 85%;
   line-height: 1.45;
-  background-color: var(--color-canvas-subtle);
+  color: #1F2328;
+  background-color: #f6f8fa;
   border-radius: 6px;
 }
 
@@ -865,7 +780,7 @@ html {
 .markdown-body .csv-data .blob-num {
   padding: 10px 8px 9px;
   text-align: right;
-  background: var(--color-canvas-default);
+  background: #ffffff;
   border: 0;
 }
 
@@ -874,8 +789,8 @@ html {
 }
 
 .markdown-body .csv-data th {
-  font-weight: var(--base-text-weight-semibold, 600);
-  background: var(--color-canvas-subtle);
+  font-weight: 600;
+  background: #f6f8fa;
   border-top: 0;
 }
 
@@ -889,8 +804,8 @@ html {
 
 .markdown-body .footnotes {
   font-size: 12px;
-  color: var(--color-fg-muted);
-  border-top: 1px solid var(--color-border-default);
+  color: #656d76;
+  border-top: 1px solid #d0d7de;
 }
 
 .markdown-body .footnotes ol {
@@ -915,12 +830,12 @@ html {
   left: -24px;
   pointer-events: none;
   content: "";
-  border: 2px solid var(--color-accent-emphasis);
+  border: 2px solid #0969da;
   border-radius: 6px;
 }
 
 .markdown-body .footnotes li:target {
-  color: var(--color-fg-default);
+  color: #1F2328;
 }
 
 .markdown-body .footnotes .data-footnote-backref g-emoji {
@@ -928,30 +843,30 @@ html {
 }
 
 .markdown-body .pl-c {
-  color: var(--color-prettylights-syntax-comment);
+  color: #57606a;
 }
 
 .markdown-body .pl-c1,
 .markdown-body .pl-s .pl-v {
-  color: var(--color-prettylights-syntax-constant);
+  color: #0550ae;
 }
 
 .markdown-body .pl-e,
 .markdown-body .pl-en {
-  color: var(--color-prettylights-syntax-entity);
+  color: #6639ba;
 }
 
 .markdown-body .pl-smi,
 .markdown-body .pl-s .pl-s1 {
-  color: var(--color-prettylights-syntax-storage-modifier-import);
+  color: #24292f;
 }
 
 .markdown-body .pl-ent {
-  color: var(--color-prettylights-syntax-entity-tag);
+  color: #116329;
 }
 
 .markdown-body .pl-k {
-  color: var(--color-prettylights-syntax-keyword);
+  color: #cf222e;
 }
 
 .markdown-body .pl-s,
@@ -961,90 +876,90 @@ html {
 .markdown-body .pl-sr .pl-cce,
 .markdown-body .pl-sr .pl-sre,
 .markdown-body .pl-sr .pl-sra {
-  color: var(--color-prettylights-syntax-string);
+  color: #0a3069;
 }
 
 .markdown-body .pl-v,
 .markdown-body .pl-smw {
-  color: var(--color-prettylights-syntax-variable);
+  color: #953800;
 }
 
 .markdown-body .pl-bu {
-  color: var(--color-prettylights-syntax-brackethighlighter-unmatched);
+  color: #82071e;
 }
 
 .markdown-body .pl-ii {
-  color: var(--color-prettylights-syntax-invalid-illegal-text);
-  background-color: var(--color-prettylights-syntax-invalid-illegal-bg);
+  color: #f6f8fa;
+  background-color: #82071e;
 }
 
 .markdown-body .pl-c2 {
-  color: var(--color-prettylights-syntax-carriage-return-text);
-  background-color: var(--color-prettylights-syntax-carriage-return-bg);
+  color: #f6f8fa;
+  background-color: #cf222e;
 }
 
 .markdown-body .pl-sr .pl-cce {
   font-weight: bold;
-  color: var(--color-prettylights-syntax-string-regexp);
+  color: #116329;
 }
 
 .markdown-body .pl-ml {
-  color: var(--color-prettylights-syntax-markup-list);
+  color: #3b2300;
 }
 
 .markdown-body .pl-mh,
 .markdown-body .pl-mh .pl-en,
 .markdown-body .pl-ms {
   font-weight: bold;
-  color: var(--color-prettylights-syntax-markup-heading);
+  color: #0550ae;
 }
 
 .markdown-body .pl-mi {
   font-style: italic;
-  color: var(--color-prettylights-syntax-markup-italic);
+  color: #24292f;
 }
 
 .markdown-body .pl-mb {
   font-weight: bold;
-  color: var(--color-prettylights-syntax-markup-bold);
+  color: #24292f;
 }
 
 .markdown-body .pl-md {
-  color: var(--color-prettylights-syntax-markup-deleted-text);
-  background-color: var(--color-prettylights-syntax-markup-deleted-bg);
+  color: #82071e;
+  background-color: #ffebe9;
 }
 
 .markdown-body .pl-mi1 {
-  color: var(--color-prettylights-syntax-markup-inserted-text);
-  background-color: var(--color-prettylights-syntax-markup-inserted-bg);
+  color: #116329;
+  background-color: #dafbe1;
 }
 
 .markdown-body .pl-mc {
-  color: var(--color-prettylights-syntax-markup-changed-text);
-  background-color: var(--color-prettylights-syntax-markup-changed-bg);
+  color: #953800;
+  background-color: #ffd8b5;
 }
 
 .markdown-body .pl-mi2 {
-  color: var(--color-prettylights-syntax-markup-ignored-text);
-  background-color: var(--color-prettylights-syntax-markup-ignored-bg);
+  color: #eaeef2;
+  background-color: #0550ae;
 }
 
 .markdown-body .pl-mdr {
   font-weight: bold;
-  color: var(--color-prettylights-syntax-meta-diff-range);
+  color: #8250df;
 }
 
 .markdown-body .pl-ba {
-  color: var(--color-prettylights-syntax-brackethighlighter-angle);
+  color: #57606a;
 }
 
 .markdown-body .pl-sg {
-  color: var(--color-prettylights-syntax-sublimelinter-gutter-mark);
+  color: #8c959f;
 }
 
 .markdown-body .pl-corl {
   text-decoration: underline;
-  color: var(--color-prettylights-syntax-constant-other-reference-link);
+  color: #0a3069;
 }
 
 .markdown-body g-emoji {
@@ -1053,7 +968,7 @@ html {
   font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
   font-size: 1em;
   font-style: normal !important;
-  font-weight: var(--base-text-weight-normal, 400);
+  font-weight: 400;
   line-height: 1;
   vertical-align: -0.075em;
 }
@@ -1068,7 +983,7 @@ html {
 }
 
 .markdown-body .task-list-item label {
-  font-weight: var(--base-text-weight-normal, 400);
+  font-weight: 400;
 }
 
 .markdown-body .task-list-item.enabled label {
@@ -1108,3 +1023,65 @@ html {
 .markdown-body ::-webkit-calendar-picker-indicator {
   filter: invert(50%);
 }
+
+.markdown-body .markdown-alert {
+  padding: 8px 16px;
+  margin-bottom: 16px;
+  color: inherit;
+  border-left: .25em solid #d0d7de;
+}
+
+.markdown-body .markdown-alert>:first-child {
+  margin-top: 0;
+}
+
+.markdown-body .markdown-alert>:last-child {
+  margin-bottom: 0;
+}
+
+.markdown-body .markdown-alert .markdown-alert-title {
+  display: flex;
+  font-weight: 500;
+  align-items: center;
+  line-height: 1;
+}
+
+.markdown-body .markdown-alert.markdown-alert-note {
+  border-left-color: #0969da;
+}
+
+.markdown-body .markdown-alert.markdown-alert-note .markdown-alert-title {
+  color: #0969da;
+}
+
+.markdown-body .markdown-alert.markdown-alert-important {
+  border-left-color: #8250df;
+}
+
+.markdown-body .markdown-alert.markdown-alert-important .markdown-alert-title {
+  color: #8250df;
+}
+
+.markdown-body .markdown-alert.markdown-alert-warning {
+  border-left-color: #9a6700;
+}
+
+.markdown-body .markdown-alert.markdown-alert-warning .markdown-alert-title {
+  color: #9a6700;
+}
+
+.markdown-body .markdown-alert.markdown-alert-tip {
+  border-left-color: #1f883d;
+}
+
+.markdown-body .markdown-alert.markdown-alert-tip .markdown-alert-title {
+  color: #1a7f37;
+}
+
+.markdown-body .markdown-alert.markdown-alert-caution {
+  border-left-color: #cf222e;
+}
+
+.markdown-body .markdown-alert.markdown-alert-caution .markdown-alert-title {
+  color: #d1242f;
+}

+ 37 - 19
src/components/chat/ChatBaseCard.vue

@@ -1,14 +1,17 @@
 <script setup>
-
 const props = defineProps({
-  id: {
-    type: [String, Number],
-    default: ''
+  loading: {
+    type: Boolean,
+    default: false
   },
-  content: {
-    type: String,
-    default: ''
+  delayLoading: {
+    type: Boolean,
+    default: false
   },
+  loadingText: {
+    type: String,
+    default: "内容生成中..."
+  }
 })
 
 </script>
@@ -16,35 +19,50 @@ const props = defineProps({
 <template>
   <div class="answer-inner">
     <div :class="['answer-card', 'px-[20px]', 'py-[20px]']">
-      <div class="chat-answer_icon text-[20px] relative flex-shrink-0">
+
+      <div class="chat-answer_icon relative flex-shrink-0">
         <svg-icon icon-class="logo-small" class="chat-logo " size="30" />
+        <div style="color: #2454FF" class="la-ball-circus la-dark la-sm flex-shrink-0" v-show="loading">
+          <div v-for="item in 5" :key="item"></div>
+        </div>
       </div>
-      <div class="flex-1 pt-[6px] ml-[16px] text-[15px]">
+
+      <div class="flex-1 pt-[4px] ml-[16px] text-[15px]">
+
+        <slot></slot>
+
+        <template v-if="loading && delayLoading">
+          <p class="font-bold text-[#1A2029] leading-[24px]">{{ loadingText }}</p>
+        </template>
+
         <slot name="text"></slot>
+
       </div>
     </div>
+
+    <slot name="button" />
   </div>
 
 </template>
 
-<style lang="scss">
+<style lang="scss" scoped>
 .chat-logo {
   position: absolute;
   transition: all 1s;
 }
 
+.chat-answer_icon {
+  width: 34px;
+  height: 34px;
+  padding: 5px;
+  border: 1px solid #ccc;
+  border-radius: 50%;
+  font-size: 22px;
+}
+
 .answer-inner {
   margin-bottom: 20px;
 
-  .chat-answer_icon {
-    width: 34px;
-    height: 34px;
-    padding: 5px;
-    border: 1px solid #ccc;
-    border-radius: 50%;
-    font-size: 22px;
-  }
-
   .answer-card {
     display: flex;
     align-items: flex-start;

+ 15 - 20
src/components/chat/ChatText.vue

@@ -1,11 +1,12 @@
 <script setup>
-import { computed, onMounted , ref} from 'vue';
+import { computed } from 'vue';
 import MarkdownIt from 'markdown-it';
 import hljs from 'highlight.js';
 import mila from 'markdown-it-link-attributes';
-import markdownItMath from 'markdown-it-math';
-import mdKatex from '@iktakahiro/markdown-it-katex';
-
+// import markdownItMath from 'markdown-it-math';
+// import mdKatex from '@iktakahiro/markdown-it-katex';
+import markdownItTexmath from 'markdown-it-texmath';
+import katex from 'katex'
 const props = defineProps({
   content: {
     type: String,
@@ -23,7 +24,7 @@ const mdi = new MarkdownIt({
   linkify: true,
   breaks: true,
   typographer: true,
-  highlight(code, language) {
+  highlight (code, language) {
     const validLang = !!(language && hljs.getLanguage(language))
     if (validLang) {
       const lang = language ?? ''
@@ -35,18 +36,12 @@ const mdi = new MarkdownIt({
 
 mdi.use(mila, { attrs: { target: '_blank', rel: 'noopener' } });
 
-mdi.use(markdownItMath, {
-  inlineOpen: '\\(',
-  inlineClose: '\\)',
-  blockOpen: '\\[',
-  blockClose: '\\]'
-});
-
-mdi.use(mdKatex, {
-  blockClass: 'katexmath-block rounded-md p-[10px]',
-  errorColor: ' #cc0000',
-})
 
+mdi.use(markdownItTexmath, {
+  engine: katex,
+  delimiters: ['dollars', 'brackets', 'doxygen', 'gitlab', 'julia', 'kramdown', 'beg_end'],
+  katexOptions: { macros: { "\\RR": "\\mathbb{R}" } }
+});
 mdi.renderer.rules.table_open = function (tokens, idx, options, env, self) { return '<div class="custom-table-wrapper"><table>'; };
 mdi.renderer.rules.table_close = function () { return '</table></div>'; };
 
@@ -73,21 +68,21 @@ const text = computed(() => {
 .markdown-body {
   .custom-table-wrapper {
     width: 710px;
-    padding: 10px;
+    padding: 10px 10px 4px 10px;
     background: #eff8fc;
     margin-bottom: 16px;
     overflow-x: scroll;
 
     &::-webkit-scrollbar {
-      height: 4px;
+      height: 6px;
     }
 
     &::-webkit-scrollbar-thumb {
-      background: #ebf0f9;
+      background: #bfbfbf;
     }
 
     &::-webkit-scrollbar-track {
-      background: #f7f8fc;
+      background: #eff8fc;
     }
   }
 

+ 73 - 0
src/utils/format.js

@@ -0,0 +1,73 @@
+// import { ORDER_OPTION_ENUM } from "./enum";
+
+
+export const formatToData = (dataSource, warnKey) => {
+  const reuslt = {
+    title: dataSource?.title,
+    list: []
+  }
+  delete dataSource.title;
+  reuslt.list = Object.entries(dataSource).map(([key, value]) => {
+    if ( Number.isFinite(value) ) value = Number(value.toFixed(2));
+    if ( key.includes("值") ) value = value? value + 'mg/L' : '';
+    return { label: key, value, isWarning: warnKey === key };
+  });
+  return reuslt;
+}
+
+export const format = {
+  textSorting(dataSource, rule) {
+    const title = dataSource.title || dataSource['进水SS超标报警'];
+
+    const list = rule.map(item => {
+      Object.keys(dataSource).forEach(key => {
+        if (item.realKey === key ) {
+          if ( dataSource[key] !== null ) {
+            item.value = (isNaN(dataSource[key]) ? dataSource[key]  : truncateDecimals(dataSource[key])) + item.value
+          } else{
+            item.value = ''
+          }
+          
+        }
+      })
+      return item;
+    }).filter(({ value }) => value)
+    return { title, list };
+  }
+}
+
+export const truncateDecimals = num => {
+  return Number((Math.floor(num * 100) / 100).toFixed(2));
+}
+
+export const replaceArray = (array, startIndex, length, replacementValue) => {
+  array.splice(startIndex, length, ...Array(length).fill(replacementValue));
+  return array;
+}
+
+export const formatEchart = (data) => {
+  const keys = Array.from(new Set(data.flatMap(item => Object.keys(item).filter(key => key !== 'time'))));
+
+  const xAxisData = data.map(item => item.time);
+  const yAxisData = keys.map(key => ({
+    title: ORDER_OPTION_ENUM[key],
+    key,
+    list: data.map(item => !item[key] ? 0 : Number(item[key].toFixed(2)))
+  }))
+
+  return [xAxisData, yAxisData];
+}
+
+export const colorToRgba = (color, alpha) => {
+  const r = parseInt(color.slice(1, 3), 16);
+  const g = parseInt(color.slice(3, 5), 16);
+  const b = parseInt(color.slice(5, 7), 16);
+
+  return `rgba(${r}, ${g}, ${b}, ${alpha})`
+}
+
+
+// 判断是不是数字
+export const isNumberComprehensive = (value) => {
+  return isFinite(value) && !isNaN(parseFloat(value));
+}

+ 55 - 59
src/views/business/record/index.vue

@@ -1,13 +1,14 @@
 <template>
+  <!-- 专家问答 -->
   <div class="page-container">
     <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
       class="search-form_container">
       <el-form-item label="问题内容" prop="unknown">
-        <el-input v-model="queryParams.sessionId" placeholder="请输入会话ID" clearable @keyup.enter.native="handleQuery" />
+        <el-input v-model="queryParams.question" placeholder="请输入问题内容" clearable @keyup.enter.native="handleQuery" />
       </el-form-item>
-      <el-form-item label="类型" prop="unknown">
+      <!-- <el-form-item label="类型" prop="unknown">
         <el-input v-model="queryParams.module" placeholder="请输入隶属哪个模块" clearable @keyup.enter.native="handleQuery" />
-      </el-form-item>
+      </el-form-item> -->
       <el-form-item>
         <el-button type="primary" icon="search" size="small" @click="handleQuery">搜索</el-button>
         <el-button icon="refresh" size="small" @click="resetQuery">重置</el-button>
@@ -16,13 +17,13 @@
 
     <el-card shadow="never" body-class="card-table_container">
       <el-row :gutter="10" class="mb8">
-        <el-col :span="1.5">
+        <!-- <el-col :span="1.5">
           <el-button type="primary" plain icon="plus" size="small" @click="handleAdd">新增</el-button>
         </el-col>
         <el-col :span="1.5">
           <el-button type="success" plain icon="edit" size="small" :disabled="single"
             @click="handleUpdate">修改</el-button>
-        </el-col>
+        </el-col> -->
         <el-col :span="1.5">
           <el-button type="danger" plain icon="delete" size="small" :disabled="multiple"
             @click="handleDelete">删除</el-button>
@@ -41,18 +42,24 @@
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="用户名" align="center" prop="id" />
-        <el-table-column label="手机号" align="center" prop="sessionId" />
+        <el-table-column label="用户名" align="center" prop="userId" />
+        <el-table-column label="手机号" align="center" prop="phone" />
         <!-- <el-table-column label="回答" align="center" prop="showVal" /> -->
-        <el-table-column label="问题内容" align="center" prop="question" />
-        <el-table-column label="点赞" align="center" prop="isSatisfied" />
-        <!-- <el-table-column label="大模型回答" align="center" prop="answer" /> -->
-        <el-table-column label="发起时间" align="center" prop="warningId" />
-        <!-- <el-table-column label="问答次数" align="center" prop="counts" />
-        <el-table-column label="是否使用搜索增强" align="center" prop="isStrong" />
-        <el-table-column label="是否中断问答" align="center" prop="isShutdown" />
-        <el-table-column label="乐观锁" align="center" prop="revision" />
-        <el-table-column label="备注" align="center" prop="remark" /> -->
+        <el-table-column label="问题内容" align="center" prop="question" width="500px">
+          <template #default="scope">
+            <el-popover effect="light" trigger="hover" placement="top" width="600">
+              <template #default>
+                <div style="font-weight: bold;">问题:</div>
+                <div>{{ scope.row.question }}</div>
+              </template>
+              <template #reference>
+                <p class="singe-line" style="text-align: left;">{{ scope.row.question }}</p>
+              </template>
+            </el-popover>
+          </template>
+        </el-table-column>
+        <el-table-column label="点赞" align="center" prop="satisfied" />
+        <el-table-column label="发起时间" align="center" prop="createTime" />
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
           <template #default="scope">
             <el-button type="primary" text size="small" icon="view" @click="handleRecordDetails(scope)">记录</el-button> 
@@ -61,44 +68,28 @@
           </template>
         </el-table-column>
       </el-table>
-
-      <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
-        @pagination="getList" />
+      
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
     </el-card>
-
     
     <el-dialog title="问答记录" v-model="recordVisible" width="900px" append-to-body class="chat-dialog_container">
-      
       <el-scrollbar height="600px">
-        <div class="">
-      <ChatAsk content="123123123"></ChatAsk>
-      <ChatAnswer content="作为污水处理厂工艺人员,一个全面的工作计划应该包括以下几个关键方面:
-
-1. 污水处理过程监控与维护:
- - **日常巡检**:定期检查各单元设备(如格栅、沉淀池、生物反应器、二次沉淀池、消毒设施等)的运行状态,确保其正常运转。
- - **数据记录**:收集并分析水质、水量、能耗等关键指标数据,以便于发现问题和优化操作。
- - **设备保养与维修**:根据检查结果安排设备维护和预防性维修,确保设备处于良好状态。
-
-2. 生产运行与控制:
- - **工艺参数调整**:根据进水水质变化,及时调整污泥龄、溶解氧、pH值等工艺参数,保证出水质量达标。
- - **生产调度**:合理安排污水处理流程,避免高峰期的压力,确保污水处理效率。
- - **应急预案**:制定并定期演练应急处理方案,应对突发情况如设备故障或大量异常废水。
-
-3. 环保与合规管理:
- - **环保法规遵守**:熟悉并执行相关的环保法规,如《水污染防治法》、《城镇污水处理厂污染物排放标准》等。
- - **环境监测**:定期进行周边环境水质监测,评估污水处理效果对环境的影响。
- - **报告与申报**:准备并提交定期的运营报告、排放许可证更新申请及相关环保报告。
-
-4. 培训与发展:
- - **员工培训**:定期对员工进行专业知识和技术技能培训,提高团队整体能力。
- - **新技术研究**:关注行业动态,学习和引入新的污水处理技术和管理方法,提升工厂的技术水平。
-
-5. 安全与健康管理:
- - **安全规程**:严格执行安全操作规程,定期进行安全培训和演练。
- - **职业健康**:关注员工的劳动保护,确保工作环境符合职业健康要求。
-
-以上是一个基本的工作计划框架,具体内容会根据实际的厂况、政策要求以及季节变化等因素进行调整。"></ChatAnswer>
-      </div>
+        <template v-for="item in chatDataSource" :key="item.id">
+          <ChatAsk :content="item.question" :sessionId="item.sessionId"></ChatAsk>
+          <ChatAnswer
+            :id="item.id"
+            :content="item.answer"
+            :loading="item.loading"
+            :delay-loading="item.delayLoading"
+            :isSatisfied="item.isSatisfied"
+          ></ChatAnswer>
+        </template>
     </el-scrollbar>
   </el-dialog>
 
@@ -211,7 +202,8 @@ export default {
         { value: 2, label: '生化报警', },
         { value: 3, label: '预测预警',}
       ],
-      recordVisible: false
+      recordVisible: false,
+      chatDataSource: []
     };
   },
   created() {
@@ -219,23 +211,27 @@ export default {
   },
   methods: {
     // 查看详情
-    handleRecordDetails(scope) {
+    handleRecordDetails({ row }) {
+      this.chatDataSource = [];
+      this.chatDataSource.push(row);
       this.recordVisible = true;
-      // getQaDetail(scope.row.id).then(res => {
-      //   console.log(res);
-      // })
     },
     /** 查询信义大模型问答记录列表 */
     getList() {
       this.loading = true;
-      const enumType1 = {
+      const enumType = {
         '0': {color: '', label: '专家问答'},
         '1': {color: 'success', label: '水质报警'},
         '2': {color: 'warning', label: '生化报警'},
         '3': {color: 'danger', label: '预测预警'}
       }
-      listRecord(this.queryParams).then(response => {
-        this.recordList = response.rows.map(item => ({ ...item, ...enumType1[item.type]  }));
+      const enumLike = {
+        0 : "否",
+        1 : "是",
+        2 : "否"
+      }
+      listRecord({...this.queryParams, module: 0}).then(response => {
+        this.recordList = response.rows.map(item => ({ ...item, ...enumType[item.type], satisfied: enumLike[item.isSatisfied]}));
         this.total = response.total;
         this.loading = false;
       });
@@ -326,7 +322,7 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
-      this.$modal.confirm('是否确认删除信义大模型问答记录编号为"' + ids + '"的数据项?').then(function () {
+      this.$modal.confirm('是否确认删除数据项?').then(function () {
         return delRecord(ids);
       }).then(() => {
         this.getList();

+ 576 - 0
src/views/business/water/index.vue

@@ -0,0 +1,576 @@
+<template>
+  <!-- 水质报警 -->
+  <div class="page-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
+      class="search-form_container">
+      <el-form-item label="报警内容" prop="unknown">
+        <el-input v-model="queryParams.question" placeholder="请输入问题内容" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="报警状态" prop="warningStatus">
+        <el-select v-model="queryParams.warningStatus">
+          <el-option value="" label="全部"></el-option>
+          <el-option :key="item.label" :value="item.val" :label="item.label" v-for="item in warningStatus"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="search" size="small" @click="handleQuery">搜索</el-button>
+        <el-button icon="refresh" size="small" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-card shadow="never" body-class="card-table_container">
+      <el-row :gutter="10" class="mb8">
+        <!-- <el-col :span="1.5">
+          <el-button type="primary" plain icon="plus" size="small" @click="handleAdd">新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="success" plain icon="edit" size="small" :disabled="single"
+            @click="handleUpdate">修改</el-button>
+        </el-col> -->
+        <el-col :span="1.5">
+          <el-button type="danger" plain icon="delete" size="small" :disabled="multiple"
+            @click="handleDelete">删除</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="warning" plain icon="download" size="small" @click="handleExport">导出</el-button>
+        </el-col>
+        <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+      </el-row>
+      <el-table v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="类型" align="center" prop="category" />
+        <el-table-column label="报警值" align="center" prop="warningVal">
+          <template #default="scope">
+            <span style="color: red;">{{ Number(scope.row.warningVal.toFixed(2)) }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="标准值" align="center" prop="designVal">
+          <template #default="scope">
+            <span>{{ scope.row.designVal }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="报警级别" align="center" prop="level" />
+        <el-table-column label="报警次数" align="center" prop="counts" />
+        <el-table-column label="报警发起时间" align="center" prop="createTime" />
+        <el-table-column label="报警关闭时间" align="center" prop="offTime" />
+        <el-table-column label="状态" align="center" prop="status" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
+          <template #default="scope">
+            <el-button type="primary" text size="small" icon="view" @click="handleRecordDetails(scope)">查看记录</el-button>
+            <!-- <el-button size="small" type="text" icon="edit" @click="handleUpdate(scope.row)">修改</el-button> -->
+            <!-- <el-button size="small" type="primary" text icon="delete" @click="handleDelete(scope.row)">删除</el-button> -->
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <el-dialog title="水质报警记录" v-model="recordVisible" width="900px" append-to-body class="chat-dialog_container">
+      <el-scrollbar height="800px">
+        <ChatBaseCard>
+          <div class="waring-answer-wrapper">
+            <dl class="message-inner warning-info_medium ">
+              <dt class="mb-[2px] font-bold text-[#1A2029]">{{ textDataSources?.title }}</dt>
+              <dd v-for="item, index in textDataSources?.list" :key="index"><span
+                  :class="{ 'text-[#F44C49]': item.isWarning }">{{ item.label }}: {{ item.value }}</span></dd>
+            </dl>
+            <div class="table-inner">
+              <div class="warning-table">
+                <div class="title">
+                  <span>当前进水数据:</span>
+                </div>
+                <div class="main">
+                  <el-table :data="jsTableData" style="width: 100%">
+                    <el-table-column prop="流量" label="流量(m³/h)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
+      Number(scope.row['流量'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="COD(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['COD'].exceed ? 'red' : '' }">{{
+      Number(scope.row['COD'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TN(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TN'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TN'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="NH3-N(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['NH3-N'].exceed ? 'red' : '' }">{{
+      Number(scope.row['NH3-N'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TP(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TP'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TP'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="SS(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['SS'].exceed ? 'red' : '' }">{{
+      Number(scope.row['SS'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </div>
+              </div>
+              <div class="warning-table">
+                <div class="title">
+                  <span>当前出水数据:</span>
+                </div>
+                <div class="main">
+                  <el-table :data="csTableData" style="width: 100%">
+                    <el-table-column prop="流量" label="流量(m³/h)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
+      Number(scope.row['流量'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="COD(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['COD'].exceed ? 'red' : '' }">{{
+      Number(scope.row['COD'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TN(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TN'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TN'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="NH3-N(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['NH3-N'].exceed ? 'red' : '' }">{{
+      Number(scope.row['NH3-N'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TP(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TP'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TP'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="SS(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['SS'].exceed ? 'red' : '' }">{{
+      Number(scope.row['SS'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </div>
+              </div>
+            </div>
+          </div>
+        </ChatBaseCard>
+
+        <section v-for="item, index in answerResult" :key="index">
+          <template v-if="item.biz === 'DECISION_REPORT'">
+            <ChatAnswer :loading="item.loading" :delay-loading="item.delayLoading" :toggleVisibleIcons="false" :content="item.answer"></ChatAnswer>
+          </template>
+
+          <template v-if="item.biz === 'DECISION_ALERT'">
+            <ChatBaseCard :loading="item.loading" :delay-loading="item.delayLoading" :toggleVisibleIcons="false">
+              <p class="mb-[15px] font-bold text-[#1A2029]">需要确定以下问题,完成决策方案:</p>
+              <ul class="radio-wrapper space-y-[14px]">
+                <li class="flex items-center" v-for="val, i in item.list" :key="i">
+                  <p class="mr-[14px]">{{ val.mainContent }}</p>
+                  <p class="radio-btn-group space-x-[14px]">
+                    <span v-for="option, index in val.options"
+                      :class="['radio-btn', { active: val.isActive === index }]"
+                      @click="handlerAlertOptions(item, val, index)">{{ option }}</span>
+                  </p>
+                </li>
+              </ul>
+            </ChatBaseCard>
+          </template>
+
+          <template v-if="item.biz === 'DECISION_SIMULATE'">
+            <button class="
+            px-[30px] py-[10px] mb-[20px]
+            rounded-[8px] 
+            bg-white text-[13px] 
+            text-[#5E5E5E] hover:text-[#2454FF]" :disabled="item.isDisable" @click="handleModelVisible">
+              水质预测推演
+            </button>
+          </template>
+
+          <template v-if="item.biz === 'DECISION_TABLE'">
+            <ChatAnswer :loading="item.loading" :delay-loading="item.delayLoading" :toggleVisibleIcons="false">
+              <div class="markdown-body text-[15px] break-all">
+                <strong class="block mb-[16px]">推荐指标调整:</strong>
+                <div class="custom-table-wrapper">
+                  <table>
+                    <thead>
+                      <tr>
+                        <th v-for="text in item.table.header" :key="text">{{ text }}</th>
+                      </tr>
+                    </thead>
+                    <tbody class="text-center">
+                      <tr>
+                        <td v-for="text in item.table.body" :key="text">{{ text }}</td>
+                      </tr>
+                    </tbody>
+                  </table>
+                </div>
+                <strong class="block mb-[16px]">预测推演结果:</strong>
+                <span>以上指标达成后,预计三小时内{{ flowParams.category }}可以达到:{{ item.content }}</span>
+              </div>
+            </ChatAnswer>
+            <button class="
+            px-[30px] py-[10px] mb-[20px]
+            rounded-[8px] 
+            bg-white text-[13px] 
+            text-[#5E5E5E] hover:text-[#2454FF]" :disabled="item.isDisable" @click="handleModelVisible">
+              水质预测推演
+            </button>
+          </template>
+        </section>
+      </el-scrollbar>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWarn, getWarn } from "@/api/business/water";
+import { formatToData } from "@/utils/format";
+import { listRecord, getRecord, delRecord, addRecord, updateRecord } from "@/api/business/record";
+import { ChatAsk, ChatAnswer, ChatBaseCard } from "@/components/chat"
+export default {
+  name: "Record",
+  components: { ChatAsk, ChatAnswer, ChatBaseCard },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 信义大模型问答记录表格数据
+      recordList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        sessionId: null,
+        type: null,
+        module: null,
+        userId: null,
+        showVal: null,
+        question: null,
+        answer: null,
+        warningId: null,
+        counts: null,
+        isStrong: null,
+        isSatisfied: null,
+        isShutdown: null,
+        revision: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      warningStatus: [
+        {
+          val: 0,
+          label: '报警中'
+        },
+        {
+          val: 1,
+          label: '历史报警'
+        },
+      ],
+      recordVisible: false,
+      textDataSources: [],
+      jsTableData: [],
+      csTableData: [],
+      answerResult: []
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    // 查看详情
+    handleRecordDetails({ row }) {
+      getWarn(row.id).then(({ data }) => {
+        const showVal = JSON.parse(data.showVal);
+        const { basic, jsData, csData } = showVal;
+        this.answerResult = [];
+        try {
+          const answer = JSON.parse(data.answer);
+          const reportList = [];
+          const alertList = [];
+          let simulateObj = null;
+
+          answer.map(item => {
+            const answerObjItem = JSON.parse(item);
+            console.log( answerObjItem );
+            switch (answerObjItem.biz) {
+              case "DECISION_REPORT":
+                reportList.push(answerObjItem.message);
+                break
+              case "DECISION_ALERT":
+                alertList.push(answerObjItem);
+                break
+              case "DECISION_SIMULATE":
+                if (row.status !== 0) return;
+                const { off, on, pred } = JSON.parse(answerObjItem.message);
+                simulateObj = {
+                  biz: 'DECISION_SIMULATE',
+                  off,
+                  on,
+                  pred,
+                  isDisable: false
+                }
+                modalData.value = simulateObj;
+            }
+          })
+
+          if (reportList.length) {
+            this.answerResult.push({
+              biz: 'DECISION_REPORT',
+              answer: reportList.join(""),
+              loading: false,
+              delayLoading: false
+            })
+          }
+
+          if (alertList.length) {
+            const [parseAnswer] = alertList.map(item => {
+              item.message = Object.keys(item.message).map(key => ({ ...item.message[key], isActive: null }));
+              return item;
+            })
+            this.answerResult.push({
+              biz: 'DECISION_ALERT',
+              loading: false,
+              delayLoading: false,
+              isAllSelect: false,
+              list: parseAnswer?.message
+            })
+          }
+
+          if (simulateObj) {
+            this.answerResult.push(simulateObj);
+          }
+
+        } catch (error) {
+          this.answerResult.push({
+            biz: 'DECISION_REPORT',
+            answer: data.answer,
+            loading: false,
+            delayLoading: false
+          })
+          console.log("error", error);
+        }
+
+        basic.title = row.title;
+        this.jsTableData = [jsData]
+        this.csTableData = [csData];
+        this.textDataSources = formatToData(basic, '报警值');
+      })
+      this.chatDataSource = [];
+      this.chatDataSource.push(row);
+      this.recordVisible = true;
+    },
+    /** 查询信义大模型问答记录列表 */
+    getList() {
+      this.loading = true;
+      const enumType = {
+        '0': { color: 'tips_warning', label: '报警中' },
+        '1': { color: 'tips_success', label: '用户关闭' },
+        '2': { color: 'tips_close', label: '系统关闭' },
+        '3': { color: 'tips_warning', label: '应急处理中' }
+      }
+      listWarn({ ...this.queryParams, type: 0 }).then(response => {
+        this.recordList = response.rows.map(item => ({
+          ...item,
+          status: enumType[item.status].label
+        }));
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        sessionId: null,
+        type: null,
+        module: null,
+        userId: null,
+        showVal: null,
+        question: null,
+        answer: null,
+        warningId: null,
+        counts: null,
+        isStrong: null,
+        isSatisfied: null,
+        isShutdown: null,
+        delFlag: null,
+        revision: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加信义大模型问答记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRecord(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改信义大模型问答记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateRecord(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRecord(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除该数据项?').then(function () {
+        return delRecord(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('business/record/export', {
+        ...this.queryParams
+      }, `record_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.waring-answer-wrapper {
+
+  .message-inner {
+    width: 194px;
+    flex-shrink: 0;
+
+    span {
+      white-space: nowrap;
+    }
+  }
+
+  .table-inner {
+    .warning-table {
+      width: 100%;
+      padding-top: 30px;
+
+      .title {
+        margin-bottom: 8px;
+        line-height: 16px;
+        font-size: 12px;
+        font-weight: bold;
+        color: #1A2029;
+      }
+    }
+  }
+}
+
+.radio-wrapper {
+
+.radio-btn-group {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 14px;
+  text-align: center;
+  color: #5E5E5E;
+
+  .radio-btn {
+    width: 62px;
+    height: 28px;
+    border-radius: 4px;
+    background: #F4F6F8;
+    font-size: 14px;
+    line-height: 26px;
+    cursor: pointer;
+
+    &.active,
+    &:hover {
+      color: #2454FF;
+      background: #E2F1FF;
+    }
+
+    &.active {
+      background: #E2F1FF url('@/assets/images/chat/bg-raido-check.png') right bottom no-repeat;
+    }
+  }
+}
+
+}
+</style>