3f39c56f4b
- 部署脚本 deploy.sh:一键部署到 154.8.162.18,端口3400,Nginx conf.d - 应用名改为「企业用工专家」(登录/注册/侧边栏/员工端等6处) - 移动端适配修复:Attendance/Dashboard/Settings/Contracts 6处grid响应式 - 帮助系统:HelpModal 组件 + TopNav 帮助图标 + RAG语义搜索集成 - 后端 rag.service.ts 新增23条帮助种子数据 + searchHelp() - 前端搜索调用 /ai/rag/help-search,RAG不可用时回退关键词匹配 - 网页图标 favicon.svg(indigo主色+建筑人形图案) - index.html 标题改为「企业用工专家」
514 lines
24 KiB
TypeScript
514 lines
24 KiB
TypeScript
import { useState, useEffect, useRef } from 'react'
|
||
import { HelpCircle, Search, ChevronDown, ChevronRight, Sparkles,
|
||
Home, Users, FileText, Calculator, Shield, UserX, Bot,
|
||
Bell, Settings, Lightbulb, AlertTriangle, CheckCircle, Phone } from 'lucide-react'
|
||
import Modal from './ui/Modal'
|
||
import api from '../lib/api'
|
||
import clsx from 'clsx'
|
||
|
||
interface HelpCategory {
|
||
id: string
|
||
title: string
|
||
icon: typeof Home
|
||
articles: HelpArticle[]
|
||
}
|
||
|
||
interface HelpArticle {
|
||
id: string
|
||
question: string
|
||
answer: string
|
||
steps?: string[]
|
||
tip?: string
|
||
warning?: string
|
||
}
|
||
|
||
const categories: HelpCategory[] = [
|
||
{
|
||
id: 'start',
|
||
title: '快速入门',
|
||
icon: Lightbulb,
|
||
articles: [
|
||
{
|
||
id: 'what-is',
|
||
question: '「企业用工专家」是什么?',
|
||
answer: '这是一个帮您管理员工、合同、工资和社保的工具。您可以把它理解为一个「人事小助手」,帮您把繁琐的人事工作变得简单。比如:记录员工信息、提醒合同到期、计算工资社保、生成法律文档等。',
|
||
},
|
||
{
|
||
id: 'first-steps',
|
||
question: '我第一次使用,该从哪里开始?',
|
||
answer: '建议按以下顺序操作,就像填表格一样简单:',
|
||
steps: [
|
||
'第一步:点击左侧菜单「员工管理」,添加您的员工信息(姓名、手机号、入职日期等)',
|
||
'第二步:在员工详情里填写合同信息(合同类型、签订日期、到期日期等)',
|
||
'第三步:在「社保管理」中设置您公司的社保缴纳基数和比例',
|
||
'第四步:在「薪税管理」中创建发薪批次,系统会自动帮您计算工资',
|
||
'第五步:有不懂的随时点这个「?」图标查看帮助',
|
||
],
|
||
tip: '不用担心填错,所有信息都可以随时修改。',
|
||
},
|
||
{
|
||
id: 'mobile',
|
||
question: '我可以在手机上使用吗?',
|
||
answer: '可以!用手机浏览器打开本网站即可。手机版会自动显示底部导航栏,方便您随时查看。建议添加到手机桌面,像 App 一样使用。',
|
||
steps: [
|
||
'苹果手机:Safari 打开 → 点击底部分享按钮 → 「添加到主屏幕」',
|
||
'安卓手机:Chrome 打开 → 点击右上角菜单 → 「添加到主屏幕」',
|
||
],
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'employee',
|
||
title: '员工管理',
|
||
icon: Users,
|
||
articles: [
|
||
{
|
||
id: 'add-employee',
|
||
question: '怎么添加新员工?',
|
||
answer: '就像填一张入职登记表:',
|
||
steps: [
|
||
'点击左侧菜单「员工管理」',
|
||
'点击右上角「添加员工」按钮',
|
||
'填写员工姓名、手机号、入职日期等基本信息',
|
||
'点击「保存」即可',
|
||
],
|
||
tip: '带 * 号的是必填项,其他可以以后再补。',
|
||
},
|
||
{
|
||
id: 'edit-employee',
|
||
question: '怎么修改员工信息?',
|
||
answer: '在员工列表中,点击员工姓名即可进入详情页,然后点击右上角「编辑」按钮修改信息。',
|
||
},
|
||
{
|
||
id: 'employee-status',
|
||
question: '员工离职了怎么处理?',
|
||
answer: '请到「解聘管理」页面处理离职流程,系统会自动帮您计算经济补偿金、生成解聘协议书等法律文件。不要直接删除员工记录,保留记录有助于日后查证。',
|
||
warning: '直接删除员工会导致该员工的所有历史记录丢失,包括合同、工资单等。',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'contract',
|
||
title: '合同管理',
|
||
icon: FileText,
|
||
articles: [
|
||
{
|
||
id: 'contract-types',
|
||
question: '合同类型有哪些?我该选哪个?',
|
||
answer: '常见的合同类型:\n• 固定期限合同:有明确到期日,比如签 3 年\n• 无固定期限合同:没有到期日,长期雇佣\n• 完成任务合同:以完成某项工作为期限\n• 未签合同:还没签合同的情况',
|
||
warning: '员工入职 1 个月内必须签订书面合同,否则企业需要支付双倍工资。',
|
||
},
|
||
{
|
||
id: 'contract-expiry',
|
||
question: '合同快到期了,系统会提醒我吗?',
|
||
answer: '会的!系统会自动检测即将到期的合同,并在顶部通知铃铛处显示提醒数字。您也可以在「通知管理」页面查看所有提醒。默认提前 30 天提醒,您可以在通知设置中修改天数。',
|
||
},
|
||
{
|
||
id: 'contract-confirm',
|
||
question: '什么是合同确认?',
|
||
answer: '合同确认是指员工通过手机查看并确认自己的劳动合同内容。系统会生成一个链接,员工用手机打开即可查看合同详情并确认签字。您可以在员工详情的「合同信息」标签页中发起确认。',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'salary',
|
||
title: '工资和社保',
|
||
icon: Calculator,
|
||
articles: [
|
||
{
|
||
id: 'create-payroll',
|
||
question: '怎么发工资?',
|
||
answer: '系统帮您自动化算薪:',
|
||
steps: [
|
||
'点击左侧菜单「薪税管理」',
|
||
'点击「创建发薪批次」',
|
||
'选择月份和批次类型(正常工资/补发等)',
|
||
'系统自动从员工信息中拉取数据并计算',
|
||
'确认无误后点击「发放」',
|
||
],
|
||
tip: '系统会自动计算个税、社保扣款等,您只需要核对数字即可。',
|
||
},
|
||
{
|
||
id: 'social-insurance',
|
||
question: '社保基数和比例怎么设置?',
|
||
answer: '在「社保管理」页面,您可以设置公司所在地的社保缴纳基数上下限和各项比例(养老、医疗、失业、工伤、生育)。这些数据通常每年会调整一次,请关注当地社保局通知。',
|
||
warning: '社保基数和比例各地不同,请以当地社保局公布的最新标准为准。',
|
||
},
|
||
{
|
||
id: 'payslip',
|
||
question: '员工怎么查看工资条?',
|
||
answer: '系统提供员工端(手机访问),员工可以通过手机查看自己的工资条。您在发薪后,系统会自动生成工资条,员工登录员工端即可查看。',
|
||
},
|
||
{
|
||
id: 'overtime',
|
||
question: '加班费怎么算?',
|
||
answer: '系统会根据您设置的加班倍率自动计算。默认规则:\n• 工作日加班:1.5 倍\n• 休息日加班:2 倍\n• 法定节假日加班:3 倍\n您可以在薪税管理的加班配置中修改倍率。',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'risk',
|
||
title: '风险检测',
|
||
icon: AlertTriangle,
|
||
articles: [
|
||
{
|
||
id: 'what-is-risk',
|
||
question: '风险检测是什么意思?',
|
||
answer: '系统会自动扫描您的员工和合同数据,发现可能存在的法律风险。比如:合同到期未续签、试用期超长、未签合同等。风险分为高、中、低三个等级,建议优先处理高风险项。',
|
||
},
|
||
{
|
||
id: 'how-to-fix',
|
||
question: '发现风险后怎么处理?',
|
||
answer: '在首页「总览」页面可以看到风险概览。点击风险项可以跳转到对应员工详情,然后根据系统建议进行处理。处理完成后风险会自动消除。',
|
||
tip: '建议每周查看一次风险提醒,及时处理避免法律纠纷。',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'ai',
|
||
title: 'AI 助手',
|
||
icon: Bot,
|
||
articles: [
|
||
{
|
||
id: 'what-is-ai',
|
||
question: 'AI 助手能帮我做什么?',
|
||
answer: 'AI 助手可以回答劳动法相关问题,比如:\n• 「员工试用期最多多久?」\n• 「经济补偿金怎么计算?」\n• 「未婚怀孕能休产假吗?」\n• 「加班费怎么算?」\n就像问一个专业律师一样,用大白话问就行。',
|
||
},
|
||
{
|
||
id: 'ai-predict',
|
||
question: '判赔预测是什么?',
|
||
answer: '如果您要解聘员工,AI 可以根据员工的信息(工资、工龄、合同等)预测可能需要支付的经济补偿金金额,帮您提前做好预算。在「AI 助手」页面选择「判赔预测」模式即可使用。',
|
||
warning: 'AI 预测结果仅供参考,实际金额请以律师建议或法院判决为准。',
|
||
},
|
||
{
|
||
id: 'ai-limit',
|
||
question: 'AI 回答准确吗?',
|
||
answer: 'AI 基于劳动法律法规训练,回答具有较高参考价值。但法律问题往往涉及具体细节,建议将 AI 回答作为参考,重要决策请咨询专业律师。',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'settings',
|
||
title: '通知和设置',
|
||
icon: Settings,
|
||
articles: [
|
||
{
|
||
id: 'notification',
|
||
question: '怎么设置提醒?',
|
||
answer: '在「通知管理」页面可以设置各类提醒:\n• 合同到期提前提醒天数\n• 未签合同提醒\n• 试用期到期提醒等\n点击通知铃铛图标可以查看所有未读提醒。',
|
||
},
|
||
{
|
||
id: 'change-password',
|
||
question: '怎么修改密码?',
|
||
answer: '点击右上角您的用户名 → 「设置」页面中可以修改密码。建议定期更换密码以保护账号安全。',
|
||
},
|
||
{
|
||
id: 'company-info',
|
||
question: '怎么修改公司信息?',
|
||
answer: '在「设置」页面可以修改公司名称、行业、规模等基本信息。这些信息会影响风险检测的准确性,请如实填写。',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'faq',
|
||
title: '常见问题',
|
||
icon: Phone,
|
||
articles: [
|
||
{
|
||
id: 'data-safe',
|
||
question: '我的数据安全吗?',
|
||
answer: '您的数据存储在加密的云端服务器上,只有您本人登录后才能查看。我们不会将您的数据分享给任何第三方。所有敏感信息(如身份证号)都经过加密存储。',
|
||
},
|
||
{
|
||
id: 'data-export',
|
||
question: '可以导出数据吗?',
|
||
answer: '可以。在员工管理页面可以导出员工名单为 Excel 文件。工资批次也可以导出为 Excel 方便财务对账。',
|
||
},
|
||
{
|
||
id: 'multi-user',
|
||
question: '可以多人同时使用吗?',
|
||
answer: '可以。在「设置」页面可以添加多个 HR 账号,不同账号可以设置不同权限。比如一个管理员、几个普通 HR。',
|
||
},
|
||
{
|
||
id: 'support',
|
||
question: '遇到问题怎么办?',
|
||
answer: '您可以:\n1. 点击页面右上角的「?」图标查看帮助文档\n2. 在「AI 助手」中直接提问\n3. 联系客服:support@hr8ai.com',
|
||
},
|
||
],
|
||
},
|
||
]
|
||
|
||
interface RAGResult {
|
||
title: string
|
||
content: string
|
||
source: string
|
||
category: string
|
||
similarity: number
|
||
}
|
||
|
||
export default function HelpModal({ open, onClose }: { open: boolean; onClose: () => void }) {
|
||
const [activeCategory, setActiveCategory] = useState(categories[0].id)
|
||
const [expandedArticle, setExpandedArticle] = useState<string | null>(null)
|
||
const [searchQuery, setSearchQuery] = useState('')
|
||
const [ragResults, setRagResults] = useState<RAGResult[] | null>(null)
|
||
const [ragLoading, setRagLoading] = useState(false)
|
||
const [ragError, setRagError] = useState(false)
|
||
const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||
|
||
// RAG 语义搜索(防抖 300ms)
|
||
useEffect(() => {
|
||
if (!searchQuery.trim()) {
|
||
setRagResults(null)
|
||
setRagError(false)
|
||
return
|
||
}
|
||
if (debounceTimer.current) clearTimeout(debounceTimer.current)
|
||
debounceTimer.current = setTimeout(async () => {
|
||
setRagLoading(true)
|
||
setRagError(false)
|
||
try {
|
||
const res = await api.post('/ai/rag/help-search', { query: searchQuery, topK: 8 }) as any
|
||
setRagResults(res.data?.results || [])
|
||
} catch {
|
||
setRagError(true)
|
||
setRagResults([])
|
||
} finally {
|
||
setRagLoading(false)
|
||
}
|
||
}, 300)
|
||
return () => { if (debounceTimer.current) clearTimeout(debounceTimer.current) }
|
||
}, [searchQuery])
|
||
|
||
const isSearching = searchQuery.trim().length > 0
|
||
const filteredCategories = isSearching
|
||
? categories.map(c => ({
|
||
...c,
|
||
articles: c.articles.filter(
|
||
a => a.question.includes(searchQuery) || a.answer.includes(searchQuery)
|
||
),
|
||
})).filter(c => c.articles.length > 0)
|
||
: categories
|
||
|
||
const currentCategory = filteredCategories.find(c => c.id === activeCategory) || filteredCategories[0]
|
||
|
||
return (
|
||
<Modal open={open} onClose={onClose} title="使用帮助" size="lg" className="p-0">
|
||
{/* 搜索框 */}
|
||
<div className="border-b border-gray-200 px-4 py-3">
|
||
<div className="relative">
|
||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
|
||
<input
|
||
type="text"
|
||
value={searchQuery}
|
||
onChange={e => setSearchQuery(e.target.value)}
|
||
placeholder="搜索问题,比如「怎么添加员工」「合同到期」..."
|
||
className="w-full pl-9 pr-3 py-2 text-sm border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex flex-col md:flex-row min-h-[400px] max-h-[60vh]">
|
||
{/* 左侧分类导航 */}
|
||
<div className="md:w-48 md:border-r border-gray-200 md:flex-shrink-0">
|
||
{/* 移动端:横向滚动 */}
|
||
<div className="md:hidden flex gap-1 overflow-x-auto p-2 border-b border-gray-200">
|
||
{filteredCategories.map(cat => {
|
||
const Icon = cat.icon
|
||
return (
|
||
<button
|
||
key={cat.id}
|
||
onClick={() => setActiveCategory(cat.id)}
|
||
className={clsx(
|
||
'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs whitespace-nowrap flex-shrink-0',
|
||
activeCategory === cat.id ? 'bg-primary/10 text-primary font-medium' : 'text-gray-600'
|
||
)}
|
||
>
|
||
<Icon className="w-3.5 h-3.5" />
|
||
{cat.title}
|
||
</button>
|
||
)
|
||
})}
|
||
</div>
|
||
{/* 桌面端:纵向列表 */}
|
||
<div className="hidden md:block py-2">
|
||
{filteredCategories.map(cat => {
|
||
const Icon = cat.icon
|
||
return (
|
||
<button
|
||
key={cat.id}
|
||
onClick={() => setActiveCategory(cat.id)}
|
||
className={clsx(
|
||
'flex items-center gap-2 w-full px-3 py-2 text-sm transition-colors text-left',
|
||
activeCategory === cat.id
|
||
? 'bg-primary/10 text-primary font-medium border-r-2 border-primary'
|
||
: 'text-gray-600 hover:bg-gray-50'
|
||
)}
|
||
>
|
||
<Icon className="w-4 h-4 flex-shrink-0" />
|
||
<span className="truncate">{cat.title}</span>
|
||
</button>
|
||
)
|
||
})}
|
||
</div>
|
||
</div>
|
||
|
||
{/* 右侧文章列表 */}
|
||
<div className="flex-1 overflow-y-auto p-4">
|
||
{/* RAG 语义搜索结果模式 */}
|
||
{isSearching && ragResults !== null ? (
|
||
<>
|
||
<h3 className="text-sm font-semibold text-gray-900 mb-3 flex items-center gap-2">
|
||
<Sparkles className="w-4 h-4 text-primary" />
|
||
AI 语义搜索结果
|
||
{ragLoading && <span className="text-xs font-normal text-gray-400">搜索中...</span>}
|
||
</h3>
|
||
{ragError ? (
|
||
/* RAG 不可用时回退到关键词匹配 */
|
||
<>
|
||
<p className="text-xs text-gray-400 mb-3">AI 搜索暂不可用,以下为关键词匹配结果:</p>
|
||
{filteredCategories.length > 0 ? (
|
||
<div className="space-y-2">
|
||
{filteredCategories.flatMap(c => c.articles).map(article => (
|
||
<div key={article.id} className="border border-gray-200 rounded-lg overflow-hidden">
|
||
<button
|
||
onClick={() => setExpandedArticle(expandedArticle === article.id ? null : article.id)}
|
||
className="flex items-center justify-between w-full px-3 py-2.5 text-left hover:bg-gray-50 transition-colors"
|
||
>
|
||
<span className="text-sm font-medium text-gray-800 pr-2">{article.question}</span>
|
||
{expandedArticle === article.id ? <ChevronDown className="w-4 h-4 text-gray-400 flex-shrink-0" /> : <ChevronRight className="w-4 h-4 text-gray-400 flex-shrink-0" />}
|
||
</button>
|
||
{expandedArticle === article.id && (
|
||
<div className="px-3 pb-3 pt-1 text-sm text-gray-600">
|
||
{article.answer.split('\n').map((line, i) => (
|
||
<p key={i} className={line.startsWith('•') ? 'pl-2' : ''}>{line}</p>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
) : (
|
||
<div className="text-center py-12 text-gray-400">
|
||
<Search className="w-8 h-8 mx-auto mb-2" />
|
||
<p className="text-sm">没有找到相关问题</p>
|
||
<p className="text-xs mt-1">试试换个关键词搜索</p>
|
||
</div>
|
||
)}
|
||
</>
|
||
) : ragResults.length > 0 ? (
|
||
<div className="space-y-2">
|
||
{ragResults.map((r, i) => (
|
||
<div key={i} className="border border-gray-200 rounded-lg overflow-hidden">
|
||
<button
|
||
onClick={() => setExpandedArticle(expandedArticle === `rag-${i}` ? null : `rag-${i}`)}
|
||
className="flex items-center justify-between w-full px-3 py-2.5 text-left hover:bg-gray-50 transition-colors"
|
||
>
|
||
<div className="flex items-center gap-2 pr-2 min-w-0">
|
||
<span className="text-sm font-medium text-gray-800 truncate">{r.title}</span>
|
||
<span className="text-xs text-gray-400 flex-shrink-0">{(r.similarity * 100).toFixed(0)}% 匹配</span>
|
||
</div>
|
||
{expandedArticle === `rag-${i}` ? <ChevronDown className="w-4 h-4 text-gray-400 flex-shrink-0" /> : <ChevronRight className="w-4 h-4 text-gray-400 flex-shrink-0" />}
|
||
</button>
|
||
{expandedArticle === `rag-${i}` && (
|
||
<div className="px-3 pb-3 pt-1 text-sm text-gray-600 space-y-2">
|
||
<p>{r.content}</p>
|
||
<div className="flex items-center gap-2 text-xs text-gray-400">
|
||
<span className="px-1.5 py-0.5 rounded bg-gray-100">{r.category}</span>
|
||
<span>来源:{r.source}</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
) : (
|
||
<div className="text-center py-12 text-gray-400">
|
||
<Search className="w-8 h-8 mx-auto mb-2" />
|
||
<p className="text-sm">没有找到相关问题</p>
|
||
<p className="text-xs mt-1">试试换个关键词,或直接在 AI 助手中提问</p>
|
||
</div>
|
||
)}
|
||
</>
|
||
) : (
|
||
/* 正常分类浏览模式 */
|
||
<>
|
||
{currentCategory ? (
|
||
<>
|
||
<h3 className="text-sm font-semibold text-gray-900 mb-3 flex items-center gap-2">
|
||
{(() => {
|
||
const Icon = currentCategory.icon
|
||
return <Icon className="w-4 h-4 text-primary" />
|
||
})()}
|
||
{currentCategory.title}
|
||
</h3>
|
||
<div className="space-y-2">
|
||
{currentCategory.articles.map(article => {
|
||
const expanded = expandedArticle === article.id
|
||
return (
|
||
<div key={article.id} className="border border-gray-200 rounded-lg overflow-hidden">
|
||
<button
|
||
onClick={() => setExpandedArticle(expanded ? null : article.id)}
|
||
className="flex items-center justify-between w-full px-3 py-2.5 text-left hover:bg-gray-50 transition-colors"
|
||
>
|
||
<span className="text-sm font-medium text-gray-800 pr-2">{article.question}</span>
|
||
{expanded ? <ChevronDown className="w-4 h-4 text-gray-400 flex-shrink-0" /> : <ChevronRight className="w-4 h-4 text-gray-400 flex-shrink-0" />}
|
||
</button>
|
||
{expanded && (
|
||
<div className="px-3 pb-3 pt-1 text-sm text-gray-600 space-y-2">
|
||
{article.answer.split('\n').map((line, i) => (
|
||
<p key={i} className={line.startsWith('•') ? 'pl-2' : ''}>{line}</p>
|
||
))}
|
||
{article.steps && (
|
||
<div className="bg-blue-50 rounded-md p-3 space-y-1.5">
|
||
<p className="text-xs font-medium text-blue-700">操作步骤:</p>
|
||
{article.steps.map((step, i) => (
|
||
<div key={i} className="flex gap-2 text-xs text-blue-900">
|
||
<span className="flex-shrink-0 w-5 h-5 rounded-full bg-blue-200 text-blue-700 flex items-center justify-center font-medium">{i + 1}</span>
|
||
<span className="pt-0.5">{step}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
{article.tip && (
|
||
<div className="flex items-start gap-2 bg-green-50 rounded-md p-2.5">
|
||
<CheckCircle className="w-4 h-4 text-green-600 flex-shrink-0 mt-0.5" />
|
||
<p className="text-xs text-green-800">{article.tip}</p>
|
||
</div>
|
||
)}
|
||
{article.warning && (
|
||
<div className="flex items-start gap-2 bg-amber-50 rounded-md p-2.5">
|
||
<AlertTriangle className="w-4 h-4 text-amber-600 flex-shrink-0 mt-0.5" />
|
||
<p className="text-xs text-amber-800">{article.warning}</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
})}
|
||
</div>
|
||
</>
|
||
) : (
|
||
<div className="text-center py-12 text-gray-400">
|
||
<Search className="w-8 h-8 mx-auto mb-2" />
|
||
<p className="text-sm">没有找到相关问题</p>
|
||
<p className="text-xs mt-1">试试换个关键词搜索</p>
|
||
</div>
|
||
)}
|
||
</>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* 底部联系方式 */}
|
||
<div className="border-t border-gray-200 px-4 py-2.5 flex items-center justify-between text-xs text-gray-500">
|
||
<span className="flex items-center gap-1.5">
|
||
<HelpCircle className="w-3.5 h-3.5" />
|
||
还有问题?在 AI 助手中直接提问
|
||
</span>
|
||
<span>support@hr8ai.com</span>
|
||
</div>
|
||
</Modal>
|
||
)
|
||
}
|