|
@@ -1,8 +1,15 @@
|
|
|
-import React from 'react'
|
|
|
|
|
-import { View, Text, ScrollView } from '@tarojs/components'
|
|
|
|
|
|
|
+import React, { useMemo } from 'react'
|
|
|
|
|
+import { View, ScrollView } from '@tarojs/components'
|
|
|
|
|
+import Taro from '@tarojs/taro'
|
|
|
|
|
+import { useQuery } from '@tanstack/react-query'
|
|
|
import { RencaiTabBarLayout } from '@d8d/rencai-shared-ui/components/RencaiTabBarLayout'
|
|
import { RencaiTabBarLayout } from '@d8d/rencai-shared-ui/components/RencaiTabBarLayout'
|
|
|
import { Navbar } from '@d8d/mini-shared-ui-components/components/navbar'
|
|
import { Navbar } from '@d8d/mini-shared-ui-components/components/navbar'
|
|
|
import { useRequireAuth } from '@d8d/rencai-auth-ui/hooks'
|
|
import { useRequireAuth } from '@d8d/rencai-auth-ui/hooks'
|
|
|
|
|
+import { UserProfileSummary } from '../../components/UserProfileSummary'
|
|
|
|
|
+import { MenuSection } from '../../components/MenuSection'
|
|
|
|
|
+import { LogoutButton } from '../../components/LogoutButton'
|
|
|
|
|
+import { talentSettingsClient } from '../../api'
|
|
|
|
|
+import type { MenuSection as MenuSectionType } from '../../types/settings'
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 人才小程序设置页
|
|
* 人才小程序设置页
|
|
@@ -12,6 +19,229 @@ import { useRequireAuth } from '@d8d/rencai-auth-ui/hooks'
|
|
|
const SettingsPage: React.FC = () => {
|
|
const SettingsPage: React.FC = () => {
|
|
|
// 检查登录状态,未登录则重定向
|
|
// 检查登录状态,未登录则重定向
|
|
|
useRequireAuth()
|
|
useRequireAuth()
|
|
|
|
|
+
|
|
|
|
|
+ // 查询用户信息(使用React Query)
|
|
|
|
|
+ const { data: profile, isLoading, error } = useQuery({
|
|
|
|
|
+ queryKey: ['user-profile'],
|
|
|
|
|
+ queryFn: async () => {
|
|
|
|
|
+ const res = await talentSettingsClient.me.$get()
|
|
|
|
|
+ if (!res.ok) {
|
|
|
|
|
+ throw new Error('获取用户信息失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ return await res.json()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 功能入口菜单配置
|
|
|
|
|
+ const menuSections = useMemo<MenuSectionType[]>(() => [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: undefined,
|
|
|
|
|
+ items: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'personal-info',
|
|
|
|
|
+ title: '修改个人信息',
|
|
|
|
|
+ icon: 'i-heroicons-user-20-solid',
|
|
|
|
|
+ bgColor: 'bg-blue-100',
|
|
|
|
|
+ iconColor: 'text-blue-500',
|
|
|
|
|
+ onPress: () => {
|
|
|
|
|
+ Taro.navigateTo({ url: '/pages/personal-info/index' })
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'account-security',
|
|
|
|
|
+ title: '账号与安全',
|
|
|
|
|
+ icon: 'i-heroicons-shield-check-20-solid',
|
|
|
|
|
+ bgColor: 'bg-green-100',
|
|
|
|
|
+ iconColor: 'text-green-500',
|
|
|
|
|
+ onPress: () => {
|
|
|
|
|
+ Taro.navigateTo({ url: '/pages/account-security/index' })
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'notification-settings',
|
|
|
|
|
+ title: '消息通知设置',
|
|
|
|
|
+ icon: 'i-heroicons-bell-20-solid',
|
|
|
|
|
+ bgColor: 'bg-purple-100',
|
|
|
|
|
+ iconColor: 'text-purple-500',
|
|
|
|
|
+ onPress: () => {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '功能开发中',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: undefined,
|
|
|
|
|
+ items: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'help-center',
|
|
|
|
|
+ title: '帮助中心',
|
|
|
|
|
+ icon: 'i-heroicons-question-mark-circle-20-solid',
|
|
|
|
|
+ bgColor: 'bg-yellow-100',
|
|
|
|
|
+ iconColor: 'text-yellow-600',
|
|
|
|
|
+ onPress: () => {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '帮助中心开发中',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'user-agreement',
|
|
|
|
|
+ title: '用户协议',
|
|
|
|
|
+ icon: 'i-heroicons-document-text-20-solid',
|
|
|
|
|
+ bgColor: 'bg-indigo-100',
|
|
|
|
|
+ iconColor: 'text-indigo-500',
|
|
|
|
|
+ onPress: () => {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '用户协议开发中',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'privacy-policy',
|
|
|
|
|
+ title: '隐私政策',
|
|
|
|
|
+ icon: 'i-heroicons-lock-closed-20-solid',
|
|
|
|
|
+ bgColor: 'bg-pink-100',
|
|
|
|
|
+ iconColor: 'text-pink-500',
|
|
|
|
|
+ onPress: () => {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '隐私政策开发中',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ ], [])
|
|
|
|
|
+
|
|
|
|
|
+ // 退出登录处理
|
|
|
|
|
+ const handleLogout = () => {
|
|
|
|
|
+ Taro.showModal({
|
|
|
|
|
+ title: '提示',
|
|
|
|
|
+ content: '确定要退出登录吗?',
|
|
|
|
|
+ success: (res) => {
|
|
|
|
|
+ if (res.confirm) {
|
|
|
|
|
+ // 确认退出
|
|
|
|
|
+ performLogout()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 执行退出登录
|
|
|
|
|
+ const performLogout = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 调用退出登录API
|
|
|
|
|
+ const res = await talentSettingsClient.logout.$post()
|
|
|
|
|
+ if (!res.ok) {
|
|
|
|
|
+ throw new Error('退出登录失败')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 清除本地存储
|
|
|
|
|
+ Taro.removeStorageSync('token')
|
|
|
|
|
+ Taro.removeStorageSync('user')
|
|
|
|
|
+
|
|
|
|
|
+ // 跳转到登录页
|
|
|
|
|
+ Taro.reLaunch({ url: '/pages/login/index' })
|
|
|
|
|
+
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '已退出登录',
|
|
|
|
|
+ icon: 'success'
|
|
|
|
|
+ })
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('退出登录失败:', error)
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '退出登录失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 加载状态
|
|
|
|
|
+ if (isLoading) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <RencaiTabBarLayout activeKey="settings">
|
|
|
|
|
+ <ScrollView className="h-[calc(100%-60px)] overflow-y-auto bg-gray-100" scrollY>
|
|
|
|
|
+ <Navbar
|
|
|
|
|
+ title="更多"
|
|
|
|
|
+ leftIcon=""
|
|
|
|
|
+ leftText=""
|
|
|
|
|
+ onClickLeft={() => {}}
|
|
|
|
|
+ backgroundColor="bg-white"
|
|
|
|
|
+ border={true}
|
|
|
|
|
+ fixed={true}
|
|
|
|
|
+ placeholder={true}
|
|
|
|
|
+ />
|
|
|
|
|
+ <View className="flex items-center justify-center h-full">
|
|
|
|
|
+ <View className="text-gray-600">加载中...</View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </ScrollView>
|
|
|
|
|
+ </RencaiTabBarLayout>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 错误状态
|
|
|
|
|
+ if (error) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <RencaiTabBarLayout activeKey="settings">
|
|
|
|
|
+ <ScrollView className="h-[calc(100%-60px)] overflow-y-auto bg-gray-100" scrollY>
|
|
|
|
|
+ <Navbar
|
|
|
|
|
+ title="更多"
|
|
|
|
|
+ leftIcon=""
|
|
|
|
|
+ leftText=""
|
|
|
|
|
+ onClickLeft={() => {}}
|
|
|
|
|
+ backgroundColor="bg-white"
|
|
|
|
|
+ border={true}
|
|
|
|
|
+ fixed={true}
|
|
|
|
|
+ placeholder={true}
|
|
|
|
|
+ />
|
|
|
|
|
+ <View className="flex items-center justify-center h-full">
|
|
|
|
|
+ <View className="text-gray-600">加载失败,请稍后重试</View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </ScrollView>
|
|
|
|
|
+ </RencaiTabBarLayout>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 使用模拟数据(当API返回空数据时)
|
|
|
|
|
+ const mockProfile: {
|
|
|
|
|
+ id: number
|
|
|
|
|
+ name: string
|
|
|
|
|
+ disabilityType: string
|
|
|
|
|
+ disabilityLevel: string
|
|
|
|
|
+ stats: {
|
|
|
|
|
+ thisMonthAttendance: number
|
|
|
|
|
+ totalAttendance: number
|
|
|
|
|
+ thisMonthSalary: number
|
|
|
|
|
+ }
|
|
|
|
|
+ } = {
|
|
|
|
|
+ id: 1,
|
|
|
|
|
+ name: '张明',
|
|
|
|
|
+ disabilityType: '肢体残疾',
|
|
|
|
|
+ disabilityLevel: '三级',
|
|
|
|
|
+ stats: {
|
|
|
|
|
+ thisMonthAttendance: 28,
|
|
|
|
|
+ totalAttendance: 156,
|
|
|
|
|
+ thisMonthSalary: 4800
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const displayProfile = profile ? {
|
|
|
|
|
+ id: profile.id,
|
|
|
|
|
+ name: profile.name || profile.nickname || '用户',
|
|
|
|
|
+ disabilityType: profile.personInfo?.disabilityType || '未知',
|
|
|
|
|
+ disabilityLevel: profile.personInfo?.disabilityLevel || '未知',
|
|
|
|
|
+ stats: {
|
|
|
|
|
+ thisMonthAttendance: 0,
|
|
|
|
|
+ totalAttendance: 0,
|
|
|
|
|
+ thisMonthSalary: 0
|
|
|
|
|
+ }
|
|
|
|
|
+ } : mockProfile
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<RencaiTabBarLayout activeKey="settings">
|
|
<RencaiTabBarLayout activeKey="settings">
|
|
|
<ScrollView className="h-[calc(100%-60px)] overflow-y-auto bg-gray-100" scrollY>
|
|
<ScrollView className="h-[calc(100%-60px)] overflow-y-auto bg-gray-100" scrollY>
|
|
@@ -27,9 +257,21 @@ const SettingsPage: React.FC = () => {
|
|
|
placeholder={true}
|
|
placeholder={true}
|
|
|
/>
|
|
/>
|
|
|
|
|
|
|
|
- {/* 页面内容 - 待实现完整功能 */}
|
|
|
|
|
- <View className="h-full flex items-center justify-center bg-gray-100">
|
|
|
|
|
- <Text className="text-gray-600">设置页面占位</Text>
|
|
|
|
|
|
|
+ {/* 个人信息摘要 */}
|
|
|
|
|
+ <View className="mt-2">
|
|
|
|
|
+ <UserProfileSummary profile={displayProfile} />
|
|
|
|
|
+ </View>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 功能入口列表 */}
|
|
|
|
|
+ <View className="px-2 mt-4">
|
|
|
|
|
+ {menuSections.map((section, index) => (
|
|
|
|
|
+ <MenuSection key={index} section={section} />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </View>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 退出登录按钮 */}
|
|
|
|
|
+ <View className="px-2">
|
|
|
|
|
+ <LogoutButton onPress={handleLogout} />
|
|
|
</View>
|
|
</View>
|
|
|
</ScrollView>
|
|
</ScrollView>
|
|
|
</RencaiTabBarLayout>
|
|
</RencaiTabBarLayout>
|