refactor: 全量迁移前端 API 调用到统一 api-services 服务层
- 新建 api-services-raw.ts 导出原始 axios 方法供特殊端点使用 - 完成 api-services.ts 全领域覆盖(auth/employee/roster/dashboard/attendance/payroll/socialInsurance/commercialInsurance/termination/policies/evidence/audit/calendar/companyFiles/notifications/settings/ai/platform/portal/survey/search) - 迁移所有 47+ 页面文件:pages/、pages/roster/、pages/portal/、pages/platform/、pages/auth/、pages/dashboard/、pages/compliance/ - 移除所有直接 import api from '../../lib/api' 引用 - 修复 Termination.tsx / WorkProcess.tsx 中 string|null 类型错误 - 修复 SocialInsurance.tsx 中 api-services-raw delete 导入名 - 修复 PlatformLogin.tsx 变量遮蔽问题 - tsc --noEmit 零错误,vite build 成功
This commit is contained in:
@@ -7,8 +7,8 @@ import remarkGfm from 'remark-gfm'
|
||||
import rehypeRaw from 'rehype-raw'
|
||||
import { Document, Packer, Paragraph, HeadingLevel, TextRun, Table, TableRow, TableCell, WidthType, BorderStyle, AlignmentType } from 'docx'
|
||||
import { saveAs } from 'file-saver'
|
||||
import api from '../lib/api'
|
||||
import { employeeApi } from '../lib/api-services'
|
||||
import { aiApi, rosterApi, employeeApi } from '../lib/api-services'
|
||||
import { post as apiPost } from '../lib/api-services-raw'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -107,30 +107,28 @@ function useAIHistory(type: 'predict' | 'review' | 'case') {
|
||||
const { data: history } = useQuery<any[]>({
|
||||
queryKey,
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/ai/conversations?type=${type}`) as any
|
||||
return res.data
|
||||
return await aiApi.conversations(type)
|
||||
},
|
||||
})
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async ({ title, input, result }: { title: string; input: string; result: string }) => {
|
||||
const res = await api.post('/ai/conversations', {
|
||||
const res = await aiApi.createConversation({
|
||||
title: `${type}:${title}`,
|
||||
messages: [{ role: 'user', content: input }, { role: 'assistant', content: result }],
|
||||
}) as any
|
||||
return res.data
|
||||
return res
|
||||
},
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey }),
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/ai/conversations/${id}`),
|
||||
mutationFn: (id: string) => aiApi.removeConversation(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey }),
|
||||
})
|
||||
|
||||
const loadHistory = useCallback(async (id: string) => {
|
||||
const res = await api.get(`/ai/conversations/${id}`) as any
|
||||
return res.data
|
||||
return await aiApi.conversation(id)
|
||||
}, [])
|
||||
|
||||
return { history, saveMutation, deleteMutation, loadHistory }
|
||||
@@ -238,20 +236,18 @@ function ChatTab() {
|
||||
const { data: conversations } = useQuery<any[]>({
|
||||
queryKey: ['ai-conversations'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/ai/conversations?type=chat') as any
|
||||
return res.data
|
||||
return await aiApi.conversations('chat')
|
||||
},
|
||||
})
|
||||
|
||||
const deleteConvMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/ai/conversations/${id}`),
|
||||
mutationFn: (id: string) => aiApi.removeConversation(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['ai-conversations'] }),
|
||||
})
|
||||
|
||||
const consultMutation = useMutation({
|
||||
mutationFn: async (data: typeof consultForm) => {
|
||||
const res = await api.post('/ai/consultation', data) as any
|
||||
return res.data
|
||||
return await aiApi.consult(data)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已提交咨询请求,专业律师将尽快与您联系')
|
||||
@@ -274,11 +270,11 @@ function ChatTab() {
|
||||
saveTimerRef.current = setTimeout(async () => {
|
||||
const title = `chat:${messages.find(m => m.role === 'user')?.content.slice(0, 30) || '新对话'}`
|
||||
if (currentConvId) {
|
||||
await api.put(`/ai/conversations/${currentConvId}`, { messages }).catch(() => {})
|
||||
await aiApi.updateConversation(currentConvId, { messages }).catch(() => {})
|
||||
} else {
|
||||
const res = await api.post('/ai/conversations', { title, messages }) as any
|
||||
if (res.data?.id) {
|
||||
setCurrentConvId(res.data.id)
|
||||
const res = await aiApi.createConversation({ title, messages }) as any
|
||||
if (res?.id) {
|
||||
setCurrentConvId(res.id)
|
||||
queryClient.invalidateQueries({ queryKey: ['ai-conversations'] })
|
||||
}
|
||||
}
|
||||
@@ -288,9 +284,9 @@ function ChatTab() {
|
||||
|
||||
const loadConversation = async (id: string) => {
|
||||
try {
|
||||
const res = await api.get(`/ai/conversations/${id}`) as any
|
||||
if (res.data?.messages) {
|
||||
setMessages(res.data.messages)
|
||||
const res = await aiApi.conversation(id) as any
|
||||
if (res?.messages) {
|
||||
setMessages(res.messages)
|
||||
setCurrentConvId(id)
|
||||
setShowHistory(false)
|
||||
}
|
||||
@@ -679,8 +675,8 @@ function PredictTab() {
|
||||
|
||||
// 4. 获取违纪记录(列表接口未含明细,需调用专用接口)
|
||||
try {
|
||||
const res = await api.get(`/roster/${emp.id}/disciplinary`) as any
|
||||
const records = res?.data || res || []
|
||||
const res = await rosterApi.disciplinary(emp.id) as any
|
||||
const records = res || []
|
||||
if (Array.isArray(records) && records.length > 0) {
|
||||
const typeMap: Record<string, string> = { LATE: '迟到', ABSENT: '旷工', INSUBORDINATION: '不服从管理', MISCONDUCT: '违纪', VIOLATE_POLICY: '违反制度', OTHER: '其他' }
|
||||
const actionMap: Record<string, string> = { ORAL_WARNING: '口头警告', WRITTEN_WARNING: '书面警告', DEDUCTION: '扣款', DEMOTION: '降职', TERMINATION: '辞退' }
|
||||
@@ -1365,10 +1361,8 @@ function ReviewTab() {
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const res = await api.post('/ai/review/upload', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
}) as any
|
||||
if (res.data?.text) {
|
||||
const res = await aiApi.reviewUpload(formData) as any
|
||||
if (res?.text) {
|
||||
setContractText(res.data.text)
|
||||
setFileName(file.name)
|
||||
toast.success(`已提取文件内容(${res.data.text.length} 字)`)
|
||||
@@ -1391,10 +1385,10 @@ function ReviewTab() {
|
||||
setLoading(true)
|
||||
setResult(null)
|
||||
try {
|
||||
const res = await api.post('/ai/review', { contractText }) as any
|
||||
setResult(res.data)
|
||||
const res = await aiApi.review(contractText) as any
|
||||
setResult(res)
|
||||
// 自动保存到历史
|
||||
if (res.data && !res.data.error) {
|
||||
if (res && !res.error) {
|
||||
const title = contractText.slice(0, 30).replace(/\n/g, ' ')
|
||||
saveMutation.mutate({ title, input: contractText, result: res.data.text || JSON.stringify(res.data) })
|
||||
}
|
||||
@@ -1421,7 +1415,7 @@ function ReviewTab() {
|
||||
const handleSave = async () => {
|
||||
if (!saveEmployeeId || !result) return
|
||||
try {
|
||||
await api.post('/ai/review/save', { employeeId: saveEmployeeId, type: 'REVIEW', input: contractText, result: result.text || JSON.stringify(result) })
|
||||
await aiApi.reviewSave({ employeeId: saveEmployeeId, type: 'REVIEW', input: contractText, result: result.text || JSON.stringify(result) })
|
||||
setShowSaveModal(false)
|
||||
setSaveEmployeeId('')
|
||||
toast.success('已保存到员工档案')
|
||||
@@ -1584,10 +1578,10 @@ function CaseTab() {
|
||||
setLoading(true)
|
||||
setResult('')
|
||||
try {
|
||||
const res = await api.post('/ai/match-case', { scenario }) as any
|
||||
setResult(res.data.result)
|
||||
const res = await aiApi.matchCase(scenario) as any
|
||||
setResult(res.result)
|
||||
// 自动保存到历史
|
||||
if (res.data?.result && !res.data.result.startsWith('出错了')) {
|
||||
if (res?.result && !res.result.startsWith('出错了')) {
|
||||
const title = scenario.slice(0, 30).replace(/\n/g, ' ')
|
||||
saveMutation.mutate({ title, input: scenario, result: res.data.result })
|
||||
}
|
||||
@@ -1612,7 +1606,7 @@ function CaseTab() {
|
||||
const handleSave = async () => {
|
||||
if (!saveEmployeeId || !result) return
|
||||
try {
|
||||
await api.post('/ai/review/save', { employeeId: saveEmployeeId, type: 'CASE', input: scenario, result })
|
||||
await aiApi.reviewSave({ employeeId: saveEmployeeId, type: 'CASE', input: scenario, result })
|
||||
setShowSaveModal(false)
|
||||
setSaveEmployeeId('')
|
||||
toast.success('已保存到员工档案')
|
||||
@@ -1625,7 +1619,7 @@ function CaseTab() {
|
||||
if (!todoEmployeeId || !todoTitle) return
|
||||
setCreatingTodo(true)
|
||||
try {
|
||||
await api.post('/ai/case-to-todo', {
|
||||
await aiApi.caseToTodo({
|
||||
employeeId: todoEmployeeId,
|
||||
title: todoTitle,
|
||||
description: result.slice(0, 500),
|
||||
@@ -1761,14 +1755,13 @@ function KnowledgeTab() {
|
||||
const { data: knowledgeList, isLoading } = useQuery<any[]>({
|
||||
queryKey: ['rag-knowledge'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/ai/rag/list') as any
|
||||
return res.data
|
||||
return await aiApi.ragList()
|
||||
},
|
||||
})
|
||||
|
||||
const addMutation = useMutation({
|
||||
mutationFn: async (data: typeof newItem) => {
|
||||
return await api.post('/ai/rag/add', data)
|
||||
return await aiApi.ragAdd(data)
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['rag-knowledge'] })
|
||||
@@ -1778,12 +1771,12 @@ function KnowledgeTab() {
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/ai/rag/${id}`),
|
||||
mutationFn: (id: string) => aiApi.ragRemove(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['rag-knowledge'] }),
|
||||
})
|
||||
|
||||
const seedMutation = useMutation({
|
||||
mutationFn: () => api.post('/ai/rag/seed'),
|
||||
mutationFn: () => aiApi.ragSeed(),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['rag-knowledge'] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ import { useState, useRef } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import { CalendarCheck, CheckCircle, Clock, AlertCircle, Plus, Trash2, Calendar, Users, BarChart3, Plane, Upload, Download, X, Send, Loader2, CheckCheck } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { employeeApi, rosterApi } from '../lib/api-services'
|
||||
import { attendanceApi, employeeApi, rosterApi } from '../lib/api-services'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -110,16 +109,14 @@ function ConfirmTab() {
|
||||
const params: any = { month }
|
||||
if (filterDepartment) params.department = filterDepartment
|
||||
if (filterStatus) params.status = filterStatus
|
||||
const res = await api.get('/attendance', { params }) as any
|
||||
return res.data
|
||||
return await attendanceApi.list({ month, department: filterDepartment || undefined, status: filterStatus || undefined })
|
||||
},
|
||||
})
|
||||
|
||||
const { data: stats } = useQuery<any>({
|
||||
queryKey: ['attendance-stats', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/attendance/stats?month=${month}`) as any
|
||||
return res.data
|
||||
return await attendanceApi.stats(month)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -131,15 +128,13 @@ function ConfirmTab() {
|
||||
const { data: publishRecords } = useQuery<any[]>({
|
||||
queryKey: ['attendance-publish-records'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/attendance/publish-records') as any
|
||||
return res.data
|
||||
return await attendanceApi.publishRecords()
|
||||
},
|
||||
})
|
||||
|
||||
const publishMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const res = await api.post('/attendance/publish', { month }) as any
|
||||
return res.data
|
||||
return await attendanceApi.publish(month)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success(`${month}月考勤表已发布`)
|
||||
@@ -150,8 +145,7 @@ function ConfirmTab() {
|
||||
|
||||
const cancelPublishMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
const res = await api.post(`/attendance/publish/${id}/cancel`) as any
|
||||
return res.data
|
||||
return await attendanceApi.cancelPublish(id)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已取消发布')
|
||||
@@ -162,8 +156,7 @@ function ConfirmTab() {
|
||||
|
||||
const batchConfirmMutation = useMutation({
|
||||
mutationFn: async (params: { all?: boolean; ids?: string[] }) => {
|
||||
const res = await api.post('/attendance/batch-confirm', { month, ...params }) as any
|
||||
return res.data
|
||||
return await attendanceApi.batchConfirm({ month, ...params })
|
||||
},
|
||||
onSuccess: (data: any) => {
|
||||
toast.success(`已批量确认 ${data.count} 条考勤记录`)
|
||||
@@ -176,8 +169,7 @@ function ConfirmTab() {
|
||||
|
||||
const singleConfirmMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
const res = await api.post('/attendance/confirm', { employeeId: list.find((i: any) => i.id === id)?.employeeId, month }) as any
|
||||
return res.data
|
||||
return await attendanceApi.confirm({ employeeId: list.find((i: any) => i.id === id)?.employeeId, month })
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已确认')
|
||||
@@ -520,17 +512,16 @@ function ShiftsTab() {
|
||||
const { data: shifts, isLoading } = useQuery<any>({
|
||||
queryKey: ['shifts'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/attendance/shifts') as any
|
||||
return res.data
|
||||
return await attendanceApi.shifts()
|
||||
},
|
||||
})
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async (data: any) => {
|
||||
if (editShift) {
|
||||
return api.put(`/attendance/shifts/${editShift.id}`, data)
|
||||
return attendanceApi.saveShift(data, editShift.id)
|
||||
}
|
||||
return api.post('/attendance/shifts', data)
|
||||
return attendanceApi.saveShift(data)
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['shifts'] })
|
||||
@@ -541,7 +532,7 @@ function ShiftsTab() {
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/attendance/shifts/${id}`),
|
||||
mutationFn: (id: string) => attendanceApi.removeShift(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['shifts'] }),
|
||||
})
|
||||
|
||||
@@ -637,29 +628,26 @@ function ScheduleTab() {
|
||||
const { data: shifts } = useQuery<any>({
|
||||
queryKey: ['shifts'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/attendance/shifts') as any
|
||||
return res.data
|
||||
return await attendanceApi.shifts()
|
||||
},
|
||||
})
|
||||
|
||||
const { data: assignments, isLoading } = useQuery<any>({
|
||||
queryKey: ['shift-assignments', date],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/attendance/shift-assignments?date=${date}`) as any
|
||||
return res.data
|
||||
return await attendanceApi.shiftAssignments(date)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: dailyData } = useQuery<any>({
|
||||
queryKey: ['daily-attendance', date],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/attendance/daily?date=${date}`) as any
|
||||
return res.data
|
||||
return await attendanceApi.daily(date)
|
||||
},
|
||||
})
|
||||
|
||||
const batchAssignMutation = useMutation({
|
||||
mutationFn: (items: any[]) => api.post('/attendance/shift-assignments/batch', { items }),
|
||||
mutationFn: (items: any[]) => attendanceApi.batchAssign(items),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['shift-assignments'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['daily-attendance'] })
|
||||
@@ -671,7 +659,7 @@ function ScheduleTab() {
|
||||
})
|
||||
|
||||
const deleteAssignmentMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/attendance/shift-assignments/${id}`),
|
||||
mutationFn: (id: string) => attendanceApi.removeAssignment(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['shift-assignments'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['daily-attendance'] })
|
||||
@@ -805,8 +793,7 @@ function DailyTab() {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['daily-attendance', date],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/attendance/daily?date=${date}`) as any
|
||||
return res.data
|
||||
return await attendanceApi.daily(date)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -880,8 +867,7 @@ function MonthlyTab() {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['monthly-report', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/attendance/monthly-report?month=${month}`) as any
|
||||
return res.data
|
||||
return await attendanceApi.monthlyReport(month)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -974,8 +960,7 @@ function LeavesTab() {
|
||||
const { data: leaves, isLoading } = useQuery<any>({
|
||||
queryKey: ['leave-records'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/attendance/leaves') as any
|
||||
return res.data
|
||||
return await attendanceApi.leaves()
|
||||
},
|
||||
})
|
||||
|
||||
@@ -985,7 +970,7 @@ function LeavesTab() {
|
||||
})
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/attendance/leaves', data),
|
||||
mutationFn: (data: any) => attendanceApi.createLeave(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['leave-records'] })
|
||||
setShowAdd(false)
|
||||
@@ -995,7 +980,7 @@ function LeavesTab() {
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/attendance/leaves/${id}`),
|
||||
mutationFn: (id: string) => attendanceApi.removeLeave(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['leave-records'] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { ScrollText, Search, Filter } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { auditApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
import EmptyState from '../components/ui/EmptyState'
|
||||
@@ -128,21 +128,19 @@ export default function AuditLog() {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['audit-logs', page, pageSize, action, entity, dateFrom, dateTo],
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) })
|
||||
if (action) params.set('action', action)
|
||||
if (entity) params.set('entity', entity)
|
||||
if (dateFrom) params.set('dateFrom', dateFrom)
|
||||
if (dateTo) params.set('dateTo', dateTo)
|
||||
const res = await api.get(`/audit?${params}`) as any
|
||||
return res.data
|
||||
const p: any = { page, pageSize }
|
||||
if (action) p.action = action
|
||||
if (entity) p.entity = entity
|
||||
if (dateFrom) p.dateFrom = dateFrom
|
||||
if (dateTo) p.dateTo = dateTo
|
||||
return await auditApi.list(p)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: stats } = useQuery<any>({
|
||||
queryKey: ['audit-stats'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/audit/stats') as any
|
||||
return res.data
|
||||
return await auditApi.stats()
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { toast } from 'sonner'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { CalendarDays, Plus, Trash2, ChevronLeft, ChevronRight, X, MapPin, User } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { dashboardApi, calendarApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
import { Input, Label } from '../components/ui/Input'
|
||||
@@ -66,22 +66,16 @@ export default function Calendar() {
|
||||
|
||||
const { data: calendarData } = useQuery<any>({
|
||||
queryKey: ['calendar', calendarMonth],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/dashboard/calendar?month=${calendarMonth}`) as any
|
||||
return res.data
|
||||
},
|
||||
queryFn: () => dashboardApi.calendar(calendarMonth),
|
||||
})
|
||||
|
||||
const { data: customEvents } = useQuery<any[]>({
|
||||
queryKey: ['custom-events', calendarMonth],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/calendar?month=${calendarMonth}`) as any
|
||||
return res.data
|
||||
},
|
||||
queryFn: () => calendarApi.events(calendarMonth),
|
||||
})
|
||||
|
||||
const createEventMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/calendar', data),
|
||||
mutationFn: (data: any) => calendarApi.createEvent(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['custom-events'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['calendar'] })
|
||||
@@ -93,7 +87,7 @@ export default function Calendar() {
|
||||
})
|
||||
|
||||
const deleteEventMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/calendar/${id}`),
|
||||
mutationFn: (id: string) => calendarApi.removeEvent(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['custom-events'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['calendar'] })
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState, useRef } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import { Building2, Upload, Trash2, FileText, AlertCircle, Calendar } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { companyFilesApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
import { Input, Label, Select } from '../components/ui/Input'
|
||||
@@ -29,13 +29,12 @@ export default function CompanyFiles() {
|
||||
const { data: files, isLoading } = useQuery<any[]>({
|
||||
queryKey: ['company-files', filterType],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/company-files', { params: filterType ? { fileType: filterType } : {} }) as any
|
||||
return res.data || []
|
||||
return await companyFilesApi.list(filterType ? { fileType: filterType } : {})
|
||||
},
|
||||
})
|
||||
|
||||
const addMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/company-files', data),
|
||||
mutationFn: (data: any) => companyFilesApi.add(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['company-files'] })
|
||||
toast.success('文件上传成功')
|
||||
@@ -46,7 +45,7 @@ export default function CompanyFiles() {
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/company-files/${id}`),
|
||||
mutationFn: (id: string) => companyFilesApi.remove(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['company-files'] })
|
||||
toast.success('已删除')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Calculator, Info, AlertCircle } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { rosterApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -24,7 +23,7 @@ function useEmployees() {
|
||||
return useQuery<EmployeeOption[]>({
|
||||
queryKey: ['roster-for-compensation'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/roster') as any
|
||||
const res = await rosterApi.list({} as any) as any
|
||||
return res.data
|
||||
},
|
||||
})
|
||||
|
||||
@@ -2,8 +2,7 @@ import { useState, useRef } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { Plus, Search, Paperclip, Trash2, X, FileText, Download, Eye } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import api from '../lib/api'
|
||||
import { rosterApi } from '../lib/api-services'
|
||||
import { rosterApi, employeeApi, attachmentApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
import { Input, Label, Select } from '../components/ui/Input'
|
||||
@@ -49,13 +48,13 @@ export default function Contracts() {
|
||||
const params: any = { search, page, pageSize }
|
||||
if (filterDepartment) params.department = filterDepartment
|
||||
if (filterContractStatus) params.contractStatus = filterContractStatus
|
||||
const res = await api.get('/roster', { params }) as any
|
||||
const res = await rosterApi.list({ search, page, pageSize, department: filterDepartment || undefined, contractStatus: filterContractStatus || undefined } as any) as any
|
||||
return res
|
||||
},
|
||||
})
|
||||
|
||||
const addMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/employees', data),
|
||||
mutationFn: (data: any) => employeeApi.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['employees'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
@@ -384,26 +383,24 @@ function EmployeeDetailDrawer({ employeeId, onClose }: { employeeId: string; onC
|
||||
const { data: employee } = useQuery<any>({
|
||||
queryKey: ['employee-detail', employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/employees/${employeeId}`) as any
|
||||
return res.data
|
||||
return await employeeApi.detail(employeeId)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: attachments } = useQuery<any[]>({
|
||||
queryKey: ['employee-attachments', employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/attachments/${employeeId}`) as any
|
||||
return res.data
|
||||
return await attachmentApi.list(employeeId)
|
||||
},
|
||||
})
|
||||
|
||||
const addAttachmentMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/attachments', data),
|
||||
mutationFn: (data: any) => attachmentApi.add(data),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['employee-attachments', employeeId] }),
|
||||
})
|
||||
|
||||
const deleteAttachmentMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/attachments/${id}`),
|
||||
mutationFn: (id: string) => attachmentApi.remove(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['employee-attachments', employeeId] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, RadialBarChart, RadialBar, PolarAngleAxis } from 'recharts'
|
||||
import { Users, AlertTriangle, CheckSquare, DollarSign, ArrowRight, RefreshCw, FileText, Calendar, TrendingUp, Briefcase, Calculator, Wallet, Building2, Receipt, Check, X, Clock, LayoutDashboard, ListTodo, ShieldAlert, UserPlus, AlertCircle, Download, ChevronRight, TrendingDown, ShieldCheck, Lightbulb, BookOpen, Sparkles, Repeat, XCircle, Loader2 } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { dashboardApi, rosterApi } from '../lib/api-services'
|
||||
import { dashboardApi, rosterApi, workProcessApi } from '../lib/api-services'
|
||||
import { post as apiPost, patch as apiPatch } from '../lib/api-services-raw'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -50,10 +50,7 @@ export default function Dashboard() {
|
||||
const [dismissedExpiring, setDismissedExpiring] = useState(false)
|
||||
const { data, isLoading, refetch, isFetching } = useQuery<DashboardData>({
|
||||
queryKey: ['dashboard'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/dashboard') as any
|
||||
return res.data
|
||||
},
|
||||
queryFn: () => dashboardApi.data(),
|
||||
})
|
||||
|
||||
const { data: expiringContracts } = useQuery<any>({
|
||||
@@ -65,10 +62,7 @@ export default function Dashboard() {
|
||||
|
||||
const { data: costAnalysis } = useQuery<any>({
|
||||
queryKey: ['cost-analysis', currentMonth],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/dashboard/cost-analysis?month=${currentMonth}`) as any
|
||||
return res.data
|
||||
},
|
||||
queryFn: () => dashboardApi.costAnalysis(currentMonth),
|
||||
})
|
||||
|
||||
const { data: complianceScore } = useQuery<any>({
|
||||
@@ -82,17 +76,17 @@ export default function Dashboard() {
|
||||
})
|
||||
|
||||
const resolveMutation = useMutation({
|
||||
mutationFn: (id: string) => api.patch(`/dashboard/todos/${id}/resolve`),
|
||||
mutationFn: (id: string) => apiPatch(`/dashboard/todos/${id}/resolve`),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['dashboard'] }),
|
||||
})
|
||||
|
||||
const ignoreMutation = useMutation({
|
||||
mutationFn: (id: string) => api.patch(`/dashboard/todos/${id}/ignore`),
|
||||
mutationFn: (id: string) => apiPatch(`/dashboard/todos/${id}/ignore`),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['dashboard'] }),
|
||||
})
|
||||
|
||||
const batchResolveMutation = useMutation({
|
||||
mutationFn: (ids: string[]) => api.patch('/dashboard/todos/batch-resolve', { ids }),
|
||||
mutationFn: (ids: string[]) => apiPatch('/dashboard/todos/batch-resolve', { ids }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
setSelectedIds(new Set())
|
||||
@@ -100,7 +94,7 @@ export default function Dashboard() {
|
||||
})
|
||||
|
||||
const batchIgnoreMutation = useMutation({
|
||||
mutationFn: (ids: string[]) => api.patch('/dashboard/todos/batch-ignore', { ids }),
|
||||
mutationFn: (ids: string[]) => apiPatch('/dashboard/todos/batch-ignore', { ids }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
setSelectedIds(new Set())
|
||||
@@ -1066,7 +1060,7 @@ export default function Dashboard() {
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
onClick={() => {
|
||||
api.post('/work-processes', {
|
||||
workProcessApi.create({
|
||||
type: 'RENEW',
|
||||
title: `合同续签-${c.employeeName}`,
|
||||
employeeId: c.employeeId,
|
||||
@@ -1075,7 +1069,7 @@ export default function Dashboard() {
|
||||
}).then(() => {
|
||||
toast.success(`已创建 ${c.employeeName} 的续签流程`)
|
||||
setShowExpiringModal(false)
|
||||
}).catch((err) => {
|
||||
}).catch((err: any) => {
|
||||
toast.error(err?.response?.data?.error?.message || '创建失败')
|
||||
})
|
||||
}}
|
||||
@@ -1085,7 +1079,7 @@ export default function Dashboard() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
api.post('/work-processes', {
|
||||
workProcessApi.create({
|
||||
type: 'TERMINATE',
|
||||
title: `合同终止-${c.employeeName}`,
|
||||
employeeId: c.employeeId,
|
||||
@@ -1094,7 +1088,7 @@ export default function Dashboard() {
|
||||
}).then(() => {
|
||||
toast.success(`已创建 ${c.employeeName} 的终止流程`)
|
||||
setShowExpiringModal(false)
|
||||
}).catch((err) => {
|
||||
}).catch((err: any) => {
|
||||
toast.error(err?.response?.data?.error?.message || '创建失败')
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { ShieldCheck, FileText, AlertCircle, CheckCircle, XCircle } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { evidenceApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import EmptyState from '../components/ui/EmptyState'
|
||||
import Pagination from '../components/ui/Pagination'
|
||||
@@ -19,8 +19,7 @@ export default function Evidence() {
|
||||
queryFn: async () => {
|
||||
const params: any = { page, pageSize }
|
||||
params.category = refType || 'ALL'
|
||||
const res = await api.get('/evidence', { params }) as any
|
||||
return res.data
|
||||
return await evidenceApi.list(params)
|
||||
},
|
||||
})
|
||||
const list = listData?.records || []
|
||||
@@ -29,8 +28,7 @@ export default function Evidence() {
|
||||
const { data: verifyResult, refetch: verifyAll } = useQuery<any>({
|
||||
queryKey: ['evidence-verify-all'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/evidence/verify-all') as any
|
||||
return res.data
|
||||
return await evidenceApi.verifyAll()
|
||||
},
|
||||
enabled: false,
|
||||
})
|
||||
|
||||
@@ -6,8 +6,7 @@ import * as XLSX from 'xlsx'
|
||||
import { Calculator, AlertCircle, Info, Check, Upload, Layers, Settings as SettingsIcon, Archive, Plus, Trash2, AlertTriangle, Download, FileText, X, ChevronLeft, Wallet, LayoutTemplate, Clock, Receipt, Users, TrendingDown, TrendingUp, BadgeCheck } from 'lucide-react'
|
||||
import { Stepper, type Step } from '../components/ui/Stepper'
|
||||
import { InlineAlert } from '../components/ui/InlineAlert'
|
||||
import api from '../lib/api'
|
||||
import { rosterApi } from '../lib/api-services'
|
||||
import { payrollApi, rosterApi, employeeApi } from '../lib/api-services'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -162,8 +161,7 @@ function BatchManager() {
|
||||
const { data: checkResult } = useQuery<any>({
|
||||
queryKey: ['batch-check', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/payroll2/batches/check', { params: { month } }) as any
|
||||
return res.data
|
||||
return await payrollApi.batchCheck(month)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -176,22 +174,20 @@ function BatchManager() {
|
||||
if (monthTo) params.monthTo = monthTo
|
||||
if (filterStatus) params.status = filterStatus
|
||||
if (filterType) params.type = filterType
|
||||
const res = await api.get('/payroll2/batches', { params }) as any
|
||||
return res.data
|
||||
return await payrollApi.batches(params)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: archivedBatches } = useQuery<any[]>({
|
||||
queryKey: ['archived-batches'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/payroll2/batches/archived/list') as any
|
||||
return res.data
|
||||
return await payrollApi.archivedBatches()
|
||||
},
|
||||
enabled: createMode === 'copy_batch',
|
||||
})
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/payroll2/batches', data),
|
||||
mutationFn: (data: any) => payrollApi.createBatch(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-check'] })
|
||||
@@ -202,7 +198,7 @@ function BatchManager() {
|
||||
})
|
||||
|
||||
const deleteBatchMutation = useMutation({
|
||||
mutationFn: (batchId: string) => api.delete(`/payroll2/batches/${batchId}`),
|
||||
mutationFn: (batchId: string) => payrollApi.removeBatch(batchId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-check'] })
|
||||
@@ -213,7 +209,7 @@ function BatchManager() {
|
||||
|
||||
const renameBatchMutation = useMutation({
|
||||
mutationFn: ({ batchId, name }: { batchId: string; name: string }) =>
|
||||
api.put(`/payroll2/batches/${batchId}/name`, { name }),
|
||||
payrollApi.renameBatch(batchId, name),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
toast.success('批次名称已更新')
|
||||
@@ -222,7 +218,7 @@ function BatchManager() {
|
||||
})
|
||||
|
||||
const unarchiveBatchMutation = useMutation({
|
||||
mutationFn: (batchId: string) => api.post(`/payroll2/batches/${batchId}/unarchive`),
|
||||
mutationFn: (batchId: string) => payrollApi.unarchiveBatch(batchId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-check'] })
|
||||
@@ -503,14 +499,13 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
const { data: batch, isLoading } = useQuery<any>({
|
||||
queryKey: ['batch-detail', batchId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/payroll2/batches/${batchId}`) as any
|
||||
return res.data
|
||||
return await payrollApi.batchDetail(batchId)
|
||||
},
|
||||
})
|
||||
|
||||
const updateEntryMutation = useMutation({
|
||||
mutationFn: ({ employeeId, data }: { employeeId: string; data: any }) =>
|
||||
api.put(`/payroll2/batches/${batchId}/entries/${employeeId}`, data),
|
||||
payrollApi.updateBatchEntry(batchId, employeeId, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
@@ -518,7 +513,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
})
|
||||
|
||||
const removeEmployeeMutation = useMutation({
|
||||
mutationFn: (employeeId: string) => api.delete(`/payroll2/batches/${batchId}/employees/${employeeId}`),
|
||||
mutationFn: (employeeId: string) => payrollApi.removeBatchEmployee(batchId, employeeId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
@@ -526,7 +521,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
})
|
||||
|
||||
const archiveMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll2/batches/${batchId}/archive`),
|
||||
mutationFn: () => payrollApi.archiveBatch(batchId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
@@ -537,7 +532,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
})
|
||||
|
||||
const unarchiveMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll2/batches/${batchId}/unarchive`),
|
||||
mutationFn: () => payrollApi.unarchiveBatch(batchId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
@@ -549,7 +544,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
})
|
||||
|
||||
const publishPayslipMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll2/batches/${batchId}/publish`),
|
||||
mutationFn: () => payrollApi.publishPayslip(batchId),
|
||||
onSuccess: (res: any) => {
|
||||
toast.success(`已发布 ${res.data?.published || 0} 条工资条`)
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
@@ -560,7 +555,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
const [showScheduleModal, setShowScheduleModal] = useState(false)
|
||||
const [scheduleDate, setScheduleDate] = useState('')
|
||||
const schedulePayslipMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll2/batches/${batchId}/schedule`, { scheduledAt: scheduleDate }),
|
||||
mutationFn: () => payrollApi.schedulePayslip(batchId, scheduleDate),
|
||||
onSuccess: (res: any) => {
|
||||
toast.success(`已设定定时发送 ${res.data?.scheduled || 0} 条工资条`)
|
||||
setShowScheduleModal(false)
|
||||
@@ -570,7 +565,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
})
|
||||
|
||||
const importOvertimeMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll/overtime/import-to-batch/${batchId}`),
|
||||
mutationFn: () => payrollApi.importOvertimeToBatch(batchId),
|
||||
onSuccess: (res: any) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
@@ -615,7 +610,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
})
|
||||
|
||||
const deleteBatchMutation = useMutation({
|
||||
mutationFn: () => api.delete(`/payroll2/batches/${batchId}`),
|
||||
mutationFn: () => payrollApi.removeBatch(batchId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-check'] })
|
||||
@@ -845,8 +840,8 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
try {
|
||||
const res = await api.get(`/payroll/batch/${batchId}/summary`) as any
|
||||
const { departments, grandTotal } = res.data
|
||||
const res = await payrollApi.batchSummary(batchId) as any
|
||||
const { departments, grandTotal } = res
|
||||
const headers = ['部门', '人数', '应发合计', '实发合计', '个人社保', '单位社保', '个人公积金', '单位公积金', '个税合计']
|
||||
const rows = departments.map((d: any) => [
|
||||
d.department, d.headcount, d.totalPay.toFixed(2), d.totalNetPay.toFixed(2),
|
||||
@@ -874,8 +869,8 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
try {
|
||||
const res = await api.get(`/payroll/batch/${batchId}/detail`) as any
|
||||
const { details } = res.data
|
||||
const res = await payrollApi.batchDetailExport(batchId) as any
|
||||
const { details } = res
|
||||
const headers = ['姓名', '部门', '基本工资', '岗位工资', '绩效工资', '工龄工资', '加班费', '交通补贴', '餐补', '住房补贴', '通讯补贴', '其他津贴', '奖金', '扣款', '其他扣款', '个人社保', '个人公积金', '个税', '应发合计', '实发工资']
|
||||
const rows = details.map((d: any) => [
|
||||
d.name, d.department,
|
||||
@@ -1161,13 +1156,12 @@ function AddEmployeeToBatch({ batchId, onClose }: { batchId: string; onClose: ()
|
||||
const { data: employees } = useQuery<any>({
|
||||
queryKey: ['employees-for-batch'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/employees', { params: { pageSize: 100 } }) as any
|
||||
return res.data
|
||||
return await employeeApi.paged({ pageSize: 100 })
|
||||
},
|
||||
})
|
||||
|
||||
const addMutation = useMutation({
|
||||
mutationFn: (employeeIds: string[]) => api.post(`/payroll2/batches/${batchId}/employees`, { employeeIds }),
|
||||
mutationFn: (employeeIds: string[]) => payrollApi.addBatchEmployees(batchId, employeeIds),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['batches'] })
|
||||
@@ -1225,13 +1219,12 @@ function TemplateManager() {
|
||||
const { data: items, isLoading } = useQuery<any[]>({
|
||||
queryKey: ['payslip-template'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/payroll2/template') as any
|
||||
return res.data
|
||||
return await payrollApi.template()
|
||||
},
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/payroll2/template/${id}`),
|
||||
mutationFn: (id: string) => payrollApi.removeTemplateItem(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['payslip-template'] })
|
||||
toast.success('已删除')
|
||||
@@ -1240,7 +1233,7 @@ function TemplateManager() {
|
||||
})
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/payroll2/template', data),
|
||||
mutationFn: (data: any) => payrollApi.createTemplateItem(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['payslip-template'] })
|
||||
setShowForm(false)
|
||||
@@ -1250,7 +1243,7 @@ function TemplateManager() {
|
||||
})
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: any }) => api.put(`/payroll2/template/${id}`, data),
|
||||
mutationFn: ({ id, data }: { id: string; data: any }) => payrollApi.updateTemplateItem(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['payslip-template'] })
|
||||
setShowForm(false)
|
||||
@@ -1491,13 +1484,12 @@ function OvertimeCalculator() {
|
||||
const { data: config, isLoading: configLoading } = useQuery<any>({
|
||||
queryKey: ['overtime-config'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/payroll/overtime/config') as any
|
||||
return res.data
|
||||
return await payrollApi.overtimeConfig()
|
||||
},
|
||||
})
|
||||
|
||||
const saveConfigMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/payroll/overtime/config', data),
|
||||
mutationFn: (data: any) => payrollApi.saveOvertimeConfig(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['overtime-config'] })
|
||||
},
|
||||
@@ -1507,8 +1499,7 @@ function OvertimeCalculator() {
|
||||
const { data: employees } = useQuery<{ items: { id: string; name: string; department: string }[] }>({
|
||||
queryKey: ['employees-for-overtime'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/employees', { params: { pageSize: 100 } }) as any
|
||||
return res.data
|
||||
return await employeeApi.paged({ pageSize: 100 })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1516,14 +1507,13 @@ function OvertimeCalculator() {
|
||||
const { data: overtimeRecords, refetch } = useQuery<any[]>({
|
||||
queryKey: ['overtime-records', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/payroll/overtime', { params: { month } }) as any
|
||||
return res.data
|
||||
return await payrollApi.overtimeRecords({ month })
|
||||
},
|
||||
enabled: step === 3,
|
||||
})
|
||||
|
||||
const batchImportMutation = useMutation({
|
||||
mutationFn: (data: any[]) => api.post('/payroll/overtime/batch', data),
|
||||
mutationFn: (data: any[]) => payrollApi.batchImportOvertime(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['overtime-records'] })
|
||||
setPreviewData([])
|
||||
@@ -1534,7 +1524,7 @@ function OvertimeCalculator() {
|
||||
// 更新单条加班记录
|
||||
const updateOvertimeMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: any }) =>
|
||||
api.put(`/payroll/overtime/${id}`, data),
|
||||
payrollApi.updateOvertime(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['overtime-records'] })
|
||||
setEditingId(null)
|
||||
@@ -1939,18 +1929,17 @@ function PayslipManager() {
|
||||
const { data: payslips, isLoading } = useQuery<any[]>({
|
||||
queryKey: ['payslips', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/payroll/payslip', { params: { month } }) as any
|
||||
return res.data
|
||||
return await payrollApi.payslips({ month })
|
||||
},
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/payroll/payslip/${id}`),
|
||||
mutationFn: (id: string) => payrollApi.removePayslip(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['payslips'] }),
|
||||
})
|
||||
|
||||
const generateFromBatchMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/payroll2/payslips/generate', data),
|
||||
mutationFn: (data: any) => payrollApi.generatePayslips(data?.month || data),
|
||||
onSuccess: (res: any) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['payslips'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
@@ -1960,7 +1949,7 @@ function PayslipManager() {
|
||||
})
|
||||
|
||||
const taxPreviewMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/payroll/tax-preview', data),
|
||||
mutationFn: (data: any) => payrollApi.taxPreview(data),
|
||||
onSuccess: (res: any) => {
|
||||
setTaxResult(res.data)
|
||||
setShowTaxPreview(true)
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useState } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import { Bell, CheckCircle, AlertCircle, Send, Settings as SettingsIcon, X } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { notificationsApi } from '../lib/api-services'
|
||||
import { post as apiPost } from '../lib/api-services-raw'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
import EmptyState from '../components/ui/EmptyState'
|
||||
@@ -39,21 +40,19 @@ export default function Notifications() {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['notification-logs', page, pageSize],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/notifications/logs?page=${page}&pageSize=${pageSize}`) as any
|
||||
return res.data
|
||||
return await notificationsApi.logs({ page, pageSize })
|
||||
},
|
||||
})
|
||||
|
||||
const { data: settings } = useQuery<any>({
|
||||
queryKey: ['notification-settings'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/notifications/settings') as any
|
||||
return res.data
|
||||
return await notificationsApi.settings()
|
||||
},
|
||||
})
|
||||
|
||||
const checkContractsMutation = useMutation({
|
||||
mutationFn: () => api.post('/notifications/check-contracts'),
|
||||
mutationFn: () => apiPost('/notifications/check-contracts'),
|
||||
onSuccess: () => {
|
||||
toast.success('合同到期检查已触发')
|
||||
queryClient.invalidateQueries({ queryKey: ['notification-logs'] })
|
||||
@@ -174,7 +173,7 @@ function SettingsModal({ settings, onClose, onSuccess }: { settings: any; onClos
|
||||
})
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: () => api.put('/notifications/settings', form),
|
||||
mutationFn: () => notificationsApi.updateSettings(form),
|
||||
onSuccess: () => { toast.success('通知设置已保存'); onSuccess() },
|
||||
onError: () => toast.error('保存失败'),
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import { FileText, Plus, ChevronRight, CheckCircle, Clock, X } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { policiesApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
import EmptyState from '../components/ui/EmptyState'
|
||||
@@ -30,21 +30,20 @@ export default function Policies() {
|
||||
const { data: listData, isLoading } = useQuery<any>({
|
||||
queryKey: ['policies', page, pageSize],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/policies', { params: { page, pageSize } }) as any
|
||||
return res.data
|
||||
return await policiesApi.list({ page, pageSize })
|
||||
},
|
||||
})
|
||||
const list = listData?.items || []
|
||||
const total = listData?.total || 0
|
||||
|
||||
const advanceMutation = useMutation({
|
||||
mutationFn: ({ id, step, note }: { id: string; step: number; note?: string }) => api.post(`/policies/${id}/advance-step`, { step, note }),
|
||||
mutationFn: ({ id, step, note }: { id: string; step: number; note?: string }) => policiesApi.advanceStep(id, step, note),
|
||||
onSuccess: () => {
|
||||
toast.success('流程步骤已推进')
|
||||
queryClient.invalidateQueries({ queryKey: ['policies'] })
|
||||
// 刷新选中制度详情
|
||||
if (selectedPolicy) {
|
||||
api.get(`/policies/${selectedPolicy.id}`).then((res: any) => setSelectedPolicy(res.data))
|
||||
policiesApi.detail(selectedPolicy.id).then((res: any) => setSelectedPolicy(res))
|
||||
}
|
||||
},
|
||||
onError: (err: any) => toast.error(err?.response?.data?.error?.message || '操作失败'),
|
||||
@@ -196,7 +195,7 @@ function CreatePolicyModal({ onClose, onSuccess }: { onClose: () => void; onSucc
|
||||
const [type, setType] = useState('RULES')
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: () => api.post('/policies', { title, content, type }),
|
||||
mutationFn: () => policiesApi.create({ title, content, type }),
|
||||
onSuccess: () => { toast.success('制度已创建'); onSuccess() },
|
||||
onError: (err: any) => toast.error(err?.response?.data?.error?.message || '创建失败'),
|
||||
})
|
||||
@@ -243,8 +242,7 @@ function ReadStats({ policyId }: { policyId: string }) {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['policy-read-stats', policyId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/policies/${policyId}/read-stats`) as any
|
||||
return res.data
|
||||
return await policiesApi.readStats(policyId)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { toast } from 'sonner'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { useConfirm } from '../hooks/useConfirm'
|
||||
import { Users, FileText, AlertTriangle, Calendar, TrendingUp, Scale, X, Plus, Check, UserX, UserPlus, DollarSign, Building2, RotateCcw, History, Upload, Wallet, Download } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { rosterApi, employeeApi, terminationApi } from '../lib/api-services'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import { useDebouncedValue } from '../hooks/useDebouncedValue'
|
||||
import Card from '../components/ui/Card'
|
||||
@@ -58,7 +58,7 @@ export default function Roster() {
|
||||
if (filterStatus === 'PROBATION') params.status = 'ACTIVE'
|
||||
if (filterContractStatus) params.contractStatus = filterContractStatus
|
||||
if (filterDepartment) params.department = filterDepartment
|
||||
const res = await api.get('/roster', { params }) as any
|
||||
const res = await rosterApi.list({ search: debouncedSearch, page, pageSize, status: filterStatus === 'PROBATION' ? 'ACTIVE' : filterStatus || undefined, contractStatus: filterContractStatus || undefined, department: filterDepartment || undefined } as any) as any
|
||||
return res
|
||||
},
|
||||
})
|
||||
@@ -83,7 +83,7 @@ export default function Roster() {
|
||||
}, [employeeParam, debouncedSearch, isLoading, employees, selectedId, setSearchParams])
|
||||
|
||||
const addMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/employees', data),
|
||||
mutationFn: (data: any) => employeeApi.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
@@ -93,7 +93,7 @@ export default function Roster() {
|
||||
})
|
||||
|
||||
const resignMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/termination/draft', {
|
||||
mutationFn: (data: any) => terminationApi.createDraft({
|
||||
employeeId: data.employeeId,
|
||||
type: 'RESIGNATION',
|
||||
reason: 'RESIGNATION',
|
||||
@@ -113,7 +113,7 @@ export default function Roster() {
|
||||
})
|
||||
|
||||
const revokeMutation = useMutation({
|
||||
mutationFn: (recordId: string) => api.delete(`/termination/${recordId}/revoke`),
|
||||
mutationFn: (recordId: string) => terminationApi.revoke(recordId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
@@ -122,7 +122,7 @@ export default function Roster() {
|
||||
})
|
||||
|
||||
const rehireMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post(`/employees/${rehireEmployee?.id}/rehire`, data),
|
||||
mutationFn: (data: any) => employeeApi.rehire(rehireEmployee?.id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
@@ -133,7 +133,7 @@ export default function Roster() {
|
||||
})
|
||||
|
||||
const salaryChangeMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post(`/roster/${salaryEmployee?.id}/salary-change`, data),
|
||||
mutationFn: (data: any) => rosterApi.salaryChange(salaryEmployee?.id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
@@ -144,7 +144,7 @@ export default function Roster() {
|
||||
})
|
||||
|
||||
const deptChangeMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post(`/roster/${deptEmployee?.id}/department-change`, data),
|
||||
mutationFn: (data: any) => rosterApi.departmentChange(deptEmployee?.id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
@@ -155,7 +155,7 @@ export default function Roster() {
|
||||
})
|
||||
|
||||
const batchRenewMutation = useMutation({
|
||||
mutationFn: (data: { contractIds: string[]; years: number }) => api.post('/employees/contracts/batch-renew', data),
|
||||
mutationFn: (data: { contractIds: string[]; years: number }) => employeeApi.batchRenew(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
@@ -167,7 +167,7 @@ export default function Roster() {
|
||||
})
|
||||
|
||||
const previewRenewMutation = useMutation({
|
||||
mutationFn: (contractIds: string[]) => api.post('/employees/contracts/preview-renew', { contractIds }),
|
||||
mutationFn: (contractIds: string[]) => employeeApi.previewRenew(contractIds),
|
||||
onSuccess: (data: any) => {
|
||||
setPreviewData(data.data)
|
||||
},
|
||||
@@ -175,7 +175,7 @@ export default function Roster() {
|
||||
|
||||
const previewTerminateMutation = useMutation({
|
||||
mutationFn: (items: Array<{ employeeId: string; reason: string; terminationDate: string }>) =>
|
||||
api.post('/termination/batch/preview', { items }),
|
||||
terminationApi.batchPreview(items),
|
||||
onSuccess: (data: any) => {
|
||||
setTerminatePreviewData(data.data)
|
||||
},
|
||||
@@ -184,12 +184,12 @@ export default function Roster() {
|
||||
const batchTerminateMutation = useMutation({
|
||||
mutationFn: async (items: Array<{ employeeId: string; reason: string; terminationDate: string }>) => {
|
||||
const results = await Promise.all(
|
||||
items.map(item => api.post('/termination/draft', {
|
||||
items.map(item => terminationApi.createDraft({
|
||||
employeeId: item.employeeId,
|
||||
type: 'TERMINATION',
|
||||
reason: item.reason,
|
||||
terminationDate: item.terminationDate,
|
||||
}).catch(err => ({ error: err, employeeId: item.employeeId })))
|
||||
}).catch((err: any) => ({ error: err, employeeId: item.employeeId })))
|
||||
)
|
||||
return results
|
||||
},
|
||||
@@ -258,8 +258,7 @@ export default function Roster() {
|
||||
const { data: departmentList } = useQuery<string[]>({
|
||||
queryKey: ['roster-departments'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/roster/departments') as any
|
||||
return res.data || []
|
||||
return await rosterApi.departments()
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import Card from '../components/ui/Card'
|
||||
import { Select } from '../components/ui/Input'
|
||||
import { InlineAlert } from '../components/ui/InlineAlert'
|
||||
import api from '../lib/api'
|
||||
import { salaryDashboardApi } from '../lib/api-services'
|
||||
|
||||
/** 金额格式化 */
|
||||
const fmt = (n: number) => (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||
@@ -21,8 +21,7 @@ export default function SalaryDashboard() {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['salary-dashboard', year],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/salary/dashboard', { params: { year } }) as any
|
||||
return res.data
|
||||
return await salaryDashboardApi.data(Number(year))
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useState, useEffect } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { Building2, Users, CreditCard, Plus, Bell, Download, Upload, FileSpreadsheet, Clock, CheckCircle, AlertCircle, ClipboardList } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { settingsApi, notificationsApi } from '../lib/api-services'
|
||||
import { post as apiPost, patch as apiPatch } from '../lib/api-services-raw'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -17,21 +18,19 @@ export default function Settings() {
|
||||
const { data: orgData } = useQuery<any>({
|
||||
queryKey: ['org-settings'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/settings/org') as any
|
||||
return res.data
|
||||
return await settingsApi.org()
|
||||
},
|
||||
})
|
||||
|
||||
const { data: usersData } = useQuery<any>({
|
||||
queryKey: ['users'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/settings/users') as any
|
||||
return res.data
|
||||
return await settingsApi.users()
|
||||
},
|
||||
})
|
||||
|
||||
const updateOrgMutation = useMutation({
|
||||
mutationFn: (data: any) => api.put('/settings/org', data),
|
||||
mutationFn: (data: any) => settingsApi.updateOrg(data),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['org-settings'] }),
|
||||
})
|
||||
|
||||
@@ -153,14 +152,13 @@ function RetirementSection({ enabled, onToggle }: { enabled: boolean; onToggle:
|
||||
const { data: policyData, isLoading } = useQuery<any>({
|
||||
queryKey: ['retirement-policy'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/settings/retirement-policy') as any
|
||||
return res.data
|
||||
return await settingsApi.retirementPolicy()
|
||||
},
|
||||
enabled,
|
||||
})
|
||||
|
||||
const confirmMutation = useMutation({
|
||||
mutationFn: (id: string) => api.post(`/settings/retirement-policy/${id}/confirm`),
|
||||
mutationFn: (id: string) => apiPost(`/settings/retirement-policy/${id}/confirm`),
|
||||
onSuccess: () => {
|
||||
toast.success('退休政策已确认生效')
|
||||
setConfirming(false)
|
||||
@@ -272,12 +270,12 @@ function UserSettings({ usersData }: { usersData: any }) {
|
||||
const users = usersData || []
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: any }) => api.put(`/settings/users/${id}`, data),
|
||||
mutationFn: ({ id, data }: { id: string; data: any }) => settingsApi.updateUser(id, data),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
||||
})
|
||||
|
||||
const toggleDisableMutation = useMutation({
|
||||
mutationFn: (id: string) => api.patch(`/settings/users/${id}/toggle-disable`),
|
||||
mutationFn: (id: string) => settingsApi.toggleDisable(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
||||
})
|
||||
|
||||
@@ -407,7 +405,7 @@ function AddUserModal({ open, onClose }: { open: boolean; onClose: () => void })
|
||||
setLoading(true)
|
||||
setError('')
|
||||
try {
|
||||
await api.post('/settings/users', form)
|
||||
await settingsApi.addUser(form)
|
||||
onClose()
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '添加失败')
|
||||
@@ -658,13 +656,12 @@ function PlanSettings({ orgData }: { orgData: any }) {
|
||||
const { data: usageData } = useQuery<any>({
|
||||
queryKey: ['usage'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/settings/usage') as any
|
||||
return res.data
|
||||
return await settingsApi.usage()
|
||||
},
|
||||
})
|
||||
|
||||
const planMutation = useMutation({
|
||||
mutationFn: (newPlan: string) => api.put('/settings/plan', { plan: newPlan }),
|
||||
mutationFn: (newPlan: string) => settingsApi.updatePlan(newPlan),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['org'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['usage'] })
|
||||
@@ -744,16 +741,14 @@ function NotificationSettings() {
|
||||
const { data: setting } = useQuery<any>({
|
||||
queryKey: ['notification-settings'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/notifications/settings') as any
|
||||
return res.data
|
||||
return await notificationsApi.settings()
|
||||
},
|
||||
})
|
||||
|
||||
const { data: logsData } = useQuery<any>({
|
||||
queryKey: ['notification-logs'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/notifications/logs', { params: { pageSize: 10 } }) as any
|
||||
return res.data
|
||||
return await notificationsApi.logs({ pageSize: 10 })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -762,12 +757,12 @@ function NotificationSettings() {
|
||||
}, [setting])
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (data: any) => api.put('/notifications/settings', data),
|
||||
mutationFn: (data: any) => notificationsApi.updateSettings(data),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['notification-settings'] }),
|
||||
})
|
||||
|
||||
const checkMutation = useMutation({
|
||||
mutationFn: () => api.post('/notifications/check-contracts') as any,
|
||||
mutationFn: () => apiPost('/notifications/check-contracts') as any,
|
||||
onSuccess: (res: any) => {
|
||||
setCheckResult(`检查完成:发现 ${res.data.checked} 个即将到期的合同,已发送 ${res.data.notified} 条通知`)
|
||||
queryClient.invalidateQueries({ queryKey: ['notification-logs'] })
|
||||
@@ -775,14 +770,14 @@ function NotificationSettings() {
|
||||
})
|
||||
|
||||
const testWechatMutation = useMutation({
|
||||
mutationFn: () => api.post('/notifications/test', { channel: 'wechat' }) as any,
|
||||
mutationFn: () => apiPost('/notifications/test', { channel: 'wechat' }) as any,
|
||||
onSuccess: (res: any) => {
|
||||
toast.success(res.success ? res.data.message : (res.error?.message || '测试失败'))
|
||||
},
|
||||
})
|
||||
|
||||
const testEmailMutation = useMutation({
|
||||
mutationFn: () => api.post('/notifications/test', { channel: 'email' }) as any,
|
||||
mutationFn: () => apiPost('/notifications/test', { channel: 'email' }) as any,
|
||||
onSuccess: (res: any) => {
|
||||
toast.success(res.success ? res.data.message : (res.error?.message || '测试失败'))
|
||||
},
|
||||
|
||||
@@ -4,7 +4,8 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { useConfirm } from '../hooks/useConfirm'
|
||||
import { Calculator, Info, Check, Settings as SettingsIcon, Plus, History, Download, AlertCircle, Clock, MapPin, Sparkles, Upload, X, Shield } from 'lucide-react'
|
||||
import { InlineAlert } from '../components/ui/InlineAlert'
|
||||
import api from '../lib/api'
|
||||
import { socialInsuranceApi, commercialInsuranceApi } from '../lib/api-services'
|
||||
import { get as apiGet, post as apiPost, put as apiPut, del as apiDel } from '../lib/api-services-raw'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -54,31 +55,28 @@ export default function SocialInsurance() {
|
||||
const { data: cities = [] } = useQuery<string[]>({
|
||||
queryKey: ['social-config-cities'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/config/cities') as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.cities()
|
||||
},
|
||||
})
|
||||
|
||||
const { data: config, isLoading: configLoading } = useQuery<any>({
|
||||
queryKey: ['social-config', city],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/config', { params: { city } }) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.config(city)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: housingConfig, isLoading: housingLoading } = useQuery<any>({
|
||||
queryKey: ['housing-config', city],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/housing-config', { params: { city } }) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.housingConfig(city)
|
||||
},
|
||||
})
|
||||
const { data: housingAllAccounts } = useQuery<any[]>({
|
||||
queryKey: ['housing-config-all-accounts', city],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/housing-config/versions', { params: { city } }) as any
|
||||
const current = (res.data || []).filter((v: any) => v.isCurrent)
|
||||
const res = await socialInsuranceApi.housingConfigVersions(city) as any
|
||||
const current = (res || []).filter((v: any) => v.isCurrent)
|
||||
return current
|
||||
},
|
||||
})
|
||||
@@ -86,8 +84,7 @@ export default function SocialInsurance() {
|
||||
const { data: versions } = useQuery<any[]>({
|
||||
queryKey: ['social-config-versions', city],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/config/versions', { params: { city } }) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.configVersions(city)
|
||||
},
|
||||
enabled: showVersions && tab === 'social',
|
||||
})
|
||||
@@ -95,8 +92,7 @@ export default function SocialInsurance() {
|
||||
const { data: housingVersions } = useQuery<any[]>({
|
||||
queryKey: ['housing-config-versions'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/housing-config/versions') as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.housingConfigVersions()
|
||||
},
|
||||
enabled: showVersions && tab === 'housing',
|
||||
})
|
||||
@@ -105,8 +101,7 @@ export default function SocialInsurance() {
|
||||
const { data: processedList, refetch: refetchProcessedList } = useQuery<any[]>({
|
||||
queryKey: ['monthly-process-list'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/monthly-process/list') as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.monthlyProcessList()
|
||||
},
|
||||
enabled: tab === 'monthly',
|
||||
})
|
||||
@@ -114,8 +109,8 @@ export default function SocialInsurance() {
|
||||
// 进入月度办理Tab时自动查询当前月状态
|
||||
useEffect(() => {
|
||||
if (tab === 'monthly') {
|
||||
api.get('/social/monthly-process/status', { params: { month: monthlyMonth } }).then((res: any) => {
|
||||
setProcessStatus(res.data)
|
||||
socialInsuranceApi.monthlyProcessStatus(monthlyMonth).then((res: any) => {
|
||||
setProcessStatus(res)
|
||||
}).catch(() => {})
|
||||
refetchProcessedList()
|
||||
}
|
||||
@@ -124,10 +119,10 @@ export default function SocialInsurance() {
|
||||
const { mutateAsync: fetchMonthlyChanges, isPending: monthlyLoading, data: monthlyChanges } = useMutation<any>({
|
||||
mutationFn: async () => {
|
||||
const [socialRes, housingRes, socialActiveRes, housingActiveRes] = await Promise.all([
|
||||
api.get('/social/monthly-changes', { params: { month: monthlyMonth } }) as any,
|
||||
api.get('/social/housing/monthly-changes', { params: { month: monthlyMonth } }) as any,
|
||||
api.get('/social/active-declaration', { params: { month: monthlyMonth } }) as any,
|
||||
api.get('/social/housing/active-declaration', { params: { month: monthlyMonth } }) as any,
|
||||
apiGet('/social/monthly-changes', { params: { month: monthlyMonth } }) as any,
|
||||
apiGet('/social/housing/monthly-changes', { params: { month: monthlyMonth } }) as any,
|
||||
apiGet('/social/active-declaration', { params: { month: monthlyMonth } }) as any,
|
||||
apiGet('/social/housing/active-declaration', { params: { month: monthlyMonth } }) as any,
|
||||
])
|
||||
return {
|
||||
social: socialRes.data,
|
||||
@@ -143,8 +138,8 @@ export default function SocialInsurance() {
|
||||
await fetchMonthlyChanges()
|
||||
setMonthlyProcessed(true)
|
||||
// 查询该月办理状态
|
||||
const statusRes = await api.get('/social/monthly-process/status', { params: { month: monthlyMonth } }) as any
|
||||
setProcessStatus(statusRes.data)
|
||||
const statusRes = await socialInsuranceApi.monthlyProcessStatus(monthlyMonth) as any
|
||||
setProcessStatus(statusRes)
|
||||
} catch {
|
||||
toast.error('获取月度办理数据失败')
|
||||
}
|
||||
@@ -154,7 +149,7 @@ export default function SocialInsurance() {
|
||||
mutationFn: async (type: 'SOCIAL' | 'HOUSING') => {
|
||||
const snapshot = type === 'SOCIAL' ? monthlyChanges.social : monthlyChanges.housing
|
||||
const activeSnapshot = type === 'SOCIAL' ? monthlyChanges.socialActive : monthlyChanges.housingActive
|
||||
const res = await api.post('/social/monthly-process/complete', {
|
||||
const res = await socialInsuranceApi.completeMonthlyProcess({
|
||||
month: monthlyMonth,
|
||||
type,
|
||||
snapshot: { changes: snapshot, active: activeSnapshot },
|
||||
@@ -174,20 +169,18 @@ export default function SocialInsurance() {
|
||||
|
||||
const { data: result, mutate: calcMutate, isPending } = useMutation<any>({
|
||||
mutationFn: async () => {
|
||||
const res = await api.post('/social/calculate', { base, city }) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.calculate(base, city)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: housingResult, mutate: calcHousingMutate, isPending: housingCalcPending } = useMutation<any>({
|
||||
mutationFn: async () => {
|
||||
const res = await api.post('/social/housing-calculate', { base, city }) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.housingCalculate(base, city)
|
||||
},
|
||||
})
|
||||
|
||||
const createVersionMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/social/config/versions', data),
|
||||
mutationFn: (data: any) => socialInsuranceApi.createConfigVersion(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['social-config'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['social-config-versions'] })
|
||||
@@ -197,7 +190,7 @@ export default function SocialInsurance() {
|
||||
})
|
||||
|
||||
const createHousingVersionMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/social/housing-config/versions', data),
|
||||
mutationFn: (data: any) => socialInsuranceApi.createHousingConfigVersion(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['housing-config'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['housing-config-versions'] })
|
||||
@@ -208,8 +201,7 @@ export default function SocialInsurance() {
|
||||
|
||||
const aiSuggestMut = useMutation<any, any, { city: string; effectiveFrom: string; type: 'social' | 'housing' }>({
|
||||
mutationFn: async (vars: { city: string; effectiveFrom: string; type: 'social' | 'housing' }) => {
|
||||
const res = await api.post('/social/ai-suggest', vars) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.aiSuggest(vars)
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (isHousing) {
|
||||
@@ -247,8 +239,7 @@ export default function SocialInsurance() {
|
||||
|
||||
const previewAdjustMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const res = await api.get(`/social/config/${config?.id}/adjust-preview`) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.adjustPreview(config?.id)
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setAdjustData(data)
|
||||
@@ -258,8 +249,7 @@ export default function SocialInsurance() {
|
||||
|
||||
const previewHousingAdjustMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const res = await api.get(`/social/housing-config/${housingConfig?.id}/adjust-preview`) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.housingAdjustPreview(housingConfig?.id)
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setAdjustData(data)
|
||||
@@ -269,7 +259,7 @@ export default function SocialInsurance() {
|
||||
|
||||
const applyAdjustMutation = useMutation({
|
||||
mutationFn: (data: { items: { employeeId: string; newBase: number }[] }) =>
|
||||
api.post(`/social/config/${config?.id}/adjust-apply`, data),
|
||||
socialInsuranceApi.applyAdjust(config?.id, data),
|
||||
onSuccess: (res: any) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['social-config'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['social-config-versions'] })
|
||||
@@ -285,7 +275,7 @@ export default function SocialInsurance() {
|
||||
|
||||
const applyHousingAdjustMutation = useMutation({
|
||||
mutationFn: (data: { items: { employeeId: string; newBase: number }[] }) =>
|
||||
api.post(`/social/housing-config/${housingConfig?.id}/adjust-apply`, data),
|
||||
socialInsuranceApi.applyHousingAdjust(housingConfig?.id, data),
|
||||
onSuccess: (res: any) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['housing-config'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['housing-config-versions'] })
|
||||
@@ -300,7 +290,7 @@ export default function SocialInsurance() {
|
||||
})
|
||||
|
||||
const resetAdjustMutation = useMutation({
|
||||
mutationFn: () => api.post(`/social/config/${config?.id}/reset-adjustment`, { city }),
|
||||
mutationFn: () => socialInsuranceApi.resetAdjust(config?.id, city),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['social-config', city] })
|
||||
queryClient.invalidateQueries({ queryKey: ['social-config-versions', city] })
|
||||
@@ -309,7 +299,7 @@ export default function SocialInsurance() {
|
||||
})
|
||||
|
||||
const resetHousingAdjustMutation = useMutation({
|
||||
mutationFn: () => api.post(`/social/housing-config/${housingConfig?.id}/reset-adjustment`, { city }),
|
||||
mutationFn: () => socialInsuranceApi.resetHousingAdjust(housingConfig?.id, city),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['housing-config', city] })
|
||||
queryClient.invalidateQueries({ queryKey: ['housing-config-versions', city] })
|
||||
@@ -1162,7 +1152,7 @@ function MonthlyRow({ item: i, type, onCorrected }: { item: any; type: 'add' | '
|
||||
const d = i.detail
|
||||
|
||||
const correctMutation = useMutation({
|
||||
mutationFn: (data: { base: number }) => api.put(`/social/records/social/${i.recordId}/correct`, data),
|
||||
mutationFn: (data: { base: number }) => socialInsuranceApi.correctRecord('social', i.recordId, data),
|
||||
onSuccess: () => {
|
||||
setEditing(false)
|
||||
toast.success('基数已修改')
|
||||
@@ -1250,7 +1240,7 @@ function MonthlyHousingRow({ item: i, type, onCorrected }: { item: any; type: 'a
|
||||
const d = i.detail
|
||||
|
||||
const correctMutation = useMutation({
|
||||
mutationFn: (data: { base: number }) => api.put(`/social/records/housing/${i.recordId}/correct`, data),
|
||||
mutationFn: (data: { base: number }) => socialInsuranceApi.correctRecord('housing', i.recordId, data),
|
||||
onSuccess: () => {
|
||||
setEditing(false)
|
||||
toast.success('基数已修改')
|
||||
@@ -1314,8 +1304,7 @@ function SpecialDeductionTab({ month, setMonth }: { month: string; setMonth: (m:
|
||||
const { data: records = [], isLoading } = useQuery<any[]>({
|
||||
queryKey: ['special-deduction', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/special-deduction/batch', { params: { month } }) as any
|
||||
return res.data
|
||||
return await socialInsuranceApi.specialDeductionBatch(month)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1323,8 +1312,8 @@ function SpecialDeductionTab({ month, setMonth }: { month: string; setMonth: (m:
|
||||
const { data: employees = [] } = useQuery<any[]>({
|
||||
queryKey: ['active-social-employees', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/active-declaration', { params: { month } }) as any
|
||||
return (res.data?.items || []).map((item: any) => ({
|
||||
const res = await socialInsuranceApi.activeDeclaration(month) as any
|
||||
return (res?.items || []).map((item: any) => ({
|
||||
id: item.employeeId,
|
||||
name: item.name,
|
||||
department: item.department,
|
||||
@@ -1341,14 +1330,13 @@ function SpecialDeductionTab({ month, setMonth }: { month: string; setMonth: (m:
|
||||
const { data: prevRecords = [] } = useQuery<any[]>({
|
||||
queryKey: ['special-deduction', prevMonth],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/special-deduction/batch', { params: { month: prevMonth } }) as any
|
||||
return res.data || []
|
||||
return await socialInsuranceApi.specialDeductionBatch(prevMonth)
|
||||
},
|
||||
})
|
||||
const prevRecordMap = new Map(prevRecords.map((r: any) => [r.employeeId, r]))
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/social/special-deduction', { ...data, month }),
|
||||
mutationFn: (data: any) => socialInsuranceApi.saveSpecialDeduction({ ...data, month }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['special-deduction'] })
|
||||
setEditing(null)
|
||||
@@ -1376,7 +1364,7 @@ function SpecialDeductionTab({ month, setMonth }: { month: string; setMonth: (m:
|
||||
mutationFn: async () => {
|
||||
let copied = 0
|
||||
for (const prev of prevRecords) {
|
||||
await api.post('/social/special-deduction', {
|
||||
await socialInsuranceApi.saveSpecialDeduction({
|
||||
employeeId: prev.employeeId,
|
||||
month,
|
||||
children: prev.children || 0,
|
||||
@@ -1661,8 +1649,7 @@ function CommercialInsuranceTab() {
|
||||
const { data: plans = [], isLoading } = useQuery<any[]>({
|
||||
queryKey: ['commercial-insurance-plans'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/commercial-insurance/plans') as any
|
||||
return res.data || []
|
||||
return await commercialInsuranceApi.plans()
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1671,8 +1658,7 @@ function CommercialInsuranceTab() {
|
||||
queryKey: ['commercial-insurance-enrollments', selectedPlanId],
|
||||
queryFn: async () => {
|
||||
if (!selectedPlanId) return []
|
||||
const res = await api.get(`/commercial-insurance/plans/${selectedPlanId}/enrollments`) as any
|
||||
return res.data || []
|
||||
return await commercialInsuranceApi.enrollments(selectedPlanId)
|
||||
},
|
||||
enabled: !!selectedPlanId,
|
||||
})
|
||||
@@ -1681,9 +1667,9 @@ function CommercialInsuranceTab() {
|
||||
const savePlanMutation = useMutation({
|
||||
mutationFn: async (data: any) => {
|
||||
if (editingPlan) {
|
||||
return api.put(`/commercial-insurance/plans/${editingPlan.id}`, data) as any
|
||||
return commercialInsuranceApi.savePlan(data, editingPlan.id) as any
|
||||
}
|
||||
return api.post('/commercial-insurance/plans', data) as any
|
||||
return commercialInsuranceApi.savePlan(data) as any
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['commercial-insurance-plans'] })
|
||||
@@ -1697,7 +1683,7 @@ function CommercialInsuranceTab() {
|
||||
|
||||
/** 删除商险方案 */
|
||||
const deletePlanMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/commercial-insurance/plans/${id}`),
|
||||
mutationFn: (id: string) => commercialInsuranceApi.removePlan(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['commercial-insurance-plans'] })
|
||||
setSelectedPlanId(null)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Search, Plus, Edit2, Trash2, AlertTriangle, Clock, Baby, HeartPulse, Activity, X } from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { specialStatusApi, employeeApi } from '../lib/api-services'
|
||||
import { Input, Select, Label } from '../components/ui/Input'
|
||||
import Button from '../components/ui/Button'
|
||||
|
||||
@@ -140,9 +140,9 @@ export default function SpecialStatus() {
|
||||
if (search) params.search = search
|
||||
if (typeFilter) params.type = typeFilter
|
||||
if (statusFilter) params.status = statusFilter
|
||||
const res = await api.get('/special-statuses', { params }) as any
|
||||
setList(res.data.list)
|
||||
setTotal(res.data.total)
|
||||
const res = await specialStatusApi.list({ page, pageSize, search: search || undefined, type: typeFilter || undefined, status: statusFilter || undefined } as any) as any
|
||||
setList(res.list)
|
||||
setTotal(res.total)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
@@ -150,8 +150,8 @@ export default function SpecialStatus() {
|
||||
|
||||
const fetchStats = async () => {
|
||||
try {
|
||||
const res = await api.get('/special-statuses/stats/overview') as any
|
||||
setStats(res.data)
|
||||
const res = await specialStatusApi.stats() as any
|
||||
setStats(res)
|
||||
} catch {
|
||||
// 忽略
|
||||
}
|
||||
@@ -159,8 +159,8 @@ export default function SpecialStatus() {
|
||||
|
||||
const fetchEmployees = async () => {
|
||||
try {
|
||||
const res = await api.get('/employees/all-lite') as any
|
||||
setEmployees(res.data || [])
|
||||
const res = await employeeApi.allLite() as any
|
||||
setEmployees(res || [])
|
||||
} catch {
|
||||
// 忽略
|
||||
}
|
||||
@@ -212,9 +212,9 @@ export default function SpecialStatus() {
|
||||
if (data.medicalMonths) data.medicalMonths = parseInt(data.medicalMonths)
|
||||
|
||||
if (editing) {
|
||||
await api.put(`/special-statuses/${editing.id}`, data)
|
||||
await specialStatusApi.update(editing.id, data)
|
||||
} else {
|
||||
await api.post('/special-statuses', data)
|
||||
await specialStatusApi.create(data)
|
||||
}
|
||||
setEditOpen(false)
|
||||
fetchList()
|
||||
@@ -227,7 +227,7 @@ export default function SpecialStatus() {
|
||||
const handleDelete = async () => {
|
||||
if (!deleteTarget) return
|
||||
try {
|
||||
await api.delete(`/special-statuses/${deleteTarget.id}`)
|
||||
await specialStatusApi.remove(deleteTarget.id)
|
||||
setDeleteTarget(null)
|
||||
fetchList()
|
||||
fetchStats()
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { FileText, Copy, X, ChevronRight, Download, BookOpen, HelpCircle, Plus, Edit, Trash2, Building2 } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import api from '../lib/api'
|
||||
import { templatesApi } from '../lib/api-services'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -110,17 +110,14 @@ function SystemTemplates() {
|
||||
const { data: list, isLoading } = useQuery<any>({
|
||||
queryKey: ['templates', category],
|
||||
queryFn: async () => {
|
||||
const params = category ? `?category=${category}` : ''
|
||||
const res = await api.get(`/templates${params}`) as any
|
||||
return res.data
|
||||
return await templatesApi.list(category || undefined)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: detail } = useQuery<any>({
|
||||
queryKey: ['template-detail', selected?.id],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/templates/${selected.id}`) as any
|
||||
return res.data
|
||||
return await templatesApi.detail(selected.id)
|
||||
},
|
||||
enabled: !!selected,
|
||||
})
|
||||
@@ -128,8 +125,8 @@ function SystemTemplates() {
|
||||
const handleRender = async () => {
|
||||
if (!selected) return
|
||||
try {
|
||||
const res = await api.post(`/templates/${selected.id}/render`, { variables }) as any
|
||||
setRendered(res.data.content)
|
||||
const res = await templatesApi.render(selected.id, variables) as any
|
||||
setRendered(res.content)
|
||||
} catch (err: any) {
|
||||
toast.error('渲染失败')
|
||||
}
|
||||
@@ -318,8 +315,7 @@ function EnterpriseTemplates() {
|
||||
queryFn: async () => {
|
||||
const params: any = { page, pageSize }
|
||||
if (category) params.category = category
|
||||
const res = await api.get('/enterprise-templates', { params }) as any
|
||||
return res.data
|
||||
return await templatesApi.enterpriseList({ page, pageSize, category: category || undefined } as any)
|
||||
},
|
||||
})
|
||||
const list = listData?.items || []
|
||||
@@ -328,8 +324,7 @@ function EnterpriseTemplates() {
|
||||
const { data: detail } = useQuery<any>({
|
||||
queryKey: ['enterprise-template-detail', selected?.id],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/enterprise-templates/${selected.id}`) as any
|
||||
return res.data
|
||||
return await templatesApi.enterpriseDetail(selected.id)
|
||||
},
|
||||
enabled: !!selected,
|
||||
})
|
||||
@@ -337,11 +332,9 @@ function EnterpriseTemplates() {
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async (data: any) => {
|
||||
if (editItem) {
|
||||
const res = await api.put(`/enterprise-templates/${editItem.id}`, data) as any
|
||||
return res.data
|
||||
return await templatesApi.saveEnterprise(data, editItem.id)
|
||||
} else {
|
||||
const res = await api.post('/enterprise-templates', data) as any
|
||||
return res.data
|
||||
return await templatesApi.saveEnterprise(data)
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
@@ -356,7 +349,7 @@ function EnterpriseTemplates() {
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
await api.delete(`/enterprise-templates/${id}`)
|
||||
await templatesApi.removeEnterprise(id)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已删除')
|
||||
@@ -368,8 +361,8 @@ function EnterpriseTemplates() {
|
||||
const handleRender = async () => {
|
||||
if (!selected) return
|
||||
try {
|
||||
const res = await api.post(`/enterprise-templates/${selected.id}/render`, { variables }) as any
|
||||
setRendered(res.data.content)
|
||||
const res = await templatesApi.renderEnterprise(selected.id, variables) as any
|
||||
setRendered(res.content)
|
||||
} catch {
|
||||
toast.error('渲染失败')
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import { AlertTriangle, Check, ChevronRight, ChevronLeft, Shield, Info, Calculat
|
||||
import { Stepper } from '../components/ui/Stepper'
|
||||
import { InlineAlert } from '../components/ui/InlineAlert'
|
||||
import jsPDF from 'jspdf'
|
||||
import api from '../lib/api'
|
||||
import { rosterApi } from '../lib/api-services'
|
||||
import { rosterApi, terminationApi } from '../lib/api-services'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
@@ -236,8 +235,7 @@ export default function Termination() {
|
||||
const { data: profile } = useQuery<EmployeeProfile>({
|
||||
queryKey: ['employee-profile', employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/roster/${employeeId}/profile`) as any
|
||||
return res.data
|
||||
return await rosterApi.profile(employeeId)
|
||||
},
|
||||
enabled: !!employeeId,
|
||||
})
|
||||
@@ -305,8 +303,7 @@ export default function Termination() {
|
||||
}[]>({
|
||||
queryKey: ['checklist', reason, employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/termination/checklist/${reason}`, { params: { employeeId } }) as any
|
||||
return res.data
|
||||
return await terminationApi.checklist(reason, employeeId)
|
||||
},
|
||||
enabled: !!reason && !!employeeId && step >= 2,
|
||||
})
|
||||
@@ -326,14 +323,13 @@ export default function Termination() {
|
||||
const { data: riskAssessment } = useQuery<{ level: string; warnings: string[] }>({
|
||||
queryKey: ['assess', employeeId, reason],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/termination/assess/${employeeId}`, { params: { reason } }) as any
|
||||
return res.data
|
||||
return await terminationApi.assess(employeeId, reason)
|
||||
},
|
||||
enabled: !!employeeId && !!reason && step >= 1,
|
||||
})
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/termination', data),
|
||||
mutationFn: (data: any) => terminationApi.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['employees'] })
|
||||
@@ -352,8 +348,7 @@ export default function Termination() {
|
||||
if (filterStatus) params.status = filterStatus
|
||||
if (filterDepartment) params.department = filterDepartment
|
||||
if (searchTerm) params.search = searchTerm
|
||||
const res = await api.get('/termination/drafts', { params }) as any
|
||||
return res.data
|
||||
return await terminationApi.drafts(params)
|
||||
},
|
||||
enabled: view === 'list',
|
||||
})
|
||||
@@ -364,8 +359,7 @@ export default function Termination() {
|
||||
const { data: draftDetail } = useQuery({
|
||||
queryKey: ['termination-detail', draftId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/termination/detail/${draftId}`) as any
|
||||
return res.data
|
||||
return await terminationApi.detail(draftId!)
|
||||
},
|
||||
enabled: !!draftId && view === 'detail',
|
||||
})
|
||||
@@ -373,8 +367,8 @@ export default function Termination() {
|
||||
// 保存草稿
|
||||
const saveDraftMutation = useMutation({
|
||||
mutationFn: (data: any) => draftId
|
||||
? api.put(`/termination/draft/${draftId}`, data)
|
||||
: api.post('/termination/draft', data),
|
||||
? terminationApi.updateDraft(draftId!, data)
|
||||
: terminationApi.createDraft(data),
|
||||
onSuccess: (res: any) => {
|
||||
const newId = draftId || res?.data?.id
|
||||
setDraftId(newId)
|
||||
@@ -386,7 +380,7 @@ export default function Termination() {
|
||||
|
||||
// 提交审批
|
||||
const submitMutation = useMutation({
|
||||
mutationFn: () => api.post(`/termination/draft/${draftId}/submit`),
|
||||
mutationFn: () => terminationApi.submit(draftId!),
|
||||
onSuccess: () => {
|
||||
toast.success('已提交审批')
|
||||
queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
|
||||
@@ -398,7 +392,7 @@ export default function Termination() {
|
||||
|
||||
// 审批通过
|
||||
const approveMutation = useMutation({
|
||||
mutationFn: (comment: string) => api.post(`/termination/draft/${draftId}/approve`, { comment }),
|
||||
mutationFn: (comment: string) => terminationApi.approve(draftId!, comment),
|
||||
onSuccess: () => {
|
||||
toast.success('审批通过')
|
||||
queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
|
||||
@@ -409,7 +403,7 @@ export default function Termination() {
|
||||
|
||||
// 审批驳回
|
||||
const rejectMutation = useMutation({
|
||||
mutationFn: (comment: string) => api.post(`/termination/draft/${draftId}/reject`, { comment }),
|
||||
mutationFn: (comment: string) => terminationApi.reject(draftId!, comment),
|
||||
onSuccess: () => {
|
||||
toast.success('已驳回')
|
||||
queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
|
||||
@@ -420,7 +414,7 @@ export default function Termination() {
|
||||
|
||||
// 执行解聘
|
||||
const executeMutation = useMutation({
|
||||
mutationFn: () => api.post(`/termination/draft/${draftId}/execute`),
|
||||
mutationFn: () => terminationApi.execute(draftId!),
|
||||
onSuccess: () => {
|
||||
toast.success('解聘已执行')
|
||||
queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
|
||||
@@ -436,7 +430,7 @@ export default function Termination() {
|
||||
|
||||
// 撤销
|
||||
const cancelMutation = useMutation({
|
||||
mutationFn: () => api.post(`/termination/draft/${draftId}/cancel`),
|
||||
mutationFn: () => terminationApi.cancel(draftId!),
|
||||
onSuccess: () => {
|
||||
toast.success('已撤销')
|
||||
queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
|
||||
@@ -451,8 +445,7 @@ export default function Termination() {
|
||||
const { data: evidenceChain } = useQuery({
|
||||
queryKey: ['evidence-chain', employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/roster/${employeeId}/evidence-chain`) as any
|
||||
return res.data
|
||||
return await rosterApi.evidenceChain(employeeId)
|
||||
},
|
||||
enabled: !!employeeId && step === 5 && saveMutation.isSuccess,
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
Repeat, Pause, FileText, XCircle, UserX, FileMinus, Briefcase,
|
||||
Loader2, ChevronRight, Trash2, Send, X, Eye,
|
||||
} from 'lucide-react'
|
||||
import api from '../lib/api'
|
||||
import { workProcessApi } from '../lib/api-services'
|
||||
import Card from '../components/ui/Card'
|
||||
import Button from '../components/ui/Button'
|
||||
import { Input, Label, Select } from '../components/ui/Input'
|
||||
@@ -155,15 +155,13 @@ export default function WorkProcess() {
|
||||
const params: any = { page, pageSize }
|
||||
if (filterType) params.type = filterType
|
||||
if (filterStatus) params.status = filterStatus
|
||||
const res = await api.get('/work-processes', { params }) as any
|
||||
return res.data
|
||||
return await workProcessApi.list({ page, pageSize, type: filterType || undefined, status: filterStatus || undefined } as any)
|
||||
},
|
||||
})
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: async (data: any) => {
|
||||
const res = await api.post('/work-processes', data) as any
|
||||
return res.data
|
||||
return await workProcessApi.create(data)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已创建草稿')
|
||||
@@ -177,8 +175,7 @@ export default function WorkProcess() {
|
||||
|
||||
const submitMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
const res = await api.post(`/work-processes/${id}/submit`) as any
|
||||
return res.data
|
||||
return await workProcessApi.submit(id)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已提交并执行')
|
||||
@@ -190,8 +187,7 @@ export default function WorkProcess() {
|
||||
|
||||
const cancelMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
const res = await api.post(`/work-processes/${id}/cancel`) as any
|
||||
return res.data
|
||||
return await workProcessApi.cancel(id)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已撤销')
|
||||
@@ -203,7 +199,7 @@ export default function WorkProcess() {
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
await api.delete(`/work-processes/${id}`)
|
||||
await workProcessApi.remove(id)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('已删除')
|
||||
@@ -214,8 +210,7 @@ export default function WorkProcess() {
|
||||
|
||||
const previewMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
const res = await api.get(`/work-processes/${id}/preview`) as any
|
||||
return res.data
|
||||
return await workProcessApi.preview(id)
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setPreviewContent(data.content)
|
||||
@@ -426,8 +421,7 @@ function DetailContent({ id, previewContent, onPreview, onSubmit, onCancel, onDe
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['work-process', id],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/work-processes/${id}`) as any
|
||||
return res.data
|
||||
return await workProcessApi.detail(id!)
|
||||
},
|
||||
enabled: !!id,
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Eye, EyeOff } from 'lucide-react'
|
||||
import Logo from '../../components/ui/Logo'
|
||||
import api from '../../lib/api'
|
||||
import { authApi } from '../../lib/api-services'
|
||||
import { Input, Label } from '../../components/ui/Input'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -25,8 +25,8 @@ export default function ForgotPassword() {
|
||||
}
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await api.post('/auth/forgot-password/send-code', { phone }) as any
|
||||
setSentCode(res.data?.code || '')
|
||||
const res = await authApi.forgotPasswordSendCode(phone) as any
|
||||
setSentCode(res?.code || '')
|
||||
setStep(2)
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '发送失败,请稍后重试')
|
||||
@@ -47,7 +47,7 @@ export default function ForgotPassword() {
|
||||
}
|
||||
setLoading(true)
|
||||
try {
|
||||
await api.post('/auth/forgot-password/verify', { phone, code, newPassword })
|
||||
await authApi.forgotPasswordVerify({ phone, code, newPassword })
|
||||
setSuccess(true)
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '重置失败,请稍后重试')
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStore } from '../../store/authStore'
|
||||
import api from '../../lib/api'
|
||||
import { authApi } from '../../lib/api-services'
|
||||
import { Input, Label } from '../../components/ui/Input'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -52,13 +52,13 @@ export default function Login() {
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await api.post('/auth/login', data) as any
|
||||
const res = await authApi.login(data) as any
|
||||
if (remember) {
|
||||
localStorage.setItem('admin-login-remember', JSON.stringify({ phone: data.phone, password: data.password }))
|
||||
} else {
|
||||
localStorage.removeItem('admin-login-remember')
|
||||
}
|
||||
setAuth(res.data.user, res.data.accessToken, res.data.refreshToken)
|
||||
setAuth(res.user, res.accessToken, res.refreshToken)
|
||||
navigate('/')
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '登录失败,请稍后重试')
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStore } from '../../store/authStore'
|
||||
import api from '../../lib/api'
|
||||
import { authApi } from '../../lib/api-services'
|
||||
import { Input, Label } from '../../components/ui/Input'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -37,8 +37,8 @@ export default function Register() {
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await api.post('/auth/register', data) as any
|
||||
setAuth(res.data.user, res.data.accessToken, res.data.refreshToken)
|
||||
const res = await authApi.register(data) as any
|
||||
setAuth(res.user, res.accessToken, res.refreshToken)
|
||||
navigate('/')
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '注册失败,请稍后重试')
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
import { InlineAlert } from '../../components/ui/InlineAlert'
|
||||
import api from '../../lib/api'
|
||||
import { dashboardApi } from '../../lib/api-services'
|
||||
|
||||
/** 风险等级配置 */
|
||||
const RISK_LEVELS: Record<string, { label: string; color: string; bg: string }> = {
|
||||
@@ -39,8 +39,7 @@ export default function RiskCenter() {
|
||||
const { data: risks = [], isLoading } = useQuery<any[]>({
|
||||
queryKey: ['risk-center'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/dashboard/risks') as any
|
||||
return res.data || []
|
||||
return await dashboardApi.risks()
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, BarChart, Bar, XAxis, YAxis, CartesianGrid, Legend } from 'recharts'
|
||||
import { Award, TrendingUp } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { dashboardApi } from '../../lib/api-services'
|
||||
|
||||
const GRADE_COLORS: Record<string, string> = {
|
||||
'A': '#237A57',
|
||||
@@ -22,8 +22,7 @@ export default function PerformanceStats() {
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['performance-stats', period],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/dashboard/performance-stats?period=${period}`)
|
||||
return res.data.data
|
||||
return await dashboardApi.performanceStats(period)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { AlertCircle, Layers, FileText, Heart, ArrowRight, ListTodo } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { dashboardApi } from '../../lib/api-services'
|
||||
import { InlineAlert } from '../../components/ui/InlineAlert'
|
||||
|
||||
interface NextAction {
|
||||
@@ -44,8 +44,7 @@ export function TaskCenter() {
|
||||
const { data, isLoading } = useQuery<{ actions: ActionGroup[]; totalCount: number }>({
|
||||
queryKey: ['next-actions'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/dashboard/workspace/next-actions') as any
|
||||
return res.data
|
||||
return await dashboardApi.nextActions()
|
||||
},
|
||||
staleTime: 60_000,
|
||||
})
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'
|
||||
import { UserPlus, UserMinus, Users, TrendingDown } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { dashboardApi } from '../../lib/api-services'
|
||||
|
||||
export default function TurnoverStats() {
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['turnover-stats'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/dashboard/turnover-stats?months=12')
|
||||
return res.data.data
|
||||
return await dashboardApi.turnoverStats(12)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Building2, Users, FileText, Calculator, TrendingUp } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { platformApi } from '../../lib/api-services'
|
||||
|
||||
interface DashboardData {
|
||||
totalOrgs: number
|
||||
@@ -29,7 +29,7 @@ export default function PlatformDashboard() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
api.get('/platform/dashboard').then((res: any) => setData(res.data)).finally(() => setLoading(false))
|
||||
platformApi.dashboard().then((data: any) => setData(data)).finally(() => setLoading(false))
|
||||
}, [])
|
||||
|
||||
if (loading) return <div className="text-center py-12 text-gray-400">加载中...</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStore } from '../../store/authStore'
|
||||
import api from '../../lib/api'
|
||||
import { authApi } from '../../lib/api-services'
|
||||
import { Input, Label } from '../../components/ui/Input'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -54,18 +54,18 @@ export default function PlatformLogin() {
|
||||
}
|
||||
}, [setValue])
|
||||
|
||||
const onSubmit = async (data: FormData) => {
|
||||
const onSubmit = async (formData: FormData) => {
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await api.post('/auth/platform-login', data) as any
|
||||
const res = await authApi.platformLogin(formData) as any
|
||||
// 登录成功后保存/清除记住的账号密码
|
||||
if (remember) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify({ phone: data.phone, password: data.password }))
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify({ phone: formData.phone, password: formData.password }))
|
||||
} else {
|
||||
localStorage.removeItem(STORAGE_KEY)
|
||||
}
|
||||
setAuth(res.data.user, res.data.accessToken, res.data.refreshToken)
|
||||
setAuth(res.user, res.accessToken, res.refreshToken)
|
||||
navigate('/platform/dashboard')
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '登录失败,请稍后重试')
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Search, Building2, Eye, Trash2, Edit2, Plus } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { platformApi } from '../../lib/api-services'
|
||||
import { Input, Select, Label } from '../../components/ui/Input'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -44,9 +44,9 @@ export default function PlatformOrgs() {
|
||||
const params: any = { page, pageSize }
|
||||
if (search) params.search = search
|
||||
if (planFilter) params.plan = planFilter
|
||||
const res = await api.get('/platform/orgs', { params }) as any
|
||||
setOrgs(res.data.list)
|
||||
setTotal(res.data.total)
|
||||
const res = await platformApi.orgs(params) as any
|
||||
setOrgs(res.list)
|
||||
setTotal(res.total)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
@@ -62,8 +62,8 @@ export default function PlatformOrgs() {
|
||||
setEditAdmin({ name: '', phone: '', password: '' })
|
||||
// 加载企业管理员信息
|
||||
try {
|
||||
const res = await api.get(`/platform/orgs/${org.id}`) as any
|
||||
const admin = res.data.users?.find((u: any) => u.role === 'ADMIN')
|
||||
const res = await platformApi.orgDetail(org.id) as any
|
||||
const admin = res.users?.find((u: any) => u.role === 'ADMIN')
|
||||
if (admin) {
|
||||
setEditAdmin({ name: admin.name || '', phone: admin.phone || '', password: '' })
|
||||
}
|
||||
@@ -75,7 +75,7 @@ export default function PlatformOrgs() {
|
||||
const handleSaveEdit = async () => {
|
||||
if (!editOrg) return
|
||||
try {
|
||||
await api.put(`/platform/orgs/${editOrg.id}`, {
|
||||
await platformApi.updateOrg(editOrg.id, {
|
||||
name: editOrg.name,
|
||||
plan: editOrg.plan,
|
||||
maxEmployees: editOrg.maxEmployees,
|
||||
@@ -85,7 +85,7 @@ export default function PlatformOrgs() {
|
||||
})
|
||||
// 如果管理员信息有改动,同步保存
|
||||
if (editAdmin.name || editAdmin.phone || editAdmin.password) {
|
||||
await api.put(`/platform/orgs/${editOrg.id}/admin`, {
|
||||
await platformApi.updateOrgAdmin(editOrg.id, {
|
||||
adminName: editAdmin.name || undefined,
|
||||
adminPhone: editAdmin.phone || undefined,
|
||||
adminPassword: editAdmin.password || undefined,
|
||||
@@ -105,7 +105,7 @@ export default function PlatformOrgs() {
|
||||
}
|
||||
setCreating(true)
|
||||
try {
|
||||
await api.post('/platform/orgs', createForm)
|
||||
await platformApi.createOrg(createForm)
|
||||
setCreateOpen(false)
|
||||
setCreateForm({
|
||||
name: '', plan: 'FREE', maxEmployees: 20, city: '',
|
||||
@@ -123,7 +123,7 @@ export default function PlatformOrgs() {
|
||||
const handleDelete = async () => {
|
||||
if (!deleteOrg) return
|
||||
try {
|
||||
await api.delete(`/platform/orgs/${deleteOrg.id}`)
|
||||
await platformApi.removeOrg(deleteOrg.id)
|
||||
setDeleteOrg(null)
|
||||
fetchOrgs()
|
||||
} catch (err: any) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Search, Ban, CheckCircle } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { platformApi } from '../../lib/api-services'
|
||||
import { Input, Select } from '../../components/ui/Input'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -37,17 +37,17 @@ export default function PlatformUsers() {
|
||||
const params: any = { page, pageSize }
|
||||
if (search) params.search = search
|
||||
if (orgFilter) params.orgId = orgFilter
|
||||
const res = await api.get('/platform/users', { params }) as any
|
||||
setUsers(res.data.list)
|
||||
setTotal(res.data.total)
|
||||
const res = await platformApi.users(params) as any
|
||||
setUsers(res.list)
|
||||
setTotal(res.total)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
api.get('/platform/orgs', { params: { pageSize: 200 } }).then((res: any) => {
|
||||
setOrgs(res.data.list.map((o: any) => ({ id: o.id, name: o.name })))
|
||||
platformApi.orgs({ pageSize: 200 }).then((res: any) => {
|
||||
setOrgs(res.list.map((o: any) => ({ id: o.id, name: o.name })))
|
||||
})
|
||||
}, [])
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function PlatformUsers() {
|
||||
|
||||
const handleToggle = async (user: UserItem) => {
|
||||
try {
|
||||
await api.put(`/platform/users/${user.id}/toggle`)
|
||||
await platformApi.toggleUser(user.id)
|
||||
fetchUsers()
|
||||
} catch (err: any) {
|
||||
alert(err.response?.data?.error?.message || '操作失败')
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { Loader2, CheckCircle, AlertCircle } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Logo from '../../components/ui/Logo'
|
||||
|
||||
export default function AutoLogin() {
|
||||
@@ -21,8 +21,7 @@ export default function AutoLogin() {
|
||||
setErrorMsg('缺少登录凭证')
|
||||
return
|
||||
}
|
||||
api.get('/portal/auto-login', { params: { token } }).then((res: any) => {
|
||||
const data = res.data?.data || res.data
|
||||
portalApi.autoLogin(token).then((data: any) => {
|
||||
if (data?.token) {
|
||||
localStorage.setItem('portalToken', data.token)
|
||||
localStorage.setItem('portalEmployee', JSON.stringify(data.employee))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { PenTool, Check, AlertCircle } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -24,8 +24,8 @@ export default function ContractConfirm() {
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
api.get(`/portal/contract-confirm/${token}`).then((res: any) => {
|
||||
setData(res.data)
|
||||
portalApi.contractInfo(token).then((data: any) => {
|
||||
setData(data)
|
||||
}).catch((err: any) => {
|
||||
setError(err.response?.data?.error?.message || '链接无效或已过期')
|
||||
}).finally(() => setLoading(false))
|
||||
@@ -39,9 +39,9 @@ export default function ContractConfirm() {
|
||||
setSendingCode(true)
|
||||
setError('')
|
||||
try {
|
||||
const res = await api.post('/portal/contract-confirm/send-code', { token }) as any
|
||||
const data = await portalApi.contractConfirmSendCode(token) as any
|
||||
setCodeSent(true)
|
||||
setDevCode(res.data?.data?.code || '')
|
||||
setDevCode(data?.code || '')
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '验证码发送失败')
|
||||
} finally {
|
||||
@@ -52,7 +52,7 @@ export default function ContractConfirm() {
|
||||
const handleConfirm = async () => {
|
||||
setSubmitting(true)
|
||||
try {
|
||||
await api.post('/portal/contract-confirm', { token, agreed: true, verifyCode })
|
||||
await portalApi.contractConfirm(token, verifyCode)
|
||||
setConfirmed(true)
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '确认失败')
|
||||
|
||||
@@ -9,17 +9,9 @@ import {
|
||||
DollarSign, FileText, CalendarCheck, ScrollText,
|
||||
TrendingUp, Clock, AlertCircle, ChevronRight,
|
||||
} from 'lucide-react'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import { InlineAlert } from '../../components/ui/InlineAlert'
|
||||
import axios from 'axios'
|
||||
|
||||
/** 员工端 API 实例(自动携带 portalToken) */
|
||||
const portalApi = axios.create({ baseURL: '/api/v1/portal' })
|
||||
portalApi.interceptors.request.use((config: any) => {
|
||||
const token = localStorage.getItem('portalToken')
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
})
|
||||
|
||||
/** 金额格式化 */
|
||||
const fmt = (n: number) => (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||
@@ -41,8 +33,7 @@ export default function EmployeeHome() {
|
||||
const { data: overview, isLoading } = useQuery<any>({
|
||||
queryKey: ['portal-home-overview'],
|
||||
queryFn: async () => {
|
||||
const res = await portalApi.get('/home/overview') as any
|
||||
return res.data
|
||||
return await portalApi.homeOverview()
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Loader2, CalendarCheck } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
|
||||
export default function MyAttendance() {
|
||||
const [month, setMonth] = useState(new Date().toISOString().slice(0, 7))
|
||||
@@ -9,8 +9,7 @@ export default function MyAttendance() {
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['portal-attendance', month],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/portal/attendance', { params: { month } }) as any
|
||||
return res.data
|
||||
return await portalApi.attendance(month)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { FileText, AlertCircle, Check, RefreshCw, Calendar, Briefcase, Clock } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
import EmptyState from '../../components/ui/EmptyState'
|
||||
@@ -9,13 +9,6 @@ import EmptyState from '../../components/ui/EmptyState'
|
||||
/** 金额格式化:保留两位小数 + 千分位 */
|
||||
const fmt = (n: number) => (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||
|
||||
const portalApi = api.create({ baseURL: '/api/v1/portal' })
|
||||
portalApi.interceptors.request.use((config: any) => {
|
||||
const token = localStorage.getItem('portalToken')
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
})
|
||||
|
||||
export default function MyContract() {
|
||||
const [resending, setResending] = useState(false)
|
||||
const [resendMsg, setResendMsg] = useState('')
|
||||
@@ -23,8 +16,7 @@ export default function MyContract() {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['my-contract'],
|
||||
queryFn: async () => {
|
||||
const res = await portalApi.get('/contract') as any
|
||||
return res.data?.data ?? null
|
||||
return await portalApi.contract()
|
||||
},
|
||||
})
|
||||
|
||||
@@ -40,8 +32,8 @@ export default function MyContract() {
|
||||
setResending(true)
|
||||
setResendMsg('')
|
||||
try {
|
||||
const res = await portalApi.post('/contract-confirm/resend', { contractId: contract?.id }) as any
|
||||
setResendMsg(res.data?.data?.message || '重发成功')
|
||||
const data = await portalApi.resendContractConfirm(contract?.id) as any
|
||||
setResendMsg(data?.message || '重发成功')
|
||||
} catch (err: any) {
|
||||
setResendMsg(err.response?.data?.error?.message || '重发失败')
|
||||
} finally {
|
||||
|
||||
@@ -6,18 +6,11 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { FileText, CheckCircle, Clock, ArrowLeft, ChevronRight, ScrollText } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
import EmptyState from '../../components/ui/EmptyState'
|
||||
|
||||
const portalApi = api.create({ baseURL: '/api/v1/portal' })
|
||||
portalApi.interceptors.request.use((config: any) => {
|
||||
const token = localStorage.getItem('portalToken')
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
})
|
||||
|
||||
export default function MyPolicies() {
|
||||
const queryClient = useQueryClient()
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
@@ -26,8 +19,7 @@ export default function MyPolicies() {
|
||||
const { data: list, isLoading } = useQuery<any>({
|
||||
queryKey: ['portal-policies'],
|
||||
queryFn: async () => {
|
||||
const res = await portalApi.get('/policies') as any
|
||||
return res.data?.data ?? res.data ?? []
|
||||
return await portalApi.policies()
|
||||
},
|
||||
})
|
||||
|
||||
@@ -36,15 +28,14 @@ export default function MyPolicies() {
|
||||
queryKey: ['portal-policy', selectedId],
|
||||
queryFn: async () => {
|
||||
if (!selectedId) return null
|
||||
const res = await portalApi.get(`/policies/${selectedId}`) as any
|
||||
return res.data?.data ?? res.data ?? null
|
||||
return await portalApi.policyDetail(selectedId)
|
||||
},
|
||||
enabled: !!selectedId,
|
||||
})
|
||||
|
||||
/** 阅读确认 */
|
||||
const readMutation = useMutation({
|
||||
mutationFn: (id: string) => portalApi.post(`/policies/${id}/read`),
|
||||
mutationFn: (id: string) => portalApi.policyRead(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portal-policies'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['portal-policy', selectedId] })
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { ClipboardList, Check, FileText, X } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
import { Input, Label } from '../../components/ui/Input'
|
||||
@@ -46,8 +46,8 @@ export default function Onboarding() {
|
||||
// 获取链接信息
|
||||
useState(() => {
|
||||
if (token) {
|
||||
api.get(`/portal/onboarding/${token}`).then((res: any) => {
|
||||
setOrgName(res.data.orgName)
|
||||
portalApi.onboardingInfo(token).then((data: any) => {
|
||||
setOrgName(data.orgName)
|
||||
}).catch((err: any) => {
|
||||
setError(err.response?.data?.error?.message || '链接无效')
|
||||
})
|
||||
@@ -63,10 +63,8 @@ export default function Onboarding() {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('fileType', currentFileType)
|
||||
const res = await api.post(`/portal/onboarding/${token}/upload`, formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
}) as any
|
||||
setUploadedFiles([...uploadedFiles, res.data.data])
|
||||
const data = await portalApi.onboardingUpload(token, formData) as any
|
||||
setUploadedFiles([...uploadedFiles, data])
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '文件上传失败')
|
||||
} finally {
|
||||
@@ -83,7 +81,7 @@ export default function Onboarding() {
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
await api.post('/portal/onboarding', { ...form, token, attachments: uploadedFiles })
|
||||
await portalApi.onboardingSubmit({ ...form, token, attachments: uploadedFiles })
|
||||
setSubmitted(true)
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '提交失败')
|
||||
|
||||
@@ -4,18 +4,10 @@
|
||||
*/
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Check, Clock, AlertCircle, FileText, Upload, User, Phone, Banknote } from 'lucide-react'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import { InlineAlert } from '../../components/ui/InlineAlert'
|
||||
import { Stepper } from '../../components/ui/Stepper'
|
||||
import axios from 'axios'
|
||||
|
||||
/** 员工端 API 实例 */
|
||||
const portalApi = axios.create({ baseURL: '/api/v1/portal' })
|
||||
portalApi.interceptors.request.use((config: any) => {
|
||||
const token = localStorage.getItem('portalToken')
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
})
|
||||
|
||||
/** 入职步骤定义 */
|
||||
const ONBOARDING_STEPS = [
|
||||
@@ -31,8 +23,7 @@ export default function OnboardingProgress() {
|
||||
const { data: progress, isLoading } = useQuery<any>({
|
||||
queryKey: ['portal-onboarding-progress'],
|
||||
queryFn: async () => {
|
||||
const res = await portalApi.get('/onboarding/progress') as any
|
||||
return res.data
|
||||
return await portalApi.onboardingProgress()
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { Check, TrendingUp, Download, Wallet, ChevronLeft, ChevronRight } from 'lucide-react'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
import EmptyState from '../../components/ui/EmptyState'
|
||||
@@ -9,14 +9,6 @@ import EmptyState from '../../components/ui/EmptyState'
|
||||
/** 金额格式化:保留两位小数 + 千分位 */
|
||||
const fmt = (n: number) => (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||
|
||||
/** 员工端 API 实例(自动携带 portalToken) */
|
||||
const portalApi = api.create({ baseURL: '/api/v1/portal' })
|
||||
portalApi.interceptors.request.use((config: any) => {
|
||||
const token = localStorage.getItem('portalToken')
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
})
|
||||
|
||||
export default function Payslip() {
|
||||
const queryClient = useQueryClient()
|
||||
const [month, setMonth] = useState(new Date().toISOString().slice(0, 7))
|
||||
@@ -25,21 +17,19 @@ export default function Payslip() {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['payslip', month],
|
||||
queryFn: async () => {
|
||||
const res = await portalApi.get('/payslip', { params: { month } }) as any
|
||||
return res.data?.data ?? null
|
||||
return await portalApi.payslip(month)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: history } = useQuery<any[]>({
|
||||
queryKey: ['payslip-history'],
|
||||
queryFn: async () => {
|
||||
const res = await portalApi.get('/payslip/history') as any
|
||||
return res.data?.data ?? []
|
||||
return await portalApi.payslipHistory()
|
||||
},
|
||||
})
|
||||
|
||||
const confirmMutation = useMutation({
|
||||
mutationFn: (id: string) => portalApi.post(`/payslip/${id}/confirm`),
|
||||
mutationFn: (id: string) => portalApi.confirmPayslip(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['payslip'] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import Logo from '../../components/ui/Logo'
|
||||
import api from '../../lib/api'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import { Input, Label } from '../../components/ui/Input'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -22,9 +22,9 @@ export default function PortalLogin() {
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await api.post('/portal/login', { phone, password }) as any
|
||||
localStorage.setItem('portalToken', res.data.token)
|
||||
localStorage.setItem('portalEmployee', JSON.stringify(res.data.employee))
|
||||
const data = await portalApi.login(phone, password) as any
|
||||
localStorage.setItem('portalToken', data.token)
|
||||
localStorage.setItem('portalEmployee', JSON.stringify(data.employee))
|
||||
navigate('/portal/payslip')
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '登录失败')
|
||||
@@ -36,9 +36,9 @@ export default function PortalLogin() {
|
||||
const handleSendCode = async () => {
|
||||
setError('')
|
||||
try {
|
||||
const res = await api.post('/portal/send-code', { phone }) as any
|
||||
const data = await portalApi.sendCode(phone) as any
|
||||
setCodeSent(true)
|
||||
setDisplayedCode(res.data.code)
|
||||
setDisplayedCode(data?.code || '')
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '发送失败')
|
||||
}
|
||||
@@ -48,9 +48,9 @@ export default function PortalLogin() {
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await api.post('/portal/verify-code', { phone, code }) as any
|
||||
localStorage.setItem('portalToken', res.data.token)
|
||||
localStorage.setItem('portalEmployee', JSON.stringify(res.data.employee))
|
||||
const data = await portalApi.verifyCode(phone, code) as any
|
||||
localStorage.setItem('portalToken', data.token)
|
||||
localStorage.setItem('portalEmployee', JSON.stringify(data.employee))
|
||||
navigate('/portal/payslip')
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error?.message || '登录失败')
|
||||
|
||||
@@ -5,19 +5,11 @@ import { useState } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import { UserX, Clock, Check, X, FileText } from 'lucide-react'
|
||||
import { portalApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
import { Input, Label, Select } from '../../components/ui/Input'
|
||||
import { InlineAlert } from '../../components/ui/InlineAlert'
|
||||
import axios from 'axios'
|
||||
|
||||
/** 员工端 API 实例 */
|
||||
const portalApi = axios.create({ baseURL: '/api/v1/portal' })
|
||||
portalApi.interceptors.request.use((config: any) => {
|
||||
const token = localStorage.getItem('portalToken')
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
})
|
||||
|
||||
/** 离职原因选项 */
|
||||
const RESIGN_REASONS = [
|
||||
@@ -51,16 +43,14 @@ export default function ResignationApply() {
|
||||
const { data: records = [], isLoading } = useQuery<any[]>({
|
||||
queryKey: ['portal-resignation-status'],
|
||||
queryFn: async () => {
|
||||
const res = await portalApi.get('/resignation/status') as any
|
||||
return Array.isArray(res?.data) ? res.data : []
|
||||
return await portalApi.resignationStatus()
|
||||
},
|
||||
})
|
||||
|
||||
/** 提交离职申请 */
|
||||
const submitMutation = useMutation({
|
||||
mutationFn: async (data: { reason: string; expectedDate: string; remark: string }) => {
|
||||
const res = await portalApi.post('/resignation/submit', data) as any
|
||||
return res.data
|
||||
return await portalApi.resignationSubmit(data)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('离职申请已提交,请等待HR审批')
|
||||
@@ -75,8 +65,7 @@ export default function ResignationApply() {
|
||||
/** 撤回离职申请 */
|
||||
const withdrawMutation = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
const res = await portalApi.post(`/resignation/${id}/withdraw`) as any
|
||||
return res.data
|
||||
return await portalApi.resignationWithdraw(id)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('离职申请已撤回')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi, attachmentApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -15,12 +15,12 @@ export default function AttachmentInfo({ employeeId, attachments }: { employeeId
|
||||
const [fileType, setFileType] = useState<'ID_CARD' | 'BANK_CARD' | 'EDUCATION' | 'OTHER'>('ID_CARD')
|
||||
|
||||
const addAttachmentMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/attachments', data),
|
||||
mutationFn: (data: any) => attachmentApi.add(data),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile', employeeId] }),
|
||||
})
|
||||
|
||||
const deleteAttachmentMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/attachments/${id}`),
|
||||
mutationFn: (id: string) => attachmentApi.remove(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile', employeeId] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi, employeeApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -18,22 +18,22 @@ export default function AttendanceOvertimeInfo({ employeeId, attendanceRecords,
|
||||
const [trainingForm, setTrainingForm] = useState({ trainingDate: '', topic: '', content: '', trainer: '', duration: 1, ackStatus: 'PENDING', ackDate: '', remark: '' })
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post(`/roster/${employeeId}/attendance`, data),
|
||||
mutationFn: (data: any) => rosterApi.attendance(employeeId, data),
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); setShowForm(false) },
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/roster/${employeeId}/attendance/${id}`),
|
||||
mutationFn: (id: string) => rosterApi.removeAttendance(employeeId, id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile'] }),
|
||||
})
|
||||
|
||||
const createTrainingMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post(`/roster/${employeeId}/training`, data),
|
||||
mutationFn: (data: any) => rosterApi.training(employeeId, data),
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); setShowForm(false) },
|
||||
})
|
||||
|
||||
const deleteTrainingMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/roster/${employeeId}/training/${id}`),
|
||||
mutationFn: (id: string) => rosterApi.removeTraining(employeeId, id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile'] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useUnsavedChanges } from "../../hooks/useUnsavedChanges"
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi, attachmentApi, employeeApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -18,12 +18,12 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil
|
||||
const [fileType, setFileType] = useState<'ID_CARD' | 'BANK_CARD' | 'EDUCATION' | 'OTHER'>('ID_CARD')
|
||||
|
||||
const addAttachmentMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/attachments', data),
|
||||
mutationFn: (data: any) => attachmentApi.add(data),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile', employeeId] }),
|
||||
})
|
||||
|
||||
const deleteAttachmentMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/attachments/${id}`),
|
||||
mutationFn: (id: string) => attachmentApi.remove(id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile', employeeId] }),
|
||||
})
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil
|
||||
})
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (data: any) => api.put(`/employees/${profile.id}`, data),
|
||||
mutationFn: (data: any) => employeeApi.update(profile.id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['roster'] })
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { employeeApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -17,12 +17,12 @@ export default function ContractInfo({ employeeId, contracts, hireDate }: { empl
|
||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null)
|
||||
|
||||
const addContractMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post('/employees/contracts', { ...data, employeeId }),
|
||||
mutationFn: (data: any) => employeeApi.addContract({ ...data, employeeId }),
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); setShowForm(false) },
|
||||
})
|
||||
|
||||
const deleteContractMutation = useMutation({
|
||||
mutationFn: (contractId: string) => api.delete(`/employees/contracts/${contractId}`),
|
||||
mutationFn: (contractId: string) => employeeApi.removeContract(contractId),
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); toast.success('合同已删除') },
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -17,12 +17,12 @@ export default function DisciplinaryInfo({ employeeId, records }: { employeeId:
|
||||
const [form, setForm] = useState({ violationDate: '', violationType: 'LATE', description: '', severity: 'WARNING', action: 'ORAL_WARNING', actionDetail: '', employeeAck: false, ackDate: '', ackMethod: 'SIGN', witness: '' })
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post(`/roster/${employeeId}/disciplinary`, data),
|
||||
mutationFn: (data: any) => rosterApi.createDisciplinary(employeeId, data),
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); setShowForm(false) },
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/roster/${employeeId}/disciplinary/${id}`),
|
||||
mutationFn: (id: string) => rosterApi.removeDisciplinary(employeeId, id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile'] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** EmployeeProfile 组件 - 员工详情页 */
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import api from '../../lib/api'
|
||||
import { rosterApi } from '../../lib/api-services'
|
||||
import { DetailTab, TAB_COUNT_KEYS } from './shared'
|
||||
import EmployeeProfileShell from './EmployeeProfileShell'
|
||||
import BasicInfo from './BasicInfo'
|
||||
@@ -23,8 +23,7 @@ export default function EmployeeProfile({ employeeId, onBack }: { employeeId: st
|
||||
const { data: profile, isLoading } = useQuery<any>({
|
||||
queryKey: ['roster-profile', employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/roster/${employeeId}/profile`) as any
|
||||
return res.data
|
||||
return await rosterApi.profile(employeeId)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi } from '../../lib/api-services'
|
||||
import { useAuthStore } from "../../store/authStore"
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
@@ -16,8 +16,7 @@ export default function EvidenceChain({ employeeId }: { employeeId: string }) {
|
||||
const { data, isLoading } = useQuery<any>({
|
||||
queryKey: ['evidence-chain', employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/roster/${employeeId}/evidence-chain`) as any
|
||||
return res.data
|
||||
return await rosterApi.evidenceChain(employeeId)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { socialInsuranceApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -148,11 +148,8 @@ export function CityHistoryTab({ socialInsRecords, housingFundRecords, changeTyp
|
||||
const correctMutation = useMutation({
|
||||
mutationFn: async (data: any) => {
|
||||
const cat = editing.cat
|
||||
const url = cat === '社保'
|
||||
? `/social/records/social/${editing.id}/correct`
|
||||
: `/social/records/housing/${editing.id}/correct`
|
||||
const res = await api.put(url, data) as any
|
||||
return res.data
|
||||
const type = cat === '社保' ? 'social' : 'housing'
|
||||
return await socialInsuranceApi.correctRecord(type, editing.id, data)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('记录已修正')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -17,12 +17,12 @@ export default function PerformanceInfo({ employeeId, records }: { employeeId: s
|
||||
const [form, setForm] = useState({ period: '', score: 80, grade: 'B', result: 'QUALIFIED', summary: '', improvementPlan: '', employeeAck: false, ackDate: '', reviewer: '' })
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: any) => api.post(`/roster/${employeeId}/performance`, data),
|
||||
mutationFn: (data: any) => rosterApi.performance(employeeId, data),
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); setShowForm(false) },
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/roster/${employeeId}/performance/${id}`),
|
||||
mutationFn: (id: string) => rosterApi.removePerformance(employeeId, id),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['roster-profile'] }),
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -28,8 +28,7 @@ export default function TerminationInfo({ employeeId, profile, records }: { empl
|
||||
const { data: evidenceChain, isLoading: evidenceLoading } = useQuery<any>({
|
||||
queryKey: ['evidence-chain', employeeId],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/roster/${employeeId}/evidence-chain`) as any
|
||||
return res.data
|
||||
return await rosterApi.evidenceChain(employeeId)
|
||||
},
|
||||
enabled: !!printRecord || showEvidence,
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import api from "../../lib/api"
|
||||
import { rosterApi, socialInsuranceApi } from '../../lib/api-services'
|
||||
import Card from "../../components/ui/Card"
|
||||
import Button from "../../components/ui/Button"
|
||||
import { Input, Label, Select } from "../../components/ui/Input"
|
||||
@@ -245,8 +245,7 @@ export function RehireModal({ employee, onClose, onSubmit, loading, error }: {
|
||||
const { data: contractTypes = [] } = useQuery<Array<{ value: string; label: string; hasEndDate: boolean }>>({
|
||||
queryKey: ['contract-types'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/roster/contract-types') as any
|
||||
return res.data || []
|
||||
return await rosterApi.contractTypes()
|
||||
},
|
||||
staleTime: Infinity,
|
||||
})
|
||||
@@ -496,15 +495,14 @@ export function AddEmployeeModal({ onClose, onSubmit, loading, error }: {
|
||||
const { data: cities = ['北京'] } = useQuery<string[]>({
|
||||
queryKey: ['social-config-cities'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/social/config/cities') as any
|
||||
return res.data?.length ? res.data : ['北京']
|
||||
const res = await socialInsuranceApi.cities() as any
|
||||
return res?.length ? res : ['北京']
|
||||
},
|
||||
})
|
||||
const { data: contractTypes = [] } = useQuery<Array<{ value: string; label: string; hasEndDate: boolean }>>({
|
||||
queryKey: ['contract-types'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/roster/contract-types') as any
|
||||
return res.data || []
|
||||
return await rosterApi.contractTypes()
|
||||
},
|
||||
staleTime: Infinity,
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import { TrendingUp, Save, History, Download, ShieldCheck, Clock, DollarSign, Sparkles, Users, FileText, Calculator, Award } from 'lucide-react'
|
||||
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell } from 'recharts'
|
||||
import api from '../../lib/api'
|
||||
import { dashboardApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -29,24 +29,21 @@ export default function AnnualValueReport() {
|
||||
const { data: report, isLoading } = useQuery<any>({
|
||||
queryKey: ['annual-value', year],
|
||||
queryFn: async () => {
|
||||
const res = await api.get(`/dashboard/annual-value?year=${year}`) as any
|
||||
return res.data
|
||||
return await dashboardApi.annualValue(year)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: history } = useQuery<any>({
|
||||
queryKey: ['annual-value-history'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/dashboard/annual-value/history') as any
|
||||
return res.data
|
||||
return await dashboardApi.annualValueHistory()
|
||||
},
|
||||
enabled: showHistory,
|
||||
})
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const res = await api.post('/dashboard/annual-value/save', { year }) as any
|
||||
return res.data
|
||||
return await dashboardApi.annualValueSave(year)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('报告已保存')
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import { Stethoscope, Save, History, CheckCircle2, AlertCircle, AlertTriangle, ChevronDown, ChevronUp } from 'lucide-react'
|
||||
import { RadialBarChart, RadialBar, PolarAngleAxis, ResponsiveContainer } from 'recharts'
|
||||
import api from '../../lib/api'
|
||||
import { dashboardApi } from '../../lib/api-services'
|
||||
import Card from '../../components/ui/Card'
|
||||
import Button from '../../components/ui/Button'
|
||||
|
||||
@@ -23,24 +23,21 @@ export default function HealthCheck() {
|
||||
const { data: healthCheck, isLoading } = useQuery<any>({
|
||||
queryKey: ['health-check'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/dashboard/health-check') as any
|
||||
return res.data
|
||||
return await dashboardApi.healthCheck()
|
||||
},
|
||||
})
|
||||
|
||||
const { data: history } = useQuery<any>({
|
||||
queryKey: ['health-check-history'],
|
||||
queryFn: async () => {
|
||||
const res = await api.get('/dashboard/health-check/history') as any
|
||||
return res.data
|
||||
return await dashboardApi.healthCheckHistory()
|
||||
},
|
||||
enabled: showHistory,
|
||||
})
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const res = await api.post('/dashboard/health-check/save') as any
|
||||
return res.data
|
||||
return await dashboardApi.healthCheckSave()
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('诊断报告已保存')
|
||||
|
||||
Reference in New Issue
Block a user