Skip to content

Commit c825425

Browse files
committed
feat: add global config setting page
1 parent 6d33945 commit c825425

File tree

8 files changed

+155
-1
lines changed

8 files changed

+155
-1
lines changed

client/pages/_app.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,15 @@ class MyApp extends App<IGlobalContext, unknown> {
6262
PageProvider.getAllPublisedPages(),
6363
]);
6464
const i18n = safeJsonParse(setting.i18n);
65+
const globalSetting = safeJsonParse(setting.globalSetting)?.[ctx?.locale];
6566
return {
6667
pageProps,
6768
setting,
6869
tags,
6970
categories,
7071
pages: pages[0] || [],
7172
i18n,
73+
globalSetting,
7274
locales: Object.keys(i18n),
7375
};
7476
};
@@ -133,7 +135,7 @@ class MyApp extends App<IGlobalContext, unknown> {
133135
}
134136

135137
render() {
136-
const { Component, pageProps, i18n, locales, router, ...contextValue } = this.props;
138+
const { Component, pageProps, i18n, globalSetting, locales, router, ...contextValue } = this.props;
137139
const locale = this.state.locale || router.locale;
138140
const { needLayoutFooter = true, hasBg = false } = pageProps;
139141
const message = i18n[locale] || {};
@@ -148,6 +150,7 @@ class MyApp extends App<IGlobalContext, unknown> {
148150
i18n,
149151
locale,
150152
locales,
153+
globalSetting,
151154
theme: this.state.theme,
152155
collapsed: this.state.collapsed,
153156
changeLocale: this.changeLocale,

client/pages/admin/setting/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { OSSSetting } from '@/components/Setting/OSSSetting';
88
import { SEOSetting } from '@/components/Setting/SEOSetting';
99
import { SMTPSetting } from '@/components/Setting/SMTPSetting';
1010
import { SystemSetting } from '@/components/Setting/SystemSetting';
11+
import { GlobalSetting } from '@/components/Setting/GlobalSetting';
1112
import { useSetting } from '@/hooks/useSetting';
1213
import { AdminLayout } from '@/layout/AdminLayout';
1314

@@ -44,6 +45,10 @@ const Setting: NextPage<IProps> = ({ type: defaultType }) => {
4445
label: 'OSS设置',
4546
content: <OSSSetting setting={setting} />,
4647
},
48+
{
49+
label: '全局设置',
50+
content: <GlobalSetting setting={setting} />,
51+
},
4752
{
4853
label: 'SMTP服务',
4954
content: <SMTPSetting setting={setting} />,
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { WarningOutlined } from '@ant-design/icons';
2+
import { Alert, Button, Input, message, Modal, Tabs } from 'antd';
3+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
4+
5+
import { JsonEditor } from '@/components/JsonEditor';
6+
import { SettingProvider } from '@/providers/setting';
7+
import { safeJsonParse } from '@/utils/json';
8+
9+
export const GlobalSetting = ({ setting }) => {
10+
const [v, forceUpdate] = useState(0);
11+
const [globalSetting, setGlobalSetting] = useState({});
12+
const locales = useMemo(
13+
() => (globalSetting && typeof globalSetting === 'object' ? Object.keys(globalSetting) : []),
14+
[v, globalSetting]
15+
);
16+
17+
useEffect(() => {
18+
try {
19+
if (setting.globalSetting) {
20+
const json = JSON.parse(setting.globalSetting);
21+
Object.keys(json).forEach((key) => {
22+
json[key] = safeJsonParse(json[key]);
23+
});
24+
setGlobalSetting(json);
25+
}
26+
} catch (e) {
27+
setGlobalSetting({});
28+
}
29+
}, [setting.globalSetting]);
30+
31+
const onEdit = useCallback((key, action) => {
32+
const add = () => {
33+
let locale = '';
34+
const onChange = function (e) {
35+
locale = e.target.value;
36+
};
37+
Modal.confirm({
38+
title: '请输入语言名称(英文)',
39+
icon: <Input onChange={onChange} />,
40+
onOk() {
41+
setGlobalSetting((json) => {
42+
json[locale] = {};
43+
return json;
44+
});
45+
forceUpdate((v) => v + 1);
46+
},
47+
okText: '确认',
48+
cancelText: '取消',
49+
transitionName: '',
50+
maskTransitionName: '',
51+
});
52+
};
53+
const remove = () => {
54+
Modal.confirm({
55+
title: '确认删除',
56+
icon: <WarningOutlined />,
57+
onOk() {
58+
setGlobalSetting((json) => {
59+
delete json[key];
60+
return json;
61+
});
62+
forceUpdate((v) => v + 1);
63+
},
64+
okText: '确认',
65+
cancelText: '取消',
66+
transitionName: '',
67+
maskTransitionName: '',
68+
});
69+
};
70+
71+
if (action === 'add') {
72+
add();
73+
} else {
74+
remove();
75+
}
76+
}, []);
77+
78+
const onChange = useCallback((locale) => {
79+
return (value) => {
80+
if (!value) return;
81+
setGlobalSetting((json) => {
82+
json[locale] = value;
83+
return json;
84+
});
85+
};
86+
}, []);
87+
88+
const save = useCallback(() => {
89+
const data = {
90+
globalSetting: JSON.stringify(globalSetting),
91+
};
92+
SettingProvider.updateSetting(data).then(() => {
93+
message.success('保存成功');
94+
});
95+
}, [globalSetting]);
96+
97+
return (
98+
<div>
99+
<Alert
100+
message="说明"
101+
description={'此处可配置系统的全局JSON配置,包含中英文的国际化配置。'}
102+
type="info"
103+
showIcon={true}
104+
style={{ marginBottom: '1rem' }}
105+
/>
106+
<Tabs type="editable-card" onEdit={onEdit}>
107+
{locales.map((locale) => (
108+
<Tabs.TabPane tab={locale} key={locale}>
109+
<JsonEditor key={locale} value={globalSetting[locale]} onChange={onChange(locale)} />
110+
</Tabs.TabPane>
111+
))}
112+
</Tabs>
113+
<Button type="primary" onClick={save}>
114+
保存
115+
</Button>
116+
</div>
117+
);
118+
};

client/src/context/global.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React from 'react';
33
export interface IGlobalContext {
44
setting?: ISetting;
55
i18n?: Record<string, unknown>;
6+
globalSetting?: IGlobalConfig;
67
locale?: string;
78
locales?: Array<string>;
89
pages?: IPage[];

client/src/layout/AdminLayout/menus.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ export const menus: {
131131
title: '国际化设置',
132132
path: '/admin/setting?type=国际化设置',
133133
},
134+
{
135+
title: '全局设置',
136+
path: '/admin/setting?type=全局设置',
137+
},
134138
{
135139
title: '数据统计',
136140
path: '/admin/setting?type=数据统计',

client/types/index.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,23 @@ interface IFile {
2121
createAt: string;
2222
}
2323

24+
interface IGlobalConfig {
25+
navConfig: NavSetting;
26+
}
27+
28+
interface CategoryItem {
29+
label: string;
30+
key: string;
31+
url?: string;
32+
}
33+
34+
interface NavSetting {
35+
categories: CategoryItem[];
36+
subCategories: {
37+
[k: string]: CategoryItem[]
38+
}
39+
}
40+
2441
interface IArticle {
2542
id: string;
2643
title: string;
@@ -170,4 +187,5 @@ interface ISetting {
170187
smtpUser?: string; // SMTP 用户
171188
smtpPass?: string; // SMTP 授权码
172189
smtpFromUser?: string; // SMTP 发件人
190+
globalSetting?: string; // 全局配置
173191
}

server/src/modules/setting/setting.constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ export const UNPROTECTED_KEYS = [
1717
'seoDesc',
1818
'baiduAnalyticsId',
1919
'googleAnalyticsId',
20+
'globalSetting'
2021
];

server/src/modules/setting/setting.entity.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ export class Setting {
1111
@Column({ type: 'text', default: null })
1212
i18n: string; // 国际化
1313

14+
@ApiProperty()
15+
@Column({ type: 'text', default: null })
16+
globalSetting: string; // 导航设置
17+
1418
@ApiProperty()
1519
@Column({ type: 'text', default: null })
1620
systemUrl: string; // 系统地址

0 commit comments

Comments
 (0)