feat(web): 主题设置联动 — 扩展 ThemeConfig 品牌字段 + 设置页面表单
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- ThemeConfig 接口增加 brand_name/brand_slogan/brand_features/brand_copyright
- 新增 BrandConfig 接口和 getPublicBrand 公开品牌信息获取
- app store 增加 themeConfig 缓存和 loadThemeConfig 方法
- ThemeSettings 页面增加品牌设置表单(品牌名称/标语/特性/版权)
This commit is contained in:
iven
2026-05-01 17:37:10 +08:00
parent 6eb2bf9c80
commit 669ca44360
3 changed files with 71 additions and 4 deletions

View File

@@ -4,6 +4,10 @@ export interface ThemeConfig {
primary_color?: string;
logo_url?: string;
sidebar_style?: 'light' | 'dark';
brand_name?: string;
brand_slogan?: string;
brand_features?: string;
brand_copyright?: string;
}
export async function getTheme() {
@@ -20,3 +24,26 @@ export async function updateTheme(theme: ThemeConfig) {
);
return data.data;
}
export interface BrandConfig {
brand_name: string;
brand_slogan: string;
brand_features: string;
brand_copyright: string;
}
const BRAND_DEFAULTS: BrandConfig = {
brand_name: 'HMS 健康管理平台',
brand_slogan: '新一代健康管理平台',
brand_features: '患者管理 · 健康监测 · 随访管理 · AI 智能分析',
brand_copyright: 'HMS 健康管理平台 · ©汕头市智界科技有限公司',
};
export async function getPublicBrand(): Promise<BrandConfig> {
try {
const res = await fetch('/api/v1/public/brand');
const json = await res.json();
if (json?.success && json?.data) return json.data;
} catch {}
return BRAND_DEFAULTS;
}

View File

@@ -1,12 +1,10 @@
import { useEffect, useState, useCallback } from 'react';
import { Form, Input, Select, Button, ColorPicker, message, Typography } from 'antd';
import { Form, Input, Select, Button, ColorPicker, message, Typography, Divider } from 'antd';
import {
getTheme,
updateTheme,
} from '../../api/themes';
// --- Component ---
export default function ThemeSettings() {
const [form] = Form.useForm();
const [, setLoading] = useState(false);
@@ -20,13 +18,20 @@ export default function ThemeSettings() {
primary_color: theme.primary_color || '#1677ff',
logo_url: theme.logo_url || '',
sidebar_style: theme.sidebar_style || 'light',
brand_name: theme.brand_name || '',
brand_slogan: theme.brand_slogan || '',
brand_features: theme.brand_features || '',
brand_copyright: theme.brand_copyright || '',
});
} catch {
// Theme may not exist yet; use defaults
form.setFieldsValue({
primary_color: '#1677ff',
logo_url: '',
sidebar_style: 'light',
brand_name: '',
brand_slogan: '',
brand_features: '',
brand_copyright: '',
});
}
setLoading(false);
@@ -40,6 +45,10 @@ export default function ThemeSettings() {
primary_color: string;
logo_url: string;
sidebar_style: 'light' | 'dark';
brand_name: string;
brand_slogan: string;
brand_features: string;
brand_copyright: string;
}) => {
setSaving(true);
try {
@@ -50,6 +59,10 @@ export default function ThemeSettings() {
: (values.primary_color as { toHexString?: () => string }).toHexString?.() ?? String(values.primary_color),
logo_url: values.logo_url,
sidebar_style: values.sidebar_style,
brand_name: values.brand_name || undefined,
brand_slogan: values.brand_slogan || undefined,
brand_features: values.brand_features || undefined,
brand_copyright: values.brand_copyright || undefined,
});
message.success('主题设置已保存');
} catch (err: unknown) {
@@ -87,6 +100,22 @@ export default function ThemeSettings() {
]}
/>
</Form.Item>
<Divider></Divider>
<Form.Item name="brand_name" label="品牌名称">
<Input placeholder="HMS 健康管理平台" />
</Form.Item>
<Form.Item name="brand_slogan" label="品牌标语">
<Input placeholder="新一代健康管理平台" />
</Form.Item>
<Form.Item name="brand_features" label="品牌特性">
<Input placeholder="患者管理 · 健康监测 · 随访管理 · AI 智能分析" />
</Form.Item>
<Form.Item name="brand_copyright" label="版权信息">
<Input placeholder="HMS 健康管理平台 · ©汕头市智界科技有限公司" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={saving}>

View File

@@ -1,4 +1,6 @@
import { create } from 'zustand';
import type { ThemeConfig } from '../api/themes';
import { getTheme } from '../api/themes';
export type ThemeName = 'blue' | 'warm' | 'dark' | 'emerald';
@@ -49,16 +51,25 @@ function loadTheme(): ThemeName {
interface AppState {
theme: ThemeName;
sidebarCollapsed: boolean;
themeConfig: ThemeConfig | null;
toggleSidebar: () => void;
setTheme: (theme: ThemeName) => void;
loadThemeConfig: () => Promise<void>;
}
export const useAppStore = create<AppState>((set) => ({
theme: loadTheme(),
sidebarCollapsed: false,
themeConfig: null,
toggleSidebar: () => set((s) => ({ sidebarCollapsed: !s.sidebarCollapsed })),
setTheme: (theme) => {
try { localStorage.setItem(STORAGE_KEY, theme); } catch {}
set({ theme });
},
loadThemeConfig: async () => {
try {
const config = await getTheme();
set({ themeConfig: config });
} catch {}
},
}));