fix: 培训/绩效/违纪列表页CRUD改用api实例(修复401鉴权失败)

This commit is contained in:
freedakgmail
2026-08-05 08:28:51 +08:00
parent b239465e78
commit 15dde27701
4 changed files with 122 additions and 38 deletions
+106
View File
@@ -399,6 +399,112 @@ async function createOrg(orgConfig: OrgConfig) {
}
}
console.log(` ✅ 历史工资条已生成`)
// 10. 生成培训记录
console.log(` 📝 生成培训记录...`)
const trainingTopics = [
{ topic: '新员工入职培训', content: '公司文化、规章制度、安全规范', trainer: '张经理', duration: 4 },
{ topic: '岗位技能培训', content: '岗位操作规范与流程', trainer: '李主管', duration: 6 },
{ topic: '安全生产培训', content: '安全生产法规与操作规程', trainer: '王安全', duration: 3 },
{ topic: '团队协作培训', content: '沟通技巧与团队建设', trainer: '刘讲师', duration: 2 },
]
for (let i = 0; i < allEmployees.length; i++) {
const emp = allEmployees[i]
const t = trainingTopics[i % trainingTopics.length]
const trainDate = new Date(2026, (i % 6), 15)
const ackStatus = i % 3 === 0 ? 'PENDING' : i % 3 === 1 ? 'SIGNED' : 'REFUSED'
await prisma.trainingRecord.create({
data: {
orgId: org.id,
employeeId: emp.id,
trainingDate: trainDate,
topic: t.topic,
content: t.content,
trainer: t.trainer,
duration: t.duration,
ackStatus: ackStatus as any,
ackDate: ackStatus === 'SIGNED' ? new Date(trainDate.getTime() + 86400000) : null,
createdBy: admin.id,
},
})
}
console.log(` ✅ 培训记录已生成 (${allEmployees.length}条)`)
// 11. 生成绩效记录
console.log(` 📊 生成绩效记录...`)
const perfResults = ['EXCELLENT', 'QUALIFIED', 'QUALIFIED', 'NEED_IMPROVE', 'UNQUALIFIED'] as const
const perfGrades = ['A', 'B', 'B', 'C', 'D']
for (let i = 0; i < allEmployees.length; i++) {
const emp = allEmployees[i]
const idx = i % perfResults.length
const score = 95 - idx * 12
await prisma.performanceRecord.create({
data: {
orgId: org.id,
employeeId: emp.id,
period: '2026-Q1',
score,
grade: perfGrades[idx],
result: perfResults[idx] as any,
summary: idx < 2 ? '工作表现优秀,完成任务质量高' : idx < 4 ? '基本完成工作目标,有待提升' : '未达到岗位要求,需制定改进计划',
improvementPlan: idx >= 3 ? '加强技能培训,设定阶段性目标' : null,
reviewer: admin.name,
employeeAck: i % 2 === 0,
createdBy: admin.id,
},
})
// 部分员工有Q2绩效
if (i % 2 === 0) {
await prisma.performanceRecord.create({
data: {
orgId: org.id,
employeeId: emp.id,
period: '2026-Q2',
score: score - 5,
grade: perfGrades[Math.min(idx + 1, 4)],
result: perfResults[Math.min(idx + 1, 4)] as any,
summary: '二季度绩效评估',
reviewer: admin.name,
employeeAck: false,
createdBy: admin.id,
},
})
}
}
console.log(` ✅ 绩效记录已生成 (${allEmployees.length}条)`)
// 12. 生成违纪记录(部分员工)
console.log(` ⚠️ 生成违纪记录...`)
const discTypes = ['LATE', 'ABSENT', 'INSUBORDINATION', 'MISCONDUCT'] as const
const discDescriptions = [
'月内累计迟到3次,超过公司允许范围',
'未经请假擅自缺勤1天',
'不服从主管工作安排,拒绝执行合理指令',
'违反公司安全操作规程,未佩戴防护设备',
]
const discActions = ['ORAL_WARNING', 'WRITTEN_WARNING', 'DEDUCTION', 'WRITTEN_WARNING'] as const
for (let i = 0; i < Math.min(allEmployees.length, 4); i++) {
const emp = allEmployees[i]
const violationDate = new Date(2026, i % 6, 10)
await prisma.disciplinaryRecord.create({
data: {
orgId: org.id,
employeeId: emp.id,
violationDate,
violationType: discTypes[i],
description: discDescriptions[i],
severity: i < 2 ? 'WARNING' : 'SERIOUS',
action: discActions[i],
actionDetail: i === 2 ? '扣除当日工资' : '',
employeeAck: i % 2 === 0,
ackDate: i % 2 === 0 ? new Date(violationDate.getTime() + 86400000) : null,
ackMethod: i % 2 === 0 ? 'SIGN' : null,
witness: i >= 2 ? '部门主管' : null,
createdBy: admin.id,
},
})
}
console.log(` ✅ 违纪记录已生成 (${Math.min(allEmployees.length, 4)}条)`)
}
// ========== 主函数 ==========
@@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'
import { Search, Plus, Edit2, Trash2, X } from 'lucide-react'
import { toast } from 'sonner'
import { rosterApi, employeeApi } from '../../lib/api-services'
import api from '../../lib/api'
import { usePageSize } from '../../hooks/usePageSize'
import { Input, Label, Select } from '../../components/ui/Input'
import Button from '../../components/ui/Button'
@@ -43,14 +44,10 @@ export default function DisciplinaryRecords() {
const isEdit = !!data.recordId
const recordId = data.recordId
delete data.recordId
const url = isEdit
? `/api/v1/roster/${empId}/disciplinary/${recordId}`
: `/api/v1/roster/${empId}/disciplinary`
return fetch(url, {
method: isEdit ? 'PUT' : 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` },
body: JSON.stringify(data),
}).then(r => r.json())
if (isEdit) {
return api.put(`/roster/${empId}/disciplinary/${recordId}`, data)
}
return api.post(`/roster/${empId}/disciplinary`, data)
},
onSuccess: () => {
toast.success('违纪记录已保存')
@@ -63,10 +60,7 @@ export default function DisciplinaryRecords() {
const deleteMut = useMutation({
mutationFn: ({ employeeId, recordId }: { employeeId: string; recordId: string }) =>
fetch(`/api/v1/roster/${employeeId}/disciplinary/${recordId}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` },
}).then(r => r.json()),
api.delete(`/roster/${employeeId}/disciplinary/${recordId}`),
onSuccess: () => {
toast.success('记录已删除')
queryClient.invalidateQueries({ queryKey: ['disciplinary-list'] })
@@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'
import { Search, Plus, Edit2, Trash2, X } from 'lucide-react'
import { toast } from 'sonner'
import { rosterApi, employeeApi } from '../../lib/api-services'
import api from '../../lib/api'
import { usePageSize } from '../../hooks/usePageSize'
import { Input, Label, Select } from '../../components/ui/Input'
import Button from '../../components/ui/Button'
@@ -36,14 +37,10 @@ export default function PerformanceRecords() {
const isEdit = !!data.recordId
const recordId = data.recordId
delete data.recordId
const url = isEdit
? `/api/v1/roster/${empId}/performance/${recordId}`
: `/api/v1/roster/${empId}/performance`
return fetch(url, {
method: isEdit ? 'PUT' : 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` },
body: JSON.stringify(data),
}).then(r => r.json())
if (isEdit) {
return api.put(`/roster/${empId}/performance/${recordId}`, data)
}
return api.post(`/roster/${empId}/performance`, data)
},
onSuccess: () => {
toast.success('绩效记录已保存')
@@ -56,10 +53,7 @@ export default function PerformanceRecords() {
const deleteMut = useMutation({
mutationFn: ({ employeeId, recordId }: { employeeId: string; recordId: string }) =>
fetch(`/api/v1/roster/${employeeId}/performance/${recordId}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` },
}).then(r => r.json()),
api.delete(`/roster/${employeeId}/performance/${recordId}`),
onSuccess: () => {
toast.success('记录已删除')
queryClient.invalidateQueries({ queryKey: ['performance-list'] })
+4 -14
View File
@@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'
import { Search, Plus, Edit2, Trash2, X } from 'lucide-react'
import { toast } from 'sonner'
import { rosterApi, employeeApi } from '../../lib/api-services'
import api from '../../lib/api'
import { usePageSize } from '../../hooks/usePageSize'
import { Input, Label, Select } from '../../components/ui/Input'
import Button from '../../components/ui/Button'
@@ -38,11 +39,7 @@ export default function TrainingRecords() {
mutationFn: (data: any) => {
const empId = data.employeeId
delete data.employeeId
return fetch(`/api/v1/roster/${empId}/training`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` },
body: JSON.stringify(data),
}).then(r => r.json())
return api.post(`/roster/${empId}/training`, data)
},
onSuccess: () => {
toast.success('培训记录已添加')
@@ -58,11 +55,7 @@ export default function TrainingRecords() {
const recordId = data.recordId
delete data.employeeId
delete data.recordId
return fetch(`/api/v1/roster/${empId}/training/${recordId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` },
body: JSON.stringify(data),
}).then(r => r.json())
return api.put(`/roster/${empId}/training/${recordId}`, data)
},
onSuccess: () => {
toast.success('培训记录已更新')
@@ -74,10 +67,7 @@ export default function TrainingRecords() {
const deleteMut = useMutation({
mutationFn: ({ employeeId, recordId }: { employeeId: string; recordId: string }) =>
fetch(`/api/v1/roster/${employeeId}/training/${recordId}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` },
}).then(r => r.json()),
api.delete(`/roster/${employeeId}/training/${recordId}`),
onSuccess: () => {
toast.success('记录已删除')
queryClient.invalidateQueries({ queryKey: ['training-list'] })