perf: modal

This commit is contained in:
archer
2023-07-26 16:01:21 +08:00
parent ffdef41bf2
commit c06a9fb52b
23 changed files with 696 additions and 997 deletions

View File

@@ -5,9 +5,9 @@
"Warning": "Warning", "Warning": "Warning",
"app": { "app": {
"App Detail": "App Detail", "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 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": { "chat": {
"Confirm to clear history": "Confirm to clear history?", "Confirm to clear history": "Confirm to clear history?",
@@ -28,5 +28,9 @@
"Datasets": "DataSets", "Datasets": "DataSets",
"Store": "Store", "Store": "Store",
"Tools": "Tools" "Tools": "Tools"
},
"user": {
"Bill Detail": "Bill Detail",
"Pay": "Pay"
} }
} }

View File

@@ -5,9 +5,9 @@
"Warning": "提示", "Warning": "提示",
"app": { "app": {
"App Detail": "应用详情", "App Detail": "应用详情",
"My Apps": "我的应用", "Confirm Del App Tip": "确认删除该应用及其所有聊天记录?",
"Confirm Save App Tip": "保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。", "Confirm Save App Tip": "保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。",
"Confirm Del App Tip": "确认删除该应用及其所有聊天记录?" "My Apps": "我的应用"
}, },
"chat": { "chat": {
"Confirm to clear history": "确认清空该应用的聊天记录?", "Confirm to clear history": "确认清空该应用的聊天记录?",
@@ -28,5 +28,9 @@
"Datasets": "知识库", "Datasets": "知识库",
"Store": "应用市场", "Store": "应用市场",
"Tools": "工具" "Tools": "工具"
},
"user": {
"Bill Detail": "账单详情",
"Pay": "充值"
} }
} }

View File

