From 798abeb1ec700ed4dfd04f4359c4c11e655b20e2 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Sun, 16 Jul 2023 00:45:36 +0800 Subject: [PATCH] feat: add global announcement --- .../shared/i18n/langs/en-US/translation.json | 2 +- .../shared/i18n/langs/zh-CN/translation.json | 2 +- client/shared/model/config.ts | 8 + client/shared/utils/consts.ts | 1 + .../src/components/GlobalAnnouncementBar.tsx | 43 ++++ client/web/src/routes/Main/index.tsx | 3 + server/admin/src/client/i18n.ts | 13 ++ .../admin/src/client/routes/system/index.tsx | 199 ++++++++++++------ 8 files changed, 207 insertions(+), 64 deletions(-) create mode 100644 client/web/src/components/GlobalAnnouncementBar.tsx diff --git a/client/shared/i18n/langs/en-US/translation.json b/client/shared/i18n/langs/en-US/translation.json index dd0af815..ee9312a8 100644 --- a/client/shared/i18n/langs/en-US/translation.json +++ b/client/shared/i18n/langs/en-US/translation.json @@ -266,6 +266,7 @@ "kaefc1e64": "Password reset successful, now back to login page", "kaf403ef0": "Light Mode", "kaf51d834": "Reset to default", + "kb01f8383": "Learn More", "kb030fbd1": "Member List", "kb0584341": "Usage Count", "kb07659b0": "Repeat password", @@ -357,7 +358,6 @@ "ke3d797fd": "Drop files to send into current converse", "ke59ffe49": "Muted, there are {{remain}} left", "ke6da074f": "The message was withdrawn successfully", - "kea977d95": "The following users are offline", "kec46a57f": "Add members", "kecb51e2c": "Old password", "kecbb0e45": "System", diff --git a/client/shared/i18n/langs/zh-CN/translation.json b/client/shared/i18n/langs/zh-CN/translation.json index 4e124aea..16a989a6 100644 --- a/client/shared/i18n/langs/zh-CN/translation.json +++ b/client/shared/i18n/langs/zh-CN/translation.json @@ -266,6 +266,7 @@ "kaefc1e64": "密码重置成功,现在回到登录页", "kaf403ef0": "亮色模式", "kaf51d834": "重置为默认值", + "kb01f8383": "了解更多", "kb030fbd1": "成员列表", "kb0584341": "使用次数", "kb07659b0": "重复密码", @@ -357,7 +358,6 @@ "ke3d797fd": "拖放文件以发送到当前会话", "ke59ffe49": "禁言中, 还剩 {{remain}}", "ke6da074f": "消息撤回成功", - "kea977d95": "以下用户已离线", "kec46a57f": "添加成员", "kecb51e2c": "旧密码", "kecbb0e45": "系统", diff --git a/client/shared/model/config.ts b/client/shared/model/config.ts index d98fcfb2..a5206749 100644 --- a/client/shared/model/config.ts +++ b/client/shared/model/config.ts @@ -50,6 +50,14 @@ export interface GlobalConfig { * 是否禁用添加好友功能 */ disableAddFriend?: boolean; + + announcement?: + | false + | { + id: string; + text: string; + link?: string; + }; } export function getGlobalConfig(): GlobalConfig { diff --git a/client/shared/utils/consts.ts b/client/shared/utils/consts.ts index f2c102b6..f0a9e8ad 100644 --- a/client/shared/utils/consts.ts +++ b/client/shared/utils/consts.ts @@ -27,4 +27,5 @@ export const defaultGlobalConfig: GlobalConfig = { disableCreateGroup: false, disablePluginStore: false, disableAddFriend: false, + announcement: false, }; diff --git a/client/web/src/components/GlobalAnnouncementBar.tsx b/client/web/src/components/GlobalAnnouncementBar.tsx new file mode 100644 index 00000000..8f405e31 --- /dev/null +++ b/client/web/src/components/GlobalAnnouncementBar.tsx @@ -0,0 +1,43 @@ +import { useLocalStorageState } from '@/hooks/useLocalStorage'; +import { Button } from 'antd'; +import React from 'react'; +import { Icon } from 'tailchat-design'; +import { t, useGlobalConfigStore } from 'tailchat-shared'; + +export const GlobalAnnouncementBar: React.FC = React.memo(() => { + const announcementInfo = useGlobalConfigStore((state) => state.announcement); + const [ackId, setAckId] = useLocalStorageState('ackGlobalAnnouncement'); + + if (!announcementInfo) { + return null; + } + + if (ackId === announcementInfo.id) { + // 如果该公告已读,也不展示 + return null; + } + + return ( +
+ {announcementInfo.text} + + {announcementInfo.link && ( + + )} + + setAckId(announcementInfo.id)} + /> +
+ ); +}); +GlobalAnnouncementBar.displayName = 'GlobalAnnouncementBar'; diff --git a/client/web/src/routes/Main/index.tsx b/client/web/src/routes/Main/index.tsx index eda26e81..a73ca86d 100644 --- a/client/web/src/routes/Main/index.tsx +++ b/client/web/src/routes/Main/index.tsx @@ -1,3 +1,4 @@ +import { GlobalAnnouncementBar } from '@/components/GlobalAnnouncementBar'; import { GlobalTemporaryTip } from '@/components/GlobalTemporaryTip'; import { useRecordMeasure } from '@/utils/measure-helper'; import React from 'react'; @@ -17,6 +18,8 @@ const MainRoute: React.FC = React.memo(() => {
+ +
diff --git a/server/admin/src/client/i18n.ts b/server/admin/src/client/i18n.ts index e58c37d0..c9ecc2c4 100644 --- a/server/admin/src/client/i18n.ts +++ b/server/admin/src/client/i18n.ts @@ -65,6 +65,13 @@ export const i18n: TushanContextProps['i18n'] = { allowCreateGroup: 'Allow Create Group', serverName: 'Server Name', serverEntryImage: 'Server Entry Page Image', + configPanel: 'Config', + announcementPanel: 'Announcement', + announcementEnable: 'Is Enable Announcement', + announcementText: 'Announcement Text', + announcementLink: 'Announcement Link', + announcementLinkTip: + 'This content is optional, and it is the address to announce more content', }, cache: { cleanTitle: 'Are you sure you want to clear the cache?', @@ -235,6 +242,12 @@ export const i18n: TushanContextProps['i18n'] = { allowCreateGroup: '允许创建群组', serverName: '服务器名', serverEntryImage: '服务器登录图', + configPanel: '配置', + announcementPanel: '公告', + announcementEnable: '是否启用公告', + announcementText: '公告文本', + announcementLink: '公告链接', + announcementLinkTip: '该内容可选,为公告更多内容的地址', }, cache: { cleanTitle: '确定要清理缓存么?', diff --git a/server/admin/src/client/routes/system/index.tsx b/server/admin/src/client/routes/system/index.tsx index 5520d8ba..4b4c42ae 100644 --- a/server/admin/src/client/routes/system/index.tsx +++ b/server/admin/src/client/routes/system/index.tsx @@ -11,7 +11,10 @@ import { Upload, useTranslation, Card, + Tabs, + Switch, } from 'tushan'; +import _get from 'lodash/get'; import { IconCheck, IconClose, IconDelete } from 'tushan/icon'; import { TailchatImage } from '../../components/TailchatImage'; @@ -45,7 +48,7 @@ export const SystemConfig: React.FC = React.memo(() => { value: val, }); fetchConfig(); - Message.success('Success'); + Message.success(t('tushan.common.success')); } catch (err) { console.log(err); Message.error(String(err)); @@ -88,6 +91,31 @@ export const SystemConfig: React.FC = React.memo(() => { } ); + const [{}, handleChangeAnnouncement] = useAsyncRequest( + async (values: { enable: boolean; link: string; text: string }) => { + console.log(values); + const { enable = false, link = '', text = '' } = values; + + if (enable) { + await request.patch('/config/client', { + key: 'announcement', + value: { + id: Date.now(), + text, + link, + }, + }); + } else { + await request.patch('/config/client', { + key: 'announcement', + value: false, + }); + } + + Message.success(t('tushan.common.success')); + } + ); + if (loading) { return ; } @@ -99,71 +127,118 @@ export const SystemConfig: React.FC = React.memo(() => { return ( -
- - {config.uploadFileLimit} - - - - {config.emailVerification ? : } - - - - {!config.disableGuestLogin ? : } - - - - {!config.disableUserRegister ? : } - - - - {!config.disableCreateGroup ? : } - - - - setServerName(val)} - onBlur={() => saveServerName()} - placeholder="Tailchat" - /> - - - -
- {config?.serverEntryImage ? ( -
-
- + + + + {config.uploadFileLimit} + + + + {config.emailVerification ? : } + + + + {!config.disableGuestLogin ? : } + + + + {!config.disableUserRegister ? : } + + + + {!config.disableCreateGroup ? : } + + + + setServerName(val)} + onBlur={() => saveServerName()} + placeholder="Tailchat" + /> + + + +
+ {config?.serverEntryImage ? ( +
+
+ +
+ + +
+ ) : ( + { + handleChangeServerEntryImage(file.originFile); }} - src={config?.serverEntryImage} /> -
- - + )}
- ) : ( - { - handleChangeServerEntryImage(file.originFile); - }} - /> - )} -
- - + + + + + +
+ + + + + + + + + + + + +
+
+ ); }); SystemConfig.displayName = 'SystemConfig'; + +export const SwitchFormInput: React.FC<{ + value?: boolean; + onChange?: (val: boolean) => void; +}> = React.memo((props) => { + return ; +}); +SwitchFormInput.displayName = 'SwitchFormInput';