diff --git a/apps/miniprogram/src/pages/doctor/alerts/index.tsx b/apps/miniprogram/src/pages/doctor/alerts/index.tsx index 947b420..91f280c 100644 --- a/apps/miniprogram/src/pages/doctor/alerts/index.tsx +++ b/apps/miniprogram/src/pages/doctor/alerts/index.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; import { View, Text, ScrollView } from '@tarojs/components'; import Taro from '@tarojs/taro'; import * as doctorApi from '@/services/doctor'; @@ -34,6 +34,8 @@ export default function AlertList() { const [total, setTotal] = useState(0); const [page, setPage] = useState(1); + const totalPages = useMemo(() => totalPages, [total]); + useEffect(() => { loadAlerts(); }, [page, activeTab]); @@ -137,11 +139,11 @@ export default function AlertList() { 上一页 - {page} / {Math.ceil(total / 20)} + {page} / {totalPages} = Math.ceil(total / 20) ? 'disabled' : ''}`} - onClick={() => page < Math.ceil(total / 20) && setPage(page + 1)} + className={`alert-pagination__btn ${page >= totalPages ? 'disabled' : ''}`} + onClick={() => page < totalPages && setPage(page + 1)} > 下一页 diff --git a/apps/miniprogram/src/pages/doctor/consultation/index.tsx b/apps/miniprogram/src/pages/doctor/consultation/index.tsx index e43b90d..98dc22b 100644 --- a/apps/miniprogram/src/pages/doctor/consultation/index.tsx +++ b/apps/miniprogram/src/pages/doctor/consultation/index.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; import { View, Text, ScrollView } from '@tarojs/components'; import Taro from '@tarojs/taro'; import * as doctorApi from '@/services/doctor'; @@ -22,6 +22,8 @@ export default function ConsultationList() { const [total, setTotal] = useState(0); const [page, setPage] = useState(1); + const totalPages = useMemo(() => totalPages, [total]); + useEffect(() => { loadSessions(); }, [page, activeTab]); @@ -112,10 +114,10 @@ export default function ConsultationList() { className={`pagination__btn ${page <= 1 ? 'disabled' : ''}`} onClick={() => page > 1 && setPage(page - 1)} >上一页 - {page} / {Math.ceil(total / 20)} + {page} / {totalPages} = Math.ceil(total / 20) ? 'disabled' : ''}`} - onClick={() => page < Math.ceil(total / 20) && setPage(page + 1)} + className={`pagination__btn ${page >= totalPages ? 'disabled' : ''}`} + onClick={() => page < totalPages && setPage(page + 1)} >下一页 )} diff --git a/apps/miniprogram/src/pages/doctor/index.tsx b/apps/miniprogram/src/pages/doctor/index.tsx index 5911e72..6420dea 100644 --- a/apps/miniprogram/src/pages/doctor/index.tsx +++ b/apps/miniprogram/src/pages/doctor/index.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; import { View, Text, Input, ScrollView } from '@tarojs/components'; import Taro from '@tarojs/taro'; import { useAuthStore } from '@/stores/auth'; @@ -11,33 +11,66 @@ interface CardConfig { label: string; initial: string; route: string; + roles?: string[]; } -const CARDS: CardConfig[] = [ +const ALL_CARDS: CardConfig[] = [ { key: 'total_patients', label: '我的患者', initial: '患', route: '/pages/doctor/patients/index' }, { key: 'unread_messages', label: '未读消息', initial: '消', route: '/pages/doctor/consultation/index' }, - { key: 'pending_follow_ups', label: '待处理随访', initial: '随', route: '/pages/doctor/followup/index' }, - { key: 'today_consultations', label: '今日咨询', initial: '诊', route: '/pages/doctor/consultation/index' }, + { key: 'pending_follow_ups', label: '待处理随访', initial: '随', route: '/pages/doctor/followup/index', roles: ['doctor', 'nurse', 'health_manager'] }, + { key: 'today_consultations', label: '今日咨询', initial: '诊', route: '/pages/doctor/consultation/index', roles: ['doctor', 'health_manager'] }, ]; -const HEALTH_CARDS: CardConfig[] = [ - { key: 'pending_lab_review', label: '待审化验', initial: '化', route: '/pages/doctor/report/index' }, +const ALL_HEALTH_CARDS: CardConfig[] = [ + { key: 'pending_lab_review', label: '待审化验', initial: '化', route: '/pages/doctor/report/index', roles: ['doctor'] }, { key: 'today_appointments', label: '今日预约', initial: '约', route: '/pages/doctor/patients/index' }, ]; -const QUICK_ACTIONS = [ - { label: '化验审核', initial: '审', route: '/pages/doctor/report/index' }, - { label: '患者查询', initial: '查', route: '/pages/doctor/patients/index' }, - { label: '随访记录', initial: '随', route: '/pages/doctor/followup/index' }, - { label: '告警中心', initial: '警', route: '/pages/doctor/alerts/index' }, +interface QuickAction { + label: string; + initial: string; + route: string; + roles: string[]; +} + +const ALL_QUICK_ACTIONS: QuickAction[] = [ + { label: '化验审核', initial: '审', route: '/pages/doctor/report/index', roles: ['doctor'] }, + { label: '患者查询', initial: '查', route: '/pages/doctor/patients/index', roles: ['doctor', 'nurse', 'health_manager'] }, + { label: '随访记录', initial: '随', route: '/pages/doctor/followup/index', roles: ['doctor', 'nurse', 'health_manager'] }, + { label: '告警中心', initial: '警', route: '/pages/doctor/alerts/index', roles: ['doctor', 'nurse', 'health_manager'] }, + { label: '透析管理', initial: '透', route: '/pages/doctor/dialysis/index', roles: ['doctor'] }, + { label: '处方管理', initial: '方', route: '/pages/doctor/prescription/index', roles: ['doctor'] }, + { label: '行动收件箱', initial: '行', route: '/pages/doctor/action-inbox/index', roles: ['doctor', 'nurse', 'health_manager'] }, ]; +const ROLE_LABELS: Record = { + doctor: '医生', + nurse: '护士', + health_manager: '健康管理师', + admin: '管理员', + operator: '运营', +}; + export default function DoctorHome() { - const { user, logout } = useAuthStore(); + const { user, logout, roles } = useAuthStore(); const [dashboard, setDashboard] = useState(null); const [alertCount, setAlertCount] = useState(0); const [loading, setLoading] = useState(true); + const hasRole = (allowed: string[] | undefined) => { + if (!allowed) return true; + return roles.some((r) => r === 'admin' || allowed.includes(r)); + }; + + const cards = useMemo(() => ALL_CARDS.filter((c) => hasRole(c.roles)), [roles]); + const healthCards = useMemo(() => ALL_HEALTH_CARDS.filter((c) => hasRole(c.roles)), [roles]); + const quickActions = useMemo(() => ALL_QUICK_ACTIONS.filter((a) => hasRole(a.roles)), [roles]); + + const roleLabel = useMemo(() => { + const primary = roles.find((r) => r !== 'admin'); + return primary ? (ROLE_LABELS[primary] || primary) : '医护'; + }, [roles]); + useEffect(() => { loadDashboard(); }, []); @@ -76,7 +109,7 @@ export default function DoctorHome() { 医护工作台 - {user?.display_name || user?.username || '医生'},您好 + {user?.display_name || user?.username || roleLabel},您好 {new Date().toLocaleDateString('zh-CN', { month: 'long', day: 'numeric', weekday: 'long' })} @@ -102,7 +135,7 @@ export default function DoctorHome() { 工作概览 - {CARDS.map((card) => ( + {cards.map((card) => ( - + {healthCards.length > 0 && ( 健康审核 - {HEALTH_CARDS.map((card) => ( + {healthCards.map((card) => ( ))} - + )} 快捷操作 - {QUICK_ACTIONS.map((action) => ( + {quickActions.map((action) => ( Math.ceil(total / 20), [total]); + if (loading && patients.length === 0) return ; return ( @@ -162,10 +164,10 @@ export default function PatientList() { > 上一页 - {page} / {Math.ceil(total / 20)} + {page} / {totalPages} = Math.ceil(total / 20) ? 'disabled' : ''}`} - onClick={() => page < Math.ceil(total / 20) && setPage(page + 1)} + className={`pagination__btn ${page >= totalPages ? 'disabled' : ''}`} + onClick={() => page < totalPages && setPage(page + 1)} > 下一页 diff --git a/apps/miniprogram/src/stores/auth.ts b/apps/miniprogram/src/stores/auth.ts index aa3a8cf..2d1dbe0 100644 --- a/apps/miniprogram/src/stores/auth.ts +++ b/apps/miniprogram/src/stores/auth.ts @@ -24,6 +24,10 @@ interface AuthState { logout: () => void; restore: () => void; isMedicalStaff: () => boolean; + isDoctor: () => boolean; + isNurse: () => boolean; + isHealthManager: () => boolean; + hasRole: (code: string) => boolean; hasPatientProfile: () => boolean; } @@ -36,7 +40,27 @@ export const useAuthStore = create((set, get) => ({ isMedicalStaff: () => { const { roles } = get(); - return roles.some((r) => r === 'doctor' || r === 'nurse' || r === 'admin'); + return roles.some((r) => r === 'doctor' || r === 'nurse' || r === 'admin' || r === 'health_manager'); + }, + + isDoctor: () => { + const { roles } = get(); + return roles.some((r) => r === 'doctor' || r === 'admin'); + }, + + isNurse: () => { + const { roles } = get(); + return roles.some((r) => r === 'nurse' || r === 'admin'); + }, + + isHealthManager: () => { + const { roles } = get(); + return roles.some((r) => r === 'health_manager' || r === 'admin'); + }, + + hasRole: (code: string) => { + const { roles } = get(); + return roles.some((r) => r === code || r === 'admin'); }, hasPatientProfile: () => {