refactor(web): 统一健康模块静态映射常量到 constants/health.ts

- 收敛 SEVERITY_COLOR/LABEL (5处→1处)
- 收敛 ALERT_STATUS_COLOR/LABEL (3处→1处)
- 收敛 DEVICE_TYPE_OPTIONS/COLOR (3处→1处)
- 收敛 GENDER_LABEL (4处→1处)
- StatusTag 组件改引用 STATUS_TAG_CONFIG
- DoctorDashboard 严重度映射改引用常量
This commit is contained in:
iven
2026-05-02 11:24:34 +08:00
parent 3bc4597041
commit b6e780e649
10 changed files with 133 additions and 201 deletions

View File

@@ -1,16 +1,24 @@
/**
* 健康管理模块共享常量
*
* 集中定义性别、血型、患者状态等下拉选项
* 供 PatientList / PatientDetail 等页面复用
* 集中定义性别、血型、患者状态、严重度、告警状态、设备类型等映射
* 供各健康模块页面复用。避免在组件中重复定义
*/
// --- 性别 ---
export const GENDER_OPTIONS = [
{ value: 'male', label: '男' },
{ value: 'female', label: '女' },
{ value: 'other', label: '其他' },
];
export const GENDER_LABEL: Record<string, string> = {
male: '男',
female: '女',
other: '其他',
};
// --- 血型 ---
export const BLOOD_TYPE_OPTIONS = [
{ value: 'A', label: 'A 型' },
{ value: 'B', label: 'B 型' },
@@ -18,9 +26,106 @@ export const BLOOD_TYPE_OPTIONS = [
{ value: 'O', label: 'O 型' },
];
// --- 患者状态 ---
export const STATUS_OPTIONS = [
{ value: '', label: '全部状态' },
{ value: 'active', label: '活跃' },
{ value: 'inactive', label: '停用' },
{ value: 'deceased', label: '已故' },
];
// --- 严重度(统一 5 处重复定义: AlertDashboard, AlertList, AlertRuleList, DoctorDashboard ---
export const SEVERITY_COLOR: Record<string, string> = {
info: 'default',
warning: 'orange',
critical: 'red',
urgent: 'magenta',
};
export const SEVERITY_LABEL: Record<string, string> = {
info: '提示',
warning: '警告',
critical: '严重',
urgent: '紧急',
};
export const SEVERITY_OPTIONS = [
{ value: 'info', label: '提示' },
{ value: 'warning', label: '警告' },
{ value: 'critical', label: '严重' },
{ value: 'urgent', label: '紧急' },
];
// --- 告警状态(统一 3 处: AlertDashboard, AlertList ---
export const ALERT_STATUS_COLOR: Record<string, string> = {
pending: 'orange',
acknowledged: 'blue',
resolved: 'green',
dismissed: 'default',
};
export const ALERT_STATUS_LABEL: Record<string, string> = {
pending: '待处理',
acknowledged: '已确认',
resolved: '已恢复',
dismissed: '已忽略',
};
export const ALERT_STATUS_OPTIONS = [
{ value: '', label: '全部状态' },
{ value: 'pending', label: '待处理' },
{ value: 'acknowledged', label: '已确认' },
{ value: 'resolved', label: '已恢复' },
{ value: 'dismissed', label: '已忽略' },
];
// --- 设备类型(统一 3 处: DeviceManage, DeviceReadingsTab, AlertRuleList ---
export const DEVICE_TYPE_OPTIONS = [
{ value: 'blood_pressure', label: '血压' },
{ value: 'blood_glucose', label: '血糖' },
{ value: 'heart_rate', label: '心率' },
{ value: 'blood_oxygen', label: '血氧' },
{ value: 'temperature', label: '体温' },
{ value: 'steps', label: '步数' },
{ value: 'sleep', label: '睡眠' },
{ value: 'stress', label: '压力' },
];
export const DEVICE_TYPE_COLOR: Record<string, string> = {
blood_pressure: 'red',
blood_glucose: 'purple',
heart_rate: 'volcano',
blood_oxygen: 'blue',
temperature: 'orange',
steps: 'green',
sleep: 'cyan',
stress: 'geekblue',
};
// --- 告警规则条件类型 ---
export const CONDITION_TYPE_OPTIONS = [
{ value: 'single_threshold', label: '单次阈值' },
{ value: 'consecutive', label: '连续触发' },
{ value: 'trend', label: '趋势变化' },
];
// --- 通用状态标签StatusTag 组件统一引用) ---
export const STATUS_TAG_CONFIG: Record<string, { color: string; label: string }> = {
// 预约状态
pending: { color: 'gold', label: '待确认' },
confirmed: { color: 'blue', label: '已确认' },
completed: { color: 'green', label: '已完成' },
cancelled: { color: 'default', label: '已取消' },
no_show: { color: 'red', label: '未到诊' },
// 随访状态
overdue: { color: 'red', label: '逾期' },
in_progress: { color: 'processing', label: '进行中' },
// 咨询状态
waiting: { color: 'gold', label: '等待中' },
active: { color: 'green', label: '进行中' },
closed: { color: 'default', label: '已关闭' },
// 患者状态
inactive: { color: 'default', label: '停用' },
deceased: { color: 'default', label: '已故' },
verified: { color: 'green', label: '已认证' },
};

View File

@@ -21,47 +21,12 @@ import {
WifiOutlined,
} from '@ant-design/icons';
import { alertApi, type Alert } from '../../api/health/alerts';
import { SEVERITY_COLOR, SEVERITY_LABEL, ALERT_STATUS_COLOR, ALERT_STATUS_LABEL, ALERT_STATUS_OPTIONS } from '../../constants/health';
import { useAlertSSE, type AlertSSEEvent } from '../../hooks/useAlertSSE';
import { AlertDetailPanel } from './components/AlertDetailPanel';
import { PageContainer } from '../../components/PageContainer';
import { EntityName } from '../../components/EntityName';
const SEVERITY_COLOR: Record<string, string> = {
info: 'default',
warning: 'orange',
critical: 'red',
urgent: 'magenta',
};
const SEVERITY_LABEL: Record<string, string> = {
info: '提示',
warning: '警告',
critical: '严重',
urgent: '紧急',
};
const STATUS_COLOR: Record<string, string> = {
pending: 'orange',
acknowledged: 'blue',
resolved: 'green',
dismissed: 'default',
};
const STATUS_LABEL: Record<string, string> = {
pending: '待处理',
acknowledged: '已确认',
resolved: '已恢复',
dismissed: '已忽略',
};
const STATUS_OPTIONS = [
{ value: '', label: '全部状态' },
{ value: 'pending', label: '待处理' },
{ value: 'acknowledged', label: '已确认' },
{ value: 'resolved', label: '已恢复' },
{ value: 'dismissed', label: '已忽略' },
];
/**
* 实时告警仪表盘 — 医生端。
*
@@ -183,7 +148,7 @@ export default function AlertDashboard() {
<Select
value={statusFilter}
onChange={setStatusFilter}
options={STATUS_OPTIONS}
options={ALERT_STATUS_OPTIONS}
style={{ width: 120 }}
placeholder="按状态筛选"
/>
@@ -264,7 +229,7 @@ export default function AlertDashboard() {
<List.Item.Meta
avatar={
<Tag
color={SEVERITY_COLOR[alert.severity]}
color={SEVERITY_COLOR[alert.severity] || 'default'}
style={{ margin: 0, minWidth: 48, textAlign: 'center' }}
>
{SEVERITY_LABEL[alert.severity] ?? alert.severity}
@@ -273,8 +238,8 @@ export default function AlertDashboard() {
title={
<Flex justify="space-between" align="center">
<span>{alert.title}</span>
<Tag color={STATUS_COLOR[alert.status]} style={{ fontSize: 11 }}>
{STATUS_LABEL[alert.status] ?? alert.status}
<Tag color={ALERT_STATUS_COLOR[alert.status] || 'default'} style={{ fontSize: 11 }}>
{ALERT_STATUS_LABEL[alert.status] ?? alert.status}
</Tag>
</Flex>
}

View File

@@ -17,6 +17,7 @@ import {
alertApi,
type Alert,
} from '../../api/health/alerts';
import { SEVERITY_COLOR, SEVERITY_LABEL, ALERT_STATUS_COLOR, ALERT_STATUS_LABEL, SEVERITY_OPTIONS, ALERT_STATUS_OPTIONS as STATUS_OPTS } from '../../constants/health';
import { AuthButton } from '../../components/AuthButton';
import { PageContainer } from '../../components/PageContainer';
import { EntityName } from '../../components/EntityName';
@@ -25,47 +26,8 @@ import { formatRelative, formatDateTime } from '../../utils/format';
// --- 常量映射 ---
const STATUS_OPTIONS = [
{ value: 'pending', label: '待处理' },
{ value: 'acknowledged', label: '已确认' },
{ value: 'resolved', label: '已恢复' },
{ value: 'dismissed', label: '已忽略' },
];
// 状态选项保留给筛选下拉使用(使用常量)
const SEVERITY_OPTIONS = [
{ value: 'info', label: '提示' },
{ value: 'warning', label: '警告' },
{ value: 'critical', label: '严重' },
{ value: 'urgent', label: '紧急' },
];
const SEVERITY_COLOR: Record<string, string> = {
info: 'default',
warning: 'orange',
critical: 'red',
urgent: 'magenta',
};
const SEVERITY_LABEL: Record<string, string> = {
info: '提示',
warning: '警告',
critical: '严重',
urgent: '紧急',
};
const STATUS_COLOR: Record<string, string> = {
pending: 'orange',
acknowledged: 'blue',
resolved: 'green',
dismissed: 'default',
};
const STATUS_LABEL: Record<string, string> = {
pending: '待处理',
acknowledged: '已确认',
resolved: '已恢复',
dismissed: '已忽略',
};
// --- 筛选器结构 ---
@@ -216,8 +178,8 @@ export default function AlertList() {
key: 'status',
width: 100,
render: (val: string) => (
<Tag color={STATUS_COLOR[val] || 'default'}>
{STATUS_LABEL[val] || val}
<Tag color={ALERT_STATUS_COLOR[val] || 'default'}>
{ALERT_STATUS_LABEL[val] || val}
</Tag>
),
},
@@ -237,7 +199,7 @@ export default function AlertList() {
key: 'actions',
width: 160,
render: (_: unknown, record: Alert) => (
<AuthButton code="health.alert.manage">
<AuthButton code="health.alerts.manage">
<Space size={4}>
{record.status === 'pending' && (
<Popconfirm
@@ -298,7 +260,7 @@ export default function AlertList() {
allowClear
placeholder="状态筛选"
style={{ width: 140 }}
options={STATUS_OPTIONS}
options={STATUS_OPTS}
value={filters.status || undefined}
onChange={(v) => handleFilterChange('status', v ?? '')}
/>

View File

@@ -8,35 +8,7 @@ import {
type CreateAlertRuleReq,
type UpdateAlertRuleReq,
} from '../../api/health/alerts';
const DEVICE_TYPES = [
{ label: '心率', value: 'heart_rate' },
{ label: '血氧', value: 'blood_oxygen' },
{ label: '体温', value: 'temperature' },
{ label: '步数', value: 'steps' },
{ label: '睡眠', value: 'sleep' },
{ label: '压力', value: 'stress' },
];
const CONDITION_TYPES = [
{ label: '单次阈值', value: 'single_threshold' },
{ label: '连续触发', value: 'consecutive' },
{ label: '趋势变化', value: 'trend' },
];
const SEVERITY_OPTIONS = [
{ label: '提示', value: 'info' },
{ label: '警告', value: 'warning' },
{ label: '严重', value: 'critical' },
{ label: '紧急', value: 'urgent' },
];
const SEVERITY_COLOR: Record<string, string> = {
info: 'default',
warning: 'orange',
critical: 'red',
urgent: 'magenta',
};
import { SEVERITY_COLOR, SEVERITY_OPTIONS, DEVICE_TYPE_OPTIONS, CONDITION_TYPE_OPTIONS } from '../../constants/health';
export default function AlertRuleList() {
const [data, setData] = useState<AlertRule[]>([]);
@@ -144,13 +116,13 @@ export default function AlertRuleList() {
title: '指标类型',
dataIndex: 'device_type',
width: 100,
render: (v: string) => DEVICE_TYPES.find((d) => d.value === v)?.label || v,
render: (v: string) => DEVICE_TYPE_OPTIONS.find((d) => d.value === v)?.label || v,
},
{
title: '条件类型',
dataIndex: 'condition_type',
width: 120,
render: (v: string) => CONDITION_TYPES.find((c) => c.value === v)?.label || v,
render: (v: string) => CONDITION_TYPE_OPTIONS.find((c) => c.value === v)?.label || v,
},
{
title: '严重程度',
@@ -219,10 +191,10 @@ export default function AlertRuleList() {
</Form.Item>
<Space style={{ width: '100%' }} size="large">
<Form.Item name="device_type" label="指标类型" rules={[{ required: true }]}>
<Select style={{ width: 160 }} options={DEVICE_TYPES} disabled={!!editingRule} />
<Select style={{ width: 160 }} options={DEVICE_TYPE_OPTIONS} disabled={!!editingRule} />
</Form.Item>
<Form.Item name="condition_type" label="条件类型" rules={[{ required: true }]}>
<Select style={{ width: 160 }} options={CONDITION_TYPES} disabled={!!editingRule} />
<Select style={{ width: 160 }} options={CONDITION_TYPE_OPTIONS} disabled={!!editingRule} />
</Form.Item>
</Space>
<Form.Item

View File

@@ -4,24 +4,7 @@ import type { ColumnsType } from 'antd/es/table';
import dayjs from 'dayjs';
import { deviceApi, type DeviceItem } from '../../api/health/devices';
const DEVICE_TYPE_OPTIONS = [
{ label: '血压', value: 'blood_pressure' },
{ label: '血糖', value: 'blood_glucose' },
{ label: '心率', value: 'heart_rate' },
{ label: '血氧', value: 'blood_oxygen' },
{ label: '步数', value: 'steps' },
{ label: '体温', value: 'temperature' },
];
const DEVICE_TYPE_COLOR: Record<string, string> = {
blood_pressure: 'red',
blood_glucose: 'purple',
heart_rate: 'volcano',
blood_oxygen: 'blue',
steps: 'green',
temperature: 'orange',
};
import { DEVICE_TYPE_OPTIONS, DEVICE_TYPE_COLOR } from '../../constants/health';
function formatTime(val?: string | null): string {
if (!val) return '-';

View File

@@ -32,15 +32,9 @@ import { PointsAccountTab } from './components/PointsAccountTab';
import { AiSuggestionTab } from './components/AiSuggestionTab';
import { FamilyMembersTab } from './components/FamilyMembersTab';
import { DailyMonitoringTab } from './components/DailyMonitoringTab';
import { GENDER_OPTIONS, BLOOD_TYPE_OPTIONS } from '../../constants/health';
import { GENDER_OPTIONS, BLOOD_TYPE_OPTIONS, GENDER_LABEL } from '../../constants/health';
import { useThemeMode } from '../../hooks/useThemeMode';
const GENDER_LABEL: Record<string, string> = {
male: '男',
female: '女',
other: '其他',
};
export default function PatientDetail() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();

View File

@@ -13,6 +13,7 @@ import {
import { TagsOutlined, AppstoreOutlined } from '@ant-design/icons';
import { patientApi, type TagItem } from '../../api/health/patients';
import type { PatientListItem } from '../../api/health/patients';
import { GENDER_LABEL, STATUS_TAG_CONFIG } from '../../constants/health';
import { useThemeMode } from '../../hooks/useThemeMode';
import { AuthButton } from '../../components/AuthButton';
@@ -120,8 +121,7 @@ export default function PatientTagManage() {
width: 80,
render: (v?: string) => {
if (!v) return '-';
const map: Record<string, string> = { male: '男', female: '女', other: '其他' };
return map[v] || v;
return GENDER_LABEL[v] || v;
},
},
{
@@ -161,17 +161,8 @@ export default function PatientTagManage() {
key: 'status',
width: 100,
render: (status: string) => {
const colorMap: Record<string, string> = {
active: 'green',
inactive: 'default',
deceased: 'default',
};
const labelMap: Record<string, string> = {
active: '活跃',
inactive: '停用',
deceased: '已故',
};
return <Tag color={colorMap[status] || 'default'}>{labelMap[status] || status}</Tag>;
const cfg = STATUS_TAG_CONFIG[status] || { color: 'default', label: status };
return <Tag color={cfg.color}>{cfg.label}</Tag>;
},
},
{

View File

@@ -14,20 +14,7 @@ import { pointsApi, type PersonalStats } from '../../../api/health/points';
import { alertApi, type Alert } from '../../../api/health/alerts';
import { useStatsData } from './useStatsData';
import { useCountUp } from '../../../hooks/useCountUp';
const SEVERITY_COLOR: Record<string, string> = {
info: 'default',
warning: 'orange',
critical: 'red',
urgent: 'magenta',
};
const SEVERITY_LABEL: Record<string, string> = {
info: '提示',
warning: '警告',
critical: '严重',
urgent: '紧急',
};
import { SEVERITY_COLOR, SEVERITY_LABEL } from '../../../constants/health';
export function DoctorDashboard() {
const navigate = useNavigate();

View File

@@ -3,20 +3,12 @@ import { Table, Select, Tabs, Card, Typography } from 'antd';
import { deviceReadingApi } from '../../../api/health/deviceReadings';
import type { DeviceReading, HourlyReading } from '../../../api/health/deviceReadings';
import { usePaginatedData } from '../../../hooks/usePaginatedData';
import { DEVICE_TYPE_OPTIONS } from '../../../constants/health';
const { Text } = Typography;
/* ---------- 常量 ---------- */
const DEVICE_TYPE_OPTIONS = [
{ value: 'heart_rate', label: '心率' },
{ value: 'blood_oxygen', label: '血氧' },
{ value: 'blood_pressure', label: '血压' },
{ value: 'blood_glucose', label: '血糖' },
{ value: 'steps', label: '步数' },
{ value: 'temperature', label: '体温' },
] as const;
const TIME_RANGE_OPTIONS = [
{ value: 1, label: '最近 1 小时' },
{ value: 6, label: '最近 6 小时' },

View File

@@ -1,30 +1,11 @@
import { Tag } from 'antd';
const STATUS_CONFIG: Record<string, { color: string; label: string }> = {
// 预约状态
pending: { color: 'gold', label: '待确认' },
confirmed: { color: 'blue', label: '已确认' },
completed: { color: 'green', label: '已完成' },
cancelled: { color: 'default', label: '已取消' },
no_show: { color: 'red', label: '未到诊' },
// 随访状态
overdue: { color: 'red', label: '逾期' },
in_progress: { color: 'processing', label: '进行中' },
// 咨询状态
waiting: { color: 'gold', label: '等待中' },
active: { color: 'green', label: '进行中' },
closed: { color: 'default', label: '已关闭' },
// 患者状态
inactive: { color: 'default', label: '停用' },
deceased: { color: 'default', label: '已故' },
verified: { color: 'green', label: '已认证' },
};
import { STATUS_TAG_CONFIG } from '../../../constants/health';
interface Props {
status: string;
}
export function StatusTag({ status }: Props) {
const cfg = STATUS_CONFIG[status] || { color: 'default' as const, label: status };
const cfg = STATUS_TAG_CONFIG[status] || { color: 'default' as const, label: status };
return <Tag color={cfg.color}>{cfg.label}</Tag>;
}