diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json index e0885b329..37e4a184f 100644 --- a/client/public/locales/en/common.json +++ b/client/public/locales/en/common.json @@ -5,9 +5,9 @@ "Warning": "Warning", "app": { "App Detail": "App Detail", - "My Apps": "My Apps", + "Confirm Del App Tip": "Confirm to delete the app and all its chats", "Confirm Save App Tip": "After saving, the advanced orchestration configuration will be overwritten. Make sure that the application does not use advanced orchestration.", - "Confirm Del App Tip": "Confirm to delete the app and all its chats" + "My Apps": "My Apps" }, "chat": { "Confirm to clear history": "Confirm to clear history?", @@ -28,5 +28,9 @@ "Datasets": "DataSets", "Store": "Store", "Tools": "Tools" + }, + "user": { + "Bill Detail": "Bill Detail", + "Pay": "Pay" } } diff --git a/client/public/locales/zh/common.json b/client/public/locales/zh/common.json index 7181d49d1..35118f55c 100644 --- a/client/public/locales/zh/common.json +++ b/client/public/locales/zh/common.json @@ -5,9 +5,9 @@ "Warning": "提示", "app": { "App Detail": "应用详情", - "My Apps": "我的应用", + "Confirm Del App Tip": "确认删除该应用及其所有聊天记录?", "Confirm Save App Tip": "保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。", - "Confirm Del App Tip": "确认删除该应用及其所有聊天记录?" + "My Apps": "我的应用" }, "chat": { "Confirm to clear history": "确认清空该应用的聊天记录?", @@ -28,5 +28,9 @@ "Datasets": "知识库", "Store": "应用市场", "Tools": "工具" + }, + "user": { + "Bill Detail": "账单详情", + "Pay": "充值" } } diff --git a/client/src/components/APIKeyModal/index.tsx b/client/src/components/APIKeyModal/index.tsx index ae6e577e8..f99c0480b 100644 --- a/client/src/components/APIKeyModal/index.tsx +++ b/client/src/components/APIKeyModal/index.tsx @@ -2,13 +2,9 @@ import React, { useState } from 'react'; import { Box, Button, - Modal, - ModalOverlay, - ModalContent, Flex, ModalFooter, ModalBody, - ModalCloseButton, Table, Thead, Tbody, @@ -26,6 +22,7 @@ import { AddIcon, DeleteIcon } from '@chakra-ui/icons'; import { getErrText, useCopyData } from '@/utils/tools'; import { useToast } from '@/hooks/useToast'; import MyIcon from '../Icon'; +import MyModal from '../MyModal'; const APIKeyModal = ({ onClose }: { onClose: () => void }) => { const { Loading } = useLoading(); @@ -60,100 +57,86 @@ const APIKeyModal = ({ onClose }: { onClose: () => void }) => { }); return ( - - - + + + + API 秘钥管理 + + + 如果你不想 API 秘钥被滥用,请勿将秘钥直接放置在前端使用~ + + + + + + + + + + + + + + {apiKeys.map(({ id, apiKey, createTime, lastUsedTime }) => ( + + + + + + + ))} + +
Api Key创建时间最后一次使用时间 +
{apiKey}{dayjs(createTime).format('YYYY/MM/DD HH:mm:ss')} + {lastUsedTime + ? dayjs(lastUsedTime).format('YYYY/MM/DD HH:mm:ss') + : '没有使用过'} + + } + size={'xs'} + aria-label={'delete'} + variant={'base'} + colorScheme={'gray'} + onClick={() => onclickRemove(id)} + /> +
+
+
+ + + + + + + setApiKey('')}> - API 秘钥管理 + 新的 API 秘钥 - 如果你不想 API 秘钥被滥用,请勿将秘钥直接放置在前端使用~ + 请保管好你的秘钥,秘钥不会再次展示~ - - - - - - - - - - - - - {apiKeys.map(({ id, apiKey, createTime, lastUsedTime }) => ( - - - - - - - ))} - -
Api Key创建时间最后一次使用时间 -
{apiKey}{dayjs(createTime).format('YYYY/MM/DD HH:mm:ss')} - {lastUsedTime - ? dayjs(lastUsedTime).format('YYYY/MM/DD HH:mm:ss') - : '没有使用过'} - - } - size={'xs'} - aria-label={'delete'} - variant={'base'} - colorScheme={'gray'} - onClick={() => onclickRemove(id)} - /> -
-
+ + copyData(apiKey)}> + {apiKey} + + - - - - -
- setApiKey('')}> - - - - - 新的 API 秘钥 - - - 请保管好你的秘钥,秘钥不会再次展示~ - - - - - copyData(apiKey)} - > - {apiKey} - - - - - - - - -
+ + ); }; diff --git a/client/src/components/ChatBox/ContextModal.tsx b/client/src/components/ChatBox/ContextModal.tsx index 2dbffd0f6..0a1c46408 100644 --- a/client/src/components/ChatBox/ContextModal.tsx +++ b/client/src/components/ChatBox/ContextModal.tsx @@ -1,15 +1,7 @@ import React from 'react'; -import { - Modal, - ModalOverlay, - ModalContent, - ModalBody, - ModalCloseButton, - ModalHeader, - Box, - useTheme -} from '@chakra-ui/react'; +import { ModalBody, Box, useTheme } from '@chakra-ui/react'; import { ChatItemType } from '@/types/chat'; +import MyModal from '../MyModal'; const ContextModal = ({ context = [], @@ -21,35 +13,23 @@ const ContextModal = ({ const theme = useTheme(); return ( - <> - - - - 完整对话记录({context.length}条) - - - {context.map((item, i) => ( - - {item.obj} - {item.value} - - ))} - - - - + + + {context.map((item, i) => ( + + {item.obj} + {item.value} + + ))} + + ); }; diff --git a/client/src/components/ChatBox/QuoteModal.tsx b/client/src/components/ChatBox/QuoteModal.tsx index 0ff91c35c..7b45148a1 100644 --- a/client/src/components/ChatBox/QuoteModal.tsx +++ b/client/src/components/ChatBox/QuoteModal.tsx @@ -1,21 +1,13 @@ import React, { useCallback, useState } from 'react'; -import { - Modal, - ModalOverlay, - ModalContent, - ModalBody, - ModalCloseButton, - ModalHeader, - Box, - useTheme -} from '@chakra-ui/react'; -import MyIcon from '@/components/Icon'; -import InputDataModal from '@/pages/kb/detail/components/InputDataModal'; +import { ModalBody, ModalCloseButton, ModalHeader, Box, useTheme } from '@chakra-ui/react'; import { getKbDataItemById } from '@/api/plugins/kb'; import { useLoading } from '@/hooks/useLoading'; import { useToast } from '@/hooks/useToast'; import { getErrText } from '@/utils/tools'; import { QuoteItemType } from '@/types/chat'; +import MyIcon from '@/components/Icon'; +import InputDataModal from '@/pages/kb/detail/components/InputDataModal'; +import MyModal from '../MyModal'; const QuoteModal = ({ onUpdateQuote, @@ -69,67 +61,59 @@ const QuoteModal = ({ return ( <> - - - - - 知识库引用({rawSearch.length}条) - - 注意: 修改知识库内容成功后,此处不会显示变更情况。点击编辑后,会显示知识库最新的内容。 - - - - - {rawSearch.map((item) => ( + + + 知识库引用({rawSearch.length}条) + + 注意: 修改知识库内容成功后,此处不会显示变更情况。点击编辑后,会显示知识库最新的内容。 + + + + + {rawSearch.map((item) => ( + + {item.source && ({item.source})} + {item.q} + {item.a} - {item.source && ({item.source})} - {item.q} - {item.a} - - onclickEdit(item)} - /> - + onclickEdit(item)} + /> - ))} - - - - + + ))} + + + {editDataItem && ( setEditDataItem(undefined)} diff --git a/client/src/components/MyModal/index.tsx b/client/src/components/MyModal/index.tsx index 655c8c142..e74d214a7 100644 --- a/client/src/components/MyModal/index.tsx +++ b/client/src/components/MyModal/index.tsx @@ -5,19 +5,40 @@ import { ModalContent, ModalHeader, ModalCloseButton, - ModalProps + ModalContentProps } from '@chakra-ui/react'; +import { DefaultTFuncReturn } from 'i18next'; -interface Props extends ModalProps { +interface Props extends ModalContentProps { showCloseBtn?: boolean; - title?: string; + title?: any; + isCentered?: boolean; + isOpen: boolean; + onClose: () => void; } -const MyModal = ({ isOpen, onClose, title, children, showCloseBtn = true, ...props }: Props) => { +const MyModal = ({ + isOpen, + onClose, + title, + children, + showCloseBtn = true, + isCentered, + w = 'auto', + maxW = ['90vw', '600px'], + ...props +}: Props) => { return ( - + - + {!!title && {title}} {showCloseBtn && } {children} diff --git a/client/src/components/WxConcat/index.tsx b/client/src/components/WxConcat/index.tsx index bcc4b631c..d3e75bed3 100644 --- a/client/src/components/WxConcat/index.tsx +++ b/client/src/components/WxConcat/index.tsx @@ -1,41 +1,26 @@ import React from 'react'; -import { - Box, - Button, - Modal, - ModalOverlay, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, - ModalCloseButton, - Image -} from '@chakra-ui/react'; +import { Button, ModalFooter, ModalBody, Image } from '@chakra-ui/react'; +import MyModal from '../MyModal'; const WxConcat = ({ onClose }: { onClose: () => void }) => { return ( - - - - 联系方式-wx - - - - + + + + - - - - - + + + + ); }; diff --git a/client/src/constants/theme.ts b/client/src/constants/theme.ts index cda927f1f..071683bcb 100644 --- a/client/src/constants/theme.ts +++ b/client/src/constants/theme.ts @@ -14,15 +14,6 @@ const { definePartsStyle: selectPart, defineMultiStyleConfig: selectMultiStyle } const { definePartsStyle: numInputPart, defineMultiStyleConfig: numInputMultiStyle } = createMultiStyleConfigHelpers(numberInputAnatomy.keys); -// modal 弹窗 -const ModalTheme = defineMultiStyleConfig({ - baseStyle: definePartsStyle({ - dialog: { - maxW: '90vw' - } - }) -}); - // 按键 const Button = defineStyleConfig({ baseStyle: { @@ -313,7 +304,6 @@ export const theme = extendTheme({ primary2: 'linear-gradient(to bottom right, #2152d9 0%,#3370ff 30%,#4e83fd 80%, #85b1ff 100%)' }, components: { - Modal: ModalTheme, Button, Input, Textarea, diff --git a/client/src/hooks/useEditInfo.tsx b/client/src/hooks/useEditInfo.tsx index 62f847ef5..01ef12789 100644 --- a/client/src/hooks/useEditInfo.tsx +++ b/client/src/hooks/useEditInfo.tsx @@ -1,16 +1,6 @@ import React, { useCallback, useRef } from 'react'; -import { - Modal, - ModalOverlay, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, - ModalCloseButton, - Input, - useDisclosure, - Button -} from '@chakra-ui/react'; +import { ModalFooter, ModalBody, Input, useDisclosure, Button } from '@chakra-ui/react'; +import MyModal from '@/components/MyModal'; export const useEditInfo = ({ title, @@ -58,28 +48,23 @@ export const useEditInfo = ({ // eslint-disable-next-line react/display-name const EditModal = useCallback( () => ( - - - - {title} - - - - - - - - - - + + + + + + + + + ), [isOpen, onClose, onclickConfirm, placeholder, title] ); diff --git a/client/src/pages/_app.tsx b/client/src/pages/_app.tsx index 4a2c6b433..ff86649bd 100644 --- a/client/src/pages/_app.tsx +++ b/client/src/pages/_app.tsx @@ -10,7 +10,7 @@ import NProgress from 'nprogress'; //nprogress module import Router from 'next/router'; import { clientInitData, feConfigs } from '@/store/static'; import { appWithTranslation, useTranslation } from 'next-i18next'; -import { getLangStore, setLangStore } from '@/utils/i18n'; +import { getLangStore } from '@/utils/i18n'; import { useRouter } from 'next/router'; import 'nprogress/nprogress.css'; @@ -47,8 +47,6 @@ function App({ Component, pageProps }: AppProps) { setGoogleVerKey(googleClientVerKey); setBaiduTongji(baiduTongji); })(); - - setLangStore('zh'); }, []); useEffect(() => { diff --git a/client/src/pages/account/components/BillDetail.tsx b/client/src/pages/account/components/BillDetail.tsx index 14d2ab9ae..a792223c2 100644 --- a/client/src/pages/account/components/BillDetail.tsx +++ b/client/src/pages/account/components/BillDetail.tsx @@ -1,9 +1,5 @@ import React from 'react'; import { - Modal, - ModalOverlay, - ModalContent, - ModalHeader, ModalBody, Flex, Box, @@ -19,64 +15,64 @@ import { UserBillType } from '@/types/user'; import dayjs from 'dayjs'; import { BillSourceMap } from '@/constants/user'; import { formatPrice } from '@/utils/user'; +import MyModal from '@/components/MyModal'; +import { useTranslation } from 'react-i18next'; const BillDetail = ({ bill, onClose }: { bill: UserBillType; onClose: () => void }) => { + const { t } = useTranslation(); + return ( - - - - 账单详情 - - - 订单号: - {bill.id} - - - 生成时间: - {dayjs(bill.time).format('YYYY/MM/DD HH:mm:ss')} - - - 应用名: - {bill.appName} - - - 来源: - {BillSourceMap[bill.source]} - - - 总金额: - {bill.total}元 - - - - 扣费模块 - - - - - - - - - - - - - {bill.list.map((item, i) => ( - - - - - - - ))} - -
模块名AI模型Token长度费用
{item.moduleName}{item.model}{item.tokenLen}{formatPrice(item.amount)}
-
+ + + + 订单号: + {bill.id} + + + 生成时间: + {dayjs(bill.time).format('YYYY/MM/DD HH:mm:ss')} + + + 应用名: + {bill.appName} + + + 来源: + {BillSourceMap[bill.source]} + + + 总金额: + {bill.total}元 + + + + 扣费模块 - -
-
+ + + + + + + + + + + + {bill.list.map((item, i) => ( + + + + + + + ))} + +
模块名AI模型Token长度费用
{item.moduleName}{item.model}{item.tokenLen}{formatPrice(item.amount)}
+
+ + + ); }; diff --git a/client/src/pages/account/components/Info.tsx b/client/src/pages/account/components/Info.tsx index 49543d355..ae1dcc3de 100644 --- a/client/src/pages/account/components/Info.tsx +++ b/client/src/pages/account/components/Info.tsx @@ -121,7 +121,7 @@ const UserInfo = () => { 余额: - {userInfo?.balance} 元 + {userInfo?.balance.toFixed(3)} - ))} - - - { - setInputVal(Math.floor(+e.target.value)); - }} - > - - { + if (payId) return; + onClose(); + }} + title={t('user.Pay')} + showCloseBtn={!payId} + > + + {!payId && ( + <> + + {[10, 20, 50, 100].map((item) => ( + + ))} + + + { + setInputVal(Math.floor(+e.target.value)); + }} + > + + void }) => { | FastAI16k - 对话 | 0.03 | | FastAI-Plus - 对话 | 0.45 | | 文件拆分 | 0.03 |`} - /> - - )} - {/* 付费二维码 */} - - {payId && 请微信扫码支付: {inputVal}元,请勿关闭页面} - - - + /> + + )} + {/* 付费二维码 */} + + {payId && 请微信扫码支付: {inputVal}元,请勿关闭页面} + + + - - {!payId && ( - <> - - - - )} - -
-
- + + {!payId && ( + <> + + + + )} + + ); }; diff --git a/client/src/pages/account/index.tsx b/client/src/pages/account/index.tsx index 2968086d0..02415f377 100644 --- a/client/src/pages/account/index.tsx +++ b/client/src/pages/account/index.tsx @@ -33,7 +33,7 @@ enum TabEnum { const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => { const tabList = useRef([ { icon: 'meLight', label: '个人信息', id: TabEnum.info, Component: }, - { icon: 'billRecordLight', label: '消费记录', id: TabEnum.bill, Component: }, + { icon: 'billRecordLight', label: '使用记录', id: TabEnum.bill, Component: }, { icon: 'payRecordLight', label: '充值记录', id: TabEnum.pay, Component: }, { icon: 'informLight', label: '通知', id: TabEnum.inform, Component: }, { icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <> } diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeVariable.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeVariable.tsx index 3fd589470..b1f50e9eb 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeVariable.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeVariable.tsx @@ -1,50 +1,17 @@ import React, { useCallback, useMemo, useState } from 'react'; import { NodeProps } from 'reactflow'; -import { - Box, - Button, - Modal, - ModalOverlay, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, - NumberInput, - NumberInputField, - NumberInputStepper, - NumberIncrementStepper, - NumberDecrementStepper, - Table, - Thead, - Tbody, - Tr, - Th, - Td, - TableContainer, - Flex, - Switch, - Input, - useDisclosure, - useTheme, - Grid, - FormControl -} from '@chakra-ui/react'; -import { AddIcon, SmallAddIcon } from '@chakra-ui/icons'; +import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react'; +import { AddIcon } from '@chakra-ui/icons'; import NodeCard from '../modules/NodeCard'; import { FlowModuleItemType } from '@/types/flow'; import Container from '../modules/Container'; import { SystemInputEnum, VariableInputEnum } from '@/constants/app'; import type { VariableItemType } from '@/types/app'; import MyIcon from '@/components/Icon'; -import { useForm } from 'react-hook-form'; -import { useFieldArray } from 'react-hook-form'; import { customAlphabet } from 'nanoid'; const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); +import VariableEditModal from '../../../VariableEditModal'; -const VariableTypeList = [ - { label: '文本', icon: 'settingLight', key: VariableInputEnum.input }, - { label: '下拉单选', icon: 'settingLight', key: VariableInputEnum.select } -]; export const defaultVariable: VariableItemType = { id: nanoid(), key: 'key', @@ -58,8 +25,6 @@ export const defaultVariable: VariableItemType = { const NodeUserGuide = ({ data: { inputs, outputs, onChangeNode, ...props } }: NodeProps) => { - const theme = useTheme(); - const variables = useMemo( () => (inputs.find((item) => item.key === SystemInputEnum.variables) @@ -67,25 +32,7 @@ const NodeUserGuide = ({ [inputs] ); - const [refresh, setRefresh] = useState(false); - const { isOpen, onClose, onOpen } = useDisclosure(); - - const { reset, getValues, setValue, register, control, handleSubmit } = useForm<{ - variable: VariableItemType; - }>({ - defaultValues: { - variable: defaultVariable - } - }); - - const { - fields: selectEnums, - append: appendEnums, - remove: removeEnums - } = useFieldArray({ - control, - name: 'variable.enums' - }); + const [editVariable, setEditVariable] = useState(); const updateVariables = useCallback( (value: VariableItemType[]) => { @@ -102,9 +49,9 @@ const NodeUserGuide = ({ const onclickSubmit = useCallback( ({ variable }: { variable: VariableItemType }) => { updateVariables(variables.map((item) => (item.id === variable.id ? variable : item))); - onClose(); + setEditVariable(undefined); }, - [onClose, updateVariables, variables] + [updateVariables, variables] ); return ( @@ -134,8 +81,7 @@ const NodeUserGuide = ({ w={'16px'} cursor={'pointer'} onClick={() => { - onOpen(); - reset({ variable: item }); + setEditVariable(item); }} /> { const newVariable = { ...defaultVariable, id: nanoid() }; updateVariables(variables.concat(newVariable)); - reset({ variable: newVariable }); - onOpen(); + setEditVariable(newVariable); }} > 新增 @@ -168,133 +113,13 @@ const NodeUserGuide = ({ - {}}> - - - - - 变量设置 - - - - 必填 - - - - 变量名 - - - - 变量 key - - - - - 字段类型 - - - {VariableTypeList.map((item) => ( - { - setValue('variable.type', item.key); - setRefresh(!refresh); - } - })} - > - - {item.label} - - ))} - - - {getValues('variable.type') === VariableInputEnum.input && ( - <> - - 最大长度 - - - - - - - - - - - - )} - - {getValues('variable.type') === VariableInputEnum.select && ( - <> - - 选项 - - - {selectEnums.map((item, i) => ( - - - - - removeEnums(i)} - /> - - ))} - - - - )} - - - - - - - - + {!!editVariable && ( + setEditVariable(undefined)} + onSubmit={onclickSubmit} + /> + )} ); }; diff --git a/client/src/pages/app/detail/components/AdEdit/index.tsx b/client/src/pages/app/detail/components/AdEdit/index.tsx index 2a741e112..3e09ef6a8 100644 --- a/client/src/pages/app/detail/components/AdEdit/index.tsx +++ b/client/src/pages/app/detail/components/AdEdit/index.tsx @@ -27,9 +27,9 @@ import { } from '@/types/flow'; import { AppModuleItemType } from '@/types/app'; import { customAlphabet } from 'nanoid'; -import { putAppById } from '@/api/app'; import { useRequest } from '@/hooks/useRequest'; import type { AppSchema } from '@/types/mongoSchema'; +import { useUserStore } from '@/store/user'; import dynamic from 'next/dynamic'; import MyIcon from '@/components/Icon'; @@ -92,6 +92,7 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => { const theme = useTheme(); const reactFlowWrapper = useRef(null); const ChatTestRef = useRef(null); + const { updateAppDetail } = useUserStore(); const { x, y, zoom } = useViewport(); const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]); @@ -245,7 +246,7 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => { const { mutate: onclickSave, isLoading } = useRequest({ mutationFn: () => { - return putAppById(app._id, { + return updateAppDetail(app._id, { modules: flow2AppModules() }); }, diff --git a/client/src/pages/app/detail/components/BasicEdit/index.tsx b/client/src/pages/app/detail/components/BasicEdit/index.tsx index 93cd7fb23..435d51182 100644 --- a/client/src/pages/app/detail/components/BasicEdit/index.tsx +++ b/client/src/pages/app/detail/components/BasicEdit/index.tsx @@ -460,22 +460,32 @@ const Settings = ({ appId }: { appId: string }) => { 相似度: {getValues('kb.searchSimilarity')}, 单次搜索数量: {getValues('kb.searchLimit')}, 空搜索时拒绝回复: {getValues('kb.searchEmptyText') !== '' ? 'true' : 'false'} - + {selectedKbList.map((item) => ( - - - - {item.name} - - + + + router.push({ + pathname: '/kb/detail', + query: { + kbId: item._id + } + }) + } + > + + + {item.name} + + + ))} diff --git a/client/src/pages/app/detail/components/InfoModal.tsx b/client/src/pages/app/detail/components/InfoModal.tsx index 2c10db9f4..c86686900 100644 --- a/client/src/pages/app/detail/components/InfoModal.tsx +++ b/client/src/pages/app/detail/components/InfoModal.tsx @@ -6,13 +6,8 @@ import { FormControl, Input, Textarea, - Modal, - ModalOverlay, - ModalContent, - ModalHeader, ModalFooter, - ModalBody, - ModalCloseButton + ModalBody } from '@chakra-ui/react'; import { useForm } from 'react-hook-form'; import { AppSchema } from '@/types/mongoSchema'; @@ -23,6 +18,7 @@ import { getErrText } from '@/utils/tools'; import { useUserStore } from '@/store/user'; import { useRequest } from '@/hooks/useRequest'; import Avatar from '@/components/Avatar'; +import MyModal from '@/components/MyModal'; const InfoModal = ({ defaultApp, @@ -120,61 +116,56 @@ const InfoModal = ({ ); return ( - - - - 应用信息设置 - - - 头像 & 名称 - - onOpenSelectFile()} - /> - - - - - - 应用介绍 - - {/* + + + 头像 & 名称 + + onOpenSelectFile()} + /> + + + + + + 应用介绍 + + {/* 该介绍主要用于记忆和在应用市场展示 */} -