mirror of
https://github.com/chaitin/MonkeyCode.git
synced 2026-02-04 07:43:28 +08:00
Merge pull request #61 from guanweiwang/develop
pref: 优化 code 展示,修复 版本问题
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"globals": "^16.0.0",
|
||||
"shiki": "^3.7.0",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.30.1",
|
||||
"vite": "^6.3.5"
|
||||
|
||||
121
ui/pnpm-lock.yaml
generated
121
ui/pnpm-lock.yaml
generated
@@ -120,6 +120,9 @@ importers:
|
||||
globals:
|
||||
specifier: ^16.0.0
|
||||
version: 16.2.0
|
||||
shiki:
|
||||
specifier: ^3.7.0
|
||||
version: 3.7.0
|
||||
typescript:
|
||||
specifier: ~5.8.3
|
||||
version: 5.8.3
|
||||
@@ -825,6 +828,27 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@shikijs/core@3.7.0':
|
||||
resolution: {integrity: sha512-yilc0S9HvTPyahHpcum8eonYrQtmGTU0lbtwxhA6jHv4Bm1cAdlPFRCJX4AHebkCm75aKTjjRAW+DezqD1b/cg==}
|
||||
|
||||
'@shikijs/engine-javascript@3.7.0':
|
||||
resolution: {integrity: sha512-0t17s03Cbv+ZcUvv+y33GtX75WBLQELgNdVghnsdhTgU3hVcWcMsoP6Lb0nDTl95ZJfbP1mVMO0p3byVh3uuzA==}
|
||||
|
||||
'@shikijs/engine-oniguruma@3.7.0':
|
||||
resolution: {integrity: sha512-5BxcD6LjVWsGu4xyaBC5bu8LdNgPCVBnAkWTtOCs/CZxcB22L8rcoWfv7Hh/3WooVjBZmFtyxhgvkQFedPGnFw==}
|
||||
|
||||
'@shikijs/langs@3.7.0':
|
||||
resolution: {integrity: sha512-1zYtdfXLr9xDKLTGy5kb7O0zDQsxXiIsw1iIBcNOO8Yi5/Y1qDbJ+0VsFoqTlzdmneO8Ij35g7QKF8kcLyznCQ==}
|
||||
|
||||
'@shikijs/themes@3.7.0':
|
||||
resolution: {integrity: sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==}
|
||||
|
||||
'@shikijs/types@3.7.0':
|
||||
resolution: {integrity: sha512-MGaLeaRlSWpnP0XSAum3kP3a8vtcTsITqoEPYdt3lQG3YCdQH4DnEhodkYcNMcU0uW0RffhoD1O3e0vG5eSBBg==}
|
||||
|
||||
'@shikijs/vscode-textmate@10.0.2':
|
||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||
|
||||
'@types/babel__core@7.20.5':
|
||||
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
||||
|
||||
@@ -1492,6 +1516,9 @@ packages:
|
||||
hast-util-sanitize@5.0.2:
|
||||
resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==}
|
||||
|
||||
hast-util-to-html@9.0.5:
|
||||
resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
|
||||
|
||||
@@ -1921,6 +1948,12 @@ packages:
|
||||
ohash@2.0.11:
|
||||
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
||||
|
||||
oniguruma-parser@0.12.1:
|
||||
resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==}
|
||||
|
||||
oniguruma-to-es@4.3.3:
|
||||
resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==}
|
||||
|
||||
optionator@0.9.4:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@@ -2114,6 +2147,15 @@ packages:
|
||||
reftools@1.1.9:
|
||||
resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==}
|
||||
|
||||
regex-recursion@6.0.2:
|
||||
resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
|
||||
|
||||
regex-utilities@2.3.0:
|
||||
resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==}
|
||||
|
||||
regex@6.0.1:
|
||||
resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==}
|
||||
|
||||
rehype-raw@7.0.0:
|
||||
resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
|
||||
|
||||
@@ -2190,6 +2232,9 @@ packages:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
shiki@3.7.0:
|
||||
resolution: {integrity: sha512-ZcI4UT9n6N2pDuM2n3Jbk0sR4Swzq43nLPgS/4h0E3B/NrFn2HKElrDtceSf8Zx/OWYOo7G1SAtBLypCp+YXqg==}
|
||||
|
||||
should-equal@2.0.0:
|
||||
resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==}
|
||||
|
||||
@@ -3074,6 +3119,39 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.44.0':
|
||||
optional: true
|
||||
|
||||
'@shikijs/core@3.7.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.7.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-to-html: 9.0.5
|
||||
|
||||
'@shikijs/engine-javascript@3.7.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.7.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
oniguruma-to-es: 4.3.3
|
||||
|
||||
'@shikijs/engine-oniguruma@3.7.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.7.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
|
||||
'@shikijs/langs@3.7.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.7.0
|
||||
|
||||
'@shikijs/themes@3.7.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.7.0
|
||||
|
||||
'@shikijs/types@3.7.0':
|
||||
dependencies:
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
'@shikijs/vscode-textmate@10.0.2': {}
|
||||
|
||||
'@types/babel__core@7.20.5':
|
||||
dependencies:
|
||||
'@babel/parser': 7.27.5
|
||||
@@ -3827,6 +3905,20 @@ snapshots:
|
||||
'@ungap/structured-clone': 1.3.0
|
||||
unist-util-position: 5.0.0
|
||||
|
||||
hast-util-to-html@9.0.5:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/unist': 3.0.3
|
||||
ccount: 2.0.1
|
||||
comma-separated-tokens: 2.0.3
|
||||
hast-util-whitespace: 3.0.0
|
||||
html-void-elements: 3.0.0
|
||||
mdast-util-to-hast: 13.2.0
|
||||
property-information: 7.1.0
|
||||
space-separated-tokens: 2.0.2
|
||||
stringify-entities: 4.0.4
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
@@ -4465,6 +4557,14 @@ snapshots:
|
||||
|
||||
ohash@2.0.11: {}
|
||||
|
||||
oniguruma-parser@0.12.1: {}
|
||||
|
||||
oniguruma-to-es@4.3.3:
|
||||
dependencies:
|
||||
oniguruma-parser: 0.12.1
|
||||
regex: 6.0.1
|
||||
regex-recursion: 6.0.2
|
||||
|
||||
optionator@0.9.4:
|
||||
dependencies:
|
||||
deep-is: 0.1.4
|
||||
@@ -4673,6 +4773,16 @@ snapshots:
|
||||
|
||||
reftools@1.1.9: {}
|
||||
|
||||
regex-recursion@6.0.2:
|
||||
dependencies:
|
||||
regex-utilities: 2.3.0
|
||||
|
||||
regex-utilities@2.3.0: {}
|
||||
|
||||
regex@6.0.1:
|
||||
dependencies:
|
||||
regex-utilities: 2.3.0
|
||||
|
||||
rehype-raw@7.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
@@ -4784,6 +4894,17 @@ snapshots:
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
shiki@3.7.0:
|
||||
dependencies:
|
||||
'@shikijs/core': 3.7.0
|
||||
'@shikijs/engine-javascript': 3.7.0
|
||||
'@shikijs/engine-oniguruma': 3.7.0
|
||||
'@shikijs/langs': 3.7.0
|
||||
'@shikijs/themes': 3.7.0
|
||||
'@shikijs/types': 3.7.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
should-equal@2.0.0:
|
||||
dependencies:
|
||||
should-type: 1.4.0
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useRef, useState, useEffect } from 'react';
|
||||
|
||||
const CHAR_WIDTH = 8; // 估算每个字符宽度,实际可根据字体调整
|
||||
const MIN_WIDTH = 200;
|
||||
const MAX_WIDTH = 1060;
|
||||
const MAX_WIDTH = 960;
|
||||
const MAX_HEIGHT = 420;
|
||||
|
||||
const Code = ({
|
||||
@@ -21,7 +21,7 @@ const Code = ({
|
||||
autoWidth?: boolean;
|
||||
}) => {
|
||||
const editorRef = useRef<any>(null);
|
||||
const [height, setHeight] = useState(100);
|
||||
const [height, setHeight] = useState(420);
|
||||
const [width, setWidth] = useState(MAX_WIDTH);
|
||||
|
||||
// 动态调整高度和宽度
|
||||
|
||||
24
ui/src/components/markDown/command.tsx
Normal file
24
ui/src/components/markDown/command.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { codeToHtml } from 'shiki';
|
||||
|
||||
const Command = ({
|
||||
children,
|
||||
theme = 'material-theme-darker',
|
||||
lang = 'shell',
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
theme?: string;
|
||||
lang?: string;
|
||||
}) => {
|
||||
const [html, setHtml] = useState<string>('');
|
||||
useEffect(() => {
|
||||
codeToHtml(String(children).replace(/\n$/, ''), {
|
||||
lang,
|
||||
theme,
|
||||
}).then((html) => setHtml(html));
|
||||
}, [children, theme, lang]);
|
||||
|
||||
return <div dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
};
|
||||
|
||||
export default Command;
|
||||
@@ -6,9 +6,11 @@ import rehypeRaw from 'rehype-raw';
|
||||
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
|
||||
import remarkBreaks from 'remark-breaks';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
|
||||
import { getBaseLanguageId } from '@/utils';
|
||||
import Diff from './diff';
|
||||
import Code from './code';
|
||||
import Command from './command';
|
||||
|
||||
interface ExtendedComponents extends Components {
|
||||
tools?: React.ComponentType<any>;
|
||||
@@ -332,18 +334,10 @@ const MarkDown = ({
|
||||
/>
|
||||
);
|
||||
},
|
||||
command: ({ children }: React.HTMLAttributes<HTMLElement>) => {
|
||||
return (
|
||||
<Code
|
||||
data={String(children).replace(/\n$/, '')}
|
||||
language={'shell'}
|
||||
options={{
|
||||
lineNumbers: 'off',
|
||||
}}
|
||||
autoHeight
|
||||
autoWidth
|
||||
/>
|
||||
);
|
||||
command: async ({
|
||||
children,
|
||||
}: React.HTMLAttributes<HTMLElement>) => {
|
||||
return <Command lang='shell'>{children}</Command>;
|
||||
},
|
||||
attemptcompletion: (props: React.HTMLAttributes<HTMLElement>) => {
|
||||
return (
|
||||
@@ -369,15 +363,7 @@ const MarkDown = ({
|
||||
}: React.HTMLAttributes<HTMLElement>) {
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
return match ? (
|
||||
<Code
|
||||
data={String(children).replace(/\n$/, '')}
|
||||
language={match?.[1] || 'plaintext'}
|
||||
autoHeight
|
||||
autoWidth
|
||||
options={{
|
||||
lineNumbers: 'off',
|
||||
}}
|
||||
/>
|
||||
<Command>{String(children).replace(/\n$/, '')}</Command>
|
||||
) : (
|
||||
<code
|
||||
{...rest}
|
||||
@@ -404,8 +390,8 @@ const MarkDown = ({
|
||||
<Code
|
||||
data={block.code}
|
||||
language={block.language || 'text'}
|
||||
autoHeight
|
||||
autoWidth
|
||||
autoHeight={false}
|
||||
autoWidth={false}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -7,7 +7,8 @@ import { useEffect, useState } from 'react';
|
||||
import packageJson from '../../../package.json';
|
||||
|
||||
const Version = () => {
|
||||
const curVersion = import.meta.env.VITE_APP_VERSION || packageJson.version;
|
||||
const curVersion =
|
||||
import.meta.env.VITE_APP_VERSION || `v${packageJson.version}`;
|
||||
const [latestVersion, setLatestVersion] = useState<string | undefined>(
|
||||
undefined
|
||||
);
|
||||
@@ -24,7 +25,7 @@ const Version = () => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (latestVersion === undefined) return null;
|
||||
// if (latestVersion === undefined) return null;
|
||||
|
||||
return (
|
||||
<Stack
|
||||
@@ -53,7 +54,7 @@ const Version = () => {
|
||||
</Stack>
|
||||
<Stack direction={'row'} alignItems={'center'} gap={0.5}>
|
||||
<Box sx={{ whiteSpace: 'nowrap' }}>{curVersion}</Box>
|
||||
{latestVersion !== `v${curVersion}` && (
|
||||
{latestVersion !== `${curVersion}` && (
|
||||
<Tooltip
|
||||
placement='top'
|
||||
arrow
|
||||
|
||||
@@ -11,7 +11,6 @@ import duration from 'dayjs/plugin/duration';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
|
||||
import { lightTheme } from './theme';
|
||||
|
||||
import router from './router';
|
||||
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
@@ -2,17 +2,14 @@ import Avatar from '@/components/avatar';
|
||||
import Card from '@/components/card';
|
||||
import { getChatInfo } from '@/api/Billing';
|
||||
import MarkDown from '@/components/markDown';
|
||||
import { Ellipsis, Icon, Modal } from '@c-x/ui';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { Ellipsis, Modal } from '@c-x/ui';
|
||||
import { styled } from '@mui/material';
|
||||
import logo from '@/assets/images/logo.png';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { DomainChatContent, DomainChatRecord } from '@/api/types';
|
||||
|
||||
type ToolInfo = any;
|
||||
|
||||
const StyledChatList = styled('div')(() => ({
|
||||
background: '#f7f8fa',
|
||||
borderRadius: 4,
|
||||
padding: 24,
|
||||
minHeight: 400,
|
||||
@@ -22,18 +19,33 @@ const StyledChatList = styled('div')(() => ({
|
||||
|
||||
const StyledChatRow = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'isUser',
|
||||
})<{ isUser: boolean }>(({ isUser, theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: isUser ? 'flex-end' : 'flex-start',
|
||||
gap: theme.spacing(1),
|
||||
marginBottom: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledChatUser = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'isUser',
|
||||
})<{ isUser: boolean }>(({ isUser }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: isUser ? 'row-reverse' : 'row',
|
||||
alignItems: 'flex-start',
|
||||
marginBottom: 28,
|
||||
alignItems: 'center',
|
||||
position: 'relative',
|
||||
}));
|
||||
|
||||
const StyledChatName = styled('div')(({ theme }) => ({
|
||||
color: theme.vars.palette.text.primary,
|
||||
fontSize: '14px',
|
||||
fontWeight: 500,
|
||||
}));
|
||||
|
||||
const StyledChatAvatar = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'isUser',
|
||||
})<{ isUser: boolean }>(({ isUser }) => ({
|
||||
margin: isUser ? '0 0 0 18px' : '0 18px 0 0',
|
||||
margin: isUser ? '0 0 0 12px' : '0 12px 0 0',
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
position: 'relative',
|
||||
@@ -44,18 +56,13 @@ const StyledChatBubble = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'isUser',
|
||||
})<{ isUser: boolean }>(({ isUser }) => ({
|
||||
background: isUser ? '#e6f7ff' : '#f5f5f5',
|
||||
borderRadius: 18,
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.06)',
|
||||
padding: '16px 20px',
|
||||
margin: isUser ? '0 36px 0 0' : '0 0 0 36px',
|
||||
borderRadius: 12,
|
||||
padding: '8px 12px',
|
||||
minHeight: 36,
|
||||
maxWidth: 1100,
|
||||
maxWidth: 1040,
|
||||
wordBreak: 'break-word',
|
||||
position: 'relative',
|
||||
transition: 'box-shadow 0.2s',
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
boxShadow: '0 4px 16px rgba(0,0,0,0.12)',
|
||||
},
|
||||
}));
|
||||
|
||||
const ChatDetailModal = ({
|
||||
@@ -68,9 +75,6 @@ const ChatDetailModal = ({
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const [content, setContent] = useState<DomainChatContent[]>([]);
|
||||
const [showToolInfo, setShowToolInfo] = useState<{ [key: string]: ToolInfo }>(
|
||||
{}
|
||||
);
|
||||
|
||||
const getChatDetailModal = () => {
|
||||
if (!data) return;
|
||||
@@ -103,7 +107,7 @@ const ChatDetailModal = ({
|
||||
maxWidth: 1300,
|
||||
},
|
||||
}}
|
||||
width={1300}
|
||||
width={1200}
|
||||
open={open}
|
||||
onCancel={onClose}
|
||||
footer={null}
|
||||
@@ -112,21 +116,24 @@ const ChatDetailModal = ({
|
||||
<StyledChatList>
|
||||
{content.map((item, idx) => {
|
||||
const isUser = item.role === 'user';
|
||||
const name = isUser ? data?.user?.username : 'AI';
|
||||
const name = isUser ? data?.user?.username : 'MonkeyCode';
|
||||
const msg = item.content || '';
|
||||
return (
|
||||
<StyledChatRow key={idx} isUser={isUser}>
|
||||
<StyledChatAvatar isUser={isUser}>
|
||||
<Avatar
|
||||
name={isUser ? name : undefined}
|
||||
src={isUser ? undefined : logo}
|
||||
sx={{
|
||||
width: 48,
|
||||
height: 48,
|
||||
fontSize: 22,
|
||||
}}
|
||||
/>
|
||||
</StyledChatAvatar>
|
||||
<StyledChatUser key={idx} isUser={isUser}>
|
||||
<StyledChatAvatar isUser={isUser}>
|
||||
<Avatar
|
||||
name={isUser ? name : undefined}
|
||||
src={isUser ? undefined : logo}
|
||||
sx={{
|
||||
width: 24,
|
||||
height: 24,
|
||||
fontSize: 16,
|
||||
}}
|
||||
/>
|
||||
</StyledChatAvatar>
|
||||
<StyledChatName>{name}</StyledChatName>
|
||||
</StyledChatUser>
|
||||
<StyledChatBubble isUser={isUser}>
|
||||
<MarkDown content={msg} />
|
||||
</StyledChatBubble>
|
||||
|
||||
@@ -135,7 +135,7 @@ const Chat = () => {
|
||||
return (
|
||||
<Card sx={{ flex: 1, height: '100%' }}>
|
||||
<Table
|
||||
height='calc(100%)'
|
||||
height='100%'
|
||||
sx={{ mx: -2 }}
|
||||
PaginationProps={{
|
||||
sx: {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { DomainCompletionRecord, DomainUser } from '@/api/types';
|
||||
import { getListCompletionRecord } from '@/api/Billing';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { Table } from '@c-x/ui';
|
||||
import Card from '@/components/card';
|
||||
import {
|
||||
ButtonBase,
|
||||
Box,
|
||||
Stack,
|
||||
MenuItem,
|
||||
Select,
|
||||
@@ -16,30 +16,14 @@ import {
|
||||
} from '@mui/material';
|
||||
import { getListUser } from '@/api/User';
|
||||
import dayjs from 'dayjs';
|
||||
import { useDebounceFn } from 'ahooks';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
import CompletionDetailModal from './completionDetailModal';
|
||||
import StyledLabel from '@/components/label';
|
||||
import { LANG_OPTIONS } from './constant';
|
||||
import { ArrowDropDown as ArrowDropDownIcon } from '@mui/icons-material';
|
||||
import User from '@/components/user';
|
||||
|
||||
// 防抖 hook
|
||||
function useDebounce(fn: (...args: any[]) => void, delay: number) {
|
||||
const timer = useRef<number | null>(null);
|
||||
const fnRef = useRef(fn);
|
||||
fnRef.current = fn;
|
||||
return useCallback(
|
||||
(...args: any[]) => {
|
||||
if (timer.current) clearTimeout(timer.current);
|
||||
timer.current = setTimeout(() => {
|
||||
fnRef.current(...args);
|
||||
}, delay);
|
||||
},
|
||||
[delay]
|
||||
);
|
||||
}
|
||||
|
||||
const Completion = () => {
|
||||
const [page, setPage] = useState(1);
|
||||
const [size, setSize] = useState(20);
|
||||
@@ -60,7 +44,7 @@ const Completion = () => {
|
||||
const { data: userOptions = { users: [] } } = useRequest(() =>
|
||||
getListUser({
|
||||
page: 1,
|
||||
size: 99999,
|
||||
size: 10,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -120,13 +104,12 @@ const Completion = () => {
|
||||
width: 150,
|
||||
render(_, record) {
|
||||
return (
|
||||
<ButtonBase
|
||||
disableRipple
|
||||
<Box
|
||||
onClick={() => setCompletionDetailModal(record)}
|
||||
sx={{ color: 'info.main' }}
|
||||
sx={{ color: 'info.main', cursor: 'pointer' }}
|
||||
>
|
||||
点击查看
|
||||
</ButtonBase>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -172,16 +155,16 @@ const Completion = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const debounceSetFilterLang = useDebounce(
|
||||
const debounceSetFilterLang = useDebounceFn(
|
||||
(val: string) => setFilterLang(val),
|
||||
500
|
||||
{
|
||||
wait: 500,
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<Card sx={{ flex: 1, height: '100%' }}>
|
||||
{/* 筛选项 */}
|
||||
<Stack direction='row' spacing={2} sx={{ mb: 2 }}>
|
||||
{/* 成员筛选 Autocomplete */}
|
||||
<Autocomplete
|
||||
size='small'
|
||||
sx={{ minWidth: 220 }}
|
||||
@@ -200,7 +183,6 @@ const Completion = () => {
|
||||
renderInput={(params) => <TextField {...params} label='成员' />}
|
||||
clearOnEscape
|
||||
/>
|
||||
{/* 语言筛选 Autocomplete */}
|
||||
<Autocomplete
|
||||
size='small'
|
||||
sx={{ minWidth: 220 }}
|
||||
@@ -212,13 +194,11 @@ const Completion = () => {
|
||||
setFilterLang(newValue ? String(newValue) : '');
|
||||
}}
|
||||
onInputChange={(_, newInputValue) =>
|
||||
debounceSetFilterLang(newInputValue)
|
||||
debounceSetFilterLang.run(newInputValue)
|
||||
}
|
||||
popupIcon={<ArrowDropDownIcon />}
|
||||
renderInput={(params) => <TextField {...params} label='语言' />}
|
||||
clearOnEscape
|
||||
/>
|
||||
{/* 是否采纳筛选 Select 保持不变 */}
|
||||
<FormControl size='small' sx={{ minWidth: 180 }}>
|
||||
<InputLabel>是否采纳</InputLabel>
|
||||
<Select
|
||||
@@ -262,6 +242,7 @@ const Completion = () => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<CompletionDetailModal
|
||||
open={!!completionDetailModal}
|
||||
onClose={() => setCompletionDetailModal(undefined)}
|
||||
|
||||
@@ -110,7 +110,6 @@ const GlobalStatistic = ({ timeRange }: { timeRange: TimeRange }) => {
|
||||
container
|
||||
spacing={2}
|
||||
sx={{
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
borderRadius: 2.5,
|
||||
}}
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { getListUser } from '@/api/User';
|
||||
import {
|
||||
Stack,
|
||||
TextField,
|
||||
MenuItem,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Select,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
} from '@mui/material';
|
||||
import dayjs from 'dayjs';
|
||||
import { Stack, MenuItem, Select } from '@mui/material';
|
||||
import { CusTabs } from '@c-x/ui';
|
||||
import GlobalStatistic from './components/globalStatistic';
|
||||
import CancelRoundedIcon from '@mui/icons-material/CancelRounded';
|
||||
import { useRequest } from 'ahooks';
|
||||
import MemberStatistic from './components/memberStatistic';
|
||||
import { useParams } from 'react-router-dom';
|
||||
@@ -27,7 +16,7 @@ const Dashboard = () => {
|
||||
const { tab, id } = useParams();
|
||||
const [tabValue, setTabValue] = useState(tab || 'global');
|
||||
const [memberData, setMemberData] = useState<DomainUser | null>(null);
|
||||
const [timeRange, setTimeRange] = useState<TimeRange>('90d');
|
||||
const [timeRange, setTimeRange] = useState<TimeRange>('24h');
|
||||
|
||||
const { data: userData, refresh } = useRequest(
|
||||
() =>
|
||||
|
||||
Reference in New Issue
Block a user