From 10b1b373c52dceea7e181debf04944cfac945738 Mon Sep 17 00:00:00 2001 From: Gavan <994259213@qq.com> Date: Fri, 4 Jul 2025 11:35:20 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=B1=95=E7=A4=BA,=20=E6=9B=B4=E5=A4=9A=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E6=A6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/src/components/avatar/index.tsx | 17 ++--- ui/src/components/markDown/code.tsx | 59 +++++++++++++++++ ui/src/components/user/index.tsx | 43 ++++++++++++ ui/src/pages/admin/adminTable.tsx | 5 +- ui/src/pages/admin/loginHistory.tsx | 5 +- ui/src/pages/chat/index.tsx | 26 ++++---- ui/src/pages/completion/index.tsx | 26 ++++---- .../components/contributionModal.tsx | 64 ++++++++++++++++++ .../dashboard/components/statisticCard.tsx | 66 +++++++++++++------ ui/src/pages/user/index.tsx | 22 ++----- ui/src/pages/user/loginHistory.tsx | 12 +++- ui/src/pages/user/memberManage.tsx | 47 ++++--------- 12 files changed, 279 insertions(+), 113 deletions(-) create mode 100644 ui/src/components/markDown/code.tsx create mode 100644 ui/src/components/user/index.tsx create mode 100644 ui/src/pages/dashboard/components/contributionModal.tsx diff --git a/ui/src/components/avatar/index.tsx b/ui/src/components/avatar/index.tsx index 3022104..276dd2d 100644 --- a/ui/src/components/avatar/index.tsx +++ b/ui/src/components/avatar/index.tsx @@ -1,6 +1,5 @@ import Logo from '@/assets/images/logo.png'; import { Avatar as MuiAvatar, type SxProps } from '@mui/material'; -import { Icon } from '@c-x/ui'; import { type ReactNode } from 'react'; interface AvatarProps { @@ -41,21 +40,15 @@ function stringAvatar(name: string) { const Avatar = (props: AvatarProps) => { const src = props.src; + const avatarObj = props.name ? stringAvatar(props.name) : undefined; return ( , - })} + ? { children: avatarObj!.children } + : { children: logo })} src={src} - > + /> ); }; diff --git a/ui/src/components/markDown/code.tsx b/ui/src/components/markDown/code.tsx new file mode 100644 index 0000000..46d826f --- /dev/null +++ b/ui/src/components/markDown/code.tsx @@ -0,0 +1,59 @@ +import React from 'react'; + +const Code = () => { + return ( +
+ { + editorRef.current = editor; + setEditorReady(true); + // 隐藏光标 + const editorDom = editor.getDomNode(); + if (editorDom) { + const style = document.createElement('style'); + style.innerHTML = `.monaco-editor .cursor { display: none !important; }`; + editorDom.appendChild(style); + } + }} + /> +
+ ); +}; + +export default Code; diff --git a/ui/src/components/user/index.tsx b/ui/src/components/user/index.tsx new file mode 100644 index 0000000..ed0e1cb --- /dev/null +++ b/ui/src/components/user/index.tsx @@ -0,0 +1,43 @@ +import { Stack, Link, Typography } from '@mui/material'; +import { Link as RouterLink } from 'react-router-dom'; +import Avatar from '../avatar'; + +const User = ({ + id, + username = '', + email = '', +}: { + id?: string; + username?: string; + email?: string; +}) => { + return ( + + + + + {username} + + + {email && ( + + {email} + + )} + + ); +}; + +export default User; diff --git a/ui/src/pages/admin/adminTable.tsx b/ui/src/pages/admin/adminTable.tsx index 4d0bfe0..d083fc2 100644 --- a/ui/src/pages/admin/adminTable.tsx +++ b/ui/src/pages/admin/adminTable.tsx @@ -17,7 +17,7 @@ import dayjs from 'dayjs'; import { DomainAdminUser } from '@/api/types'; import { Controller, useForm } from 'react-hook-form'; import { useEffect, useState } from 'react'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import User from '@/components/user'; const AddAdminModal = ({ open, @@ -182,6 +182,9 @@ const AdminTable = () => { { title: '账号', dataIndex: 'username', + render: (text) => { + return ; + }, }, { title: '最近活跃时间', diff --git a/ui/src/pages/admin/loginHistory.tsx b/ui/src/pages/admin/loginHistory.tsx index 43460ae..1018254 100644 --- a/ui/src/pages/admin/loginHistory.tsx +++ b/ui/src/pages/admin/loginHistory.tsx @@ -5,7 +5,8 @@ import dayjs from 'dayjs'; import { useRequest } from 'ahooks'; import { getAdminLoginHistory } from '@/api/User'; import { ColumnsType } from '@c-x/ui/dist/Table'; -import { DomainListAdminLoginHistoryResp, DomainAdminUser } from '@/api/types'; +import { DomainListAdminLoginHistoryResp } from '@/api/types'; +import User from '@/components/user'; type LoginHistory = NonNullable< DomainListAdminLoginHistoryResp['login_histories'] @@ -18,7 +19,7 @@ const LoginHistory = () => { title: '账号', dataIndex: 'user', render: (user, record) => { - return record?.user?.username; + return ; }, }, { diff --git a/ui/src/pages/chat/index.tsx b/ui/src/pages/chat/index.tsx index e7c5a30..b1cca2f 100644 --- a/ui/src/pages/chat/index.tsx +++ b/ui/src/pages/chat/index.tsx @@ -1,23 +1,17 @@ import React, { useState, useEffect } from 'react'; -import { Table, Ellipsis } from '@c-x/ui'; +import { Table } from '@c-x/ui'; import { getListChatRecord } from '@/api/Billing'; -import { aggregatedTime } from '@/utils'; import dayjs from 'dayjs'; -import { convertTokensToRMB } from '@/utils'; import Card from '@/components/card'; -import { Box, Stack, styled, Chip } from '@mui/material'; +import { Box } from '@mui/material'; import StyledLabel from '@/components/label'; import ChatDetailModal from './chatDetailModal'; import { ColumnsType } from '@c-x/ui/dist/Table'; -import { DomainChatRecord } from '@/api/types'; +import { DomainChatRecord, DomainUser } from '@/api/types'; import { addCommasToNumber } from '@/utils'; - -const StyledHighlightText = styled('span')(({ theme }) => ({ - color: theme.vars.palette.text.primary, - fontWeight: 700, -})); +import User from '@/components/user'; const Chat = () => { const [page, setPage] = useState(1); @@ -47,9 +41,15 @@ const Chat = () => { { dataIndex: 'user', title: '成员', - width: 160, - render(value: DomainChatRecord['user']) { - return value?.username; + width: 260, + render(value: DomainUser) { + return ( + + ); }, }, { diff --git a/ui/src/pages/completion/index.tsx b/ui/src/pages/completion/index.tsx index f6e40c0..bd87d04 100644 --- a/ui/src/pages/completion/index.tsx +++ b/ui/src/pages/completion/index.tsx @@ -1,29 +1,18 @@ -import React, { - useState, - useEffect, - useMemo, - useCallback, - useRef, -} from 'react'; -import { DomainCompletionRecord } from '@/api/types'; +import { useState, useEffect, useCallback, useRef } 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 { - Box, - Button, ButtonBase, - Chip, Stack, - alpha, MenuItem, Select, FormControl, InputLabel, Autocomplete, TextField, - InputAdornment, } from '@mui/material'; import { getListUser } from '@/api/User'; import dayjs from 'dayjs'; @@ -33,6 +22,7 @@ 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) { @@ -113,8 +103,14 @@ const Completion = () => { { dataIndex: 'user', title: '成员', - render(value: DomainCompletionRecord['user']) { - return value?.username; + render(value: DomainUser) { + return ( + + ); }, }, { diff --git a/ui/src/pages/dashboard/components/contributionModal.tsx b/ui/src/pages/dashboard/components/contributionModal.tsx new file mode 100644 index 0000000..055b69c --- /dev/null +++ b/ui/src/pages/dashboard/components/contributionModal.tsx @@ -0,0 +1,64 @@ +import { Box, Stack } from '@mui/material'; +import { DomainUserCodeRank } from '@/api/types'; +import { Modal } from '@c-x/ui'; +import { StyledItem, StyledSerialNumber, StyledText } from './statisticCard'; + +const ContributionModal = ({ + open, + onCancel, + data, +}: { + open: boolean; + onCancel: () => void; + data: DomainUserCodeRank[]; +}) => { + return ( + + + {data.map((item, index) => ( + + + + {index + 1} + + + {/* */} + + {item.username} + + + + {item.lines} + + ))} + + + ); +}; + +export default ContributionModal; diff --git a/ui/src/pages/dashboard/components/statisticCard.tsx b/ui/src/pages/dashboard/components/statisticCard.tsx index 7d5008a..5c64809 100644 --- a/ui/src/pages/dashboard/components/statisticCard.tsx +++ b/ui/src/pages/dashboard/components/statisticCard.tsx @@ -1,9 +1,10 @@ -import React from 'react'; -import { styled, Stack, Box } from '@mui/material'; +import React, { useState } from 'react'; +import { styled, Stack, Box, Button } from '@mui/material'; import { Empty } from '@c-x/ui'; import dayjs from 'dayjs'; import { useNavigate } from 'react-router-dom'; import { TimeRange } from '../index'; +import ContributionModal from './contributionModal'; import Card from '@/components/card'; import { @@ -23,13 +24,13 @@ const StyledCardValue = styled('div')(({ theme }) => ({ fontWeight: 700, })); -const StyledItem = styled('div')(({ theme }) => ({ +export const StyledItem = styled('div')(({ theme }) => ({ display: 'flex', alignItems: 'center', gap: theme.spacing(2), })); -const StyledText = styled('a')(({ theme }) => ({ +export const StyledText = styled('a')(({ theme }) => ({ fontSize: 14, color: theme.palette.text.primary, overflow: 'hidden', @@ -37,20 +38,22 @@ const StyledText = styled('a')(({ theme }) => ({ whiteSpace: 'nowrap', })); -const StyledSerialNumber = styled('span')<{ num: number }>(({ theme, num }) => { - const numToColor = { - 1: '#FE4545', - 2: '#FF6600', - 3: '#FFC600', - }; - const color = numToColor[num as 1] || '#BCBCBC'; - return { - color: color, - fontSize: 14, - fontWeight: 700, - width: 8, - }; -}); +export const StyledSerialNumber = styled('span')<{ num: number }>( + ({ theme, num }) => { + const numToColor = { + 1: '#FE4545', + 2: '#FF6600', + 3: '#FFC600', + }; + const color = numToColor[num as 1] || '#BCBCBC'; + return { + color: color, + fontSize: 14, + fontWeight: 700, + width: 8, + }; + } +); export const ContributionCard = ({ data = [], @@ -60,11 +63,34 @@ export const ContributionCard = ({ timeRange: TimeRange; }) => { const navigate = useNavigate(); - + const [contributionModalOpen, setContributionModalOpen] = useState(false); return ( + setContributionModalOpen(false)} + data={data} + /> - 用户贡献榜 + + 用户贡献榜 + setContributionModalOpen(true)} + > + 查看更多 + + {timeRange === '90d' ? '最近 90 天' : '最近 24 小时'} diff --git a/ui/src/pages/user/index.tsx b/ui/src/pages/user/index.tsx index 2e2c011..edc8cf8 100644 --- a/ui/src/pages/user/index.tsx +++ b/ui/src/pages/user/index.tsx @@ -52,13 +52,13 @@ const User = () => { }); return ( - - - + + + - - + + 强制成员启用两步认证 { }} /> - - 禁止成员使用密码登录 { } /> - - - - + 第三方登录 { 配置 - - - - + diff --git a/ui/src/pages/user/loginHistory.tsx b/ui/src/pages/user/loginHistory.tsx index 208dc85..ef67063 100644 --- a/ui/src/pages/user/loginHistory.tsx +++ b/ui/src/pages/user/loginHistory.tsx @@ -6,6 +6,7 @@ import { Table } from '@c-x/ui'; import dayjs from 'dayjs'; import { ColumnsType } from '@c-x/ui/dist/Table'; import { DomainListLoginHistoryResp } from '@/api/types'; +import User from '@/components/user'; type LoginHistory = NonNullable< DomainListLoginHistoryResp['login_histories'] @@ -18,7 +19,13 @@ const LoginHistory = () => { title: '账号', dataIndex: 'user', render: (user, record) => { - return record?.user?.username; + return ( + + ); }, }, { @@ -54,7 +61,7 @@ const LoginHistory = () => { }, ]; return ( - + { 登录历史 { title: '账号', dataIndex: 'username', render: (text, record) => { - return <> - - navigate(`/dashboard/member/${record.id}`)} sx={{ - '&:hover': { - color: 'info.main', - }, - cursor: 'pointer' - }}> - - - {text} - - - {record.email} - - ; + return ( + + ); }, }, { @@ -282,7 +274,9 @@ const MemberManage = () => { dataIndex: 'last_active_at', width: 120, render: (text, record) => { - return record.last_active_at === 0 ? '从未使用' : dayjs.unix(text).fromNow(); + return record.last_active_at === 0 + ? '从未使用' + : dayjs.unix(text).fromNow(); }, }, { @@ -305,9 +299,8 @@ const MemberManage = () => { }, }, ]; - console.log(currentUser); return ( - + {currentUser?.status === ConstsUserStatus.UserStatusActive && ( 解锁成员 @@ -337,20 +330,7 @@ const MemberManage = () => { > 成员列表 - +
Date: Fri, 4 Jul 2025 11:40:09 +0800 Subject: [PATCH 2/2] fix: ts error --- ui/src/components/markDown/code.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/components/markDown/code.tsx b/ui/src/components/markDown/code.tsx index 46d826f..b1f1987 100644 --- a/ui/src/components/markDown/code.tsx +++ b/ui/src/components/markDown/code.tsx @@ -1,3 +1,4 @@ +// @ts-nocheck import React from 'react'; const Code = () => {