… chart will be displayed. ### What problem does this PR solve? feat: #345 even if the backend data returns empty, the skeleton of the chart will be displayed. ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.3.0
| @@ -50,9 +50,10 @@ const data = [ | |||
| interface IProps extends CategoricalChartProps { | |||
| data?: Array<{ xAxis: string; yAxis: number }>; | |||
| showLegend?: boolean; | |||
| } | |||
| const RagLineChart = ({ data }: IProps) => { | |||
| const RagLineChart = ({ data, showLegend = false }: IProps) => { | |||
| return ( | |||
| <ResponsiveContainer width="100%" height="100%"> | |||
| <LineChart | |||
| @@ -72,7 +73,7 @@ const RagLineChart = ({ data }: IProps) => { | |||
| <XAxis dataKey="xAxis" /> | |||
| <YAxis /> | |||
| <Tooltip /> | |||
| <Legend /> | |||
| {showLegend && <Legend />} | |||
| <Line | |||
| type="monotone" | |||
| dataKey="yAxis" | |||
| @@ -349,19 +349,18 @@ export default { | |||
| 'This sets the maximum length of the model’s output, measured in the number of tokens (words or pieces of words).', | |||
| quote: 'Show Quote', | |||
| quoteTip: 'Should the source of the original text be displayed?', | |||
| overview: 'API', | |||
| overview: 'Chat Bot API', | |||
| pv: 'Number of messages', | |||
| uv: 'Active user number', | |||
| speed: 'Token output speed', | |||
| tokens: 'Consume the token number', | |||
| round: 'Session Interaction Number', | |||
| thumbUp: 'customer satisfaction', | |||
| publicUrl: 'Public URL', | |||
| preview: 'Preview', | |||
| embedded: 'Embedded', | |||
| serviceApiEndpoint: 'Service API Endpoint', | |||
| apiKey: 'Api Key', | |||
| apiReference: 'Api Reference', | |||
| apiReference: 'API Documents', | |||
| dateRange: 'Date Range:', | |||
| backendServiceApi: 'Backend service API', | |||
| createNewKey: 'Create new key', | |||
| @@ -321,21 +321,20 @@ export default { | |||
| '這設置了模型輸出的最大長度,以標記(單詞或單詞片段)的數量來衡量。', | |||
| quote: '顯示引文', | |||
| quoteTip: '是否應該顯示原文出處?', | |||
| overview: 'API', | |||
| overview: '聊天 API', | |||
| pv: '消息數', | |||
| uv: '活躍用戶數', | |||
| speed: 'Token 輸出速度', | |||
| tokens: '消耗Token數', | |||
| round: '會話互動數', | |||
| thumbUp: '用戶滿意度', | |||
| publicUrl: '公共url', | |||
| preview: '預覽', | |||
| embedded: '嵌入', | |||
| serviceApiEndpoint: '服務API端點', | |||
| apiKey: 'API鍵', | |||
| apiReference: 'API參考', | |||
| serviceApiEndpoint: '服務 API 端點', | |||
| apiKey: 'API 鍵', | |||
| apiReference: 'API 文件', | |||
| dateRange: '日期範圍:', | |||
| backendServiceApi: '後端服務API', | |||
| backendServiceApi: '後端服務 API', | |||
| createNewKey: '創建新密鑰', | |||
| created: '創建於', | |||
| action: '操作', | |||
| @@ -338,21 +338,20 @@ export default { | |||
| '这设置了模型输出的最大长度,以标记(单词或单词片段)的数量来衡量。', | |||
| quote: '显示引文', | |||
| quoteTip: '是否应该显示原文出处?', | |||
| overview: 'API', | |||
| overview: '聊天 API', | |||
| pv: '消息数', | |||
| uv: '活跃用户数', | |||
| speed: 'Token 输出速度', | |||
| tokens: '消耗Token数', | |||
| round: '会话互动数', | |||
| thumbUp: '用户满意度', | |||
| publicUrl: '公共Url', | |||
| preview: '预览', | |||
| embedded: '嵌入', | |||
| serviceApiEndpoint: '服务API端点', | |||
| apiKey: 'API键', | |||
| apiReference: 'API参考', | |||
| apiKey: 'API 键', | |||
| apiReference: 'API 文档', | |||
| dateRange: '日期范围:', | |||
| backendServiceApi: '后端服务API', | |||
| backendServiceApi: '后端服务 API', | |||
| createNewKey: '创建新密钥', | |||
| created: '创建于', | |||
| action: '操作', | |||
| @@ -50,7 +50,9 @@ const ChatApiKeyModal = ({ | |||
| title={t('apiKey')} | |||
| open={visible} | |||
| onCancel={hideModal} | |||
| cancelButtonProps={{ style: { display: 'none' } }} | |||
| style={{ top: 300 }} | |||
| onOk={hideModal} | |||
| width={'50vw'} | |||
| > | |||
| <Table | |||
| @@ -5,7 +5,7 @@ | |||
| .chartItem { | |||
| height: 300px; | |||
| padding: 10px 0 30px; | |||
| padding: 10px 0 50px; | |||
| } | |||
| .chartLabel { | |||
| @@ -2,6 +2,7 @@ import LineChart from '@/components/line-chart'; | |||
| import { useSetModalState, useTranslate } from '@/hooks/commonHooks'; | |||
| import { IModalProps } from '@/interfaces/common'; | |||
| import { IDialog, IStats } from '@/interfaces/database/chat'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import { Button, Card, DatePicker, Flex, Modal, Space, Typography } from 'antd'; | |||
| import { RangePickerProps } from 'antd/es/date-picker'; | |||
| import dayjs from 'dayjs'; | |||
| @@ -19,13 +20,29 @@ import styles from './index.less'; | |||
| const { Paragraph } = Typography; | |||
| const { RangePicker } = DatePicker; | |||
| const StatsLineChart = ({ statsType }: { statsType: keyof IStats }) => { | |||
| const { t } = useTranslate('chat'); | |||
| const chartList = useSelectChartStatsList(); | |||
| const list = | |||
| chartList[statsType]?.map((x) => ({ | |||
| ...x, | |||
| xAxis: formatDate(x.xAxis), | |||
| })) ?? []; | |||
| return ( | |||
| <div className={styles.chartItem}> | |||
| <b className={styles.chartLabel}>{t(camelCase(statsType))}</b> | |||
| <LineChart data={list}></LineChart> | |||
| </div> | |||
| ); | |||
| }; | |||
| const ChatOverviewModal = ({ | |||
| visible, | |||
| hideModal, | |||
| dialog, | |||
| }: IModalProps<any> & { dialog: IDialog }) => { | |||
| const { t } = useTranslate('chat'); | |||
| const chartList = useSelectChartStatsList(); | |||
| const { | |||
| visible: apiKeyVisible, | |||
| hideModal: hideApiKeyModal, | |||
| @@ -53,6 +70,8 @@ const ChatOverviewModal = ({ | |||
| title={t('overview')} | |||
| open={visible} | |||
| onCancel={hideModal} | |||
| cancelButtonProps={{ style: { display: 'none' } }} | |||
| onOk={hideModal} | |||
| width={'100vw'} | |||
| > | |||
| <Flex vertical gap={'middle'}> | |||
| @@ -76,14 +95,8 @@ const ChatOverviewModal = ({ | |||
| </a> | |||
| </Space> | |||
| </Card> | |||
| <Card title={dialog.name}> | |||
| <Card title={`${dialog.name} Web App`}> | |||
| <Flex gap={8} vertical> | |||
| {t('publicUrl')} | |||
| {/* <Flex className={styles.linkText} gap={10}> | |||
| <span>{urlWithToken}</span> | |||
| <CopyToClipboard text={urlWithToken}></CopyToClipboard> | |||
| <ReloadOutlined onClick={createUrlToken} /> | |||
| </Flex> */} | |||
| <Space size={'middle'}> | |||
| <Button onClick={handlePreview}>{t('preview')}</Button> | |||
| <Button onClick={showEmbedModal}>{t('embedded')}</Button> | |||
| @@ -101,12 +114,12 @@ const ChatOverviewModal = ({ | |||
| /> | |||
| </Space> | |||
| <div className={styles.chartWrapper}> | |||
| {Object.keys(chartList).map((x) => ( | |||
| <div key={x} className={styles.chartItem}> | |||
| <b className={styles.chartLabel}>{t(camelCase(x))}</b> | |||
| <LineChart data={chartList[x as keyof IStats]}></LineChart> | |||
| </div> | |||
| ))} | |||
| <StatsLineChart statsType={'pv'}></StatsLineChart> | |||
| <StatsLineChart statsType={'round'}></StatsLineChart> | |||
| <StatsLineChart statsType={'speed'}></StatsLineChart> | |||
| <StatsLineChart statsType={'thumb_up'}></StatsLineChart> | |||
| <StatsLineChart statsType={'tokens'}></StatsLineChart> | |||
| <StatsLineChart statsType={'uv'}></StatsLineChart> | |||
| </div> | |||
| </Flex> | |||
| <ChatApiKeyModal | |||
| @@ -210,6 +210,7 @@ const model: DvaModel<ChatModelState> = { | |||
| omit(payload, ['dialogId']), | |||
| ); | |||
| if (data.retcode === 0) { | |||
| message.success(i18n.t('message.deleted')); | |||
| yield put({ | |||
| type: 'listToken', | |||
| payload: { dialog_id: payload.dialogId }, | |||