fix(mp): T40 UI 审计修复 — 28 项设计系统合规 + 安全加固 + 讨论记录

T40 UI 审计修复(60 页面全覆盖):
- 新增 $acc-d/$wrn-d 渐变中间色变量,修复首页轮播渐变硬编码
- 替换 8 处裸 white 为 $white 设计变量(5 个 SCSS 文件)
- 修复 7 处触摸目标 40/44px → 48px(健康/消息/咨询/预约/首页)
- 3 页面新增 Loading 状态(体征录入/个人中心/就诊人添加)
- statusTag 移除硬编码布局值,改用 SCSS mixin 控制
- 医生端 14 页面架构 Hook 层补充(useThrottledDidShow 替换 useEffect)
- 移除 action-inbox 未使用 import

安全 P0 修复:
- JWT 中间件加固:token 类型校验 + 过期预检 + 类型别名简化
- 速率限制增强:滑动窗口 + 暴力破解防护
- analytics handler 错误处理完善

文档:
- T40 审计报告(24 PASS / 36 PASS_WITH_ISSUES / 0 NEEDS_WORK)
- 5 份 DevTools/性能审计讨论记录
- wiki 症状导航 + 小程序章节更新
This commit is contained in:
iven
2026-05-14 23:12:54 +08:00
parent 447126b6c5
commit 8f353946e1
90 changed files with 2089 additions and 830 deletions

View File

@@ -1,6 +1,7 @@
import React, { useState, useCallback, useRef } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow, useReachBottom, usePullDownRefresh } from '@tarojs/taro';
import Taro, { useReachBottom, usePullDownRefresh } from '@tarojs/taro';
import { useThrottledDidShow } from '@/hooks/useThrottledDidShow';
import { listMyTransactions } from '../../../services/points';
import type { PointsTransaction } from '../../../services/points';
import { usePointsStore } from '../../../stores/points';
@@ -17,7 +18,8 @@ const TYPE_TABS = [
export default function PointsDetail() {
const modeClass = useElderClass();
const { account, refresh: refreshPoints } = usePointsStore();
const account = usePointsStore((s) => s.account);
const refreshPoints = usePointsStore((s) => s.refresh);
const [transactions, setTransactions] = useState<PointsTransaction[]>([]);
const [activeTab, setActiveTab] = useState('');
const [page, setPage] = useState(1);
@@ -64,10 +66,10 @@ export default function PointsDetail() {
[refreshPoints, fetchTransactions, activeTab],
);
useDidShow(() => {
useThrottledDidShow(() => {
Taro.setNavigationBarTitle({ title: '积分明细' });
loadAll();
});
}, 10000);
usePullDownRefresh(() => {
loadAll().finally(() => {

View File

@@ -196,6 +196,6 @@
.confirm-btn-text {
font-size: var(--tk-font-num);
color: white;
color: $white;
font-weight: bold;
}

View File

@@ -1,6 +1,7 @@
import React, { useState, useCallback } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import Taro from '@tarojs/taro';
import { useThrottledDidShow } from '@/hooks/useThrottledDidShow';
import {
listProducts,
exchangeProduct,
@@ -32,14 +33,15 @@ const TYPE_CLASS: Record<string, string> = {
export default function ExchangeConfirm() {
const modeClass = useElderClass();
const [product, setProduct] = useState<PointsProduct | null>(null);
const { account, refresh: refreshPoints } = usePointsStore();
const account = usePointsStore((s) => s.account);
const refreshPoints = usePointsStore((s) => s.refresh);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
useDidShow(() => {
useThrottledDidShow(() => {
Taro.setNavigationBarTitle({ title: '确认兑换' });
loadData();
});
}, 10000);
const loadData = useCallback(async () => {
const instance = Taro.getCurrentInstance();
@@ -101,7 +103,7 @@ export default function ExchangeConfirm() {
showCancel: false,
confirmText: '查看订单',
success: () => {
Taro.navigateTo({
Taro.redirectTo({
url: `/pages/pkg-mall/orders/index`,
});
},

View File

@@ -1,6 +1,7 @@
import React, { useState, useCallback, useRef } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow, useReachBottom, usePullDownRefresh } from '@tarojs/taro';
import Taro, { useReachBottom, usePullDownRefresh } from '@tarojs/taro';
import { useThrottledDidShow } from '@/hooks/useThrottledDidShow';
import { listMyOrders } from '../../../services/points';
import type { PointsOrder } from '../../../services/points';
import EmptyState from '../../../components/EmptyState';
@@ -70,10 +71,10 @@ export default function MallOrders() {
[fetchOrders, activeTab],
);
useDidShow(() => {
useThrottledDidShow(() => {
Taro.setNavigationBarTitle({ title: '我的订单' });
loadAll();
});
}, 10000);
usePullDownRefresh(() => {
loadAll().finally(() => {
@@ -133,7 +134,7 @@ export default function MallOrders() {
text='暂无订单'
hint='去商城兑换心仪商品吧'
actionText='去商城'
onAction={() => Taro.redirectTo({ url: '/pages/mall/index' })}
onAction={() => Taro.switchTab({ url: '/pages/mall/index' })}
/>
) : (
<View className='order-list'>