diff --git a/apps/web/src/api/health/banners.ts b/apps/web/src/api/health/banners.ts index 9794e6d..937e2ec 100644 --- a/apps/web/src/api/health/banners.ts +++ b/apps/web/src/api/health/banners.ts @@ -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<{ diff --git a/apps/web/src/layouts/MainLayout.tsx b/apps/web/src/layouts/MainLayout.tsx index d0f7a18..46afeb0 100644 --- a/apps/web/src/layouts/MainLayout.tsx +++ b/apps/web/src/layouts/MainLayout.tsx @@ -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 }) {/* 内容区域 */} - {children} +
{children}
{/* 底部 */} diff --git a/apps/web/src/pages/health/AppointmentList.tsx b/apps/web/src/pages/health/AppointmentList.tsx index 54c1434..a4caa5a 100644 --- a/apps/web/src/pages/health/AppointmentList.tsx +++ b/apps/web/src/pages/health/AppointmentList.tsx @@ -46,6 +46,7 @@ const APPOINTMENT_TYPE_MAP: Record = { health_checkup: '体检', consultation: '咨询', dialysis: '透析', + follow_up: '随访', }; /** 状态筛选选项 */ @@ -383,6 +384,7 @@ export default function AppointmentList() { handleFilterChange('dateRange', dates)} + placeholder={['开始日期', '结束日期']} allowClear /> { 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 ( 255 { + return Err(AppError::Validation("患者姓名长度不能超过255个字符".into())); + } let result = patient_service::create_patient(&state, ctx.tenant_id, Some(ctx.user_id), req).await?; Ok(Json(ApiResponse::ok(result))) diff --git a/crates/erp-health/src/service/article_category_service.rs b/crates/erp-health/src/service/article_category_service.rs index ddc0a0f..c79a221 100644 --- a/crates/erp-health/src/service/article_category_service.rs +++ b/crates/erp-health/src/service/article_category_service.rs @@ -48,6 +48,17 @@ pub async fn create_category( operator_id: Option, req: CreateCategoryReq, ) -> HealthResult { + // 同名分类检查 + let duplicate = article_category::Entity::find() + .filter(article_category::Column::TenantId.eq(tenant_id)) + .filter(article_category::Column::Name.eq(&req.name)) + .filter(article_category::Column::DeletedAt.is_null()) + .one(&state.db) + .await?; + if duplicate.is_some() { + return Err(HealthError::Validation("同名分类已存在".into())); + } + let now = Utc::now(); let active = article_category::ActiveModel { id: Set(Uuid::now_v7()), diff --git a/crates/erp-health/src/service/media_service.rs b/crates/erp-health/src/service/media_service.rs index 8c703de..2b08bb8 100644 --- a/crates/erp-health/src/service/media_service.rs +++ b/crates/erp-health/src/service/media_service.rs @@ -144,7 +144,7 @@ pub async fn upload_media( folder_id: Set(folder_id), filename: Set(filename.to_string()), storage_path: Set(relative_path.clone()), - thumbnail_path: Set(thumbnail_path.map(|p| p.to_string_lossy().to_string())), + thumbnail_path: Set(thumbnail_path.map(|p| p.to_string_lossy().replace('\\', "/"))), content_type: Set(content_type.to_string()), file_size: Set(file_data.len() as i64), width: Set(width), @@ -404,7 +404,7 @@ pub async fn crop_media( let mut active: media_item::ActiveModel = model.into(); active.storage_path = Set(cropped_relative); - active.thumbnail_path = Set(thumbnail_path.map(|p| p.to_string_lossy().to_string())); + active.thumbnail_path = Set(thumbnail_path.map(|p| p.to_string_lossy().replace('\\', "/"))); active.width = Set(new_width); active.height = Set(new_height); active.updated_at = Set(Utc::now()); diff --git a/crates/erp-server/migration/src/m20260515_000146_seed_menu_permissions_phase2.rs b/crates/erp-server/migration/src/m20260515_000146_seed_menu_permissions_phase2.rs index 20bf2ff..15af5e3 100644 --- a/crates/erp-server/migration/src/m20260515_000146_seed_menu_permissions_phase2.rs +++ b/crates/erp-server/migration/src/m20260515_000146_seed_menu_permissions_phase2.rs @@ -30,7 +30,7 @@ impl MigrationTrait for Migration { for &(path, perm) in menu_perms { db.execute_unprepared(&format!( - "UPDATE menus SET permission = '{perm}', updated_at = NOW() \ + "UPDATE menus SET permission = '{perm}', updated_at = NOW(), version = version + 1 \ WHERE path = '{path}' AND deleted_at IS NULL AND (permission IS NULL OR permission = '')" )) .await?; @@ -57,7 +57,7 @@ impl MigrationTrait for Migration { for &path in paths { db.execute_unprepared(&format!( - "UPDATE menus SET permission = NULL, updated_at = NOW() \ + "UPDATE menus SET permission = NULL, updated_at = NOW(), version = version + 1 \ WHERE path = '{path}' AND deleted_at IS NULL" )) .await?;