feat: 添加功能调查问卷,218项功能可在线打分
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import { Star, ChevronDown, ChevronRight, Check, Search, ClipboardList, Send } from 'lucide-react'
|
||||
import Modal from './ui/Modal'
|
||||
import { toast } from 'sonner'
|
||||
import api from '../lib/api'
|
||||
import { surveyPages, totalFeatures } from '../data/surveyData'
|
||||
|
||||
interface FeatureScore {
|
||||
score: number
|
||||
useful: '' | 'yes' | 'no' | 'maybe'
|
||||
remark: string
|
||||
}
|
||||
|
||||
export default function SurveyModal({ open, onClose }: { open: boolean; onClose: () => void }) {
|
||||
const [expandedPage, setExpandedPage] = useState<number | null>(1)
|
||||
const [scores, setScores] = useState<Record<string, FeatureScore>>({})
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
const setScore = (id: string, score: number) => {
|
||||
setScores(prev => ({
|
||||
...prev,
|
||||
[id]: { ...prev[id], score: prev[id]?.score === score ? 0 : score },
|
||||
}))
|
||||
}
|
||||
|
||||
const setUseful = (id: string, useful: 'yes' | 'no' | 'maybe') => {
|
||||
setScores(prev => ({
|
||||
...prev,
|
||||
[id]: { ...prev[id], useful: prev[id]?.useful === useful ? '' : useful },
|
||||
}))
|
||||
}
|
||||
|
||||
const setRemark = (id: string, remark: string) => {
|
||||
setScores(prev => ({
|
||||
...prev,
|
||||
[id]: { ...prev[id], remark },
|
||||
}))
|
||||
}
|
||||
|
||||
const ratedCount = useMemo(() => Object.values(scores).filter(s => s.score > 0).length, [scores])
|
||||
|
||||
const filteredPages = useMemo(() => {
|
||||
if (!searchQuery.trim()) return surveyPages
|
||||
const q = searchQuery.toLowerCase()
|
||||
return surveyPages.map(p => ({
|
||||
...p,
|
||||
features: p.features.filter(f => f.name.toLowerCase().includes(q) || f.desc.toLowerCase().includes(q)),
|
||||
})).filter(p => p.features.length > 0)
|
||||
}, [searchQuery])
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const items = Object.entries(scores)
|
||||
.filter(([, v]) => v.score > 0 || v.useful || v.remark)
|
||||
.map(([id, v]) => ({ featureId: id, score: v.score, useful: v.useful, remark: v.remark }))
|
||||
if (items.length === 0) {
|
||||
toast.info('请至少对一项功能进行评分')
|
||||
return
|
||||
}
|
||||
setSubmitting(true)
|
||||
try {
|
||||
await api.post('/survey/submit', { items })
|
||||
toast.success(`已提交 ${items.length} 项评分,感谢您的反馈!`)
|
||||
onClose()
|
||||
} catch {
|
||||
localStorage.setItem('survey-results', JSON.stringify({ items, submittedAt: new Date().toISOString() }))
|
||||
toast.success(`已保存 ${items.length} 项评分到本地`)
|
||||
onClose()
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose} title="功能调查问卷" size="lg" className="p-0">
|
||||
<div className="border-b border-gray-200 px-4 py-3 space-y-2">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-600">
|
||||
<ClipboardList className="w-4 h-4 shrink-0" />
|
||||
<span>对 {totalFeatures} 项功能打分(1=无用 ~ 5=非常有用),帮助我们改进产品</span>
|
||||
<span className="ml-auto text-xs text-primary font-medium">已评 {ratedCount}/{totalFeatures}</span>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索功能名称..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full pl-8 pr-3 py-1.5 text-sm border border-gray-200 rounded-md focus:outline-none focus:border-primary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 页面列表 */}
|
||||
<div className="max-h-[60vh] overflow-y-auto">
|
||||
{filteredPages.map(page => {
|
||||
const isExpanded = expandedPage === page.id || !!searchQuery.trim()
|
||||
const pageRated = page.features.filter(f => scores[f.id]?.score).length
|
||||
return (
|
||||
<div key={page.id} className="border-b border-gray-100">
|
||||
<button
|
||||
onClick={() => setExpandedPage(isExpanded && !searchQuery ? null : page.id)}
|
||||
className="w-full flex items-center gap-2 px-4 py-2.5 hover:bg-gray-50 text-left"
|
||||
>
|
||||
{isExpanded ? <ChevronDown className="w-4 h-4 text-gray-400 shrink-0" /> : <ChevronRight className="w-4 h-4 text-gray-400 shrink-0" />}
|
||||
<span className="text-sm font-medium text-gray-700">{page.id}. {page.name}</span>
|
||||
<span className="ml-auto text-xs text-gray-400">{page.features.length} 项{pageRated > 0 && ` · 已评 ${pageRated}`}</span>
|
||||
</button>
|
||||
{isExpanded && (
|
||||
<div className="px-4 pb-3 space-y-2">
|
||||
{page.features.map(f => {
|
||||
const s = scores[f.id]
|
||||
return (
|
||||
<div key={f.id} className="flex items-start gap-3 py-1.5 rounded-md hover:bg-gray-50 px-2">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-sm text-gray-700">{f.name}</div>
|
||||
<div className="text-xs text-gray-400">{f.desc}</div>
|
||||
<div className="flex items-center gap-1 mt-1">
|
||||
{[1, 2, 3, 4, 5].map(n => (
|
||||
<button
|
||||
key={n}
|
||||
onClick={() => setScore(f.id, n)}
|
||||
className="p-0.5"
|
||||
aria-label={`${n}星`}
|
||||
>
|
||||
<Star
|
||||
className={`w-4 h-4 ${(s?.score || 0) >= n ? 'text-amber-400 fill-amber-400' : 'text-gray-300'}`}
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
<div className="flex gap-1 ml-3">
|
||||
{([['yes', '有用', 'text-emerald-600 border-emerald-200 bg-emerald-50'], ['no', '无用', 'text-rose-600 border-rose-200 bg-rose-50'], ['maybe', '待定', 'text-amber-600 border-amber-200 bg-amber-50']] as const).map(([val, label, cls]) => (
|
||||
<button
|
||||
key={val}
|
||||
onClick={() => setUseful(f.id, val)}
|
||||
className={`px-2 py-0.5 text-xs rounded border transition-all ${s?.useful === val ? cls : 'text-gray-400 border-gray-200 hover:bg-gray-100'}`}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{(s?.score > 0 || s?.useful) && (
|
||||
<input
|
||||
type="text"
|
||||
placeholder="优化建议(可选)"
|
||||
value={s?.remark || ''}
|
||||
onChange={(e) => setRemark(f.id, e.target.value)}
|
||||
className="mt-1.5 w-full text-xs px-2 py-1 border border-gray-200 rounded focus:outline-none focus:border-primary"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 底部提交 */}
|
||||
<div className="border-t border-gray-200 px-4 py-3 flex items-center justify-between">
|
||||
<span className="text-xs text-gray-500">已评分 {ratedCount} / {totalFeatures} 项</span>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="px-3 py-1.5 text-sm text-gray-600 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
关闭
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
disabled={submitting || ratedCount === 0}
|
||||
className="px-4 py-1.5 text-sm text-white bg-primary rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center gap-1.5"
|
||||
>
|
||||
<Send className="w-3.5 h-3.5" />
|
||||
{submitting ? '提交中...' : '提交问卷'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import { ChevronDown, Settings as SettingsIcon, Bell, Menu, HelpCircle, Smartphone } from 'lucide-react'
|
||||
import { ChevronDown, Settings as SettingsIcon, Bell, Menu, HelpCircle, Smartphone, ClipboardList } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useAuthStore } from '../../store/authStore'
|
||||
@@ -7,6 +7,7 @@ import api from '../../lib/api'
|
||||
import Breadcrumb from './Breadcrumb'
|
||||
import HelpModal from '../HelpModal'
|
||||
import PortalQRModal from '../PortalQRModal'
|
||||
import SurveyModal from '../SurveyModal'
|
||||
|
||||
export default function TopNav({ onMenuClick }: { onMenuClick?: () => void }) {
|
||||
const navigate = useNavigate()
|
||||
@@ -14,6 +15,7 @@ export default function TopNav({ onMenuClick }: { onMenuClick?: () => void }) {
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
const [helpOpen, setHelpOpen] = useState(false)
|
||||
const [portalQROpen, setPortalQROpen] = useState(false)
|
||||
const [surveyOpen, setSurveyOpen] = useState(false)
|
||||
|
||||
const { data: dashboardData } = useQuery<any>({
|
||||
queryKey: ['dashboard'],
|
||||
@@ -58,6 +60,14 @@ export default function TopNav({ onMenuClick }: { onMenuClick?: () => void }) {
|
||||
<HelpCircle className="w-4 h-4 text-gray-600" />
|
||||
</button>
|
||||
<HelpModal open={helpOpen} onClose={() => setHelpOpen(false)} />
|
||||
<button
|
||||
onClick={() => setSurveyOpen(true)}
|
||||
className="p-1.5 rounded-md hover:bg-gray-100"
|
||||
aria-label="功能调查"
|
||||
>
|
||||
<ClipboardList className="w-4 h-4 text-gray-600" />
|
||||
</button>
|
||||
<SurveyModal open={surveyOpen} onClose={() => setSurveyOpen(false)} />
|
||||
<Link to="/settings" className="p-1.5 rounded-md hover:bg-gray-100" aria-label="设置">
|
||||
<SettingsIcon className="w-4 h-4 text-gray-600" />
|
||||
</Link>
|
||||
|
||||
@@ -0,0 +1,453 @@
|
||||
/** 功能调查问卷数据 — 来源:docs/前端页面功能分析.md */
|
||||
|
||||
export interface SurveyFeature {
|
||||
id: string
|
||||
name: string
|
||||
desc: string
|
||||
}
|
||||
|
||||
export interface SurveyPage {
|
||||
id: number
|
||||
name: string
|
||||
file: string
|
||||
features: SurveyFeature[]
|
||||
}
|
||||
|
||||
export const surveyPages: SurveyPage[] = [
|
||||
{
|
||||
id: 1, name: 'Settings(设置页面)', file: 'frontend/src/pages/Settings.tsx',
|
||||
features: [
|
||||
{ id: '1.1', name: '组织信息管理', desc: '编辑公司名称、联系人、薪资发放频率等基本信息' },
|
||||
{ id: '1.2', name: '退休政策提醒', desc: '设置退休政策提醒,显示退休人员名单及确认状态' },
|
||||
{ id: '1.3', name: '用户管理', desc: '添加、编辑、禁用系统用户账号' },
|
||||
{ id: '1.4', name: '计划设置(Plan)', desc: '查看当前套餐计划信息' },
|
||||
{ id: '1.5', name: '通知设置', desc: '配置系统通知偏好' },
|
||||
{ id: '1.6', name: '数据导入', desc: '批量导入员工或其他数据' },
|
||||
{ id: '1.7', name: '数据导出', desc: '导出系统数据到文件' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2, name: 'Evidence(证据管理页面)', file: 'frontend/src/pages/Evidence.tsx',
|
||||
features: [
|
||||
{ id: '2.1', name: '证据链列表', desc: '展示所有证据记录,含分类、状态等信息' },
|
||||
{ id: '2.2', name: '分类筛选', desc: '按证据类别筛选记录' },
|
||||
{ id: '2.3', name: '全局完整性验证', desc: '一键验证所有证据链的完整性' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3, name: 'EvidenceChain(员工证据链详情)', file: 'frontend/src/pages/roster/EvidenceChain.tsx',
|
||||
features: [
|
||||
{ id: '3.1', name: '证据链详情展示', desc: '展示员工个人证据链,按类别分组显示' },
|
||||
{ id: '3.2', name: '风险提醒', desc: '显示证据链中的风险提示信息' },
|
||||
{ id: '3.3', name: '证据导出', desc: '将证据链导出为纯文本格式' },
|
||||
{ id: '3.4', name: '签署状态显示', desc: '显示每条证据的签署状态' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 4, name: 'Policies(政策管理页面)', file: 'frontend/src/pages/Policies.tsx',
|
||||
features: [
|
||||
{ id: '4.1', name: '政策列表', desc: '展示所有公司政策及其当前流程阶段' },
|
||||
{ id: '4.2', name: '创建政策', desc: '新建政策,填写标题和内容' },
|
||||
{ id: '4.3', name: '民主程序推进', desc: '支持四步流程:起草→讨论→协商→公示' },
|
||||
{ id: '4.4', name: '政策详情查看', desc: '查看政策完整内容和流程状态' },
|
||||
{ id: '4.5', name: '员工签收统计', desc: '展示已公示政策的员工阅读和确认统计' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 5, name: 'MyPolicies(员工端政策页面)', file: 'frontend/src/pages/portal/MyPolicies.tsx',
|
||||
features: [
|
||||
{ id: '5.1', name: '政策列表展示', desc: '展示已公示的政策列表' },
|
||||
{ id: '5.2', name: '待签收提醒', desc: '显示待确认阅读的政策数量' },
|
||||
{ id: '5.3', name: '政策阅读', desc: '查看政策详细内容' },
|
||||
{ id: '5.4', name: '签收确认', desc: '员工确认已阅读政策' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 6, name: 'Money(财务/薪资页面)', file: 'frontend/src/pages/Money.tsx',
|
||||
features: [
|
||||
{ id: '6.1', name: '加班费计算器', desc: '配置加班计算规则,导入考勤数据,生成加班费记录' },
|
||||
{ id: '6.2', name: '考勤数据导入', desc: '通过 CSV 导入考勤数据用于加班计算' },
|
||||
{ id: '6.3', name: '导入数据预览', desc: '导入前预览数据内容' },
|
||||
{ id: '6.4', name: '加班记录查看', desc: '展示已生成的加班费记录列表' },
|
||||
{ id: '6.5', name: '薪资模板管理', desc: '创建、编辑、删除薪资模板项目(输入型/计算型)' },
|
||||
{ id: '6.6', name: '公式配置', desc: '为计算型薪资项配置计算公式' },
|
||||
{ id: '6.7', name: '批量加班处理', desc: '批量处理多条加班记录' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 7, name: 'AttendanceOvertimeInfo(员工考勤加班详情)', file: 'frontend/src/pages/roster/AttendanceOvertimeInfo.tsx',
|
||||
features: [
|
||||
{ id: '7.1', name: '考勤记录展示', desc: '展示员工个人考勤记录(Tab 切换)' },
|
||||
{ id: '7.2', name: '加班记录展示', desc: '展示员工个人加班记录' },
|
||||
{ id: '7.3', name: '培训记录展示', desc: '展示员工培训记录' },
|
||||
{ id: '7.4', name: '添加考勤记录', desc: '手动添加单条考勤记录' },
|
||||
{ id: '7.5', name: '添加培训记录', desc: '手动添加单条培训记录' },
|
||||
{ id: '7.6', name: '删除记录', desc: '删除考勤或培训记录' },
|
||||
{ id: '7.7', name: '加班汇总', desc: '显示加班总时长和加班费汇总' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 8, name: 'Attendance(考勤确认页面)', file: 'frontend/src/pages/Attendance.tsx',
|
||||
features: [
|
||||
{ id: '8.1', name: '月度考勤列表', desc: '展示员工月度考勤数据(出勤天数、加班时长等)' },
|
||||
{ id: '8.2', name: '统计概览', desc: '显示总数、待确认、已确认、有争议的数量统计' },
|
||||
{ id: '8.3', name: '月份筛选', desc: '按月份筛选考勤记录' },
|
||||
{ id: '8.4', name: '考勤状态管理', desc: '支持待确认/已确认/有争议三种状态' },
|
||||
{ id: '8.5', name: '争议备注', desc: '显示考勤争议的备注信息' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 9, name: 'Templates(文档模板页面)', file: 'frontend/src/pages/Templates.tsx',
|
||||
features: [
|
||||
{ id: '9.1', name: '模板分类浏览', desc: '按类别浏览文档模板' },
|
||||
{ id: '9.2', name: '模板选择', desc: '选择模板进行编辑和渲染' },
|
||||
{ id: '9.3', name: '变量输入', desc: '填写模板变量(如员工姓名、日期等)' },
|
||||
{ id: '9.4', name: '模板渲染', desc: '根据输入变量渲染模板内容' },
|
||||
{ id: '9.5', name: '复制渲染结果', desc: '一键复制渲染后的文本' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 10, name: 'AuditLog(系统操作日志页面)', file: 'frontend/src/pages/AuditLog.tsx',
|
||||
features: [
|
||||
{ id: '10.1', name: '操作日志列表', desc: '展示系统操作记录(操作人、动作、对象、时间)' },
|
||||
{ id: '10.2', name: '动作类型筛选', desc: '按操作类型筛选日志' },
|
||||
{ id: '10.3', name: '实体类型筛选', desc: '按操作对象类型筛选日志' },
|
||||
{ id: '10.4', name: '日期范围筛选', desc: '按时间范围筛选日志' },
|
||||
{ id: '10.5', name: '统计概览', desc: '显示日志统计信息' },
|
||||
{ id: '10.6', name: '分页', desc: '日志列表分页展示' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 11, name: 'Dashboard(工作台)', file: 'frontend/src/pages/Dashboard.tsx',
|
||||
features: [
|
||||
{ id: '11.1', name: '关键指标卡片', desc: '展示员工总数、风险数、待办数、月度薪资总额' },
|
||||
{ id: '11.2', name: '紧急风险横幅', desc: '高亮显示即将到期的合同、未签合同等紧急风险' },
|
||||
{ id: '11.3', name: '合规健康评分', desc: '展示合规健康分数及 AI 改进建议' },
|
||||
{ id: '11.4', name: '月度人工成本分析', desc: '展示当月社保、公积金、薪资等成本构成' },
|
||||
{ id: '11.5', name: '年度人工成本趋势', desc: '展示全年人工成本变化趋势图' },
|
||||
{ id: '11.6', name: '合同到期预警', desc: '列出即将到期和已过期的合同' },
|
||||
{ id: '11.7', name: '月度动态列表', desc: '展示本月入职、离职、调薪等关键人事动态' },
|
||||
{ id: '11.8', name: '风险分布下钻', desc: '按风险类型展示分布,支持下钻查看详情' },
|
||||
{ id: '11.9', name: '月度 HR 日历', desc: '以日历形式展示本月关键 HR 节点' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 12, name: 'Roster(员工花名册)', file: 'frontend/src/pages/Roster.tsx',
|
||||
features: [
|
||||
{ id: '12.1', name: '员工列表', desc: '展示所有员工的基本信息、状态、合同状态' },
|
||||
{ id: '12.2', name: '搜索功能', desc: '按姓名、手机号搜索员工' },
|
||||
{ id: '12.3', name: '状态筛选', desc: '按在职/离职状态筛选' },
|
||||
{ id: '12.4', name: '合同状态筛选', desc: '按合同状态(正常/即将到期/已到期/未签)筛选' },
|
||||
{ id: '12.5', name: '添加员工', desc: '弹窗表单添加新员工' },
|
||||
{ id: '12.6', name: '批量导入', desc: '通过 CSV 文件批量导入员工' },
|
||||
{ id: '12.7', name: '批量续签', desc: '选中多个员工批量发起合同续签' },
|
||||
{ id: '12.8', name: '批量解聘', desc: '选中多个员工批量发起解聘流程' },
|
||||
{ id: '12.9', name: '调薪操作', desc: '对单个员工发起调薪' },
|
||||
{ id: '12.10', name: '调岗操作', desc: '对单个员工发起部门调岗' },
|
||||
{ id: '12.11', name: '离职处理', desc: '对单个员工发起离职流程' },
|
||||
{ id: '12.12', name: '重新入职', desc: '对已离职员工发起重新入职' },
|
||||
{ id: '12.13', name: '撤销离职', desc: '撤销已发起的离职流程' },
|
||||
{ id: '12.14', name: '查看员工档案', desc: '跳转到员工详情档案页' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 13, name: 'Contracts(合同管理)', file: 'frontend/src/pages/Contracts.tsx',
|
||||
features: [
|
||||
{ id: '13.1', name: '合同列表', desc: '展示员工合同状态列表(含特殊状态标记:孕期、医疗期、工伤)' },
|
||||
{ id: '13.2', name: '搜索员工', desc: '按姓名/手机号搜索' },
|
||||
{ id: '13.3', name: '添加员工', desc: '弹窗添加新员工(含合同信息)' },
|
||||
{ id: '13.4', name: '合同详情抽屉', desc: '侧边抽屉展示员工合同详细信息' },
|
||||
{ id: '13.5', name: '附件管理', desc: '上传、预览、下载、删除合同附件(身份证、银行卡、合同扫描件等)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 14, name: 'Termination(解聘补偿)', file: 'frontend/src/pages/Termination.tsx',
|
||||
features: [
|
||||
{ id: '14.1', name: '解聘草稿列表', desc: '展示所有解聘草稿及状态' },
|
||||
{ id: '14.2', name: '多步解聘向导', desc: '选择员工→选择原因→合规检查→费用结算→工作交接→确认提交' },
|
||||
{ id: '14.3', name: '解聘原因选择', desc: '选择解聘原因并展示法律依据和建议' },
|
||||
{ id: '14.4', name: '合规检查', desc: '自动检查解聘流程的合规性' },
|
||||
{ id: '14.5', name: '补偿计算', desc: '自动计算经济补偿金、代通知金、双倍工资等' },
|
||||
{ id: '14.6', name: '工作交接清单', desc: '管理交接事项清单' },
|
||||
{ id: '14.7', name: '草稿详情查看', desc: '查看解聘草稿完整详情' },
|
||||
{ id: '14.8', name: '审批操作', desc: '审批通过/驳回解聘草稿' },
|
||||
{ id: '14.9', name: '执行解聘', desc: '执行已审批通过的解聘' },
|
||||
{ id: '14.10', name: '撤销解聘', desc: '撤销已发起的解聘流程' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 15, name: 'Compensation(补偿计算器)', file: 'frontend/src/pages/Compensation.tsx',
|
||||
features: [
|
||||
{ id: '15.1', name: '经济补偿计算', desc: '根据入职日期、离职日期、月均工资计算经济补偿金' },
|
||||
{ id: '15.2', name: '双倍工资计算', desc: '根据入职日期和合同签订日期计算未签合同双倍工资' },
|
||||
{ id: '15.3', name: '员工选择', desc: '选择已有员工自动填充信息' },
|
||||
{ id: '15.4', name: '手动输入', desc: '手动输入各项参数进行计算' },
|
||||
{ id: '15.5', name: '社平工资封顶', desc: '按当地社平工资三倍封顶计算' },
|
||||
{ id: '15.6', name: '违法解除倍数', desc: '支持违法解除双倍补偿计算' },
|
||||
{ id: '15.7', name: '法律依据展示', desc: '展示计算结果对应的法律条文' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 16, name: 'SocialInsurance(社保公积金)', file: 'frontend/src/pages/SocialInsurance.tsx',
|
||||
features: [
|
||||
{ id: '16.1', name: '月度处理', desc: '查看月度增减员变化,处理社保/公积金申报' },
|
||||
{ id: '16.2', name: '社保政策配置', desc: '按城市配置社保缴纳比例和基数上下限' },
|
||||
{ id: '16.3', name: '公积金政策配置', desc: '按城市配置公积金缴纳比例和基数上下限' },
|
||||
{ id: '16.4', name: '专项扣除配置', desc: '配置个人所得税专项扣除信息' },
|
||||
{ id: '16.5', name: '新版本创建', desc: '创建新的社保/公积金政策版本' },
|
||||
{ id: '16.6', name: '缴纳计算', desc: '根据员工工资和政策计算缴纳金额' },
|
||||
{ id: '16.7', name: 'AI 政策建议', desc: 'AI 辅助建议政策更新' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 17, name: 'Notifications(通知管理)', file: 'frontend/src/pages/Notifications.tsx',
|
||||
features: [
|
||||
{ id: '17.1', name: '通知概览', desc: '展示已启用的通知类型及数量' },
|
||||
{ id: '17.2', name: '通知日志', desc: '展示已发送通知的历史记录' },
|
||||
{ id: '17.3', name: '合同到期检查', desc: '手动触发合同到期检查' },
|
||||
{ id: '17.4', name: '提醒天数配置', desc: '配置合同到期提前提醒天数' },
|
||||
{ id: '17.5', name: '薪资/社保/公积金/税务日配置', desc: '配置各项事务的提醒日期' },
|
||||
{ id: '17.6', name: '微信通知配置', desc: '配置企业微信 Webhook URL' },
|
||||
{ id: '17.7', name: '邮件通知配置', desc: '配置邮件通知开关和参数' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 18, name: 'AIAssistant(AI 助手)', file: 'frontend/src/pages/AIAssistant.tsx',
|
||||
features: [
|
||||
{ id: '18.1', name: '智能问答', desc: '劳动法相关问题的 AI 对话' },
|
||||
{ id: '18.2', name: '风险预测', desc: 'AI 分析预测潜在用工风险' },
|
||||
{ id: '18.3', name: '合同审查', desc: 'AI 审查合同条款合规性' },
|
||||
{ id: '18.4', name: '案例匹配', desc: '根据情况匹配相关法律案例' },
|
||||
{ id: '18.5', name: '知识库', desc: '查询劳动法合规知识库' },
|
||||
{ id: '18.6', name: '对话历史', desc: '查看和继续历史对话' },
|
||||
{ id: '18.7', name: '语音输入', desc: '支持语音输入提问' },
|
||||
{ id: '18.8', name: '新建对话', desc: '发起新的 AI 对话' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 19, name: 'Login(HR 端登录)', file: 'frontend/src/pages/auth/Login.tsx',
|
||||
features: [
|
||||
{ id: '19.1', name: '手机号+密码登录', desc: 'HR 端账号密码登录' },
|
||||
{ id: '19.2', name: '表单校验', desc: '手机号格式和密码非空校验' },
|
||||
{ id: '19.3', name: '密码显示切换', desc: '显示/隐藏密码' },
|
||||
{ id: '19.4', name: '忘记密码链接', desc: '跳转重置密码页面' },
|
||||
{ id: '19.5', name: '注册链接', desc: '跳转注册新企业页面' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 20, name: 'ForgotPassword(忘记密码)', file: 'frontend/src/pages/auth/ForgotPassword.tsx',
|
||||
features: [
|
||||
{ id: '20.1', name: '发送验证码', desc: '输入手机号发送验证码' },
|
||||
{ id: '20.2', name: '验证码+新密码重置', desc: '输入验证码和新密码完成重置' },
|
||||
{ id: '20.3', name: '密码显示切换', desc: '显示/隐藏新密码' },
|
||||
{ id: '20.4', name: '重新获取验证码', desc: '返回第一步重新获取验证码' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 21, name: 'Register(注册新企业)', file: 'frontend/src/pages/auth/Register.tsx',
|
||||
features: [
|
||||
{ id: '21.1', name: '企业注册', desc: '填写企业名称、手机号、密码注册新企业' },
|
||||
{ id: '21.2', name: '表单校验', desc: '企业名称长度、手机号格式、密码长度、两次密码一致性校验' },
|
||||
{ id: '21.3', name: '密码显示切换', desc: '显示/隐藏密码' },
|
||||
{ id: '21.4', name: '注册后自动登录', desc: '注册成功后自动登录并跳转工作台' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 22, name: 'PortalLogin(员工端登录)', file: 'frontend/src/pages/portal/PortalLogin.tsx',
|
||||
features: [
|
||||
{ id: '22.1', name: '密码登录', desc: '员工手机号+密码登录' },
|
||||
{ id: '22.2', name: '验证码登录', desc: '员工手机号+短信验证码登录' },
|
||||
{ id: '22.3', name: '登录模式切换', desc: '密码登录/验证码登录切换' },
|
||||
{ id: '22.4', name: '发送验证码', desc: '向员工手机发送验证码' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 23, name: 'AutoLogin(员工端自动登录)', file: 'frontend/src/pages/portal/AutoLogin.tsx',
|
||||
features: [
|
||||
{ id: '23.1', name: '扫码自动登录', desc: '通过一次性 Token 自动登录员工端' },
|
||||
{ id: '23.2', name: '登录状态展示', desc: '展示加载中/成功/失败状态' },
|
||||
{ id: '23.3', name: '失败回退', desc: '登录失败时提供手动登录入口' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 24, name: 'Onboarding(入职信息填报)', file: 'frontend/src/pages/portal/Onboarding.tsx',
|
||||
features: [
|
||||
{ id: '24.1', name: '入职表单填写', desc: '填写姓名、手机号、身份证号、紧急联系人等' },
|
||||
{ id: '24.2', name: '入职材料上传', desc: '上传身份证、学历证明、银行卡等材料' },
|
||||
{ id: '24.3', name: '文件类型选择', desc: '选择上传文件的类型(身份证正反面、学历、银行卡、其他)' },
|
||||
{ id: '24.4', name: '已传文件管理', desc: '查看和删除已上传文件' },
|
||||
{ id: '24.5', name: '提交成功页', desc: '提交后展示成功提示' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 25, name: 'Payslip(员工端工资条)', file: 'frontend/src/pages/portal/Payslip.tsx',
|
||||
features: [
|
||||
{ id: '25.1', name: '月度工资条', desc: '展示当月工资明细(基本工资、加班费、津贴、扣款)' },
|
||||
{ id: '25.2', name: '月份切换', desc: '上月/下月切换查看历史工资条' },
|
||||
{ id: '25.3', name: '工资趋势图', desc: '展示近几个月工资趋势条形图' },
|
||||
{ id: '25.4', name: '确认查收', desc: '员工确认已阅当月工资条' },
|
||||
{ id: '25.5', name: '导出 CSV', desc: '导出历史工资条为 CSV 文件' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 26, name: 'MyContract(我的劳动合同 - 员工端)', file: 'frontend/src/pages/portal/MyContract.tsx',
|
||||
features: [
|
||||
{ id: '26.1', name: '合同概览', desc: '展示合同类型、签订方式、起止日期、试用期等信息' },
|
||||
{ id: '26.2', name: '到期提醒', desc: '合同30天内到期时展示提醒横幅' },
|
||||
{ id: '26.3', name: '签署确认状态', desc: '展示合同是否已确认签署' },
|
||||
{ id: '26.4', name: '重发确认链接', desc: '未确认时可重发合同签署确认链接' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 27, name: 'ContractConfirm(合同签署确认)', file: 'frontend/src/pages/portal/ContractConfirm.tsx',
|
||||
features: [
|
||||
{ id: '27.1', name: '合同信息展示', desc: '展示合同类型、期限、起止日期、试用期等' },
|
||||
{ id: '27.2', name: '阅读确认', desc: '勾选确认已阅读合同内容' },
|
||||
{ id: '27.3', name: '验证码验证', desc: '发送验证码并验证身份' },
|
||||
{ id: '27.4', name: '签署确认', desc: '确认签署并记录时间、IP、设备信息' },
|
||||
{ id: '27.5', name: '成功页面', desc: '确认成功后展示成功提示' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 28, name: 'PortalNav(员工端导航栏)', file: 'frontend/src/pages/portal/PortalNav.tsx',
|
||||
features: [
|
||||
{ id: '28.1', name: '页面导航', desc: '工资条/我的合同/规章制度三个导航入口' },
|
||||
{ id: '28.2', name: '当前页高亮', desc: '高亮显示当前所在页面' },
|
||||
{ id: '28.3', name: '退出登录', desc: '员工端退出登录' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 29, name: 'EmployeeProfile(员工详情档案)', file: 'frontend/src/pages/roster/EmployeeProfile.tsx',
|
||||
features: [
|
||||
{ id: '29.1', name: 'Tab 分组导航', desc: '按分组展示 Tab:人事信息、薪酬、考勤绩效、风险合规、变更历史' },
|
||||
{ id: '29.2', name: 'Tab 计数徽标', desc: '每个 Tab 显示对应记录数量' },
|
||||
{ id: '29.3', name: '离职员工 Tab 隐藏', desc: '离职员工自动隐藏考勤和绩效 Tab' },
|
||||
{ id: '29.4', name: '员工状态展示', desc: '展示员工姓名和在职/离职状态' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 30, name: 'BasicInfo(基本信息 Tab)', file: 'frontend/src/pages/roster/BasicInfo.tsx',
|
||||
features: [
|
||||
{ id: '30.1', name: '基本信息展示', desc: '展示员工部门、性别、手机号、入职日期、月薪等' },
|
||||
{ id: '30.2', name: '信息编辑', desc: '编辑员工基本信息(部门、薪资、联系方式等)' },
|
||||
{ id: '30.3', name: '特殊状态标记', desc: '标记三期/医疗期/工伤状态' },
|
||||
{ id: '30.4', name: '社保公积金基数', desc: '设置社保基数、公积金基数、专项扣除' },
|
||||
{ id: '30.5', name: '城市设置', desc: '设置员工所在城市(影响社保政策)' },
|
||||
{ id: '30.6', name: '附件上传', desc: '上传身份证、银行卡、学历证书等附件' },
|
||||
{ id: '30.7', name: '附件管理', desc: '查看和删除已上传附件' },
|
||||
{ id: '30.8', name: '入职二维码', desc: '生成员工端自动登录二维码' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 31, name: 'ContractInfo(劳动合同 Tab)', file: 'frontend/src/pages/roster/ContractInfo.tsx',
|
||||
features: [
|
||||
{ id: '31.1', name: '合同列表', desc: '展示员工所有合同记录' },
|
||||
{ id: '31.2', name: '添加合同', desc: '新增合同(类型、期限、试用期、签署方式等)' },
|
||||
{ id: '31.3', name: '合同附件上传', desc: '上传合同扫描件等附件' },
|
||||
{ id: '31.4', name: '合同删除', desc: '删除合同记录' },
|
||||
{ id: '31.5', name: '续签建议', desc: '根据合同次数和工龄自动建议合同类型(无固定期限等)' },
|
||||
{ id: '31.6', name: '合同签署确认链接', desc: '发送电子合同签署确认链接' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 32, name: 'PayslipSocialInfo(薪酬社保 Tab)', file: 'frontend/src/pages/roster/PayslipSocialInfo.tsx',
|
||||
features: [
|
||||
{ id: '32.1', name: '工资条列表', desc: '展示员工所有月度工资条(含合计行)' },
|
||||
{ id: '32.2', name: '缴纳记录', desc: '展示社保/公积金月度缴纳记录' },
|
||||
{ id: '32.3', name: '城市变更历史', desc: '展示员工城市变更记录' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 33, name: 'DisciplinaryInfo(违纪记录 Tab)', file: 'frontend/src/pages/roster/DisciplinaryInfo.tsx',
|
||||
features: [
|
||||
{ id: '33.1', name: '违纪记录列表', desc: '展示员工违纪记录' },
|
||||
{ id: '33.2', name: '新增违纪记录', desc: '录入违纪类型、事实描述、严重程度、处理结果' },
|
||||
{ id: '33.3', name: '员工签字确认', desc: '标记员工是否已签字确认违纪处理' },
|
||||
{ id: '33.4', name: '删除违纪记录', desc: '删除违纪记录' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 34, name: 'PerformanceInfo(绩效考核 Tab)', file: 'frontend/src/pages/roster/PerformanceInfo.tsx',
|
||||
features: [
|
||||
{ id: '34.1', name: '绩效记录列表', desc: '展示员工绩效考核记录' },
|
||||
{ id: '34.2', name: '新增绩效记录', desc: '录入考核周期、得分、等级、结果、评语、改进计划' },
|
||||
{ id: '34.3', name: '员工签字确认', desc: '标记员工是否已签字确认考核结果' },
|
||||
{ id: '34.4', name: '删除绩效记录', desc: '删除绩效记录' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 35, name: 'TerminationInfo(离职/解聘 Tab)', file: 'frontend/src/pages/roster/TerminationInfo.tsx',
|
||||
features: [
|
||||
{ id: '35.1', name: '离职记录列表', desc: '展示员工离职/解聘记录' },
|
||||
{ id: '35.2', name: '解聘通知书打印', desc: '生成并打印解除劳动合同通知书' },
|
||||
{ id: '35.3', name: '费用结算明细', desc: '展示补偿金、代通知金等费用结算' },
|
||||
{ id: '35.4', name: '证据链关联', desc: '关联展示解聘相关证据链' },
|
||||
{ id: '35.5', name: '已撤销记录', desc: '展示已撤销的解聘记录' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 36, name: 'AttachmentInfo(附件管理 Tab)', file: 'frontend/src/pages/roster/AttachmentInfo.tsx',
|
||||
features: [
|
||||
{ id: '36.1', name: '附件列表', desc: '展示员工所有附件文件' },
|
||||
{ id: '36.2', name: '按类型上传', desc: '选择文件类型(身份证/银行卡/学历/其他)上传' },
|
||||
{ id: '36.3', name: '附件预览', desc: '预览已上传的附件' },
|
||||
{ id: '36.4', name: '附件下载', desc: '下载附件文件' },
|
||||
{ id: '36.5', name: '附件删除', desc: '删除附件' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 37, name: 'ChangeHistoryTab(变更历史 Tab)', file: 'frontend/src/pages/roster/ChangeHistoryTab.tsx',
|
||||
features: [
|
||||
{ id: '37.1', name: '薪资变更历史', desc: '展示薪资调整记录(原薪资、新薪资、变动额、原因)' },
|
||||
{ id: '37.2', name: '部门变更历史', desc: '展示部门调岗记录' },
|
||||
{ id: '37.3', name: '社保变更历史', desc: '展示社保缴纳变更记录' },
|
||||
{ id: '37.4', name: '公积金变更历史', desc: '展示公积金缴纳变更记录' },
|
||||
{ id: '37.5', name: '离职/解聘历史', desc: '展示离职解聘记录' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 38, name: 'AnnualValueReport(年度价值报告)', file: 'frontend/src/pages/tools/AnnualValueReport.tsx',
|
||||
features: [
|
||||
{ id: '38.1', name: '价值指标卡片', desc: '展示规避损失、节约工时、节约成本、总价值' },
|
||||
{ id: '38.2', name: '年度统计', desc: '展示处理风险数、AI咨询数、合同审查数等年度统计' },
|
||||
{ id: '38.3', name: '月度时间轴', desc: '展示全年月度价值变化趋势图' },
|
||||
{ id: '38.4', name: '年份切换', desc: '切换查看不同年份的价值报告' },
|
||||
{ id: '38.5', name: '报告保存', desc: '保存当前年度价值报告' },
|
||||
{ id: '38.6', name: '历史报告', desc: '查看已保存的历史报告' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 39, name: 'HealthCheck(用工体检诊断)', file: 'frontend/src/pages/tools/HealthCheck.tsx',
|
||||
features: [
|
||||
{ id: '39.1', name: '总体健康评分', desc: '展示用工合规总体评分和等级(健康/中等风险/高风险)' },
|
||||
{ id: '39.2', name: '6 维度诊断', desc: '从6个维度深度诊断用工合规状况' },
|
||||
{ id: '39.3', name: '维度展开详情', desc: '展开查看每个维度的详细问题' },
|
||||
{ id: '39.4', name: '报告保存', desc: '保存当前诊断报告' },
|
||||
{ id: '39.5', name: '历史报告', desc: '查看已保存的历史诊断报告' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 40, name: 'MedicalPeriodCalculator(医疗期计算器)', file: 'frontend/src/pages/tools/MedicalPeriodCalculator.tsx',
|
||||
features: [
|
||||
{ id: '40.1', name: '医疗期计算', desc: '根据工龄、地区、病休天数计算法定医疗期' },
|
||||
{ id: '40.2', name: '上海特殊规定', desc: '支持上海地区特殊医疗期计算规则' },
|
||||
{ id: '40.3', name: '全国通用规定', desc: '支持全国通用医疗期计算(劳部发[1994]479号)' },
|
||||
{ id: '40.4', name: '法律依据展示', desc: '展示计算结果对应的法律条文' },
|
||||
{ id: '40.5', name: '注意事项提示', desc: '展示医疗期相关注意事项' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 41, name: 'RosterModals(花名册弹窗组件)', file: 'frontend/src/pages/roster/modals.tsx',
|
||||
features: [
|
||||
{ id: '41.1', name: '调薪弹窗', desc: '输入新薪资、生效日期、原因发起调薪' },
|
||||
{ id: '41.2', name: '调岗弹窗', desc: '输入新部门、生效日期、原因发起调岗' },
|
||||
{ id: '41.3', name: '离职弹窗', desc: '发起员工离职流程' },
|
||||
{ id: '41.4', name: '重新入职弹窗', desc: '对已离职员工发起重新入职' },
|
||||
{ id: '41.5', name: '添加员工弹窗', desc: '录入新员工基本信息' },
|
||||
{ id: '41.6', name: '批量导入弹窗', desc: '上传 CSV 批量导入员工' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
/** 总功能数 */
|
||||
export const totalFeatures = surveyPages.reduce((sum, p) => sum + p.features.length, 0)
|
||||
Reference in New Issue
Block a user