|
@@ -0,0 +1,551 @@
|
|
|
|
|
+import React, { useEffect } from 'react'
|
|
|
|
|
+import { View, Text, ScrollView } from '@tarojs/components'
|
|
|
|
|
+import Taro from '@tarojs/taro'
|
|
|
|
|
+import { useQuery } from '@tanstack/react-query'
|
|
|
|
|
+import { YongrenTabBarLayout } from '@d8d/yongren-shared-ui'
|
|
|
|
|
+import { PageContainer } from '@d8d/mini-shared-ui-components'
|
|
|
|
|
+import { enterpriseDisabilityClient } from './api'
|
|
|
|
|
+import { useRequireAuth } from '@d8d/mini-enterprise-auth-ui'
|
|
|
|
|
+import './TalentDetail.css'
|
|
|
|
|
+
|
|
|
|
|
+export interface TalentDetailProps {
|
|
|
|
|
+ // 组件属性定义(目前为空)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 类型定义 - 匹配企业专用人才详情API的CompanyPersonDetailSchema
|
|
|
|
|
+interface TalentDetailData {
|
|
|
|
|
+ personId: number
|
|
|
|
|
+ name: string
|
|
|
|
|
+ gender: string
|
|
|
|
|
+ idCard: string
|
|
|
|
|
+ disabilityType: string
|
|
|
|
|
+ disabilityLevel: string
|
|
|
|
|
+ birthDate?: string
|
|
|
|
|
+ phone?: string
|
|
|
|
|
+ jobStatus: string
|
|
|
|
|
+ bankCards: Array<{
|
|
|
|
|
+ cardId: number
|
|
|
|
|
+ bankName: string
|
|
|
|
|
+ cardNumber: string
|
|
|
|
|
+ isDefault: boolean
|
|
|
|
|
+ }>
|
|
|
|
|
+ photos: Array<{
|
|
|
|
|
+ fileId: number
|
|
|
|
|
+ fileName: string
|
|
|
|
|
+ fileUrl: string
|
|
|
|
|
+ }>
|
|
|
|
|
+ // 兼容字段
|
|
|
|
|
+ id?: number // 兼容旧代码,映射personId
|
|
|
|
|
+ status?: string // 兼容旧代码,映射jobStatus
|
|
|
|
|
+ age?: number // 根据birthDate计算
|
|
|
|
|
+ idAddress?: string // 可能来自其他API
|
|
|
|
|
+ province?: string // 可能来自其他API
|
|
|
|
|
+ city?: string // 可能来自其他API
|
|
|
|
|
+ joinDate?: string // 可能来自工作信息API
|
|
|
|
|
+ salary?: number // 可能来自薪资信息API
|
|
|
|
|
+ companyId?: number // 可能来自其他API
|
|
|
|
|
+ disabilityId?: string // 可能来自其他API
|
|
|
|
|
+ specificDisability?: string // 可能来自其他API
|
|
|
|
|
+ [key: string]: any
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface WorkInfoData {
|
|
|
|
|
+ id: number
|
|
|
|
|
+ orderId?: number
|
|
|
|
|
+ position?: string
|
|
|
|
|
+ department?: string
|
|
|
|
|
+ startDate?: string
|
|
|
|
|
+ endDate?: string
|
|
|
|
|
+ status?: string
|
|
|
|
|
+ companyId?: number
|
|
|
|
|
+ [key: string]: any
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface SalaryData {
|
|
|
|
|
+ id: number
|
|
|
|
|
+ personId: number
|
|
|
|
|
+ amount?: number
|
|
|
|
|
+ paymentDate?: string
|
|
|
|
|
+ period?: string
|
|
|
|
|
+ type?: string
|
|
|
|
|
+ notes?: string
|
|
|
|
|
+ [key: string]: any
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface FileData {
|
|
|
|
|
+ id: string
|
|
|
|
|
+ name: string
|
|
|
|
|
+ url?: string
|
|
|
|
|
+ size?: number
|
|
|
|
|
+ type?: string
|
|
|
|
|
+ createdAt?: string
|
|
|
|
|
+ [key: string]: any
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 企业专用API响应类型
|
|
|
|
|
+interface WorkHistoryItem {
|
|
|
|
|
+ 订单ID: number
|
|
|
|
|
+ 订单名称: string | null
|
|
|
|
|
+ 入职日期: string | null
|
|
|
|
|
+ 实际入职日期: string | null
|
|
|
|
|
+ 离职日期: string | null
|
|
|
|
|
+ 工作状态: string
|
|
|
|
|
+ 个人薪资: number
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface WorkHistoryResponse {
|
|
|
|
|
+ 工作历史: WorkHistoryItem[]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface SalaryHistoryItem {
|
|
|
|
|
+ 月份: string | null
|
|
|
|
|
+ 基本工资: number
|
|
|
|
|
+ 补贴: number
|
|
|
|
|
+ 扣款: number
|
|
|
|
|
+ 实发工资: number
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface SalaryHistoryResponse {
|
|
|
|
|
+ 薪资历史: SalaryHistoryItem[]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface CreditInfoItem {
|
|
|
|
|
+ 文件ID: string
|
|
|
|
|
+ 文件URL: string | null
|
|
|
|
|
+ 上传时间: string | null
|
|
|
|
|
+ 文件类型: string | null
|
|
|
|
|
+ 银行卡号: string | null
|
|
|
|
|
+ 持卡人姓名: string | null
|
|
|
|
|
+ 银行名称: number | null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface CreditInfoResponse {
|
|
|
|
|
+ 征信信息: CreditInfoItem[]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const TalentDetail: React.FC<TalentDetailProps> = () => {
|
|
|
|
|
+ const { isLoggedIn } = useRequireAuth()
|
|
|
|
|
+ const router = Taro.useRouter()
|
|
|
|
|
+ const talentId = router.params.id ? parseInt(router.params.id) : 0
|
|
|
|
|
+
|
|
|
|
|
+ // 获取人才基本信息
|
|
|
|
|
+ const { data: talentDetail, isLoading: talentLoading, error: talentError } = useQuery({
|
|
|
|
|
+ queryKey: ['talentDetail', talentId],
|
|
|
|
|
+ queryFn: async () => {
|
|
|
|
|
+ if (!talentId) throw new Error('无效的人才ID')
|
|
|
|
|
+ const response = await enterpriseDisabilityClient[':id'].$get({
|
|
|
|
|
+ param: { id: talentId.toString() }
|
|
|
|
|
+ })
|
|
|
|
|
+ if (response.status !== 200) {
|
|
|
|
|
+ throw new Error('获取人才详情失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = await response.json() as TalentDetailData
|
|
|
|
|
+ // 添加兼容字段映射
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...data,
|
|
|
|
|
+ id: data.personId, // 映射id字段
|
|
|
|
|
+ status: data.jobStatus, // 映射status字段
|
|
|
|
|
+ // 计算年龄
|
|
|
|
|
+ age: data.birthDate ? Math.floor((Date.now() - new Date(data.birthDate).getTime()) / (1000 * 60 * 60 * 24 * 365.25)) : undefined
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ enabled: isLoggedIn && talentId > 0
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 获取工作信息 - 使用企业专用工作历史API
|
|
|
|
|
+ const { data: workInfo, isLoading: workLoading } = useQuery({
|
|
|
|
|
+ queryKey: ['workInfo', talentId],
|
|
|
|
|
+ queryFn: async () => {
|
|
|
|
|
+ if (!talentId) throw new Error('无效的人才ID')
|
|
|
|
|
+ // 使用企业专用工作历史API:/api/v1/yongren/disability-person/{id}/work-history
|
|
|
|
|
+ const response = await enterpriseDisabilityClient[':id']['work-history'].$get({
|
|
|
|
|
+ param: { id: talentId.toString() }
|
|
|
|
|
+ })
|
|
|
|
|
+ if (response.status !== 200) {
|
|
|
|
|
+ // 可能没有工作信息,返回空对象
|
|
|
|
|
+ return {} as WorkInfoData
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = await response.json() as WorkHistoryResponse
|
|
|
|
|
+ // 企业专用工作历史API返回的是工作历史列表,取最新的一条作为当前工作信息
|
|
|
|
|
+ const workHistory = data?.工作历史 || []
|
|
|
|
|
+ if (workHistory.length === 0) {
|
|
|
|
|
+ return {} as WorkInfoData
|
|
|
|
|
+ }
|
|
|
|
|
+ // 取最新的一条工作记录(按入职日期降序)
|
|
|
|
|
+ const latestWork = workHistory[0]
|
|
|
|
|
+ return {
|
|
|
|
|
+ id: latestWork.订单ID || talentId,
|
|
|
|
|
+ orderId: latestWork.订单ID,
|
|
|
|
|
+ position: latestWork.订单名称 || undefined,
|
|
|
|
|
+ department: undefined, // 企业专用API没有部门字段
|
|
|
|
|
+ startDate: latestWork.入职日期 || undefined,
|
|
|
|
|
+ endDate: latestWork.离职日期 || undefined,
|
|
|
|
|
+ status: latestWork.工作状态,
|
|
|
|
|
+ companyId: undefined // 企业专用API没有公司ID字段
|
|
|
|
|
+ } as WorkInfoData
|
|
|
|
|
+ },
|
|
|
|
|
+ enabled: isLoggedIn && talentId > 0
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 获取薪资信息 - 使用企业专用薪资历史API
|
|
|
|
|
+ const { data: salaryInfo, isLoading: salaryLoading } = useQuery({
|
|
|
|
|
+ queryKey: ['salaryInfo', talentId],
|
|
|
|
|
+ queryFn: async () => {
|
|
|
|
|
+ if (!talentId) throw new Error('无效的人才ID')
|
|
|
|
|
+ // 使用企业专用薪资历史API:/api/v1/yongren/disability-person/{id}/salary-history
|
|
|
|
|
+ const response = await enterpriseDisabilityClient[':id']['salary-history'].$get({
|
|
|
|
|
+ param: { id: talentId.toString() }
|
|
|
|
|
+ })
|
|
|
|
|
+ if (response.status !== 200) {
|
|
|
|
|
+ // 可能没有薪资信息,返回空对象
|
|
|
|
|
+ return {} as SalaryData
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = await response.json() as SalaryHistoryResponse
|
|
|
|
|
+ // 企业专用薪资历史API返回结构:{ 薪资历史: [...] }
|
|
|
|
|
+ const salaryHistory = data?.薪资历史 || []
|
|
|
|
|
+ if (salaryHistory.length === 0) {
|
|
|
|
|
+ return {} as SalaryData
|
|
|
|
|
+ }
|
|
|
|
|
+ // 取最新的一条薪资记录(按月份降序)
|
|
|
|
|
+ const latestSalary = salaryHistory[0]
|
|
|
|
|
+ return {
|
|
|
|
|
+ id: talentId,
|
|
|
|
|
+ personId: talentId,
|
|
|
|
|
+ amount: latestSalary.实发工资 || latestSalary.基本工资,
|
|
|
|
|
+ paymentDate: latestSalary.月份 || undefined,
|
|
|
|
|
+ type: '月薪', // 默认类型
|
|
|
|
|
+ period: '月度' // 默认周期
|
|
|
|
|
+ } as SalaryData
|
|
|
|
|
+ },
|
|
|
|
|
+ enabled: isLoggedIn && talentId > 0
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 获取薪资历史记录 - 使用企业专用薪资历史API
|
|
|
|
|
+ const { data: salaryHistory, isLoading: historyLoading } = useQuery({
|
|
|
|
|
+ queryKey: ['salaryHistory', talentId],
|
|
|
|
|
+ queryFn: async () => {
|
|
|
|
|
+ if (!talentId) throw new Error('无效的人才ID')
|
|
|
|
|
+ // 使用企业专用薪资历史API:/api/v1/yongren/disability-person/{id}/salary-history
|
|
|
|
|
+ const response = await enterpriseDisabilityClient[':id']['salary-history'].$get({
|
|
|
|
|
+ param: { id: talentId.toString() }
|
|
|
|
|
+ })
|
|
|
|
|
+ if (response.status !== 200) {
|
|
|
|
|
+ return [] as SalaryData[]
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = await response.json() as SalaryHistoryResponse
|
|
|
|
|
+ // 企业专用薪资历史API返回结构:{ 薪资历史: [...] }
|
|
|
|
|
+ const salaryHistoryData = data?.薪资历史 || []
|
|
|
|
|
+ // 转换为SalaryData数组
|
|
|
|
|
+ return salaryHistoryData.map((item: SalaryHistoryItem, index: number) => ({
|
|
|
|
|
+ id: index + 1,
|
|
|
|
|
+ personId: talentId,
|
|
|
|
|
+ amount: item.实发工资 || item.基本工资,
|
|
|
|
|
+ paymentDate: item.月份 || undefined,
|
|
|
|
|
+ type: '月薪', // 默认类型
|
|
|
|
|
+ period: '月度' // 默认周期
|
|
|
|
|
+ })) as SalaryData[]
|
|
|
|
|
+ },
|
|
|
|
|
+ enabled: isLoggedIn && talentId > 0
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 获取个人征信文件 - 使用企业专用征信信息API
|
|
|
|
|
+ const { data: creditFiles, isLoading: filesLoading } = useQuery({
|
|
|
|
|
+ queryKey: ['creditFiles', talentId],
|
|
|
|
|
+ queryFn: async () => {
|
|
|
|
|
+ if (!talentId) throw new Error('无效的人才ID')
|
|
|
|
|
+ // 使用企业专用征信信息API:/api/v1/yongren/disability-person/{id}/credit-info
|
|
|
|
|
+ const response = await enterpriseDisabilityClient[':id']['credit-info'].$get({
|
|
|
|
|
+ param: { id: talentId.toString() }
|
|
|
|
|
+ })
|
|
|
|
|
+ if (response.status !== 200) {
|
|
|
|
|
+ return [] as FileData[]
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = await response.json() as CreditInfoResponse
|
|
|
|
|
+ // 企业专用征信信息API返回结构:{ 征信信息: [...] }
|
|
|
|
|
+ const creditInfoList = data?.征信信息 || []
|
|
|
|
|
+ // 转换为FileData数组
|
|
|
|
|
+ return creditInfoList.map((item: CreditInfoItem) => ({
|
|
|
|
|
+ id: item.文件ID || '',
|
|
|
|
|
+ name: item.银行卡号 ? `银行卡 ${item.银行卡号}` : item.持卡人姓名 ? `征信文件 - ${item.持卡人姓名}` : '征信文件',
|
|
|
|
|
+ url: item.文件URL || undefined,
|
|
|
|
|
+ size: undefined, // 征信信息API不返回文件大小
|
|
|
|
|
+ type: item.文件类型 || undefined,
|
|
|
|
|
+ createdAt: item.上传时间 || undefined
|
|
|
|
|
+ })) as FileData[]
|
|
|
|
|
+ },
|
|
|
|
|
+ enabled: isLoggedIn && talentId > 0
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 页面加载时设置标题
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ Taro.setNavigationBarTitle({
|
|
|
|
|
+ title: '人才详情'
|
|
|
|
|
+ })
|
|
|
|
|
+ }, [])
|
|
|
|
|
+
|
|
|
|
|
+ const isLoading = talentLoading || workLoading || salaryLoading || filesLoading || historyLoading
|
|
|
|
|
+ const hasError = talentError
|
|
|
|
|
+
|
|
|
|
|
+ // 获取头像颜色
|
|
|
|
|
+ const getAvatarColor = (id: number) => {
|
|
|
|
|
+ const colors = ['blue', 'green', 'purple', 'orange', 'red', 'teal']
|
|
|
|
|
+ const index = id % colors.length
|
|
|
|
|
+ return colors[index]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 格式化日期
|
|
|
|
|
+ const formatDate = (dateStr?: string) => {
|
|
|
|
|
+ if (!dateStr) return '未指定'
|
|
|
|
|
+ return dateStr.split('T')[0]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 格式化金额
|
|
|
|
|
+ const formatCurrency = (amount?: number) => {
|
|
|
|
|
+ if (!amount) return '¥0'
|
|
|
|
|
+ return `¥${amount.toLocaleString()}`
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <YongrenTabBarLayout activeKey="talent">
|
|
|
|
|
+ <PageContainer padding={false} className="pb-0">
|
|
|
|
|
+ <ScrollView
|
|
|
|
|
+ className="h-[calc(100vh-120px)] overflow-y-auto"
|
|
|
|
|
+ scrollY
|
|
|
|
|
+ >
|
|
|
|
|
+ {isLoading ? (
|
|
|
|
|
+ // 加载状态
|
|
|
|
|
+ <View className="p-4 space-y-4">
|
|
|
|
|
+ {[1, 2, 3].map((i) => (
|
|
|
|
|
+ <View key={i} className="bg-white p-4 rounded-lg animate-pulse">
|
|
|
|
|
+ <View className="h-6 bg-gray-200 rounded w-1/3 mb-3" />
|
|
|
|
|
+ <View className="space-y-2">
|
|
|
|
|
+ <View className="h-4 bg-gray-200 rounded w-full" />
|
|
|
|
|
+ <View className="h-4 bg-gray-200 rounded w-2/3" />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ) : hasError ? (
|
|
|
|
|
+ // 错误状态
|
|
|
|
|
+ <View className="p-4">
|
|
|
|
|
+ <View className="bg-white p-4 rounded-lg text-center">
|
|
|
|
|
+ <Text className="text-red-500 text-sm">加载失败: {(talentError as Error).message}</Text>
|
|
|
|
|
+ <Text className="text-gray-400 text-xs mt-1">请返回重试</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ) : talentDetail ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ {/* 顶部信息区域 - 对照原型第576-605行 */}
|
|
|
|
|
+ <View className="gradient-bg text-white p-5">
|
|
|
|
|
+ <View className="flex justify-between items-start">
|
|
|
|
|
+ <View className="flex items-center">
|
|
|
|
|
+ <View className={`name-avatar ${getAvatarColor(talentDetail.id)} w-16 h-16 rounded-full border-2 border-white mr-4 flex items-center justify-center`}>
|
|
|
|
|
+ <Text className="text-white text-2xl font-bold">
|
|
|
|
|
+ {talentDetail.name.charAt(0)}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View>
|
|
|
|
|
+ <Text className="text-xl font-bold">{talentDetail.name}</Text>
|
|
|
|
|
+ <Text className="text-sm opacity-80">
|
|
|
|
|
+ {talentDetail.disabilityType || '未指定'} · {talentDetail.disabilityLevel || '未分级'} · {talentDetail.status || '未知'}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="bg-white/20 rounded-full p-2">
|
|
|
|
|
+ <Text className="i-heroicons-ellipsis-vertical-20-solid text-white" />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="mt-4 flex justify-between">
|
|
|
|
|
+ <View className="text-center">
|
|
|
|
|
+ <Text className="text-2xl font-bold">{formatCurrency(talentDetail.salary)}</Text>
|
|
|
|
|
+ <Text className="text-xs opacity-80">当前薪资</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="text-center">
|
|
|
|
|
+ <Text className="text-2xl font-bold">
|
|
|
|
|
+ {talentDetail.joinDate ? Math.floor((Date.now() - new Date(talentDetail.joinDate).getTime()) / (1000 * 60 * 60 * 24)) : 0}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ <Text className="text-xs opacity-80">在职天数</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="text-center">
|
|
|
|
|
+ <Text className="text-2xl font-bold">98%</Text>
|
|
|
|
|
+ <Text className="text-xs opacity-80">出勤率</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 详细信息区域 - 对照原型第608-864行 */}
|
|
|
|
|
+ <View className="p-4">
|
|
|
|
|
+ {/* 基本信息卡片 */}
|
|
|
|
|
+ <View className="card bg-white p-4 mb-4">
|
|
|
|
|
+ <Text className="font-semibold text-gray-700 mb-3">基本信息</Text>
|
|
|
|
|
+ <View className="grid grid-cols-2 gap-3 text-sm">
|
|
|
|
|
+ <View>
|
|
|
|
|
+ <Text className="text-gray-500">性别</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{talentDetail.gender || '未指定'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View>
|
|
|
|
|
+ <Text className="text-gray-500">年龄</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{talentDetail.age || '未知'}岁</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View>
|
|
|
|
|
+ <Text className="text-gray-500">身份证号</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{talentDetail.idCard || '未提供'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View>
|
|
|
|
|
+ <Text className="text-gray-500">残疾证号</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{talentDetail.disabilityId || '未提供'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="col-span-2">
|
|
|
|
|
+ <Text className="text-gray-500">联系地址</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{talentDetail.idAddress || '未提供'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="col-span-2">
|
|
|
|
|
+ <Text className="text-gray-500">联系电话</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{talentDetail.phone || '未提供'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 工作信息卡片 */}
|
|
|
|
|
+ <View className="card bg-white p-4 mb-4">
|
|
|
|
|
+ <Text className="font-semibold text-gray-700 mb-3">工作信息</Text>
|
|
|
|
|
+ <View className="space-y-3 text-sm">
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">入职日期</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{formatDate(talentDetail.joinDate)}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">工作状态</Text>
|
|
|
|
|
+ <Text className={`text-xs px-2 py-1 rounded-full ${
|
|
|
|
|
+ talentDetail.status === '在职'
|
|
|
|
|
+ ? 'bg-green-100 text-green-800'
|
|
|
|
|
+ : talentDetail.status === '待入职'
|
|
|
|
|
+ ? 'bg-yellow-100 text-yellow-800'
|
|
|
|
|
+ : 'bg-gray-100 text-gray-800'
|
|
|
|
|
+ }`}>
|
|
|
|
|
+ {talentDetail.status || '未知'}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">岗位类型</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{workInfo?.position || '未指定'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">所属订单</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{workInfo?.orderId ? `订单 #${workInfo.orderId}` : '无'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 薪资信息卡片 */}
|
|
|
|
|
+ <View className="card bg-white p-4 mb-4">
|
|
|
|
|
+ <Text className="font-semibold text-gray-700 mb-3">薪资信息</Text>
|
|
|
|
|
+ <View className="space-y-3 text-sm">
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">当前薪资</Text>
|
|
|
|
|
+ <Text className="text-gray-800 font-semibold">{formatCurrency(talentDetail.salary)}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">薪资结构</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{salaryInfo?.type || '月薪'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">发薪日</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{salaryInfo?.paymentDate ? formatDate(salaryInfo.paymentDate) : '每月底'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="flex justify-between">
|
|
|
|
|
+ <Text className="text-gray-500">薪资周期</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{salaryInfo?.period || '月度'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 薪资历史记录卡片 */}
|
|
|
|
|
+ <View className="card bg-white p-4 mb-4">
|
|
|
|
|
+ <Text className="font-semibold text-gray-700 mb-3">薪资历史记录</Text>
|
|
|
|
|
+ {historyLoading ? (
|
|
|
|
|
+ <View className="space-y-2">
|
|
|
|
|
+ {[1, 2, 3].map((i) => (
|
|
|
|
|
+ <View key={i} className="h-10 bg-gray-200 rounded animate-pulse" />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ) : salaryHistory && salaryHistory.length > 0 ? (
|
|
|
|
|
+ <View className="space-y-3">
|
|
|
|
|
+ <View className="grid grid-cols-4 gap-2 text-xs text-gray-500 font-medium pb-2 border-b border-gray-200">
|
|
|
|
|
+ <Text>日期</Text>
|
|
|
|
|
+ <Text>薪资</Text>
|
|
|
|
|
+ <Text>类型</Text>
|
|
|
|
|
+ <Text>周期</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ {salaryHistory.slice(0, 5).map((record, index) => (
|
|
|
|
|
+ <View key={index} className="grid grid-cols-4 gap-2 text-sm">
|
|
|
|
|
+ <Text className="text-gray-800">{formatDate(record.paymentDate)}</Text>
|
|
|
|
|
+ <Text className="text-gray-800 font-medium">{formatCurrency(record.amount)}</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{record.type || '月薪'}</Text>
|
|
|
|
|
+ <Text className="text-gray-800">{record.period || '月度'}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ {salaryHistory.length > 5 && (
|
|
|
|
|
+ <Text className="text-center text-xs text-blue-500 mt-2">
|
|
|
|
|
+ 查看更多 ({salaryHistory.length - 5} 条记录)
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <View className="text-center py-4">
|
|
|
|
|
+ <Text className="text-gray-400 text-sm">暂无薪资历史记录</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </View>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 个人征信文件区域 */}
|
|
|
|
|
+ <View className="card bg-white p-4">
|
|
|
|
|
+ <Text className="font-semibold text-gray-700 mb-3">个人征信文件</Text>
|
|
|
|
|
+ {filesLoading ? (
|
|
|
|
|
+ <View className="space-y-2">
|
|
|
|
|
+ {[1, 2].map((i) => (
|
|
|
|
|
+ <View key={i} className="h-10 bg-gray-200 rounded animate-pulse" />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ) : creditFiles && creditFiles.length > 0 ? (
|
|
|
|
|
+ <View className="space-y-3">
|
|
|
|
|
+ {creditFiles.map((file) => (
|
|
|
|
|
+ <View key={file.id} className="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
|
|
|
|
|
+ <View className="flex items-center">
|
|
|
|
|
+ <Text className="i-heroicons-document-text-20-solid text-gray-400 mr-2" />
|
|
|
|
|
+ <View>
|
|
|
|
|
+ <Text className="text-sm text-gray-800">{file.name}</Text>
|
|
|
|
|
+ <Text className="text-xs text-gray-500">
|
|
|
|
|
+ {file.size ? `${(file.size / 1024).toFixed(1)} KB` : '大小未知'} · {formatDate(file.createdAt)}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View className="flex space-x-2">
|
|
|
|
|
+ <Text className="i-heroicons-eye-20-solid text-blue-500" />
|
|
|
|
|
+ <Text className="i-heroicons-arrow-down-tray-20-solid text-green-500" />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <View className="text-center py-4">
|
|
|
|
|
+ <Text className="text-gray-400 text-sm">暂无征信文件</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <View className="p-4">
|
|
|
|
|
+ <View className="bg-white p-4 rounded-lg text-center">
|
|
|
|
|
+ <Text className="text-gray-500 text-sm">未找到人才信息</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </ScrollView>
|
|
|
|
|
+ </PageContainer>
|
|
|
|
|
+ </YongrenTabBarLayout>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export default TalentDetail
|