diff --git a/packages/admin-client/package.json b/packages/admin-client/package.json
index 9743343..26b61a5 100644
--- a/packages/admin-client/package.json
+++ b/packages/admin-client/package.json
@@ -11,16 +11,18 @@
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
+ "@ant-design/icons": "^5.2.6",
"@tanstack/react-query": "^5.17.0",
"antd": "^5.12.8",
- "@ant-design/icons": "^5.2.6",
"axios": "^1.6.5",
"dayjs": "^1.11.10",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-markdown": "^10.1.0",
"react-router-dom": "^6.21.1",
- "zustand": "^4.4.7",
- "recharts": "^2.10.4"
+ "recharts": "^2.10.4",
+ "remark-gfm": "^4.0.1",
+ "zustand": "^4.4.7"
},
"devDependencies": {
"@types/react": "^18.2.47",
diff --git a/packages/admin-client/src/features/supervisor/presentation/pages/SupervisorPage.tsx b/packages/admin-client/src/features/supervisor/presentation/pages/SupervisorPage.tsx
index 130f9c7..85b95f9 100644
--- a/packages/admin-client/src/features/supervisor/presentation/pages/SupervisorPage.tsx
+++ b/packages/admin-client/src/features/supervisor/presentation/pages/SupervisorPage.tsx
@@ -9,6 +9,8 @@ import {
DollarOutlined,
ClearOutlined,
} from '@ant-design/icons';
+import ReactMarkdown from 'react-markdown';
+import remarkGfm from 'remark-gfm';
import { useSupervisorChat } from '../../application/useSupervisor';
import type { ChatMessage } from '../../infrastructure/supervisor.api';
@@ -137,7 +139,15 @@ export function SupervisorPage() {
>
{msg.role === 'user' ? '管理员' : '系统总监'}
-
{msg.content}
+ {msg.role === 'assistant' ? (
+
+
+ {msg.content}
+
+
+ ) : (
+ {msg.content}
+ )}
))}
diff --git a/packages/admin-client/src/index.css b/packages/admin-client/src/index.css
index 9f728d4..c403ffe 100644
--- a/packages/admin-client/src/index.css
+++ b/packages/admin-client/src/index.css
@@ -11,3 +11,84 @@ body {
#root {
min-height: 100vh;
}
+
+/* Supervisor Markdown Styles */
+.supervisor-markdown {
+ line-height: 1.7;
+}
+
+.supervisor-markdown h2 {
+ font-size: 16px;
+ font-weight: 600;
+ margin: 16px 0 8px;
+ padding-bottom: 4px;
+ border-bottom: 1px solid #e8e8e8;
+}
+
+.supervisor-markdown h3 {
+ font-size: 14px;
+ font-weight: 600;
+ margin: 12px 0 6px;
+}
+
+.supervisor-markdown p {
+ margin: 6px 0;
+}
+
+.supervisor-markdown ul,
+.supervisor-markdown ol {
+ margin: 4px 0;
+ padding-left: 20px;
+}
+
+.supervisor-markdown li {
+ margin: 2px 0;
+}
+
+.supervisor-markdown table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 8px 0;
+ font-size: 13px;
+}
+
+.supervisor-markdown th {
+ background: #fafafa;
+ font-weight: 600;
+ text-align: left;
+ padding: 8px 12px;
+ border: 1px solid #e8e8e8;
+}
+
+.supervisor-markdown td {
+ padding: 6px 12px;
+ border: 1px solid #e8e8e8;
+}
+
+.supervisor-markdown tr:hover td {
+ background: #fafafa;
+}
+
+.supervisor-markdown code {
+ background: #f5f5f5;
+ padding: 1px 4px;
+ border-radius: 3px;
+ font-size: 13px;
+}
+
+.supervisor-markdown hr {
+ border: none;
+ border-top: 1px solid #e8e8e8;
+ margin: 12px 0;
+}
+
+.supervisor-markdown strong {
+ font-weight: 600;
+}
+
+.supervisor-markdown blockquote {
+ border-left: 3px solid #d9d9d9;
+ margin: 8px 0;
+ padding: 4px 12px;
+ color: #666;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3ea8916..85e84dd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -47,12 +47,18 @@ importers:
react-dom:
specifier: ^18.2.0
version: 18.3.1(react@18.3.1)
+ react-markdown:
+ specifier: ^10.1.0
+ version: 10.1.0(@types/react@18.3.27)(react@18.3.1)
react-router-dom:
specifier: ^6.21.1
version: 6.30.3(react-dom@18.3.1)(react@18.3.1)
recharts:
specifier: ^2.10.4
version: 2.15.4(react-dom@18.3.1)(react@18.3.1)
+ remark-gfm:
+ specifier: ^4.0.1
+ version: 4.0.1
zustand:
specifier: ^4.4.7
version: 4.5.7(@types/react@18.3.27)(react@18.3.1)
@@ -5624,6 +5630,11 @@ packages:
engines: {node: '>=10'}
dev: true
+ /escape-string-regexp@5.0.0:
+ resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+ engines: {node: '>=12'}
+ dev: false
+
/eslint-plugin-react-hooks@4.6.2(eslint@8.57.1):
resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==}
engines: {node: '>=10'}
@@ -7672,10 +7683,23 @@ packages:
engines: {node: '>=4'}
dev: false
+ /markdown-table@3.0.4:
+ resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
+ dev: false
+
/math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ /mdast-util-find-and-replace@3.0.2:
+ resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ escape-string-regexp: 5.0.0
+ unist-util-is: 6.0.1
+ unist-util-visit-parents: 6.0.2
+ dev: false
+
/mdast-util-from-markdown@2.0.2:
resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==}
dependencies:
@@ -7695,6 +7719,75 @@ packages:
- supports-color
dev: false
+ /mdast-util-gfm-autolink-literal@2.0.1:
+ resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ ccount: 2.0.1
+ devlop: 1.1.0
+ mdast-util-find-and-replace: 3.0.2
+ micromark-util-character: 2.1.1
+ dev: false
+
+ /mdast-util-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ micromark-util-normalize-identifier: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /mdast-util-gfm-strikethrough@2.0.0:
+ resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /mdast-util-gfm-table@2.0.0:
+ resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ markdown-table: 3.0.4
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /mdast-util-gfm-task-list-item@2.0.0:
+ resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /mdast-util-gfm@3.1.0:
+ resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==}
+ dependencies:
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-gfm-autolink-literal: 2.0.1
+ mdast-util-gfm-footnote: 2.1.0
+ mdast-util-gfm-strikethrough: 2.0.0
+ mdast-util-gfm-table: 2.0.0
+ mdast-util-gfm-task-list-item: 2.0.0
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/mdast-util-mdx-expression@2.0.1:
resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
dependencies:
@@ -7839,6 +7932,78 @@ packages:
micromark-util-types: 2.0.2
dev: false
+ /micromark-extension-gfm-autolink-literal@2.1.0:
+ resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==}
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ dev: false
+
+ /micromark-extension-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==}
+ dependencies:
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ dev: false
+
+ /micromark-extension-gfm-strikethrough@2.1.0:
+ resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==}
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ dev: false
+
+ /micromark-extension-gfm-table@2.1.1:
+ resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==}
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ dev: false
+
+ /micromark-extension-gfm-tagfilter@2.0.0:
+ resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
+ dependencies:
+ micromark-util-types: 2.0.2
+ dev: false
+
+ /micromark-extension-gfm-task-list-item@2.1.0:
+ resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==}
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ dev: false
+
+ /micromark-extension-gfm@3.0.0:
+ resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
+ dependencies:
+ micromark-extension-gfm-autolink-literal: 2.1.0
+ micromark-extension-gfm-footnote: 2.1.0
+ micromark-extension-gfm-strikethrough: 2.1.0
+ micromark-extension-gfm-table: 2.1.1
+ micromark-extension-gfm-tagfilter: 2.0.0
+ micromark-extension-gfm-task-list-item: 2.1.0
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-types: 2.0.2
+ dev: false
+
/micromark-factory-destination@2.0.1:
resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
dependencies:
@@ -9629,6 +9794,19 @@ packages:
/reflect-metadata@0.2.2:
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
+ /remark-gfm@4.0.1:
+ resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-gfm: 3.1.0
+ micromark-extension-gfm: 3.0.0
+ remark-parse: 11.0.0
+ remark-stringify: 11.0.0
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/remark-parse@11.0.0:
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
dependencies:
@@ -9650,6 +9828,14 @@ packages:
vfile: 6.0.3
dev: false
+ /remark-stringify@11.0.0:
+ resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-to-markdown: 2.1.2
+ unified: 11.0.5
+ dev: false
+
/repeat-string@1.6.1:
resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
engines: {node: '>=0.10'}