From 04599d568b1586c13d9324ca52770a80de48b57e Mon Sep 17 00:00:00 2001 From: Gavan <994259213@qq.com> Date: Wed, 2 Jul 2025 18:27:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=A1=A5=E5=85=A8=E5=B1=95=E7=A4=BA,=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/package.json | 1 + ui/pnpm-lock.yaml | 34 ++ ui/src/api/types.ts | 21 +- ui/src/assets/fonts/iconfont.js | 2 +- .../completion/completionDetailModal.tsx | 337 +++++++----------- ui/src/pages/completion/constant.ts | 67 ++++ ui/src/pages/completion/index.tsx | 163 ++++++++- ui/src/pages/invite/index.tsx | 83 +++-- ui/src/theme.ts | 20 +- 9 files changed, 483 insertions(+), 245 deletions(-) create mode 100644 ui/src/pages/completion/constant.ts diff --git a/ui/package.json b/ui/package.json index 26a74a7..a46043f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,6 +14,7 @@ "@c-x/ui": "^1.0.9", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", + "@monaco-editor/react": "4.7.0-rc.0", "@mui/icons-material": "^6.4.12", "@mui/lab": "6.0.0-beta.19", "@mui/material": "^6.4.12", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index b3ec09f..ad5893d 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@emotion/styled': specifier: ^11.14.0 version: 11.14.0(@emotion/react@11.14.0(@types/react@19.1.8)(react@19.1.0))(@types/react@19.1.8)(react@19.1.0) + '@monaco-editor/react': + specifier: 4.7.0-rc.0 + version: 4.7.0-rc.0(monaco-editor@0.52.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mui/icons-material': specifier: ^6.4.12 version: 6.4.12(@mui/material@6.4.12(@emotion/react@11.14.0(@types/react@19.1.8)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.8)(react@19.1.0))(@types/react@19.1.8)(react@19.1.0))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@types/react@19.1.8)(react@19.1.0) @@ -548,6 +551,16 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@monaco-editor/loader@1.5.0': + resolution: {integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==} + + '@monaco-editor/react@4.7.0-rc.0': + resolution: {integrity: sha512-YfjXkDK0bcwS0zo8PXptvQdCQfOPPtzGsAzmIv7PnoUGFdIohsR+NVDyjbajMddF+3cWUm/3q9NzP/DUke9a+w==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@mui/base@5.0.0-beta.66': resolution: {integrity: sha512-1SzcNbtIms0o/Dx+599B6QbvR5qUMBUjwc2Gs47h1HsF7RcEFXxqaq7zrWkIWbvGctIIPx0j330oGx/SkF+UmA==} engines: {node: '>=14.0.0'} @@ -1836,6 +1849,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + monaco-editor@0.52.2: + resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2203,6 +2219,9 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2843,6 +2862,17 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@monaco-editor/loader@1.5.0': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.7.0-rc.0(monaco-editor@0.52.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@monaco-editor/loader': 1.5.0 + monaco-editor: 0.52.2 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + '@mui/base@5.0.0-beta.66(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@babel/runtime': 7.27.6 @@ -4363,6 +4393,8 @@ snapshots: dependencies: brace-expansion: 2.0.2 + monaco-editor@0.52.2: {} + ms@2.1.3: {} nanoid@3.3.11: {} @@ -4783,6 +4815,8 @@ snapshots: space-separated-tokens@2.0.2: {} + state-local@1.0.7: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 diff --git a/ui/src/api/types.ts b/ui/src/api/types.ts index e85cc37..16e8cb1 100644 --- a/ui/src/api/types.ts +++ b/ui/src/api/types.ts @@ -131,6 +131,7 @@ export interface DomainCompletionInfo { content?: string; created_at?: number; id?: string; + prompt?: string; } export interface DomainCompletionRecord { @@ -330,11 +331,13 @@ export interface DomainProviderModel { export interface DomainRegisterReq { /** 邀请码 */ - code?: string; + code: string; /** 邮箱 */ - email?: string; + email: string; /** 密码 */ - password?: string; + password: string; + /** 用户名 */ + username: string; } export interface DomainSetting { @@ -585,6 +588,12 @@ export interface GetChatInfoParams { } export interface GetListChatRecordParams { + /** 作者 */ + author?: string; + /** 是否接受筛选 */ + is_accept?: boolean; + /** 语言 */ + language?: string; /** 下一页标识 */ next_token?: string; /** 分页 */ @@ -599,6 +608,12 @@ export interface GetCompletionInfoParams { } export interface GetListCompletionRecordParams { + /** 作者 */ + author?: string; + /** 是否接受筛选 */ + is_accept?: boolean; + /** 语言 */ + language?: string; /** 下一页标识 */ next_token?: string; /** 分页 */ diff --git a/ui/src/assets/fonts/iconfont.js b/ui/src/assets/fonts/iconfont.js index acbe161..f682689 100644 --- a/ui/src/assets/fonts/iconfont.js +++ b/ui/src/assets/fonts/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4940939='',(c=>{var a=(l=(l=document.getElementsByTagName("script"))[l.length-1]).getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,o,i,h,e,n=function(a,l){l.parentNode.insertBefore(a,l)};if(a&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}t=function(){var a,l=document.createElement("div");l.innerHTML=c._iconfont_svg_string_4940939,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?n(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),t()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(i=t,h=c.document,e=!1,d(),h.onreadystatechange=function(){"complete"==h.readyState&&(h.onreadystatechange=null,m())})}function m(){e||(e=!0,i())}function d(){try{h.documentElement.doScroll("left")}catch(a){return void setTimeout(d,50)}m()}})(window); \ No newline at end of file +window._iconfont_svg_string_4940939='',(c=>{var a=(l=(l=document.getElementsByTagName("script"))[l.length-1]).getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,o,i,h,e,n=function(a,l){l.parentNode.insertBefore(a,l)};if(a&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}t=function(){var a,l=document.createElement("div");l.innerHTML=c._iconfont_svg_string_4940939,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?n(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),t()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(i=t,h=c.document,e=!1,d(),h.onreadystatechange=function(){"complete"==h.readyState&&(h.onreadystatechange=null,m())})}function m(){e||(e=!0,i())}function d(){try{h.documentElement.doScroll("left")}catch(a){return void setTimeout(d,50)}m()}})(window); \ No newline at end of file diff --git a/ui/src/pages/completion/completionDetailModal.tsx b/ui/src/pages/completion/completionDetailModal.tsx index 681e130..883d1be 100644 --- a/ui/src/pages/completion/completionDetailModal.tsx +++ b/ui/src/pages/completion/completionDetailModal.tsx @@ -1,16 +1,10 @@ -import Avatar from '@/components/avatar'; import Card from '@/components/card'; -import { getChatInfo } from '@/api/Billing'; -import MarkDown from '@/components/markDown'; -import { addCommasToNumber, processText } from '@/utils'; -import { Ellipsis, Icon, Modal } from '@c-x/ui'; -import { Box, Stack, Tooltip, useTheme } from '@mui/material'; -import dayjs from 'dayjs'; -import { useEffect, useState } from 'react'; -import { DomainCompletionRecord } from '@/api/types'; +import { getCompletionInfo } from '@/api/Billing'; +import { Modal } from '@c-x/ui'; +import MonacoEditor from '@monaco-editor/react'; -type ConversationItem = any; -type ToolInfo = any; +import { useEffect, useState, useRef } from 'react'; +import { DomainCompletionRecord } from '@/api/types'; const ChatDetailModal = ({ data, @@ -21,51 +15,77 @@ const ChatDetailModal = ({ open: boolean; onClose: () => void; }) => { - const theme = useTheme(); - const [ChatDetailModal, setChatDetailModal] = - useState(null); - const [content, setContent] = useState(''); - const [showToolInfo, setShowToolInfo] = useState<{ [key: string]: ToolInfo }>( - {} - ); + const [editorValue, setEditorValue] = useState(''); + const editorRef = useRef(null); + const [editorReady, setEditorReady] = useState(false); + const [highlightInfo, setHighlightInfo] = useState(null); const getChatDetailModal = () => { if (!data) return; - getChatInfo({ id: data.id! }).then((res) => { - setContent( - data.program_language - ? `\`\`\`${data.program_language}\n${res.content || ''}\n\`\`\`` - : res.content || '' - ); + getCompletionInfo({ id: data.id! }).then((res) => { + const rawPrompt = res.prompt || ''; + const content = res.content || ''; + // 找到三个特殊标记的位置 + const prefixTag = '<|fim_prefix|>'; + const suffixTag = '<|fim_suffix|>'; + const middleTag = '<|fim_middle|>'; + const prefixIdx = rawPrompt.indexOf(prefixTag); + const suffixIdx = rawPrompt.indexOf(suffixTag); + const middleIdx = rawPrompt.indexOf(middleTag); + // 去掉特殊标记 + const prompt = rawPrompt + .replace(prefixTag, '') + .replace(suffixTag, '') + .replace(middleTag, ''); + // 重新定位插入点(因为去掉了前面的 tag,位置会变) + // 计算插入点:suffixTag 在原始 prompt 的位置,去掉 prefixTag 后的 offset + let insertIdx = suffixIdx; + if (prefixIdx !== -1 && prefixIdx < suffixIdx) { + insertIdx -= prefixTag.length; + } + if (middleIdx !== -1 && middleIdx < suffixIdx) { + insertIdx -= middleTag.length; + } + // 插入 content + const newValue = + prompt.slice(0, insertIdx) + content + prompt.slice(insertIdx); + setEditorValue(newValue); + // 计算高亮范围(行列) + const before = newValue.slice(0, insertIdx); + const contentLines = content.split('\n'); + const beforeLines = before.split('\n'); + const startLine = beforeLines.length; + const startColumn = beforeLines[beforeLines.length - 1].length + 1; + const endLine = startLine + contentLines.length - 1; + const endColumn = + contentLines.length === 1 + ? startColumn + content.length + : contentLines[contentLines.length - 1].length + 1; + setHighlightInfo({ startLine, startColumn, endLine, endColumn }); }); - // getConversationChatDetailModal({ id }).then((res) => { - // const newAnswer = res.answer - // const toolWrapsIds = newAnswer.match(//g)?.map(match => { - // const idMatch = match.match(//); - // return idMatch ? idMatch[1] : null; - // }).filter(Boolean) || []; - // const toolIds = newAnswer.match(//g)?.map(match => { - // const idMatch = match.match(//); - // return idMatch ? idMatch[1] : null; - // }).filter(Boolean) || []; - // const obj: { [key: string]: ToolInfo } = {} - // toolWrapsIds.forEach(id => { - // obj[id!] = { - // done: true, - // } - // }) - // toolIds.forEach(id => { - // obj[id!] = { - // args: false, - // result: false, - // done: true, - // } - // }) - // setShowToolInfo(obj) - // setChatDetailModal({ ...res, answer: processText(res.answer) }) - // }) }; + useEffect(() => { + if (editorReady && highlightInfo && editorRef.current) { + editorRef.current.deltaDecorations( + [], + [ + { + range: { + startLineNumber: highlightInfo.startLine, + startColumn: highlightInfo.startColumn, + endLineNumber: highlightInfo.endLine, + endColumn: highlightInfo.endColumn, + }, + options: { + inlineClassName: 'completion-highlight', + }, + }, + ] + ); + } + }, [editorReady, highlightInfo, editorValue]); + useEffect(() => { if (open) getChatDetailModal(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -79,164 +99,71 @@ const ChatDetailModal = ({ onCancel={onClose} footer={null} > - {ChatDetailModal ? ( - - +
+ - {ChatDetailModal.created_at && ( - - - {dayjs(ChatDetailModal.created_at).format( - 'YYYY-MM-DD HH:mm:ss' - )} - - )} - {ChatDetailModal.remote_ip && ( - - - {ChatDetailModal.remote_ip} - - )} - {ChatDetailModal.model && ( - - - 使用模型 - {ChatDetailModal.model} - - )} - {data?.input_tokens && data?.output_tokens && ( - - - 输入 Token 使用: {addCommasToNumber(data?.input_tokens)} - - - 输出 Token 使用: {addCommasToNumber(data?.output_tokens)} - - - } - > - - - Token 统计 - - {addCommasToNumber( - data?.input_tokens + data?.output_tokens - )} - - - - - )} - - {ChatDetailModal.references?.length > 0 && ( - <> - - 内容来源 - - - {ChatDetailModal.references.map((item: any, index: number) => ( - - - } - /> - - - {item.title} - - - - ))} - - - )} - - 回答 - - - ) : ( - - )} - - + onMount={(editor) => { + 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); + } + }} + /> +
+ ); diff --git a/ui/src/pages/completion/constant.ts b/ui/src/pages/completion/constant.ts new file mode 100644 index 0000000..3d62dfb --- /dev/null +++ b/ui/src/pages/completion/constant.ts @@ -0,0 +1,67 @@ +export const LANG_OPTIONS = [ + 'JavaScript', + 'JavaScriptReact', + 'TypeScript', + 'TypeScriptReact', + 'Python', + 'Java', + 'C', + 'C++', + 'C#', + 'Go', + 'PHP', + 'Ruby', + 'Swift', + 'Kotlin', + 'Rust', + 'Dart', + 'Objective-C', + 'Scala', + 'Perl', + 'R', + 'Shell Script', + 'PowerShell', + 'HTML', + 'CSS', + 'SCSS', + 'Less', + 'JSON', + 'YAML', + 'XML', + 'Markdown', + 'SQL', + 'GraphQL', + 'Dockerfile', + 'Makefile', + 'Lua', + 'Haskell', + 'Elixir', + 'Erlang', + 'F#', + 'Groovy', + 'Visual Basic', + 'Assembly', + 'Matlab', + 'Fortran', + 'COBOL', + 'Prolog', + 'Scheme', + 'Lisp', + 'Julia', + 'SASS', + 'TOML', + 'INI', + 'LaTeX', + 'CMake', + 'Batch', + 'CoffeeScript', + 'Crystal', + 'OCaml', + 'Nim', + 'ReScript', + 'Solidity', + 'Vue', + 'Svelte', + 'JSX', + 'TSX', +]; diff --git a/ui/src/pages/completion/index.tsx b/ui/src/pages/completion/index.tsx index 71cec74..334e164 100644 --- a/ui/src/pages/completion/index.tsx +++ b/ui/src/pages/completion/index.tsx @@ -1,15 +1,54 @@ -import React, { useState, useEffect } from 'react'; +import React, { + useState, + useEffect, + useMemo, + useCallback, + useRef, +} from 'react'; import { DomainCompletionRecord } 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 } from '@mui/material'; +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'; 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'; + +// 防抖 hook +function useDebounce(fn: (...args: any[]) => void, delay: number) { + const timer = useRef(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); @@ -20,26 +59,60 @@ const Completion = () => { const [completionDetailModal, setCompletionDetailModal] = useState< DomainCompletionRecord | undefined >(); - const fetchData = async () => { + + // 新增筛选项 state + const [filterUser, setFilterUser] = useState(''); + const [filterLang, setFilterLang] = useState(''); + const [filterAccept, setFilterAccept] = useState< + 'accepted' | 'unaccepted' | '' + >(''); + + const { data: userOptions = { users: [] } } = useRequest(() => + getListUser({ + page: 1, + size: 99999, + }) + ); + + useEffect(() => { + setPage(1); // 筛选变化时重置页码 + fetchData({ + page: 1, + language: filterLang, + author: filterUser, + is_accept: filterAccept, + }); + }, [filterUser, filterLang, filterAccept]); + + const fetchData = async (params: { + page?: number; + size?: number; + language?: string; + author?: string; + is_accept?: 'accepted' | 'unaccepted' | ''; + }) => { setLoading(true); const res = await getListCompletionRecord({ - page: page, - size: size, + page: params.page || page, + size: params.size || size, + language: params.language || filterLang, + author: params.author || filterUser, + is_accept: + params.is_accept === 'accepted' + ? true + : params.is_accept === 'unaccepted' + ? false + : undefined, }); setLoading(false); setTotal(res?.total_count || 0); setDataSource(res.records || []); }; - useEffect(() => { - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [page, size]); const columns: ColumnsType = [ { dataIndex: 'user', title: '成员', - render(value: DomainCompletionRecord['user']) { return value?.username; }, @@ -60,7 +133,6 @@ const Completion = () => { ); }, }, - { dataIndex: 'is_accept', title: '是否采纳', @@ -72,7 +144,6 @@ const Completion = () => { ); }, }, - { dataIndex: 'program_language', title: '编程语言', @@ -88,7 +159,6 @@ const Completion = () => { { dataIndex: 'output_tokens', title: '输出 Token', - render(value: number) { return addCommasToNumber(value); }, @@ -102,11 +172,72 @@ const Completion = () => { }, }, ]; + + const debounceSetFilterLang = useDebounce( + (val: string) => setFilterLang(val), + 500 + ); + return ( + {/* 筛选项 */} + + {/* 成员筛选 Autocomplete */} + option.username || ''} + value={ + userOptions.users?.find((item) => item.username === filterUser) || + null + } + onChange={(_, newValue) => + setFilterUser(newValue ? newValue.username! : '') + } + isOptionEqualToValue={(option, value) => + option.username === value.username + } + renderInput={(params) => } + clearOnEscape + /> + {/* 语言筛选 Autocomplete */} + option || ''} + value={filterLang || ''} + freeSolo + onChange={(_, newValue) => { + setFilterLang(newValue ? String(newValue) : ''); + }} + onInputChange={(_, newInputValue) => + debounceSetFilterLang(newInputValue) + } + popupIcon={} + renderInput={(params) => } + clearOnEscape + /> + {/* 是否采纳筛选 Select 保持不变 */} + + 是否采纳 + + + { onChange: (page, size) => { setPage(page); setSize(size); + fetchData({ + page, + size, + }); }, }} /> diff --git a/ui/src/pages/invite/index.tsx b/ui/src/pages/invite/index.tsx index 777ba61..758b31c 100644 --- a/ui/src/pages/invite/index.tsx +++ b/ui/src/pages/invite/index.tsx @@ -50,7 +50,7 @@ const StyledPaper = styled(Paper)(({ theme }) => ({ padding: theme.spacing(4), background: 'rgba(255, 255, 255, 0.85)', backdropFilter: 'blur(10px)', - width: 600, + width: 500, borderRadius: theme.spacing(2), boxShadow: '0px 0px 4px 0px rgba(54,59,76,0.1), 0px 20px 40px 0px rgba(54,59,76,0.1)', @@ -67,6 +67,27 @@ const StepCard = styled(Box)(({ theme }) => ({ borderRadius: theme.spacing(2), })); +const IconWrapper = styled(Box)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: theme.palette.text.primary, + marginRight: theme.spacing(2), + fontSize: 16, +})); + +const StyledTextField = styled(TextField)(({ theme }) => ({ + '.MuiInputBase-root': { + backgroundColor: '#fff', + paddingLeft: '20px', + }, + '.MuiInputBase-input': { + paddingTop: '16px', + paddingBottom: '16px', + fontSize: 14, + }, +})); + const Invite = () => { const { id, step } = useParams(); const [showPassword, setShowPassword] = useState(false); @@ -79,6 +100,7 @@ const Invite = () => { defaultValues: { email: '', password: '', + username: '', }, }); @@ -92,7 +114,7 @@ const Invite = () => { }; const onRegister = handleSubmit((data) => { - register({ ...data, code: id }).then(() => { + register({ ...data, code: id! }).then(() => { onNext(); }); }); @@ -127,6 +149,35 @@ const Invite = () => { return !loginSetting.enable_dingtalk_oauth ? ( + + ( + + + + ), + }, + }} + /> + )} + /> + { }, }} render={({ field }) => ( - { slotProps={{ input: { startAdornment: ( - + + + ), }, }} @@ -178,7 +224,7 @@ const Invite = () => { }, }} render={({ field }) => ( - { slotProps={{ input: { startAdornment: ( - + + + ), endAdornment: ( @@ -349,7 +390,7 @@ const Invite = () => {