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?;