fix: bill, app detail

This commit is contained in:
archer
2023-07-19 08:36:06 +08:00
parent 58cbf10c85
commit 7a76f54148
12 changed files with 64 additions and 42 deletions

View File

@@ -27,19 +27,20 @@ import { useMarkdown } from '@/hooks/useMarkdown';
import { AppModuleItemType, VariableItemType } from '@/types/app';
import { SystemInputEnum, VariableInputEnum } from '@/constants/app';
import { useForm } from 'react-hook-form';
import MySelect from '@/components/Select';
import { MessageItemType } from '@/pages/api/openapi/v1/chat/completions';
import MyTooltip from '../MyTooltip';
import { fileDownload } from '@/utils/file';
import { htmlTemplate } from '@/constants/common';
import { useRouter } from 'next/router';
import { useGlobalStore } from '@/store/global';
import dynamic from 'next/dynamic';
const QuoteModal = dynamic(() => import('./QuoteModal'));
import styles from './index.module.scss';
import { QuoteItemType } from '@/pages/api/app/modules/kb/search';
import { FlowModuleTypeEnum } from '@/constants/flow';
import MyTooltip from '../MyTooltip';
import MySelect from '@/components/Select';
import styles from './index.module.scss';
const textareaMinH = '22px';
export type StartChatFnProps = {
@@ -139,6 +140,7 @@ const ChatBox = (
const { copyData } = useCopyData();
const { toast } = useToast();
const { userInfo } = useUserStore();
const { isPc } = useGlobalStore();
const TextareaDom = useRef<HTMLTextAreaElement>(null);
const controller = useRef(new AbortController());
@@ -312,7 +314,7 @@ const ChatBox = (
setTimeout(() => {
generatingScroll();
TextareaDom.current?.focus();
isPc && TextareaDom.current?.focus();
}, 100);
} catch (err: any) {
toast({
@@ -342,13 +344,13 @@ const ChatBox = (
[
isChatting,
chatHistory,
setChatHistory,
resetInputVal,
toast,
scrollToBottom,
onStartChat,
generatingMessage,
generatingScroll
generatingScroll,
isPc
]
);

View File

@@ -11,7 +11,7 @@ export enum OpenAiChatEnum {
export const defaultApp: AppSchema = {
_id: '',
userId: 'userId',
name: '模型名称',
name: '模型加载中',
avatar: '/icon/logo.png',
intro: '',
updateTime: Date.now(),

View File

@@ -39,8 +39,12 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
const { kb_ids = [], userChatInput } = req.body as Props;
if (!userChatInput || !Array.isArray(kb_ids)) {
throw new Error('params is error');
if (!userChatInput) {
throw new Error('用户输入为空');
}
if (!Array.isArray(kb_ids) || kb_ids.length === 0) {
throw new Error('没有选择知识库');
}
const result = await kbSearch({

View File

@@ -27,7 +27,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
_id: item._id,
shareId: item.shareId,
name: item.name,
tokens: item.tokens,
total: item.total,
maxContext: item.maxContext,
lastTime: item.lastTime
}))

View File

@@ -188,7 +188,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// bill
finishTaskBill({
billId
billId,
shareId
});
} catch (err: any) {
delTaskBill(billId);

View File

@@ -51,17 +51,8 @@ const Settings = ({ appId }: { appId: string }) => {
}, [appDetail, setIsLoading, toast, router]);
// load app data
const { isLoading, refetch } = useQuery([appId], () => loadAppDetail(appId, true), {
onError(err: any) {
toast({
title: err?.message || '获取应用异常',
status: 'error'
});
router.replace('/app/list');
},
onSettled() {
router.prefetch(`/chat?appId=${appId}`);
}
const { refetch } = useQuery([appId], () => loadAppDetail(appId, true), {
enabled: false
});
return (
@@ -168,7 +159,7 @@ const Settings = ({ appId }: { appId: string }) => {
)}
<ConfirmChild />
<Loading loading={isLoading} fixed={false} />
<Loading fixed={false} />
</Flex>
);
};

View File

@@ -38,6 +38,7 @@ import { defaultShareChat } from '@/constants/model';
import type { ShareChatEditType } from '@/types/app';
import MyTooltip from '@/components/MyTooltip';
import { useRequest } from '@/hooks/useRequest';
import { formatPrice } from '@/utils/user';
const Share = ({ appId }: { appId: string }) => {
const { toast } = useToast();
@@ -82,12 +83,6 @@ const Share = ({ appId }: { appId: string }) => {
}
});
// format share used token
const formatTokens = (tokens: number) => {
if (tokens < 10000) return tokens;
return `${(tokens / 10000).toFixed(2)}`;
};
return (
<Box position={'relative'} pt={[0, 5, 8]} px={[5, 8]} minH={'50vh'}>
<Flex justifyContent={'space-between'}>
@@ -118,7 +113,7 @@ const Share = ({ appId }: { appId: string }) => {
<Tr>
<Th></Th>
<Th></Th>
<Th>tokens消</Th>
<Th></Th>
<Th>使</Th>
<Th></Th>
</Tr>
@@ -128,7 +123,7 @@ const Share = ({ appId }: { appId: string }) => {
<Tr key={item._id}>
<Td>{item.name}</Td>
<Td>{item.maxContext}</Td>
<Td>{formatTokens(item.tokens)}</Td>
<Td>{formatPrice(item.total)}</Td>
<Td>{item.lastTime ? formatTimeToChatTime(item.lastTime) : '未使用'}</Td>
<Td>
<Flex>

View File

@@ -4,6 +4,8 @@ import { Box, Flex, IconButton, useTheme } from '@chakra-ui/react';
import { useUserStore } from '@/store/user';
import dynamic from 'next/dynamic';
import { defaultApp } from '@/constants/model';
import { useToast } from '@/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import Tabs from '@/components/Tabs';
import SideTabs from '@/components/SideTabs';
@@ -28,8 +30,9 @@ enum TabEnum {
const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const router = useRouter();
const theme = useTheme();
const { toast } = useToast();
const { appId } = router.query as { appId: string };
const { appDetail = defaultApp, clearAppModules } = useUserStore();
const { appDetail = defaultApp, loadAppDetail, clearAppModules } = useUserStore();
const setCurrentTab = useCallback(
(tab: `${TabEnum}`) => {
@@ -65,6 +68,19 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
};
}, []);
useQuery([appId], () => loadAppDetail(appId, true), {
onError(err: any) {
toast({
title: err?.message || '获取应用异常',
status: 'error'
});
router.replace('/app/list');
},
onSettled() {
router.prefetch(`/chat?appId=${appId}`);
}
});
return (
<PageContainer>
<Flex flexDirection={['column', 'row']} h={'100%'}>

View File

@@ -47,7 +47,7 @@ export const pushTaskBillListItem = async ({
});
} catch (error) {}
};
export const finishTaskBill = async ({ billId }: { billId: string }) => {
export const finishTaskBill = async ({ billId, shareId }: { billId: string; shareId?: string }) => {
try {
// update bill
const res = await Bill.findByIdAndUpdate(billId, [
@@ -63,6 +63,13 @@ export const finishTaskBill = async ({ billId }: { billId: string }) => {
if (!res) return;
const total = res.list.reduce((sum, item) => sum + item.amount, 0) || 0;
if (shareId) {
updateShareChatBill({
shareId,
total
});
}
console.log('finish bill:', formatPrice(total));
// 账号扣费
@@ -85,16 +92,19 @@ export const delTaskBill = async (billId?: string) => {
export const updateShareChatBill = async ({
shareId,
tokens
total
}: {
shareId: string;
tokens: number;
total: number;
}) => {
try {
await ShareChat.findByIdAndUpdate(shareId, {
$inc: { tokens },
lastTime: new Date()
});
await ShareChat.findOneAndUpdate(
{ shareId },
{
$inc: { total },
lastTime: new Date()
}
);
} catch (error) {
console.log('update shareChat error', error);
}

View File

@@ -20,7 +20,7 @@ const ShareChatSchema = new Schema({
type: String,
required: true
},
tokens: {
total: {
type: Number,
default: 0
},

View File

@@ -25,7 +25,10 @@ export const generateToken = (userId: string) => {
/* set cookie */
export const setCookie = (res: NextApiResponse, userId: string) => {
res.setHeader('Set-Cookie', `token=${generateToken(userId)}; Path=/; HttpOnly; Max-Age=604800`);
res.setHeader(
'Set-Cookie',
`token=${generateToken(userId)}; Path=/; HttpOnly; Max-Age=604800; Samesite=None; Secure;`
);
};
/* clear cookie */
export const clearCookie = (res: NextApiResponse) => {

View File

@@ -137,7 +137,7 @@ export interface ShareChatSchema {
userId: string;
appId: string;
name: string;
tokens: number;
total: number;
maxContext: number;
lastTime: Date;
}