From 55d0ed9de6f1f086f67347cf1e3a01a0eff5ed6e Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Tue, 6 Jun 2023 22:07:55 +0800 Subject: [PATCH] feat: inform --- Dockerfile | 1 + src/api/user.ts | 8 +- src/components/Badge/index.tsx | 42 ++++++++ src/components/Icon/icons/inform.svg | 1 + src/components/Icon/index.tsx | 3 +- src/components/Layout/index.tsx | 13 ++- src/components/Layout/navbar.tsx | 69 +++++++------ src/components/Layout/navbarPhone.tsx | 21 ++-- src/constants/theme.ts | 3 + src/constants/user.ts | 10 ++ src/pages/api/user/inform/countUnread.ts | 31 ++++++ src/pages/api/user/inform/list.ts | 40 ++++++++ src/pages/api/user/inform/read.ts | 29 ++++++ src/pages/api/user/inform/send.ts | 61 ++++++++++++ src/pages/number/components/BillTable.tsx | 24 ++++- src/pages/number/components/InformTable.tsx | 91 +++++++++++++++++ .../number/components/PayRecordTable.tsx | 98 ++++++++++++------- .../number/components/PromotionTable.tsx | 22 ++++- src/pages/number/index.tsx | 43 +++++--- src/service/models/inform.ts | 40 ++++++++ src/service/mongo.ts | 1 + src/types/mongoSchema.d.ts | 12 ++- 22 files changed, 561 insertions(+), 102 deletions(-) create mode 100644 src/components/Badge/index.tsx create mode 100644 src/components/Icon/icons/inform.svg create mode 100644 src/pages/api/user/inform/countUnread.ts create mode 100644 src/pages/api/user/inform/list.ts create mode 100644 src/pages/api/user/inform/read.ts create mode 100644 src/pages/api/user/inform/send.ts create mode 100644 src/pages/number/components/InformTable.tsx create mode 100644 src/service/models/inform.ts diff --git a/Dockerfile b/Dockerfile index 5b312044a..256f77e8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ WORKDIR /app # Install dependencies based on the preferred package manager COPY package.json pnpm-lock.yaml* ./ +RUN pnpm config set registry https://registry.npmmirror.com/ RUN \ [ -f pnpm-lock.yaml ] && pnpm install || \ (echo "Lockfile not found." && exit 1) diff --git a/src/api/user.ts b/src/api/user.ts index 0d156f153..76bf88127 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -4,7 +4,7 @@ import { ResLogin, PromotionRecordType } from './response/user'; import { UserAuthTypeEnum } from '@/constants/common'; import { UserBillType, UserType, UserUpdateParams } from '@/types/user'; import type { PagingData, RequestPaging } from '@/types'; -import { PaySchema } from '@/types/mongoSchema'; +import { informSchema, PaySchema } from '@/types/mongoSchema'; export const sendAuthCode = (data: { username: string; @@ -81,3 +81,9 @@ export const checkPayResult = (payId: string) => GET(`/user/checkPayResu /* promotion records */ export const getPromotionRecords = (data: RequestPaging) => GET(`/user/promotion/getPromotions?${Obj2Query(data)}`); + +export const getInforms = (data: RequestPaging) => + POST>(`/user/inform/list`, data); + +export const getUnreadCount = () => GET(`/user/inform/countUnread`); +export const readInform = (id: string) => GET(`/user/inform/read`, { id }); diff --git a/src/components/Badge/index.tsx b/src/components/Badge/index.tsx new file mode 100644 index 000000000..afacd520e --- /dev/null +++ b/src/components/Badge/index.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { Box } from '@chakra-ui/react'; + +const Badge = ({ + children, + isDot = false, + max = 99, + count = 0 +}: { + children: React.ReactNode; + isDot?: boolean; + max?: number; + count?: number; +}) => { + return ( + + {children} + {count > 0 && ( + + {isDot ? ( + + ) : ( + + {count > max ? `${max}+` : count} + + )} + + )} + + ); +}; + +export default Badge; diff --git a/src/components/Icon/icons/inform.svg b/src/components/Icon/icons/inform.svg new file mode 100644 index 000000000..04de1b7af --- /dev/null +++ b/src/components/Icon/icons/inform.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/Icon/index.tsx b/src/components/Icon/index.tsx index 3ebb82146..7a5585709 100644 --- a/src/components/Icon/index.tsx +++ b/src/components/Icon/index.tsx @@ -28,7 +28,8 @@ const map = { kb: require('./icons/kb.svg').default, appStore: require('./icons/appStore.svg').default, menu: require('./icons/menu.svg').default, - edit: require('./icons/edit.svg').default + edit: require('./icons/edit.svg').default, + inform: require('./icons/inform.svg').default }; export type IconName = keyof typeof map; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 98df102c2..b29e6954a 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -7,6 +7,9 @@ import { throttle } from 'lodash'; import Auth from './auth'; import Navbar from './navbar'; import NavbarPhone from './navbarPhone'; +import { useQuery } from '@tanstack/react-query'; +import { useUserStore } from '@/store/user'; +import { getUnreadCount } from '@/api/user'; const pcUnShowLayoutRoute: Record = { '/': true, @@ -24,6 +27,7 @@ const Layout = ({ children }: { children: JSX.Element }) => { const { colorMode, setColorMode } = useColorMode(); const { Loading } = useLoading(); const { loading, setScreenWidth, isPc } = useGlobalStore(); + const { userInfo } = useUserStore(); const isChatPage = useMemo( () => router.pathname === '/chat' && Object.values(router.query).join('').length !== 0, @@ -49,6 +53,11 @@ const Layout = ({ children }: { children: JSX.Element }) => { }; }, [setScreenWidth]); + const { data: unread = 0 } = useQuery(['getUnreadCount'], getUnreadCount, { + enabled: !!userInfo, + refetchInterval: 5000 + }); + return ( <> { ) : ( <> - + {children} @@ -76,7 +85,7 @@ const Layout = ({ children }: { children: JSX.Element }) => { {children} - + )} diff --git a/src/components/Layout/navbar.tsx b/src/components/Layout/navbar.tsx index e37c1c8a7..75114791e 100644 --- a/src/components/Layout/navbar.tsx +++ b/src/components/Layout/navbar.tsx @@ -1,18 +1,20 @@ import React, { useMemo } from 'react'; -import { Box, Flex, Tooltip } from '@chakra-ui/react'; +import { Box, Flex, Tooltip, Link } from '@chakra-ui/react'; import { useRouter } from 'next/router'; import MyIcon from '../Icon'; import { useUserStore } from '@/store/user'; import { useChatStore } from '@/store/chat'; import Avatar from '../Avatar'; import { HUMAN_ICON } from '@/constants/chat'; +import NextLink from 'next/link'; +import Badge from '../Badge'; export enum NavbarTypeEnum { normal = 'normal', small = 'small' } -const Navbar = () => { +const Navbar = ({ unread }: { unread: number }) => { const router = useRouter(); const { userInfo, lastModelId } = useUserStore(); const { lastChatModelId, lastChatId } = useChatStore(); @@ -58,6 +60,20 @@ const Navbar = () => { [lastChatId, lastChatModelId, lastModelId] ); + const itemStyles: any = { + mb: 3, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + cursor: 'pointer', + w: '60px', + h: '45px', + _hover: { + color: '#ffffff' + } + }; + return ( { openDelay={100} gutter={-10} > - { - if (item.link === router.asPath) return; - router.push(item.link); - }} - cursor={'pointer'} - w={'60px'} - h={'45px'} - _hover={{ - color: '#ffffff' - }} + { })} > - + ))} + {unread > 0 && ( + + + + + + + + )} - window.open('https://github.com/c121914yu/FastGPT')} > - + ); diff --git a/src/components/Layout/navbarPhone.tsx b/src/components/Layout/navbarPhone.tsx index b1961b27d..26b8d482a 100644 --- a/src/components/Layout/navbarPhone.tsx +++ b/src/components/Layout/navbarPhone.tsx @@ -3,8 +3,9 @@ import { useRouter } from 'next/router'; import MyIcon from '../Icon'; import { Flex } from '@chakra-ui/react'; import { useChatStore } from '@/store/chat'; +import Badge from '../Badge'; -const NavbarPhone = () => { +const NavbarPhone = ({ unread }: { unread: number }) => { const router = useRouter(); const { lastChatModelId, lastChatId } = useChatStore(); const navbarList = useMemo( @@ -12,25 +13,29 @@ const NavbarPhone = () => { { icon: 'tabbarChat', link: `/chat?modelId=${lastChatModelId}&chatId=${lastChatId}`, - activeLink: ['/chat'] + activeLink: ['/chat'], + unread: 0 }, { icon: 'tabbarModel', link: `/model`, - activeLink: ['/model'] + activeLink: ['/model'], + unread: 0 }, { icon: 'tabbarMore', link: '/tools', - activeLink: ['/tools'] + activeLink: ['/tools'], + unread: 0 }, { icon: 'tabbarMe', link: '/number', - activeLink: ['/number'] + activeLink: ['/number'], + unread } ], - [lastChatId, lastChatModelId] + [lastChatId, lastChatModelId, unread] ); return ( @@ -82,7 +87,9 @@ const NavbarPhone = () => { router.push(item.link); }} > - + + + ))} diff --git a/src/constants/theme.ts b/src/constants/theme.ts index aa1eb4b51..c8db64557 100644 --- a/src/constants/theme.ts +++ b/src/constants/theme.ts @@ -203,6 +203,9 @@ export const theme = extendTheme({ 800: '#2152d9', 900: '#1237b3', 1000: '#07228c' + }, + myRead: { + 600: '#ff4d4f' } }, fonts: { diff --git a/src/constants/user.ts b/src/constants/user.ts index 52c0428fc..c4edb6c1c 100644 --- a/src/constants/user.ts +++ b/src/constants/user.ts @@ -30,3 +30,13 @@ export const PromotionTypeMap = { [PromotionEnum.shareModel]: '应用分享', [PromotionEnum.withdraw]: '提现' }; + +export enum InformTypeEnum { + system = 'system' +} + +export const InformTypeMap = { + [InformTypeEnum.system]: { + label: '系统通知' + } +}; diff --git a/src/pages/api/user/inform/countUnread.ts b/src/pages/api/user/inform/countUnread.ts new file mode 100644 index 000000000..94fdc56f5 --- /dev/null +++ b/src/pages/api/user/inform/countUnread.ts @@ -0,0 +1,31 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/service/response'; +import { connectToDatabase, Inform } from '@/service/mongo'; +import { authUser } from '@/service/utils/auth'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!req.headers.cookie) { + return jsonRes(res, { + data: 0 + }); + } + const { userId } = await authUser({ req, authToken: true }); + + await connectToDatabase(); + + const data = await Inform.countDocuments({ + userId, + read: false + }); + + jsonRes(res, { + data + }); + } catch (err) { + jsonRes(res, { + data: 0 + }); + } +} diff --git a/src/pages/api/user/inform/list.ts b/src/pages/api/user/inform/list.ts new file mode 100644 index 000000000..93d394bf4 --- /dev/null +++ b/src/pages/api/user/inform/list.ts @@ -0,0 +1,40 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/service/response'; +import { connectToDatabase, Inform } from '@/service/mongo'; +import { authUser } from '@/service/utils/auth'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { userId } = await authUser({ req, authToken: true }); + + const { pageNum, pageSize = 10 } = req.body as { + pageNum: number; + pageSize: number; + }; + + await connectToDatabase(); + + const [informs, total] = await Promise.all([ + Inform.find({ userId }) + .sort({ time: -1 }) // 按照创建时间倒序排列 + .skip((pageNum - 1) * pageSize) + .limit(pageSize), + Inform.countDocuments({ userId }) + ]); + + jsonRes(res, { + data: { + pageNum, + pageSize, + data: informs, + total + } + }); + } catch (err) { + jsonRes(res, { + code: 500, + error: err + }); + } +} diff --git a/src/pages/api/user/inform/read.ts b/src/pages/api/user/inform/read.ts new file mode 100644 index 000000000..c7fcb2b3e --- /dev/null +++ b/src/pages/api/user/inform/read.ts @@ -0,0 +1,29 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/service/response'; +import { connectToDatabase, Inform } from '@/service/mongo'; +import { authUser } from '@/service/utils/auth'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { userId } = await authUser({ req, authToken: true }); + + await connectToDatabase(); + + const { id } = req.query as { id: string }; + + await Inform.findOneAndUpdate( + { + _id: id, + userId + }, + { + read: true + } + ); + + jsonRes(res); + } catch (err) { + jsonRes(res); + } +} diff --git a/src/pages/api/user/inform/send.ts b/src/pages/api/user/inform/send.ts new file mode 100644 index 000000000..462de1185 --- /dev/null +++ b/src/pages/api/user/inform/send.ts @@ -0,0 +1,61 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/service/response'; +import { connectToDatabase, Inform, User } from '@/service/mongo'; +import { authUser } from '@/service/utils/auth'; +import { InformTypeEnum } from '@/constants/user'; + +export type Props = { + type: `${InformTypeEnum}`; + title: string; + content: string; + userId?: string; +}; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + await authUser({ req, authRoot: true }); + + await connectToDatabase(); + + jsonRes(res, { + data: await sendInform(req.body), + message: '发送通知成功' + }); + } catch (err) { + jsonRes(res, { + code: 500, + error: err + }); + } +} + +export async function sendInform({ type, title, content, userId }: Props) { + if (!type || !title || !content) { + return Promise.reject('参数错误'); + } + + if (userId) { + await Inform.create({ + type, + title, + content, + userId + }); + + return; + } + + // send to all user + const users = await User.find({}, '_id'); + await Inform.insertMany( + users.map(({ _id }) => ({ + type, + title, + content, + userId: _id + })) + ); + + return; +} diff --git a/src/pages/number/components/BillTable.tsx b/src/pages/number/components/BillTable.tsx index e7d9182ca..d21352d8f 100644 --- a/src/pages/number/components/BillTable.tsx +++ b/src/pages/number/components/BillTable.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import { Table, Thead, Tbody, Tr, Th, Td, TableContainer, Flex } from '@chakra-ui/react'; +import { Table, Thead, Tbody, Tr, Th, Td, TableContainer, Flex, Box } from '@chakra-ui/react'; import { BillTypeMap } from '@/constants/user'; import { getUserBills } from '@/api/user'; import type { UserBillType } from '@/types/user'; import { usePagination } from '@/hooks/usePagination'; import { useLoading } from '@/hooks/useLoading'; import dayjs from 'dayjs'; +import MyIcon from '@/components/Icon'; const BillTable = () => { const { Loading } = useLoading(); @@ -13,7 +14,9 @@ const BillTable = () => { const { data: bills, isLoading, - Pagination + Pagination, + pageSize, + total } = usePagination({ api: getUserBills }); @@ -48,9 +51,20 @@ const BillTable = () => { - - - + + {!isLoading && bills.length === 0 && ( + + + + 无使用记录~ + + + )} + {total > pageSize && ( + + + + )} ); }; diff --git a/src/pages/number/components/InformTable.tsx b/src/pages/number/components/InformTable.tsx new file mode 100644 index 000000000..8194b1cf6 --- /dev/null +++ b/src/pages/number/components/InformTable.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { + Box, + Flex, + Accordion, + AccordionItem, + AccordionButton, + AccordionPanel, + AccordionIcon +} from '@chakra-ui/react'; +import { getInforms, readInform } from '@/api/user'; +import { usePagination } from '@/hooks/usePagination'; +import { useLoading } from '@/hooks/useLoading'; +import type { informSchema } from '@/types/mongoSchema'; +import { formatTimeToChatTime } from '@/utils/tools'; +import MyIcon from '@/components/Icon'; + +const BillTable = () => { + const { Loading } = useLoading(); + + const { + data: informs, + isLoading, + total, + pageSize, + Pagination, + getData, + pageNum + } = usePagination({ + api: getInforms + }); + + return ( + <> + + {informs.map((item) => ( + { + if (!item.read) { + await readInform(item._id); + getData(pageNum); + } + }} + > + + + + {!item.read && ( + + )} + {item.title} + + + {formatTimeToChatTime(item.time)} + + + + + + {item.content} + + ))} + + {!isLoading && informs.length === 0 && ( + + + + 暂无通知~ + + + )} + {total > pageSize && ( + + + + )} + + + ); +}; + +export default BillTable; diff --git a/src/pages/number/components/PayRecordTable.tsx b/src/pages/number/components/PayRecordTable.tsx index 14fc34f28..11c1d4966 100644 --- a/src/pages/number/components/PayRecordTable.tsx +++ b/src/pages/number/components/PayRecordTable.tsx @@ -1,5 +1,16 @@ import React, { useState, useCallback } from 'react'; -import { Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react'; +import { + Button, + Table, + Thead, + Tbody, + Tr, + Th, + Td, + TableContainer, + Flex, + Box +} from '@chakra-ui/react'; import { getPayOrders, checkPayResult } from '@/api/user'; import { PaySchema } from '@/types/mongoSchema'; import dayjs from 'dayjs'; @@ -7,15 +18,17 @@ import { useQuery } from '@tanstack/react-query'; import { formatPrice } from '@/utils/user'; import { useGlobalStore } from '@/store/global'; import { useToast } from '@/hooks/useToast'; +import { useLoading } from '@/hooks/useLoading'; +import MyIcon from '@/components/Icon'; const PayRecordTable = () => { + const { Loading, setIsLoading } = useLoading(); const [payOrders, setPayOrders] = useState([]); - const { setLoading } = useGlobalStore(); const { toast } = useToast(); const handleRefreshPayOrder = useCallback( async (payId: string) => { - setLoading(true); + setIsLoading(true); try { const data = await checkPayResult(payId); @@ -33,50 +46,61 @@ const PayRecordTable = () => { console.log(error); } - setLoading(false); + setIsLoading(false); }, - [setLoading, toast] + [setIsLoading, toast] ); - useQuery(['initPayOrder'], getPayOrders, { + const { isInitialLoading } = useQuery(['initPayOrder'], getPayOrders, { onSuccess(res) { setPayOrders(res); } }); return ( - - - - - - - - - - - - - {payOrders.map((item) => ( - - - - - - + <> + +
订单号时间金额状态
{item.orderId} - {item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'} - {formatPrice(item.price)}元{item.status} - {item.status === 'NOTPAY' && ( - - )} -
+ + + + + + + - ))} - -
订单号时间金额状态
-
+ + + {payOrders.map((item) => ( + + {item.orderId} + + {item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'} + + {formatPrice(item.price)}元 + {item.status} + + {item.status === 'NOTPAY' && ( + + )} + + + ))} + + + + {!isInitialLoading && payOrders.length === 0 && ( + + + + 无支付记录~ + + + )} + + ); }; diff --git a/src/pages/number/components/PromotionTable.tsx b/src/pages/number/components/PromotionTable.tsx index 2ddcb0f70..65686d64b 100644 --- a/src/pages/number/components/PromotionTable.tsx +++ b/src/pages/number/components/PromotionTable.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import { Flex, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react'; +import { Flex, Table, Thead, Tbody, Tr, Th, Td, TableContainer, Box } from '@chakra-ui/react'; import { useLoading } from '@/hooks/useLoading'; import dayjs from 'dayjs'; import { getPromotionRecords } from '@/api/user'; import { usePagination } from '@/hooks/usePagination'; import { PromotionRecordType } from '@/api/response/user'; import { PromotionTypeMap } from '@/constants/user'; +import MyIcon from '@/components/Icon'; const OpenApi = () => { const { Loading } = useLoading(); @@ -13,6 +14,8 @@ const OpenApi = () => { const { data: promotionRecords, isLoading, + total, + pageSize, Pagination } = usePagination({ api: getPromotionRecords @@ -44,9 +47,20 @@ const OpenApi = () => { - - - + + {!isLoading && promotionRecords.length === 0 && ( + + + + 无佣金记录~ + + + )} + {total > pageSize && ( + + + + )} ); }; diff --git a/src/pages/number/index.tsx b/src/pages/number/index.tsx index ed670488f..9c34d3158 100644 --- a/src/pages/number/index.tsx +++ b/src/pages/number/index.tsx @@ -43,6 +43,10 @@ const PromotionTable = dynamic(() => import('./components/PromotionTable'), { loading: () => , ssr: false }); +const InformTable = dynamic(() => import('./components/InformTable'), { + loading: () => , + ssr: false +}); const PayModal = dynamic(() => import('./components/PayModal'), { loading: () => , ssr: false @@ -55,14 +59,16 @@ const WxConcat = dynamic(() => import('@/components/WxConcat'), { enum TableEnum { 'bill' = 'bill', 'pay' = 'pay', - 'promotion' = 'promotion' + 'promotion' = 'promotion', + 'inform' = 'inform' } -const NumberSetting = () => { - const tableType = useRef([ - { label: '账单详情', value: TableEnum.bill, Component: BilTable }, - { label: '充值记录', value: TableEnum.pay, Component: PayRecordTable }, - { label: '佣金记录', value: TableEnum.pay, Component: PromotionTable } +const NumberSetting = ({ tableType }: { tableType: `${TableEnum}` }) => { + const tableList = useRef([ + { label: '账单', value: TableEnum.bill, Component: BilTable }, + { label: '充值', value: TableEnum.pay, Component: PayRecordTable }, + { label: '佣金', value: TableEnum.promotion, Component: PromotionTable }, + { label: '通知', value: TableEnum.inform, Component: InformTable } ]); const router = useRouter(); const { copyData } = useCopyData(); @@ -232,21 +238,26 @@ const NumberSetting = () => { colorScheme={'myBlue'} onClick={onOpenWxConcat} > - 提现 + {residueAmount < 50 ? '50元起提' : '提现'} - + item.value === tableType)} + onChange={(i) => router.replace(`/number?type=${tableList.current[i].value}`)} + > - {tableType.current.map((item) => ( + {tableList.current.map((item) => ( @@ -255,7 +266,7 @@ const NumberSetting = () => { ))} - {tableType.current.map((Item) => ( + {tableList.current.map((Item) => ( @@ -272,3 +283,9 @@ const NumberSetting = () => { }; export default NumberSetting; + +NumberSetting.getInitialProps = ({ query, req }: any) => { + return { + tableType: query?.type || TableEnum.bill + }; +}; diff --git a/src/service/models/inform.ts b/src/service/models/inform.ts new file mode 100644 index 000000000..1e5bf27cb --- /dev/null +++ b/src/service/models/inform.ts @@ -0,0 +1,40 @@ +import { Schema, model, models, Model } from 'mongoose'; +import { informSchema } from '@/types/mongoSchema'; +import { InformTypeMap } from '@/constants/user'; + +const InformSchema = new Schema({ + userId: { + type: Schema.Types.ObjectId, + ref: 'user', + required: true + }, + time: { + type: Date, + default: () => new Date() + }, + type: { + type: String, + enum: Object.keys(InformTypeMap) + }, + title: { + type: String, + required: true + }, + content: { + type: String, + required: true + }, + read: { + type: Boolean, + default: false + } +}); + +try { + InformSchema.index({ time: -1 }); + InformSchema.index({ userId: 1 }); +} catch (error) { + console.log(error); +} + +export const Inform: Model = models['inform'] || model('inform', InformSchema); diff --git a/src/service/mongo.ts b/src/service/mongo.ts index 4dfaf3e8f..f93c1ee47 100644 --- a/src/service/mongo.ts +++ b/src/service/mongo.ts @@ -68,3 +68,4 @@ export * from './models/promotionRecord'; export * from './models/collection'; export * from './models/shareChat'; export * from './models/kb'; +export * from './models/inform'; diff --git a/src/types/mongoSchema.d.ts b/src/types/mongoSchema.d.ts index de5a225fd..df0b29b9d 100644 --- a/src/types/mongoSchema.d.ts +++ b/src/types/mongoSchema.d.ts @@ -7,7 +7,7 @@ import { EmbeddingModelType } from '@/constants/model'; import type { DataType } from './data'; -import { BillTypeEnum } from '@/constants/user'; +import { BillTypeEnum, InformTypeEnum } from '@/constants/user'; import { TrainingModeEnum } from '@/constants/plugin'; export interface UserModelSchema { @@ -155,3 +155,13 @@ export interface kbSchema { name: string; tags: string[]; } + +export interface informSchema { + _id: string; + userId: string; + time: Date; + type: `${InformTypeEnum}`; + title: string; + content: string; + read: boolean; +}