fix(miniprogram): 修复多角色找茬测试 V3 发现的 8 个问题
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

1. EmptyState 默认 emoji 📭 → serif 首字圆形图标(影响 23 处使用)
2. 预约页英文副标题 "Appointment" 移除
3. consultation 页技术错误信息直接渲染到 UI → 用户友好提示
4. auth store restore() 增加 fallback:secureGet 失败时读 wx.getStorageSync
5. request.ts 新增 safeGet():token/tenantId 读取容错
6. doctor/consultation useMemo 自引用死循环 → Math.ceil(total/20)
7. doctor/alerts 同样自引用 bug 修复
8. doctor/patients 死代码 totalPages + useMemo import 清理
This commit is contained in:
iven
2026-05-08 17:34:42 +08:00
parent 3dac6a9eda
commit 81c174a902
9 changed files with 36 additions and 16 deletions

View File

@@ -8,11 +8,24 @@
padding: 120px 40px;
}
.empty-state-icon {
font-size: 80px;
.empty-state-icon-wrap {
width: 120px;
height: 120px;
border-radius: 50%;
background: $surface-alt;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24px;
}
.empty-state-icon-char {
font-family: Georgia, 'Times New Roman', serif;
font-size: 48px;
font-weight: 600;
color: $tx3;
}
.empty-state-text {
font-size: 30px;
color: $tx2;

View File

@@ -11,15 +11,18 @@ interface EmptyStateProps {
}
export default React.memo(function EmptyState({
icon = '📭',
icon,
text,
hint,
actionText,
onAction,
}: EmptyStateProps) {
const displayChar = icon || text.charAt(0);
return (
<View className='empty-state'>
<Text className='empty-state-icon'>{icon}</Text>
<View className='empty-state-icon-wrap'>
<Text className='empty-state-icon-char'>{displayChar}</Text>
</View>
<Text className='empty-state-text'>{text}</Text>
{hint && <Text className='empty-state-hint'>{hint}</Text>}
{actionText && onAction && (

View File

@@ -90,7 +90,6 @@ export default function AppointmentList() {
{/* 页面标题 */}
<View className='page-header'>
<Text className='page-title'></Text>
<Text className='page-subtitle'>Appointment</Text>
</View>
{/* 预约列表 */}

View File

@@ -52,9 +52,8 @@ export default function Consultation() {
}
setTotal(resp.total || 0);
setPage(pageNum);
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : '加载失败';
setError(msg);
} catch {
setError('加载失败,请稍后重试');
} finally {
setLoading(false);
loadingRef.current = false;

View File

@@ -34,7 +34,7 @@ export default function AlertList() {
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const totalPages = useMemo(() => totalPages, [total]);
const totalPages = useMemo(() => Math.ceil(total / 20), [total]);
useEffect(() => {
loadAlerts();

View File

@@ -22,7 +22,7 @@ export default function ConsultationList() {
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const totalPages = useMemo(() => totalPages, [total]);
const totalPages = useMemo(() => Math.ceil(total / 20), [total]);
useEffect(() => {
loadSessions();

View File

@@ -95,8 +95,6 @@ export default function PatientList() {
return `${age}`;
};
const totalPages = useMemo(() => Math.ceil(total / 20), [total]);
if (loading && patients.length === 0) return <Loading />;
return (

View File

@@ -9,13 +9,21 @@ interface ApiResponse<T> {
message?: string;
}
function safeGet(key: string): string {
try {
return secureGet(key);
} catch {
return Taro.getStorageSync(key) || '';
}
}
async function getHeaders(): Promise<Record<string, string>> {
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
const token = secureGet('access_token');
const token = safeGet('access_token');
if (token) headers['Authorization'] = `Bearer ${token}`;
const patientId = Taro.getStorageSync('current_patient_id');
if (patientId) headers['X-Patient-Id'] = patientId;
const tenantId = secureGet('tenant_id');
const tenantId = safeGet('tenant_id');
if (tenantId) headers['X-Tenant-Id'] = tenantId;
return headers;
}

View File

@@ -71,9 +71,9 @@ export const useAuthStore = create<AuthState>((set, get) => ({
let user: AuthState['user'] = null;
let roles: string[] = [];
try {
const userData = secureGet('user_data');
const userData = secureGet('user_data') || Taro.getStorageSync('user_data');
if (userData) user = JSON.parse(userData);
const rolesData = secureGet('user_roles');
const rolesData = secureGet('user_roles') || Taro.getStorageSync('user_roles');
if (rolesData) roles = JSON.parse(rolesData);
} catch { /* secure storage 不可用时保持默认值 */ }
const currentPatient = Taro.getStorageSync('current_patient') || null;