fix: E2E 测试发现的 10 项 BUG 修复 — 全栈验证通过
P0 修复:
- 侧边栏路由不稳定: Content 区域添加 key={currentPath} 强制重渲染
- 轮播图缩略图不显示: BannerManage 导入 resolveMediaUrl + 反斜杠转正斜杠
- 超长名称导致 500: patient_handler 添加 name.len() > 255 校验
- 迁移 m20260515_000146: version 乐观锁 version+1 修复
P1 修复:
- 排班路由被冻结: routeConfig.ts 移除 /health/schedules 的 frozen 标记
- 轮播图 Switch 切换无效: 切换前先 GET 最新 version 避免乐观锁冲突
- thumbnail_url 反斜杠: media_service 存储时统一 replace('\', '/')
P2 修复:
- 预约类型 follow_up 未映射: APPOINTMENT_TYPE_MAP 补充 '随访'
- 日期选择器未汉化: DatePicker.RangePicker 添加中文 placeholder
- 轮播图 title 必填校验: banner_handler 添加空标题拒绝
- 文章分类重名: article_category_service 添加同名检查
This commit is contained in:
@@ -69,6 +69,15 @@ export const bannerApi = {
|
||||
return data.data;
|
||||
},
|
||||
|
||||
/** 获取单个轮播图 */
|
||||
get: async (id: string) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: BannerItem;
|
||||
}>(`/health/banners/${id}`);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
/** 创建轮播图 */
|
||||
create: async (req: CreateBannerReq) => {
|
||||
const { data } = await client.post<{
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SearchOutlined,
|
||||
AppstoreOutlined,
|
||||
RightOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useAppStore } from '../stores/app';
|
||||
@@ -493,7 +494,7 @@ export default function MainLayout({ children }: { children: React.ReactNode })
|
||||
|
||||
{/* 内容区域 */}
|
||||
<Content style={{ padding: 20, minHeight: 'calc(100vh - 56px - 48px)' }}>
|
||||
{children}
|
||||
<div key={currentPath}>{children}</div>
|
||||
</Content>
|
||||
|
||||
{/* 底部 */}
|
||||
|
||||
@@ -46,6 +46,7 @@ const APPOINTMENT_TYPE_MAP: Record<string, string> = {
|
||||
health_checkup: '体检',
|
||||
consultation: '咨询',
|
||||
dialysis: '透析',
|
||||
follow_up: '随访',
|
||||
};
|
||||
|
||||
/** 状态筛选选项 */
|
||||
@@ -383,6 +384,7 @@ export default function AppointmentList() {
|
||||
<DatePicker.RangePicker
|
||||
value={filters.dateRange as [Dayjs, Dayjs] | null}
|
||||
onChange={(dates) => handleFilterChange('dateRange', dates)}
|
||||
placeholder={['开始日期', '结束日期']}
|
||||
allowClear
|
||||
/>
|
||||
<Input
|
||||
|
||||
@@ -30,6 +30,7 @@ import { mediaApi, type MediaItem } from '../../api/health/media';
|
||||
import { AuthButton } from '../../components/AuthButton';
|
||||
import { PageContainer } from '../../components/PageContainer';
|
||||
import { formatDateTime } from '../../utils/format';
|
||||
import { resolveMediaUrl } from '../../utils/media';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
|
||||
// --- 常量 ---
|
||||
@@ -208,9 +209,10 @@ export default function BannerManage() {
|
||||
const handleToggleStatus = useCallback(async (record: BannerItem) => {
|
||||
try {
|
||||
const newStatus = record.status === 'active' ? 'inactive' : 'active';
|
||||
const latest = await bannerApi.get(record.id);
|
||||
await bannerApi.update(record.id, {
|
||||
status: newStatus,
|
||||
version: record.version,
|
||||
version: latest.version,
|
||||
});
|
||||
message.success(newStatus === 'active' ? '已启用' : '已停用');
|
||||
fetchData();
|
||||
@@ -259,7 +261,7 @@ export default function BannerManage() {
|
||||
if (!src) return '-';
|
||||
return (
|
||||
<Image
|
||||
src={src}
|
||||
src={resolveMediaUrl(src.replace(/\\/g, '/'))}
|
||||
width={60}
|
||||
height={40}
|
||||
style={{ borderRadius: 4, objectFit: 'cover' }}
|
||||
|
||||
@@ -235,7 +235,6 @@ const ENTRIES: RoutePermissionEntry[] = [
|
||||
{
|
||||
path: "/health/schedules",
|
||||
permissions: ["health.appointment.list", "health.appointment.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user