@@ -2,13 +2,9 @@ import React, { useState } from 'react';
import { import {
Box, Box,
Button, Button,
Modal,
ModalOverlay,
ModalContent,
Flex, Flex,
ModalFooter, ModalFooter,
ModalBody, ModalBody,
ModalCloseButton,
Table, Table,
Thead, Thead,
Tbody, Tbody,
@@ -26,6 +22,7 @@ import { AddIcon, DeleteIcon } from '@chakra-ui/icons';
import { getErrText, useCopyData } from '@/utils/tools'; import { getErrText, useCopyData } from '@/utils/tools';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import MyIcon from '../Icon'; import MyIcon from '../Icon';
import MyModal from '../MyModal';
const APIKeyModal = ({ onClose }: { onClose: () => void }) => { const APIKeyModal = ({ onClose }: { onClose: () => void }) => {
const { Loading } = useLoading(); const { Loading } = useLoading();
@@ -60,100 +57,86 @@ const APIKeyModal = ({ onClose }: { onClose: () => void }) => {
}); });
return ( return (
<Modal isOpen onClose={onClose}> <MyModal isOpen onClose={onClose} w={'600px'}>
<ModalOverlay /> <Box py={3} px={5}>
<ModalContent w={'600px'} maxW={'90vw'} position={'relative'}> <Box fontWeight={'bold'} fontSize={'2xl'}>
API
</Box>
<Box fontSize={'sm'} color={'myGray.600'}>
API 使~
</Box>
</Box>
<ModalBody minH={'300px'} maxH={['70vh', '500px']} overflow={'overlay'}>
<TableContainer mt={2} position={'relative'}>
<Table>
<Thead>
<Tr>
<Th>Api Key</Th>
<Th></Th>
<Th>使</Th>
<Th />
</Tr>
</Thead>
<Tbody fontSize={'sm'}>
{apiKeys.map(({ id, apiKey, createTime, lastUsedTime }) => (
<Tr key={id}>
<Td>{apiKey}</Td>
<Td>{dayjs(createTime).format('YYYY/MM/DD HH:mm:ss')}</Td>
<Td>
{lastUsedTime
? dayjs(lastUsedTime).format('YYYY/MM/DD HH:mm:ss')
: '没有使用过'}
</Td>
<Td>
<IconButton
icon={<DeleteIcon />}
size={'xs'}
aria-label={'delete'}
variant={'base'}
colorScheme={'gray'}
onClick={() => onclickRemove(id)}
/>
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</ModalBody>
<ModalFooter>
<Button
variant="base"
leftIcon={<AddIcon color={'myGray.600'} fontSize={'sm'} />}
onClick={() => onclickCreateApiKey()}
>
</Button>
</ModalFooter>
<Loading loading={isGetting || isCreating || isDeleting} fixed={false} />
<MyModal isOpen={!!apiKey} w={'400px'} onClose={() => setApiKey('')}>
<Box py={3} px={5}> <Box py={3} px={5}>
<Box fontWeight={'bold'} fontSize={'2xl'}> <Box fontWeight={'bold'} fontSize={'2xl'}>
API API
</Box> </Box>
<Box fontSize={'sm'} color={'myGray.600'}> <Box fontSize={'sm'} color={'myGray.600'}>
API 使~ ~
</Box> </Box>
</Box> </Box>
<ModalCloseButton /> <ModalBody>
<ModalBody minH={'300px'} maxH={['70vh', '500px']} overflow={'overlay'}> <Flex bg={'myGray.100'} px={3} py={2} cursor={'pointer'} onClick={() => copyData(apiKey)}>
<TableContainer mt={2} position={'relative'}> <Box flex={1}>{apiKey}</Box>
<Table> <MyIcon name={'copy'} w={'16px'}></MyIcon>
<Thead> </Flex>
<Tr>
<Th>Api Key</Th>
<Th></Th>
<Th>使</Th>
<Th />
</Tr>
</Thead>
<Tbody fontSize={'sm'}>
{apiKeys.map(({ id, apiKey, createTime, lastUsedTime }) => (
<Tr key={id}>
<Td>{apiKey}</Td>
<Td>{dayjs(createTime).format('YYYY/MM/DD HH:mm:ss')}</Td>
<Td>
{lastUsedTime
? dayjs(lastUsedTime).format('YYYY/MM/DD HH:mm:ss')
: '没有使用过'}
</Td>
<Td>
<IconButton
icon={<DeleteIcon />}
size={'xs'}
aria-label={'delete'}
variant={'base'}
colorScheme={'gray'}
onClick={() => onclickRemove(id)}
/>
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button variant="base" onClick={() => setApiKey('')}>
variant="base"
leftIcon={<AddIcon color={'myGray.600'} fontSize={'sm'} />}
onClick={() => onclickCreateApiKey()}
>
</Button> </Button>
</ModalFooter> </ModalFooter>
</MyModal>
<Loading loading={isGetting || isCreating || isDeleting} fixed={false} /> </MyModal>
</ModalContent>
<Modal isOpen={!!apiKey} onClose={() => setApiKey('')}>
<ModalOverlay />
<ModalContent w={'400px'} maxW={'90vw'}>
<Box py={3} px={5}>
<Box fontWeight={'bold'} fontSize={'2xl'}>
API
</Box>
<Box fontSize={'sm'} color={'myGray.600'}>
~
</Box>
</Box>
<ModalCloseButton />
<ModalBody>
<Flex
bg={'myGray.100'}
px={3}
py={2}
cursor={'pointer'}
onClick={() => copyData(apiKey)}
>
<Box flex={1}>{apiKey}</Box>
<MyIcon name={'copy'} w={'16px'}></MyIcon>
</Flex>
</ModalBody>
<ModalFooter>
<Button variant="base" onClick={() => setApiKey('')}>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Modal>
); );
}; };

View File

@@ -1,15 +1,7 @@
import React from 'react'; import React from 'react';
import { import { ModalBody, Box, useTheme } from '@chakra-ui/react';
Modal,
ModalOverlay,
ModalContent,
ModalBody,
ModalCloseButton,
ModalHeader,
Box,
useTheme
} from '@chakra-ui/react';
import { ChatItemType } from '@/types/chat'; import { ChatItemType } from '@/types/chat';
import MyModal from '../MyModal';
const ContextModal = ({ const ContextModal = ({
context = [], context = [],
@@ -21,35 +13,23 @@ const ContextModal = ({
const theme = useTheme(); const theme = useTheme();
return ( return (
<> <MyModal isOpen={true} onClose={onClose} title={`完整对话记录(${context.length}条)`} h={'80vh'}>
<Modal isOpen={true} onClose={onClose}> <ModalBody pt={0} whiteSpace={'pre-wrap'} textAlign={'justify'} fontSize={'sm'}>
<ModalOverlay /> {context.map((item, i) => (
<ModalContent <Box
position={'relative'} key={i}
maxW={'min(90vw, 700px)'} p={2}
h={'80vh'} borderRadius={'lg'}
overflow={'overlay'} border={theme.borders.base}
> _notLast={{ mb: 2 }}
<ModalHeader>({context.length})</ModalHeader> position={'relative'}
<ModalCloseButton /> >
<ModalBody pt={0} whiteSpace={'pre-wrap'} textAlign={'justify'} fontSize={'sm'}> <Box fontWeight={'bold'}>{item.obj}</Box>
{context.map((item, i) => ( <Box>{item.value}</Box>
<Box </Box>
key={i} ))}
p={2} </ModalBody>
borderRadius={'lg'} </MyModal>
border={theme.borders.base}
_notLast={{ mb: 2 }}
position={'relative'}
>
<Box fontWeight={'bold'}>{item.obj}</Box>
<Box>{item.value}</Box>
</Box>
))}
</ModalBody>
</ModalContent>
</Modal>
</>
); );
}; };

View File

@@ -1,21 +1,13 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { import { ModalBody, ModalCloseButton, ModalHeader, Box, useTheme } from '@chakra-ui/react';
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 { getKbDataItemById } from '@/api/plugins/kb'; import { getKbDataItemById } from '@/api/plugins/kb';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/hooks/useLoading';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import { QuoteItemType } from '@/types/chat'; import { QuoteItemType } from '@/types/chat';
import MyIcon from '@/components/Icon';
import InputDataModal from '@/pages/kb/detail/components/InputDataModal';
import MyModal from '../MyModal';
const QuoteModal = ({ const QuoteModal = ({
onUpdateQuote, onUpdateQuote,
@@ -69,67 +61,59 @@ const QuoteModal = ({
return ( return (
<> <>
<Modal isOpen={true} onClose={onClose}> <MyModal isOpen={true} onClose={onClose} h={'80vh'}>
<ModalOverlay /> <ModalHeader>
<ModalContent ({rawSearch.length})
position={'relative'} <Box fontSize={'sm'} fontWeight={'normal'}>
maxW={'min(90vw, 700px)'} 注意: 修改知识库内容成功后
h={'80vh'} </Box>
overflow={'overlay'} </ModalHeader>
> <ModalCloseButton />
<ModalHeader> <ModalBody pt={0} whiteSpace={'pre-wrap'} textAlign={'justify'} fontSize={'sm'}>
({rawSearch.length}) {rawSearch.map((item) => (
<Box fontSize={'sm'} fontWeight={'normal'}> <Box
注意: 修改知识库内容成功后 key={item.id}
</Box> flex={'1 0 0'}
</ModalHeader> p={2}
<ModalCloseButton /> borderRadius={'lg'}
<ModalBody pt={0} whiteSpace={'pre-wrap'} textAlign={'justify'} fontSize={'sm'}> border={theme.borders.base}
{rawSearch.map((item) => ( _notLast={{ mb: 2 }}
position={'relative'}
_hover={{ '& .edit': { display: 'flex' } }}
>
{item.source && <Box color={'myGray.600'}>({item.source})</Box>}
<Box>{item.q}</Box>
<Box>{item.a}</Box>
<Box <Box
key={item.id} className="edit"
flex={'1 0 0'} display={'none'}
p={2} position={'absolute'}
borderRadius={'lg'} right={0}
border={theme.borders.base} top={0}
_notLast={{ mb: 2 }} bottom={0}
position={'relative'} w={'40px'}
_hover={{ '& .edit': { display: 'flex' } }} bg={'rgba(255,255,255,0.9)'}
alignItems={'center'}
justifyContent={'center'}
boxShadow={'-10px 0 10px rgba(255,255,255,1)'}
> >
{item.source && <Box color={'myGray.600'}>({item.source})</Box>} <MyIcon
<Box>{item.q}</Box> name={'edit'}
<Box>{item.a}</Box> w={'18px'}
<Box h={'18px'}
className="edit" cursor={'pointer'}
display={'none'} color={'myGray.600'}
position={'absolute'} _hover={{
right={0} color: 'myBlue.700'
top={0} }}
bottom={0} onClick={() => onclickEdit(item)}
w={'40px'} />
bg={'rgba(255,255,255,0.9)'}
alignItems={'center'}
justifyContent={'center'}
boxShadow={'-10px 0 10px rgba(255,255,255,1)'}
>
<MyIcon
name={'edit'}
w={'18px'}
h={'18px'}
cursor={'pointer'}
color={'myGray.600'}
_hover={{
color: 'myBlue.700'
}}
onClick={() => onclickEdit(item)}
/>
</Box>
</Box> </Box>
))} </Box>
</ModalBody> ))}
<Loading fixed={false} /> </ModalBody>
</ModalContent> <Loading fixed={false} />
</Modal> </MyModal>
{editDataItem && ( {editDataItem && (
<InputDataModal <InputDataModal
onClose={() => setEditDataItem(undefined)} onClose={() => setEditDataItem(undefined)}

View File

@@ -5,19 +5,40 @@ import {
ModalContent, ModalContent,
ModalHeader, ModalHeader,
ModalCloseButton, ModalCloseButton,
ModalProps ModalContentProps
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { DefaultTFuncReturn } from 'i18next';
interface Props extends ModalProps { interface Props extends ModalContentProps {
showCloseBtn?: boolean; 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 ( return (
<Modal isOpen={isOpen} onClose={onClose} autoFocus={false} {...props}> <Modal isOpen={isOpen} onClose={onClose} autoFocus={false} isCentered={isCentered}>
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent
w={w}
minW={['300px', '400px']}
maxW={maxW}
position={'relative'}
overflow={'overlay'}
{...props}
>
{!!title && <ModalHeader>{title}</ModalHeader>} {!!title && <ModalHeader>{title}</ModalHeader>}
{showCloseBtn && <ModalCloseButton />} {showCloseBtn && <ModalCloseButton />}
{children} {children}

View File

@@ -1,41 +1,26 @@
import React from 'react'; import React from 'react';
import { import { Button, ModalFooter, ModalBody, Image } from '@chakra-ui/react';
Box, import MyModal from '../MyModal';
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Image
} from '@chakra-ui/react';
const WxConcat = ({ onClose }: { onClose: () => void }) => { const WxConcat = ({ onClose }: { onClose: () => void }) => {
return ( return (
<Modal isOpen={true} onClose={onClose}> <MyModal isOpen={true} onClose={onClose} title={'联系方式-wx'}>
<ModalOverlay /> <ModalBody textAlign={'center'}>
<ModalContent> <Image
<ModalHeader>-wx</ModalHeader> style={{ margin: 'auto' }}
<ModalCloseButton /> src={'https://otnvvf-imgs.oss.laf.run/wx300.jpg'}
<ModalBody textAlign={'center'}> width={'200px'}
<Image height={'200px'}
style={{ margin: 'auto' }} alt=""
src={'https://otnvvf-imgs.oss.laf.run/wx300.jpg'} />
width={'200px'} </ModalBody>
height={'200px'}
alt=""
/>
</ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} onClick={onClose}> <Button variant={'base'} onClick={onClose}>
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent> </MyModal>
</Modal>
); );
}; };

View File

@@ -14,15 +14,6 @@ const { definePartsStyle: selectPart, defineMultiStyleConfig: selectMultiStyle }
const { definePartsStyle: numInputPart, defineMultiStyleConfig: numInputMultiStyle } = const { definePartsStyle: numInputPart, defineMultiStyleConfig: numInputMultiStyle } =
createMultiStyleConfigHelpers(numberInputAnatomy.keys); createMultiStyleConfigHelpers(numberInputAnatomy.keys);
// modal 弹窗
const ModalTheme = defineMultiStyleConfig({
baseStyle: definePartsStyle({
dialog: {
maxW: '90vw'
}
})
});
// 按键 // 按键
const Button = defineStyleConfig({ const Button = defineStyleConfig({
baseStyle: { baseStyle: {
@@ -313,7 +304,6 @@ export const theme = extendTheme({
primary2: 'linear-gradient(to bottom right, #2152d9 0%,#3370ff 30%,#4e83fd 80%, #85b1ff 100%)' primary2: 'linear-gradient(to bottom right, #2152d9 0%,#3370ff 30%,#4e83fd 80%, #85b1ff 100%)'
}, },
components: { components: {
Modal: ModalTheme,
Button, Button,
Input, Input,
Textarea, Textarea,

View File

@@ -1,16 +1,6 @@
import React, { useCallback, useRef } from 'react'; import React, { useCallback, useRef } from 'react';
import { import { ModalFooter, ModalBody, Input, useDisclosure, Button } from '@chakra-ui/react';
Modal, import MyModal from '@/components/MyModal';
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Input,
useDisclosure,
Button
} from '@chakra-ui/react';
export const useEditInfo = ({ export const useEditInfo = ({
title, title,
@@ -58,28 +48,23 @@ export const useEditInfo = ({
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
const EditModal = useCallback( const EditModal = useCallback(
() => ( () => (
<Modal isOpen={isOpen} onClose={onClose}> <MyModal isOpen={isOpen} onClose={onClose} title={title}>
<ModalOverlay /> <ModalBody>
<ModalContent> <Input
<ModalHeader>{title}</ModalHeader> ref={inputRef}
<ModalCloseButton /> defaultValue={defaultValue.current}
<ModalBody> placeholder={placeholder}
<Input autoFocus
ref={inputRef} maxLength={20}
defaultValue={defaultValue.current} />
placeholder={placeholder} </ModalBody>
autoFocus <ModalFooter>
maxLength={20} <Button mr={3} variant={'base'} onClick={onClose}>
/>
</ModalBody> </Button>
<ModalFooter> <Button onClick={onclickConfirm}></Button>
<Button mr={3} variant={'base'} onClick={onClose}> </ModalFooter>
</MyModal>
</Button>
<Button onClick={onclickConfirm}></Button>
</ModalFooter>
</ModalContent>
</Modal>
), ),
[isOpen, onClose, onclickConfirm, placeholder, title] [isOpen, onClose, onclickConfirm, placeholder, title]
); );

View File

@@ -10,7 +10,7 @@ import NProgress from 'nprogress'; //nprogress module
import Router from 'next/router'; import Router from 'next/router';
import { clientInitData, feConfigs } from '@/store/static'; import { clientInitData, feConfigs } from '@/store/static';
import { appWithTranslation, useTranslation } from 'next-i18next'; import { appWithTranslation, useTranslation } from 'next-i18next';
import { getLangStore, setLangStore } from '@/utils/i18n'; import { getLangStore } from '@/utils/i18n';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import 'nprogress/nprogress.css'; import 'nprogress/nprogress.css';
@@ -47,8 +47,6 @@ function App({ Component, pageProps }: AppProps) {
setGoogleVerKey(googleClientVerKey); setGoogleVerKey(googleClientVerKey);
setBaiduTongji(baiduTongji); setBaiduTongji(baiduTongji);
})(); })();
setLangStore('zh');
}, []); }, []);
useEffect(() => { useEffect(() => {

View File

@@ -1,9 +1,5 @@
import React from 'react'; import React from 'react';
import { import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody, ModalBody,
Flex, Flex,
Box, Box,
@@ -19,64 +15,64 @@ import { UserBillType } from '@/types/user';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { BillSourceMap } from '@/constants/user'; import { BillSourceMap } from '@/constants/user';
import { formatPrice } from '@/utils/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 BillDetail = ({ bill, onClose }: { bill: UserBillType; onClose: () => void }) => {
const { t } = useTranslation();
return ( return (
<Modal isOpen={true} onClose={onClose} isCentered> <MyModal isOpen={true} onClose={onClose} title={t('user.Bill Detail')}>
<ModalOverlay /> <ModalBody>
<ModalContent minW={'min(90vw,600px)'}> <Flex alignItems={'center'} pb={4}>
<ModalHeader></ModalHeader> <Box flex={'0 0 80px'}>:</Box>
<ModalBody> <Box>{bill.id}</Box>
<Flex alignItems={'center'} pb={4}> </Flex>
<Box flex={'0 0 80px'}>:</Box> <Flex alignItems={'center'} pb={4}>
<Box>{bill.id}</Box> <Box flex={'0 0 80px'}>:</Box>
</Flex> <Box>{dayjs(bill.time).format('YYYY/MM/DD HH:mm:ss')}</Box>
<Flex alignItems={'center'} pb={4}> </Flex>
<Box flex={'0 0 80px'}>:</Box> <Flex alignItems={'center'} pb={4}>
<Box>{dayjs(bill.time).format('YYYY/MM/DD HH:mm:ss')}</Box> <Box flex={'0 0 80px'}>:</Box>
</Flex> <Box>{bill.appName}</Box>
<Flex alignItems={'center'} pb={4}> </Flex>
<Box flex={'0 0 80px'}>:</Box> <Flex alignItems={'center'} pb={4}>
<Box>{bill.appName}</Box> <Box flex={'0 0 80px'}>:</Box>
</Flex> <Box>{BillSourceMap[bill.source]}</Box>
<Flex alignItems={'center'} pb={4}> </Flex>
<Box flex={'0 0 80px'}>:</Box> <Flex alignItems={'center'} pb={4}>
<Box>{BillSourceMap[bill.source]}</Box> <Box flex={'0 0 80px'}>:</Box>
</Flex> <Box fontWeight={'bold'}>{bill.total}</Box>
<Flex alignItems={'center'} pb={4}> </Flex>
<Box flex={'0 0 80px'}>:</Box> <Box pb={4}>
<Box fontWeight={'bold'}>{bill.total}</Box> <Box flex={'0 0 80px'} mb={1}>
</Flex>
<Box pb={4}>
<Box flex={'0 0 80px'} mb={1}>
</Box>
<TableContainer>
<Table>
<Thead>
<Tr>
<Th></Th>
<Th>AI模型</Th>
<Th>Token长度</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{bill.list.map((item, i) => (
<Tr key={i}>
<Td>{item.moduleName}</Td>
<Td>{item.model}</Td>
<Td>{item.tokenLen}</Td>
<Td>{formatPrice(item.amount)}</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</Box> </Box>
</ModalBody> <TableContainer>
</ModalContent> <Table>
</Modal> <Thead>
<Tr>
<Th></Th>
<Th>AI模型</Th>
<Th>Token长度</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{bill.list.map((item, i) => (
<Tr key={i}>
<Td>{item.moduleName}</Td>
<Td>{item.model}</Td>
<Td>{item.tokenLen}</Td>
<Td>{formatPrice(item.amount)}</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</Box>
</ModalBody>
</MyModal>
); );
}; };

View File

@@ -121,7 +121,7 @@ const UserInfo = () => {
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box> <Box flex={'0 0 50px'}>:</Box>
<Box> <Box>
<strong>{userInfo?.balance}</strong> <strong>{userInfo?.balance.toFixed(3)}</strong>
</Box> </Box>
<Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}> <Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}>

View File

@@ -1,26 +1,17 @@
import React, { useState, useCallback } from 'react'; import React, { useState, useCallback } from 'react';
import { import { ModalFooter, ModalBody, Button, Input, Box, Grid } from '@chakra-ui/react';
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Button,
Input,
Box,
Grid
} from '@chakra-ui/react';
import { getPayCode, checkPayResult } from '@/api/user'; import { getPayCode, checkPayResult } from '@/api/user';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import { useTranslation } from 'react-i18next';
import Markdown from '@/components/Markdown'; import Markdown from '@/components/Markdown';
import MyModal from '@/components/MyModal';
const PayModal = ({ onClose }: { onClose: () => void }) => { const PayModal = ({ onClose }: { onClose: () => void }) => {
const router = useRouter(); const router = useRouter();
const { t } = useTranslation();
const { toast } = useToast(); const { toast } = useToast();
const [inputVal, setInputVal] = useState<number | ''>(''); const [inputVal, setInputVal] = useState<number | ''>('');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -71,46 +62,42 @@ const PayModal = ({ onClose }: { onClose: () => void }) => {
); );
return ( return (
<> <MyModal
<Modal isOpen={true}
isOpen={true} onClose={() => {
onClose={() => { if (payId) return;
if (payId) return; onClose();
onClose(); }}
}} title={t('user.Pay')}
> showCloseBtn={!payId}
<ModalOverlay /> >
<ModalContent minW={'auto'}> <ModalBody py={0}>
<ModalHeader></ModalHeader> {!payId && (
{!payId && <ModalCloseButton />} <>
<Grid gridTemplateColumns={'repeat(4,1fr)'} gridGap={5} mb={4}>
<ModalBody py={0}> {[10, 20, 50, 100].map((item) => (
{!payId && ( <Button
<> key={item}
<Grid gridTemplateColumns={'repeat(4,1fr)'} gridGap={5} mb={4}> variant={item === inputVal ? 'solid' : 'outline'}
{[10, 20, 50, 100].map((item) => ( onClick={() => setInputVal(item)}
<Button >
key={item} {item}
variant={item === inputVal ? 'solid' : 'outline'} </Button>
onClick={() => setInputVal(item)} ))}
> </Grid>
{item} <Box mb={4}>
</Button> <Input
))} value={inputVal}
</Grid> type={'number'}
<Box mb={4}> step={1}
<Input placeholder={'其他金额,请取整数'}
value={inputVal} onChange={(e) => {
type={'number'} setInputVal(Math.floor(+e.target.value));
step={1} }}
placeholder={'其他金额,请取整数'} ></Input>
onChange={(e) => { </Box>
setInputVal(Math.floor(+e.target.value)); <Markdown
}} source={`
></Input>
</Box>
<Markdown
source={`
| 计费项 | 价格: 元/ 1K tokens(包含上下文)| | 计费项 | 价格: 元/ 1K tokens(包含上下文)|
| --- | --- | | --- | --- |
| 知识库 - 索引 | 0.002 | | 知识库 - 索引 | 0.002 |
@@ -118,36 +105,34 @@ const PayModal = ({ onClose }: { onClose: () => void }) => {
| FastAI16k - 对话 | 0.03 | | FastAI16k - 对话 | 0.03 |
| FastAI-Plus - 对话 | 0.45 | | FastAI-Plus - 对话 | 0.45 |
| 文件拆分 | 0.03 |`} | 文件拆分 | 0.03 |`}
/> />
</> </>
)} )}
{/* 付费二维码 */} {/* 付费二维码 */}
<Box textAlign={'center'}> <Box textAlign={'center'}>
{payId && <Box mb={3}>: {inputVal}</Box>} {payId && <Box mb={3}>: {inputVal}</Box>}
<Box id={'payQRCode'} display={'inline-block'}></Box> <Box id={'payQRCode'} display={'inline-block'}></Box>
</Box> </Box>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
{!payId && ( {!payId && (
<> <>
<Button variant={'base'} onClick={onClose}> <Button variant={'base'} onClick={onClose}>
</Button> </Button>
<Button <Button
ml={3} ml={3}
isLoading={loading} isLoading={loading}
isDisabled={!inputVal || inputVal === 0} isDisabled={!inputVal || inputVal === 0}
onClick={handleClickPay} onClick={handleClickPay}
> >
</Button> </Button>
</> </>
)} )}
</ModalFooter> </ModalFooter>
</ModalContent> </MyModal>
</Modal>
</>
); );
}; };

View File

@@ -33,7 +33,7 @@ enum TabEnum {
const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => { const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const tabList = useRef([ const tabList = useRef([
{ icon: 'meLight', label: '个人信息', id: TabEnum.info, Component: <BillTable /> }, { icon: 'meLight', label: '个人信息', id: TabEnum.info, Component: <BillTable /> },
{ icon: 'billRecordLight', label: '消费记录', id: TabEnum.bill, Component: <BillTable /> }, { icon: 'billRecordLight', label: '使用记录', id: TabEnum.bill, Component: <BillTable /> },
{ icon: 'payRecordLight', label: '充值记录', id: TabEnum.pay, Component: <PayRecordTable /> }, { icon: 'payRecordLight', label: '充值记录', id: TabEnum.pay, Component: <PayRecordTable /> },
{ icon: 'informLight', label: '通知', id: TabEnum.inform, Component: <InformTable /> }, { icon: 'informLight', label: '通知', id: TabEnum.inform, Component: <InformTable /> },
{ icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <></> } { icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <></> }

View File

@@ -1,50 +1,17 @@
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import { import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react';
Box, import { AddIcon } from '@chakra-ui/icons';
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 NodeCard from '../modules/NodeCard'; import NodeCard from '../modules/NodeCard';
import { FlowModuleItemType } from '@/types/flow'; import { FlowModuleItemType } from '@/types/flow';
import Container from '../modules/Container'; import Container from '../modules/Container';
import { SystemInputEnum, VariableInputEnum } from '@/constants/app'; import { SystemInputEnum, VariableInputEnum } from '@/constants/app';
import type { VariableItemType } from '@/types/app'; import type { VariableItemType } from '@/types/app';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { useForm } from 'react-hook-form';
import { useFieldArray } from 'react-hook-form';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); 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 = { export const defaultVariable: VariableItemType = {
id: nanoid(), id: nanoid(),
key: 'key', key: 'key',
@@ -58,8 +25,6 @@ export const defaultVariable: VariableItemType = {
const NodeUserGuide = ({ const NodeUserGuide = ({
data: { inputs, outputs, onChangeNode, ...props } data: { inputs, outputs, onChangeNode, ...props }
}: NodeProps<FlowModuleItemType>) => { }: NodeProps<FlowModuleItemType>) => {
const theme = useTheme();
const variables = useMemo( const variables = useMemo(
() => () =>
(inputs.find((item) => item.key === SystemInputEnum.variables) (inputs.find((item) => item.key === SystemInputEnum.variables)
@@ -67,25 +32,7 @@ const NodeUserGuide = ({
[inputs] [inputs]
); );
const [refresh, setRefresh] = useState(false); const [editVariable, setEditVariable] = useState<VariableItemType>();
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 updateVariables = useCallback( const updateVariables = useCallback(
(value: VariableItemType[]) => { (value: VariableItemType[]) => {
@@ -102,9 +49,9 @@ const NodeUserGuide = ({
const onclickSubmit = useCallback( const onclickSubmit = useCallback(
({ variable }: { variable: VariableItemType }) => { ({ variable }: { variable: VariableItemType }) => {
updateVariables(variables.map((item) => (item.id === variable.id ? variable : item))); updateVariables(variables.map((item) => (item.id === variable.id ? variable : item)));
onClose(); setEditVariable(undefined);
}, },
[onClose, updateVariables, variables] [updateVariables, variables]
); );
return ( return (
@@ -134,8 +81,7 @@ const NodeUserGuide = ({
w={'16px'} w={'16px'}
cursor={'pointer'} cursor={'pointer'}
onClick={() => { onClick={() => {
onOpen(); setEditVariable(item);
reset({ variable: item });
}} }}
/> />
<MyIcon <MyIcon
@@ -159,8 +105,7 @@ const NodeUserGuide = ({
onClick={() => { onClick={() => {
const newVariable = { ...defaultVariable, id: nanoid() }; const newVariable = { ...defaultVariable, id: nanoid() };
updateVariables(variables.concat(newVariable)); updateVariables(variables.concat(newVariable));
reset({ variable: newVariable }); setEditVariable(newVariable);
onOpen();
}} }}
> >
@@ -168,133 +113,13 @@ const NodeUserGuide = ({
</Box> </Box>
</Container> </Container>
</NodeCard> </NodeCard>
<Modal isOpen={isOpen} onClose={() => {}}> {!!editVariable && (
<ModalOverlay /> <VariableEditModal
<ModalContent maxW={'Min(400px,90vw)'}> defaultVariable={editVariable}
<ModalHeader display={'flex'}> onClose={() => setEditVariable(undefined)}
<MyIcon name={'variable'} mr={2} w={'24px'} color={'#FF8A4C'} /> onSubmit={onclickSubmit}
/>
</ModalHeader> )}
<ModalBody>
<Flex alignItems={'center'}>
<Box w={'70px'}></Box>
<Switch {...register('variable.required')} />
</Flex>
<Flex mt={5} alignItems={'center'}>
<Box w={'80px'}></Box>
<Input {...register('variable.label', { required: '变量名不能为空' })} />
</Flex>
<Flex mt={5} alignItems={'center'}>
<Box w={'80px'}> key</Box>
<Input {...register('variable.key', { required: '变量 key 不能为空' })} />
</Flex>
<Box mt={5} mb={2}>
</Box>
<Grid gridTemplateColumns={'repeat(2,130px)'} gridGap={4}>
{VariableTypeList.map((item) => (
<Flex
key={item.key}
px={4}
py={1}
border={theme.borders.base}
borderRadius={'md'}
cursor={'pointer'}
{...(item.key === getValues('variable.type')
? {
bg: 'myWhite.600'
}
: {
_hover: {
boxShadow: 'md'
},
onClick: () => {
setValue('variable.type', item.key);
setRefresh(!refresh);
}
})}
>
<MyIcon name={item.icon as any} w={'16px'} />
<Box ml={3}>{item.label}</Box>
</Flex>
))}
</Grid>
{getValues('variable.type') === VariableInputEnum.input && (
<>
<Box mt={5} mb={2}>
</Box>
<Box>
<NumberInput max={100} min={1} step={1} position={'relative'}>
<NumberInputField
{...register('variable.maxLen', {
min: 1,
max: 100,
valueAsNumber: true
})}
max={100}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
</Box>
</>
)}
{getValues('variable.type') === VariableInputEnum.select && (
<>
<Box mt={5} mb={2}>
</Box>
<Box>
{selectEnums.map((item, i) => (
<Flex key={item.id} mb={2} alignItems={'center'}>
<FormControl>
<Input
{...register(`variable.enums.${i}.value`, {
required: '选项内容不能为空'
})}
/>
</FormControl>
<MyIcon
ml={3}
name={'delete'}
w={'16px'}
cursor={'pointer'}
p={2}
borderRadius={'lg'}
_hover={{ bg: 'red.100' }}
onClick={() => removeEnums(i)}
/>
</Flex>
))}
</Box>
<Button
variant={'solid'}
w={'100%'}
textAlign={'left'}
leftIcon={<SmallAddIcon />}
bg={'myGray.100 !important'}
onClick={() => appendEnums({ value: '' })}
>
</Button>
</>
)}
</ModalBody>
<ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}>
</Button>
<Button onClick={handleSubmit(onclickSubmit)}></Button>
</ModalFooter>
</ModalContent>
</Modal>
</> </>
); );
}; };

View File

@@ -27,9 +27,9 @@ import {
} from '@/types/flow'; } from '@/types/flow';
import { AppModuleItemType } from '@/types/app'; import { AppModuleItemType } from '@/types/app';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import { putAppById } from '@/api/app';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/hooks/useRequest';
import type { AppSchema } from '@/types/mongoSchema'; import type { AppSchema } from '@/types/mongoSchema';
import { useUserStore } from '@/store/user';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
@@ -92,6 +92,7 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
const theme = useTheme(); const theme = useTheme();
const reactFlowWrapper = useRef<HTMLDivElement>(null); const reactFlowWrapper = useRef<HTMLDivElement>(null);
const ChatTestRef = useRef<ChatTestComponentRef>(null); const ChatTestRef = useRef<ChatTestComponentRef>(null);
const { updateAppDetail } = useUserStore();
const { x, y, zoom } = useViewport(); const { x, y, zoom } = useViewport();
const [nodes, setNodes, onNodesChange] = useNodesState<FlowModuleItemType>([]); const [nodes, setNodes, onNodesChange] = useNodesState<FlowModuleItemType>([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]);
@@ -245,7 +246,7 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
const { mutate: onclickSave, isLoading } = useRequest({ const { mutate: onclickSave, isLoading } = useRequest({
mutationFn: () => { mutationFn: () => {
return putAppById(app._id, { return updateAppDetail(app._id, {
modules: flow2AppModules() modules: flow2AppModules()
}); });
}, },

View File

@@ -460,22 +460,32 @@ const Settings = ({ appId }: { appId: string }) => {
: {getValues('kb.searchSimilarity')}, : {getValues('kb.searchLimit')}, : {getValues('kb.searchSimilarity')}, : {getValues('kb.searchLimit')},
: {getValues('kb.searchEmptyText') !== '' ? 'true' : 'false'} : {getValues('kb.searchEmptyText') !== '' ? 'true' : 'false'}
</Flex> </Flex>
<Grid templateColumns={['1fr', 'repeat(2,1fr)']} my={2} gridGap={[2, 4]}> <Grid templateColumns={['repeat(2,1fr)', 'repeat(3,1fr)']} my={2} gridGap={[2, 4]}>
{selectedKbList.map((item) => ( {selectedKbList.map((item) => (
<Flex <MyTooltip key={item._id} label={'查看知识库详情'}>
key={item._id} <Flex
alignItems={'center'} alignItems={'center'}
p={2} p={2}
bg={'white'} bg={'white'}
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'} boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
borderRadius={'md'} borderRadius={'md'}
border={theme.borders.base} border={theme.borders.base}
> cursor={'pointer'}
<Avatar src={item.avatar} w={'18px'} mr={1} /> onClick={() =>
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}> router.push({
{item.name} pathname: '/kb/detail',
</Box> query: {
</Flex> kbId: item._id
}
})
}
>
<Avatar src={item.avatar} w={'18px'} mr={1} />
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}>
{item.name}
</Box>
</Flex>
</MyTooltip>
))} ))}
</Grid> </Grid>
</Box> </Box>

View File

@@ -6,13 +6,8 @@ import {
FormControl, FormControl,
Input, Input,
Textarea, Textarea,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter, ModalFooter,
ModalBody, ModalBody
ModalCloseButton
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { AppSchema } from '@/types/mongoSchema'; import { AppSchema } from '@/types/mongoSchema';
@@ -23,6 +18,7 @@ import { getErrText } from '@/utils/tools';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/store/user';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/hooks/useRequest';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import MyModal from '@/components/MyModal';
const InfoModal = ({ const InfoModal = ({
defaultApp, defaultApp,
@@ -120,61 +116,56 @@ const InfoModal = ({
); );
return ( return (
<Modal isOpen={true} onClose={onClose}> <MyModal isOpen={true} onClose={onClose} title={'应用信息设置'}>
<ModalOverlay /> <ModalBody>
<ModalContent maxW={'min(90vw,470px)'}> <Box> & </Box>
<ModalHeader></ModalHeader> <Flex mt={2} alignItems={'center'}>
<ModalCloseButton /> <Avatar
<ModalBody> src={getValues('avatar')}
<Box> & </Box> w={['26px', '34px']}
<Flex mt={2} alignItems={'center'}> h={['26px', '34px']}
<Avatar cursor={'pointer'}
src={getValues('avatar')} borderRadius={'lg'}
w={['26px', '34px']} mr={4}
h={['26px', '34px']} title={'点击切换头像'}
cursor={'pointer'} onClick={() => onOpenSelectFile()}
borderRadius={'lg'} />
mr={4} <FormControl>
title={'点击切换头像'} <Input
onClick={() => onOpenSelectFile()} bg={'myWhite.600'}
/> placeholder={'给应用设置一个名称'}
<FormControl> {...register('name', {
<Input required: '展示名称不能为空'
bg={'myWhite.600'} })}
placeholder={'给应用设置一个名称'} ></Input>
{...register('name', { </FormControl>
required: '展示名称不能为空' </Flex>
})} <Box mt={7} mb={1}>
></Input>
</FormControl> </Box>
</Flex> {/* <Box color={'myGray.500'} mb={2} fontSize={'sm'}>
<Box mt={7} mb={1}>
</Box>
{/* <Box color={'myGray.500'} mb={2} fontSize={'sm'}>
该介绍主要用于记忆和在应用市场展示 该介绍主要用于记忆和在应用市场展示
</Box> */} </Box> */}
<Textarea <Textarea
rows={4} rows={4}
maxLength={500} maxLength={500}
placeholder={'给你的 AI 应用一个介绍'} placeholder={'给你的 AI 应用一个介绍'}
bg={'myWhite.600'} bg={'myWhite.600'}
{...register('intro')} {...register('intro')}
/> />
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'base'} mr={3} onClick={onClose}>
</Button> </Button>
<Button isLoading={btnLoading} onClick={saveUpdateModel}> <Button isLoading={btnLoading} onClick={saveUpdateModel}>
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent>
<File onSelect={onSelectFile} /> <File onSelect={onSelectFile} />
</Modal> </MyModal>
); );
}; };

View File

@@ -4,13 +4,9 @@ import {
Flex, Flex,
Box, Box,
Button, Button,
Modal,
ModalOverlay,
ModalContent,
ModalBody, ModalBody,
ModalHeader, ModalHeader,
ModalFooter, ModalFooter,
ModalCloseButton,
useTheme, useTheme,
Textarea Textarea
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@@ -22,6 +18,7 @@ import type { SelectedKbType } from '@/types/plugin';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import MySlider from '@/components/Slider'; import MySlider from '@/components/Slider';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
export type KbParamsType = { export type KbParamsType = {
searchSimilarity: number; searchSimilarity: number;
@@ -45,17 +42,15 @@ export const KBSelectModal = ({
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
return ( return (
<Modal isOpen={true} isCentered={!isPc} onClose={onClose}> <MyModal
<ModalOverlay /> isOpen={true}
<ModalContent isCentered={!isPc}
display={'flex'} maxW={['90vw', '800px']}
flexDirection={'column'} w={'800px'}
w={'800px'} onClose={onClose}
maxW={'90vw'} >
h={['90vh', 'auto']} <Flex flexDirection={'column'} h={['90vh', 'auto']}>
>
<ModalHeader>({selectedKbList.length})</ModalHeader> <ModalHeader>({selectedKbList.length})</ModalHeader>
<ModalCloseButton />
<ModalBody <ModalBody
flex={['1 0 0', '0 0 auto']} flex={['1 0 0', '0 0 auto']}
maxH={'80vh'} maxH={'80vh'}
@@ -115,8 +110,8 @@ export const KBSelectModal = ({
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent> </Flex>
</Modal> </MyModal>
); );
}; };
@@ -137,11 +132,8 @@ export const KbParamsModal = ({
}); });
return ( return (
<Modal isOpen={true} onClose={onClose}> <MyModal isOpen={true} onClose={onClose} title={'搜索参数调整'}>
<ModalOverlay /> <Flex flexDirection={'column'}>
<ModalContent display={'flex'} flexDirection={'column'} w={'600px'} maxW={'90vw'}>
<ModalHeader></ModalHeader>
<ModalCloseButton />
<ModalBody> <ModalBody>
<Box display={['block', 'flex']} pt={3} pb={5}> <Box display={['block', 'flex']} pt={3} pb={5}>
<Box flex={'0 0 100px'} mb={[8, 0]}> <Box flex={'0 0 100px'} mb={[8, 0]}>
@@ -214,8 +206,8 @@ export const KbParamsModal = ({
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent> </Flex>
</Modal> </MyModal>
); );
}; };

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react'; import React, { useState } from 'react';
import { import {
Flex, Flex,
Box, Box,
@@ -11,19 +11,9 @@ import {
Td, Td,
Tbody, Tbody,
useDisclosure, useDisclosure,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter, ModalFooter,
ModalBody, ModalBody,
ModalCloseButton,
FormControl, FormControl,
Slider,
SliderTrack,
SliderFilledTrack,
SliderThumb,
SliderMark,
Input Input
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
@@ -36,12 +26,12 @@ import { formatTimeToChatTime, useCopyData, getErrText } from '@/utils/tools';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { defaultShareChat } from '@/constants/model'; import { defaultShareChat } from '@/constants/model';
import type { ShareChatEditType } from '@/types/app'; import type { ShareChatEditType } from '@/types/app';
import MyTooltip from '@/components/MyTooltip';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/hooks/useRequest';
import { formatPrice } from '@/utils/user'; import { formatPrice } from '@/utils/user';
import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
const Share = ({ appId }: { appId: string }) => { const Share = ({ appId }: { appId: string }) => {
const { toast } = useToast();
const { Loading, setIsLoading } = useLoading(); const { Loading, setIsLoading } = useLoading();
const { copyData } = useCopyData(); const { copyData } = useCopyData();
const { const {
@@ -175,42 +165,41 @@ const Share = ({ appId }: { appId: string }) => {
</Flex> </Flex>
)} )}
{/* create shareChat modal */} {/* create shareChat modal */}
<Modal isOpen={isOpenCreateShareChat} onClose={onCloseCreateShareChat}> <MyModal
<ModalOverlay /> isOpen={isOpenCreateShareChat}
<ModalContent maxW={'min(90vw,500px)'}> onClose={onCloseCreateShareChat}
<ModalHeader></ModalHeader> title={'创建免登录窗口'}
<ModalCloseButton /> >
<ModalBody> <ModalBody>
<FormControl> <FormControl>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<Box flex={'0 0 60px'} w={0}> <Box flex={'0 0 60px'} w={0}>
: :
</Box> </Box>
<Input <Input
placeholder="记录名字,仅用于展示" placeholder="记录名字,仅用于展示"
maxLength={20} maxLength={20}
{...registerShareChat('name', { {...registerShareChat('name', {
required: '记录名称不能为空' required: '记录名称不能为空'
})} })}
/> />
</Flex> </Flex>
</FormControl> </FormControl>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onCloseCreateShareChat}> <Button variant={'base'} mr={3} onClick={onCloseCreateShareChat}>
</Button> </Button>
<Button <Button
isLoading={creating} isLoading={creating}
onClick={submitShareChat((data) => onclickCreateShareChat(data))} onClick={submitShareChat((data) => onclickCreateShareChat(data))}
> >
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent> </MyModal>
</Modal>
<Loading loading={isFetching} fixed={false} /> <Loading loading={isFetching} fixed={false} />
</Box> </Box>
); );

View File

@@ -2,9 +2,6 @@ import React, { useState } from 'react';
import { import {
Box, Box,
Button, Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader, ModalHeader,
ModalFooter, ModalFooter,
ModalBody, ModalBody,
@@ -28,6 +25,7 @@ import { useForm } from 'react-hook-form';
import { useFieldArray } from 'react-hook-form'; import { useFieldArray } from 'react-hook-form';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import MyModal from '@/components/MyModal';
const VariableTypeList = [ const VariableTypeList = [
{ label: '文本', icon: 'settingLight', key: VariableInputEnum.input }, { label: '文本', icon: 'settingLight', key: VariableInputEnum.input },
@@ -67,133 +65,130 @@ const VariableEditModal = ({
}); });
return ( return (
<Modal isOpen={true} onClose={onClose}> <MyModal isOpen={true} onClose={onClose}>
<ModalOverlay /> <ModalHeader display={'flex'}>
<ModalContent maxW={'Min(400px,90vw)'}> <MyIcon name={'variable'} mr={2} w={'24px'} color={'#FF8A4C'} />
<ModalHeader display={'flex'}>
<MyIcon name={'variable'} mr={2} w={'24px'} color={'#FF8A4C'} /> </ModalHeader>
<ModalBody>
</ModalHeader> <Flex alignItems={'center'}>
<ModalBody> <Box w={'70px'}></Box>
<Flex alignItems={'center'}> <Switch {...register('variable.required')} />
<Box w={'70px'}></Box> </Flex>
<Switch {...register('variable.required')} /> <Flex mt={5} alignItems={'center'}>
</Flex> <Box w={'80px'}></Box>
<Flex mt={5} alignItems={'center'}> <Input {...register('variable.label', { required: '变量名不能为空' })} />
<Box w={'80px'}></Box> </Flex>
<Input {...register('variable.label', { required: '变量名不能为空' })} /> <Flex mt={5} alignItems={'center'}>
</Flex> <Box w={'80px'}> key</Box>
<Flex mt={5} alignItems={'center'}> <Input {...register('variable.key', { required: '变量 key 不能为空' })} />
<Box w={'80px'}> key</Box> </Flex>
<Input {...register('variable.key', { required: '变量 key 不能为空' })} />
</Flex>
<Box mt={5} mb={2}> <Box mt={5} mb={2}>
</Box> </Box>
<Grid gridTemplateColumns={'repeat(2,130px)'} gridGap={4}> <Grid gridTemplateColumns={'repeat(2,130px)'} gridGap={4}>
{VariableTypeList.map((item) => ( {VariableTypeList.map((item) => (
<Flex <Flex
key={item.key} key={item.key}
px={4} px={4}
py={1} py={1}
border={theme.borders.base} border={theme.borders.base}
borderRadius={'md'} borderRadius={'md'}
cursor={'pointer'} cursor={'pointer'}
{...(item.key === getValues('variable.type') {...(item.key === getValues('variable.type')
? { ? {
bg: 'myWhite.600' bg: 'myWhite.600'
}
: {
_hover: {
boxShadow: 'md'
},
onClick: () => {
setValue('variable.type', item.key);
setRefresh(!refresh);
} }
: { })}
_hover: { >
boxShadow: 'md' <MyIcon name={item.icon as any} w={'16px'} />
}, <Box ml={3}>{item.label}</Box>
onClick: () => { </Flex>
setValue('variable.type', item.key); ))}
setRefresh(!refresh); </Grid>
}
})}
>
<MyIcon name={item.icon as any} w={'16px'} />
<Box ml={3}>{item.label}</Box>
</Flex>
))}
</Grid>
{getValues('variable.type') === VariableInputEnum.input && ( {getValues('variable.type') === VariableInputEnum.input && (
<> <>
<Box mt={5} mb={2}> <Box mt={5} mb={2}>
</Box> </Box>
<Box> <Box>
<NumberInput max={100} min={1} step={1} position={'relative'}> <NumberInput max={100} min={1} step={1} position={'relative'}>
<NumberInputField <NumberInputField
{...register('variable.maxLen', { {...register('variable.maxLen', {
min: 1, min: 1,
max: 100, max: 100,
valueAsNumber: true valueAsNumber: true
})} })}
max={100} max={100}
/> />
<NumberInputStepper> <NumberInputStepper>
<NumberIncrementStepper /> <NumberIncrementStepper />
<NumberDecrementStepper /> <NumberDecrementStepper />
</NumberInputStepper> </NumberInputStepper>
</NumberInput> </NumberInput>
</Box> </Box>
</> </>
)} )}
{getValues('variable.type') === VariableInputEnum.select && ( {getValues('variable.type') === VariableInputEnum.select && (
<> <>
<Box mt={5} mb={2}> <Box mt={5} mb={2}>
</Box> </Box>
<Box> <Box>
{selectEnums.map((item, i) => ( {selectEnums.map((item, i) => (
<Flex key={item.id} mb={2} alignItems={'center'}> <Flex key={item.id} mb={2} alignItems={'center'}>
<FormControl> <FormControl>
<Input <Input
{...register(`variable.enums.${i}.value`, { {...register(`variable.enums.${i}.value`, {
required: '选项内容不能为空' required: '选项内容不能为空'
})} })}
/>
</FormControl>
<MyIcon
ml={3}
name={'delete'}
w={'16px'}
cursor={'pointer'}
p={2}
borderRadius={'lg'}
_hover={{ bg: 'red.100' }}
onClick={() => removeEnums(i)}
/> />
</Flex> </FormControl>
))} <MyIcon
</Box> ml={3}
<Button name={'delete'}
variant={'solid'} w={'16px'}
w={'100%'} cursor={'pointer'}
textAlign={'left'} p={2}
leftIcon={<SmallAddIcon />} borderRadius={'lg'}
bg={'myGray.100 !important'} _hover={{ bg: 'red.100' }}
onClick={() => appendEnums({ value: '' })} onClick={() => removeEnums(i)}
> />
</Flex>
</Button> ))}
</> </Box>
)} <Button
</ModalBody> variant={'solid'}
w={'100%'}
textAlign={'left'}
leftIcon={<SmallAddIcon />}
bg={'myGray.100 !important'}
onClick={() => appendEnums({ value: '' })}
>
</Button>
</>
)}
</ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'base'} mr={3} onClick={onClose}>
</Button> </Button>
<Button onClick={handleSubmit(onSubmit)}></Button> <Button onClick={handleSubmit(onSubmit)}></Button>
</ModalFooter> </ModalFooter>
</ModalContent> </MyModal>
</Modal>
); );
}; };

View File

@@ -3,9 +3,6 @@ import {
Box, Box,
Flex, Flex,
Button, Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader, ModalHeader,
ModalFooter, ModalFooter,
ModalBody, ModalBody,
@@ -26,6 +23,7 @@ import { useGlobalStore } from '@/store/global';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/hooks/useRequest';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
type FormType = { type FormType = {
avatar: string; avatar: string;
@@ -92,92 +90,89 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
}); });
return ( return (
<Modal isOpen onClose={onClose} isCentered={!isPc}> <MyModal isOpen onClose={onClose} isCentered={!isPc}>
<ModalOverlay /> <ModalHeader fontSize={'2xl'}> AI </ModalHeader>
<ModalContent maxW={'min(700px,90vw)'}> <ModalBody>
<ModalHeader fontSize={'2xl'}> AI </ModalHeader> <Box color={'myGray.800'} fontWeight={'bold'}>
<ModalBody>
<Box color={'myGray.800'} fontWeight={'bold'}> </Box>
<Flex mt={3} alignItems={'center'}>
</Box> <MyTooltip label={'点击设置头像'}>
<Flex mt={3} alignItems={'center'}> <Avatar
<MyTooltip label={'点击设置头像'}> flexShrink={0}
<Avatar src={getValues('avatar')}
flexShrink={0} w={['32px', '36px']}
src={getValues('avatar')} h={['32px', '36px']}
w={['32px', '36px']} cursor={'pointer'}
h={['32px', '36px']} borderRadius={'md'}
cursor={'pointer'} onClick={onOpenSelectFile}
borderRadius={'md'}
onClick={onOpenSelectFile}
/>
</MyTooltip>
<Input
flex={1}
ml={4}
autoFocus
bg={'myWhite.600'}
{...register('name', {
required: '应用名不能为空~'
})}
/> />
</Flex> </MyTooltip>
<Box mt={[4, 7]} mb={[0, 3]} color={'myGray.800'} fontWeight={'bold'}> <Input
flex={1}
</Box> ml={4}
<Grid autoFocus
userSelect={'none'} bg={'myWhite.600'}
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']} {...register('name', {
gridGap={[2, 4]} required: '应用名不能为空~'
> })}
{appTemplates.map((item) => ( />
<Card </Flex>
key={item.id} <Box mt={[4, 7]} mb={[0, 3]} color={'myGray.800'} fontWeight={'bold'}>
border={theme.borders.base}
p={3} </Box>
borderRadius={'md'} <Grid
cursor={'pointer'} userSelect={'none'}
boxShadow={'sm'} gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']}
{...(getValues('templateId') === item.id gridGap={[2, 4]}
? { >
bg: 'myWhite.600' {appTemplates.map((item) => (
<Card
key={item.id}
border={theme.borders.base}
p={3}
borderRadius={'md'}
cursor={'pointer'}
boxShadow={'sm'}
{...(getValues('templateId') === item.id
? {
bg: 'myWhite.600'
}
: {
_hover: {
boxShadow: 'md'
} }
: { })}
_hover: { onClick={() => {
boxShadow: 'md' setValue('templateId', item.id);
} setRefresh((state) => !state);
})} }}
onClick={() => { >
setValue('templateId', item.id); <Flex alignItems={'center'}>
setRefresh((state) => !state); <Avatar src={item.avatar} borderRadius={'md'} w={'20px'} />
}} <Box ml={3} fontWeight={'bold'}>
> {item.name}
<Flex alignItems={'center'}>
<Avatar src={item.avatar} borderRadius={'md'} w={'20px'} />
<Box ml={3} fontWeight={'bold'}>
{item.name}
</Box>
</Flex>
<Box fontSize={'sm'} mt={4}>
{item.intro}
</Box> </Box>
</Card> </Flex>
))} <Box fontSize={'sm'} mt={4}>
</Grid> {item.intro}
</ModalBody> </Box>
</Card>
))}
</Grid>
</ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'base'} mr={3} onClick={onClose}>
</Button> </Button>
<Button isLoading={creating} onClick={handleSubmit((data) => onclickCreate(data))}> <Button isLoading={creating} onClick={handleSubmit((data) => onclickCreate(data))}>
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent>
<File onSelect={onSelectFile} /> <File onSelect={onSelectFile} />
</Modal> </MyModal>
); );
}; };

View File

@@ -1,23 +1,13 @@
import React, { useState, useCallback } from 'react'; import React, { useState, useCallback } from 'react';
import { import { Box, Flex, Button, Textarea, IconButton } from '@chakra-ui/react';
Box,
Flex,
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
Textarea,
IconButton
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { postKbDataFromList, putKbDataById, delOneKbDataByDataId } from '@/api/plugins/kb'; import { postKbDataFromList, putKbDataById, delOneKbDataByDataId } from '@/api/plugins/kb';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { TrainingModeEnum } from '@/constants/plugin'; import { TrainingModeEnum } from '@/constants/plugin';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import MyIcon from '@/components/Icon';
import { vectorModelList } from '@/store/static'; import { vectorModelList } from '@/store/static';
import MyIcon from '@/components/Icon';
import MyModal from '@/components/MyModal';
export type FormData = { dataId?: string; a: string; q: string }; export type FormData = { dataId?: string; a: string; q: string };
@@ -133,19 +123,15 @@ const InputDataModal = ({
); );
return ( return (
<Modal isOpen={true} onClose={onClose} isCentered> <MyModal
<ModalOverlay /> isOpen={true}
<ModalContent onClose={onClose}
m={0} isCentered
display={'flex'} title={defaultValues.dataId ? '变更数据' : '手动导入数据'}
flexDirection={'column'} w={'90vw'}
h={'90vh'} maxW={'90vw'}
maxW={'90vw'} >
position={'relative'} <Flex display={'flex'} flexDirection={'column'} h={'90vh'}>
>
<ModalHeader>{defaultValues.dataId ? '变更数据' : '手动导入数据'}</ModalHeader>
<ModalCloseButton />
<Box <Box
display={'flex'} display={'flex'}
flexDirection={['column', 'row']} flexDirection={['column', 'row']}
@@ -225,8 +211,8 @@ const InputDataModal = ({
{defaultValues.dataId ? '确认变更' : '确认导入'} {defaultValues.dataId ? '确认变更' : '确认导入'}
</Button> </Button>
</Flex> </Flex>
</ModalContent> </Flex>
</Modal> </MyModal>
); );
}; };