Commit 8167df7e by HoMeTown

feat: 推荐问题

parent f7ff1644
...@@ -9,3 +9,11 @@ export function fetchLoginByUid(uid: string) { ...@@ -9,3 +9,11 @@ export function fetchLoginByUid(uid: string) {
userId: uid, userId: uid,
}) })
} }
/**
* 获取协议列表
* @returns
*/
export function fetchGetAgreementList() {
return http.post('/config-center/api/commonconfig/mobile/v1/query_agreement_list')
}
...@@ -38,7 +38,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => { ...@@ -38,7 +38,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
setToken(res.data.token) setToken(res.data.token)
setIsLoggedIn(true) setIsLoggedIn(true)
setShowLoginModal(false) setShowLoginModal(false)
showToast('登录成功!', 'success') showToast('欢迎使用晓得AI助手~', 'success', { icon: '🎉' })
return return
} }
showToast('登录失败', 'error') showToast('登录失败', 'error')
...@@ -47,7 +47,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => { ...@@ -47,7 +47,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const logout = () => { const logout = () => {
setIsLoggedIn(false) setIsLoggedIn(false)
setToken('') setToken('')
showToast('已退出', 'success') showToast('期待您再次使用~', 'success', { icon: '👋🏻' })
} }
const toggleLoginModal = () => { const toggleLoginModal = () => {
......
...@@ -15,6 +15,7 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose }) => { ...@@ -15,6 +15,7 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose }) => {
const handleLogin = () => { const handleLogin = () => {
login() login()
} }
return ( return (
<Modal backdrop="blur" isOpen={isOpen} onClose={onClose}> <Modal backdrop="blur" isOpen={isOpen} onClose={onClose}>
<ModalContent> <ModalContent>
...@@ -26,10 +27,7 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose }) => { ...@@ -26,10 +27,7 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose }) => {
为帮助您更好了解晓得AI 助手服务内容,保障您的合法权益。 为帮助您更好了解晓得AI 助手服务内容,保障您的合法权益。
</p> </p>
<p> <p>
请您认真阅读 请您认真阅读《服务协议》《隐私政策》 ,特别是其中有关使用限制、免责声明、个人信息保护等内容。
<Link showAnchorIcon underline="hover">《服务协议》</Link>
<Link showAnchorIcon underline="hover">《隐私政策》</Link>
,特别是其中有关使用限制、免责声明、个人信息保护等内容。
</p> </p>
<p> <p>
您需在仔细阅读并确认同意相关协议后方可使用本服务。 您需在仔细阅读并确认同意相关协议后方可使用本服务。
...@@ -39,8 +37,10 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose }) => { ...@@ -39,8 +37,10 @@ export const LoginModal: React.FC<LoginModalProps> = ({ isOpen, onClose }) => {
isSelected={isSelected} isSelected={isSelected}
onValueChange={setIsSelected} onValueChange={setIsSelected}
> >
我已阅读并同意
</Checkbox> </Checkbox>
我已阅读并同意
<Link isExternal href="https://sit-sdream-public-1300557051.insurbank.cn/config-center/agreement/%E6%99%93%E5%BE%97AI%E5%8A%A9%E6%89%8B%E6%9C%8D%E5%8A%A1%E5%8D%8F%E8%AE%AE.html" showAnchorIcon underline="hover">《服务协议》</Link>
<Link isExternal href="https://sit-sdream-public-1300557051.insurbank.cn/config-center/agreement/%E6%99%93%E5%BE%97AI%E5%8A%A9%E6%89%8B%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96.html" showAnchorIcon underline="hover">《隐私政策》</Link>
</p> </p>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
......
/**
* 推荐问题 - 其他
*/
export const RECOMMEND_QUESTIONS_OTHER = [
'请介绍一下你们公司?',
'演示利率与实际利率关系?',
'什么叫保本核算周期期满日?',
'请说明一下年金保险有哪些种类?',
'请解释一下投资连结保险和万能保险的区别?',
'分红型保险的红利来源有哪些?',
]
/**
* 推荐问题 - 产品
*/
export const RECOMMEND_QUESTIONS_PRODUCT = [
'美好生活A01产品保费要求',
'美好生活分红型保险的红利领取方式变更',
'国民幸福终身寿险每年交10000,3年交,保额是多少',
'福寿双全A01产品保费要求是什么',
'购买美好生活B01产品后如何操作投保人变更',
'共同富裕B款产品如何购买',
'共同富裕B款账户价值如何计算',
'国民共同富裕B款专属商业养老保险在哪些渠道可以购买',
'国民国泰民安 101 期限保本型(三年滚动)商业养老金产品投资资产的比例如何规定的',
'国泰民安 101 净值查询]',
'国泰民安201赎回资金到账时间',
'商业养老金501产品投资方向有哪些',
]
...@@ -9,6 +9,7 @@ import HomeIcon1 from '@/assets/homeIcon1.png' ...@@ -9,6 +9,7 @@ import HomeIcon1 from '@/assets/homeIcon1.png'
import HomeIcon2 from '@/assets/homeIcon2.png' import HomeIcon2 from '@/assets/homeIcon2.png'
import { GradientBackground } from '@/components/GradientBackground' import { GradientBackground } from '@/components/GradientBackground'
import { ChatEditor } from '@/components/ChatEditor' import { ChatEditor } from '@/components/ChatEditor'
import { RECOMMEND_QUESTIONS_OTHER, RECOMMEND_QUESTIONS_PRODUCT } from '@/config/recommendQuestion'
export const Home: React.FC = () => { export const Home: React.FC = () => {
const placeholders = [ const placeholders = [
...@@ -40,8 +41,8 @@ export const Home: React.FC = () => { ...@@ -40,8 +41,8 @@ export const Home: React.FC = () => {
{/* 欢迎语 */} {/* 欢迎语 */}
<div className="gap-[20px] flex justify-center flex-row flex-wrap mt-[42px] sm:mt-[62px] lg:mt-[112px]"> <div className="gap-[20px] flex justify-center flex-row flex-wrap mt-[42px] sm:mt-[62px] lg:mt-[112px]">
<WelcomeWord /> <WelcomeWord />
<QuestionList dotColor="#D4CCFF" title="产品问答" iconImg={HomeIcon1} /> <QuestionList questions={RECOMMEND_QUESTIONS_PRODUCT} dotColor="#D4CCFF" title="产品问答" iconImg={HomeIcon1} />
<QuestionList dotColor="#CBECFF" title="其他问答" iconImg={HomeIcon2} /> <QuestionList questions={RECOMMEND_QUESTIONS_OTHER} dotColor="#CBECFF" title="其他问答" iconImg={HomeIcon2} />
</div> </div>
</div> </div>
)} )}
......
import { Button } from '@nextui-org/react' import { Button } from '@nextui-org/react'
import type React from 'react' import type React from 'react'
import { Image } from '@nextui-org/image' import { Image } from '@nextui-org/image'
import { motion } from 'framer-motion' import { AnimatePresence, motion } from 'framer-motion'
import { useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import Refresh from '@/assets/svg/refresh.svg?react' import Refresh from '@/assets/svg/refresh.svg?react'
import { type WithAuthProps, withAuth } from '@/auth/withAuth' import { type WithAuthProps, withAuth } from '@/auth/withAuth'
...@@ -10,37 +10,65 @@ interface QuestionListProps { ...@@ -10,37 +10,65 @@ interface QuestionListProps {
title: string title: string
iconImg: string iconImg: string
dotColor: string dotColor: string
questions: string[]
showRefresh?: boolean showRefresh?: boolean
displayCount?: number
}
const containerVariants = {
hidden: {},
visible: {},
} }
const list = { const itemVariants = {
hidden: { opacity: 1, scale: 0 }, hidden: { opacity: 0, y: 20, scale: 0.8 },
visible: { visible: (i: number) => ({
opacity: 1, opacity: 1,
y: 0,
scale: 1, scale: 1,
transition: { transition: {
delayChildren: 0.2, delay: i * 0.1,
staggerChildren: 0.1, type: 'spring',
stiffness: 500,
damping: 20,
mass: 0.8,
}, },
}),
exit: {
opacity: 0,
scale: 0.8,
transition: { duration: 0.2 },
}, },
} }
const item = { function getRandomIndices(total: number, count: number): number[] {
hidden: { y: 20, opacity: 0 }, const indices = new Set<number>()
visible: { while (indices.size < count) {
y: 0, indices.add(Math.floor(Math.random() * total))
opacity: 1, }
}, return Array.from(indices)
} }
const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({ checkAuth, dotColor, title, iconImg, showRefresh = true }) => { const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({ checkAuth, questions, dotColor, title, iconImg, showRefresh = true, displayCount = 4 }) => {
const [isRotating, setIsRotating] = useState(false) const [isRotating, setIsRotating] = useState(false)
const [displayedItems, setDisplayedItems] = useState<string[]>([])
const updateDisplayedItems = useCallback(() => {
const indices = getRandomIndices(questions.length, Math.min(displayCount, questions.length))
setDisplayedItems(indices.map(index => questions[index]))
}, [questions, displayCount])
const handleRefresh = () => { const handleRefresh = () => {
setIsRotating(true) setIsRotating(true)
updateDisplayedItems()
setIsRotating(false)
} }
const handleClick = () => { const handleClick = () => {
checkAuth() checkAuth()
} }
useEffect(() => {
updateDisplayedItems()
}, [updateDisplayedItems])
return ( return (
<div className="h-[276px] bg-white box-border px-[20px] py-[24px] rounded-[24px] w-full sm:w-[360px] md:w-[300px]"> <div className="h-[276px] bg-white box-border px-[20px] py-[24px] rounded-[24px] w-full sm:w-[360px] md:w-[300px]">
<h3 className="h-[32px] flex items-center justify-between"> <h3 className="h-[32px] flex items-center justify-between">
...@@ -76,21 +104,34 @@ const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({ checkAu ...@@ -76,21 +104,34 @@ const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({ checkAu
</h3> </h3>
<motion.ul <motion.ul
key={displayedItems.join(',')}
variants={containerVariants}
initial="hidden" initial="hidden"
animate="visible" animate="visible"
variants={list}
className="mt-[18px] flex flex-col gap-[8px]" className="mt-[18px] flex flex-col gap-[8px]"
> >
<motion.li <AnimatePresence mode="wait">
variants={item} {
> displayedItems.map((item, index) => (
<Button onClick={handleClick} color="primary" variant="flat" className="w-full bg-[#F7FCFF] "> <motion.li
<div className="w-full text-nowrap text-ellipsis overflow-hidden text-[#82969C]"> key={`${item}-${index}`}
<span style={{ color: dotColor }}>·</span> custom={index}
<span className="ml-[8px]">推荐几款60周岁还能投的医疗保推荐几款60周岁还能投的医疗保</span> variants={itemVariants}
</div> initial="hidden"
</Button> animate="visible"
</motion.li> exit="exit"
layout
>
<Button onClick={handleClick} color="primary" variant="flat" className="w-full bg-[#F7FCFF] ">
<div className="w-full text-nowrap text-ellipsis overflow-hidden text-[#82969C]">
<span style={{ color: dotColor }}>·</span>
<span className="ml-[8px]">{item}</span>
</div>
</Button>
</motion.li>
))
}
</AnimatePresence>
</motion.ul> </motion.ul>
</div> </div>
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment