From b8f3e41bb33a0062c0dbf9f8ad08c6935db61896 Mon Sep 17 00:00:00 2001 From: ShineKOT <1917095344@qq.com> Date: Wed, 26 Nov 2025 18:02:01 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E5=88=87=E6=8D=A2=E7=BB=84=E4=BB=B6=EF=BC=88=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=86=85=E5=AE=B9=E9=A1=B9=E6=89=A9=E5=B1=95=EF=BC=8C?= =?UTF-8?q?=E9=A2=84=E7=BD=AE=E7=B1=BB=E5=9E=8B=E4=B8=BATHEME=5FTOGGLING?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- src/panel-component/index.ts | 2 + src/panel-component/theme-toggling/index.ts | 15 +++ .../theme-toggling.controller.ts | 96 +++++++++++++++++++ .../theme-toggling/theme-toggling.provider.ts | 27 ++++++ .../theme-toggling/theme-toggling.scss | 13 +++ .../theme-toggling/theme-toggling.state.ts | 16 ++++ .../theme-toggling/theme-toggling.tsx | 78 +++++++++++++++ 8 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/panel-component/theme-toggling/index.ts create mode 100644 src/panel-component/theme-toggling/theme-toggling.controller.ts create mode 100644 src/panel-component/theme-toggling/theme-toggling.provider.ts create mode 100644 src/panel-component/theme-toggling/theme-toggling.scss create mode 100644 src/panel-component/theme-toggling/theme-toggling.state.ts create mode 100644 src/panel-component/theme-toggling/theme-toggling.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 52420f12d71..0030a0dfaf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ ### Added - 新增重复器表格组件 - +- 新增主题切换组件(直接内容项扩展,预置类型为THEME_TOGGLING) ### Change - 数据看板的直接内容不显示标题栏 diff --git a/src/panel-component/index.ts b/src/panel-component/index.ts index 5b7163aaa8d..a0659a9eca4 100644 --- a/src/panel-component/index.ts +++ b/src/panel-component/index.ts @@ -39,9 +39,11 @@ import IBizViewMessage from './view-message'; import IBizViewMsgPos from './view-msg-pos'; import IBizSettingContainer from './setting-container'; import IBizSplitContainer from './split-container'; +import IBizThemeToggling from './theme-toggling'; export const IBizPanelComponents = { install: (v: App): void => { + v.use(IBizThemeToggling); v.use(IBizSplitContainer); v.use(IBizPanelCtrlViewPageCaption); v.use(IBizPanelContainer); diff --git a/src/panel-component/theme-toggling/index.ts b/src/panel-component/theme-toggling/index.ts new file mode 100644 index 00000000000..7bc29aef1e4 --- /dev/null +++ b/src/panel-component/theme-toggling/index.ts @@ -0,0 +1,15 @@ +import { App } from 'vue'; +import { registerPanelItemProvider } from '@ibiz-template/runtime'; +import { withInstall } from '@ibiz-template/vue3-util'; +import { ThemeToggling } from './theme-toggling'; +import { ThemeTogglingProvider } from './theme-toggling.provider'; + +export const IBizThemeToggling = withInstall(ThemeToggling, function (v: App) { + v.component(ThemeToggling.name!, ThemeToggling); + registerPanelItemProvider( + 'RAWITEM_THEME_TOGGLING', + () => new ThemeTogglingProvider(), + ); +}); + +export default IBizThemeToggling; \ No newline at end of file diff --git a/src/panel-component/theme-toggling/theme-toggling.controller.ts b/src/panel-component/theme-toggling/theme-toggling.controller.ts new file mode 100644 index 00000000000..0c892fe8a51 --- /dev/null +++ b/src/panel-component/theme-toggling/theme-toggling.controller.ts @@ -0,0 +1,96 @@ +import { PanelItemController } from '@ibiz-template/runtime'; +import { IPanelRawItem } from '@ibiz/model-core'; +import { ThemeTogglingState } from './theme-toggling.state'; + +/** + * @description 主题切换控制器 + * @export + * @class ThemeTogglingController + * @extends {PanelItemController} + */ +export class ThemeTogglingController extends PanelItemController { + /** + * @description 状态 + * @type {ThemeTogglingState} + * @memberof ThemeTogglingController + */ + declare state: ThemeTogglingState; + + /** + * @description 媒体查询 + * @protected + * @type {MediaQueryList} + * @memberof ThemeTogglingController + */ + protected mediaQuery!: MediaQueryList; + + /** + * @description 创建状态对象 + * @protected + * @returns {*} {ThemeTogglingState} + * @memberof ThemeTogglingController + */ + protected createState(): ThemeTogglingState { + return new ThemeTogglingState(this.parent?.state); + } + + /** + * @description 初始化 + * @protected + * @returns {*} {Promise} + * @memberof ThemeTogglingController + */ + protected async onInit(): Promise { + await super.onInit(); + this.state.theme = ibiz.util.theme.getTheme(); + this.handleSystemThemeChange = this.handleSystemThemeChange.bind(this); + this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + this.mediaQuery.addEventListener('change', this.handleSystemThemeChange); + } + + /** + * @description 获取系统主题 + * @protected + * @returns {*} {('light' | 'dark')} + * @memberof ThemeTogglingController + */ + protected getSystemTheme(): 'light' | 'dark' { + // 检测系统当前是否使用深色主题 + const isDarkMode = this.mediaQuery.matches; + if (isDarkMode) return 'dark'; + // 系统没有明确偏好 默认为亮色 + return 'light'; + } + + /** + * @description 处理系统主题变更 + * @protected + * @param {MediaQueryListEvent} ev + * @memberof ThemeTogglingController + */ + protected handleSystemThemeChange(ev: MediaQueryListEvent): void { + const themeName = ev.matches ? 'dark' : 'light'; + if (this.state.theme === 'auto') ibiz.util.theme.setTheme(themeName); + } + + /** + * @description 切换主题 + * @param {string} theme + * @memberof ThemeTogglingController + */ + switchTheme(theme: string): void { + if (theme === this.state.theme) return; + this.state.theme = theme; + const themeName = theme === 'auto' ? this.getSystemTheme() : theme; + ibiz.util.theme.setTheme(themeName); + } + + /** + * @description 销毁 + * @memberof ThemeTogglingController + */ + destroy(): void { + super.destroy(); + this.mediaQuery.removeEventListener('change', this.handleSystemThemeChange); + } +} diff --git a/src/panel-component/theme-toggling/theme-toggling.provider.ts b/src/panel-component/theme-toggling/theme-toggling.provider.ts new file mode 100644 index 00000000000..aa918270003 --- /dev/null +++ b/src/panel-component/theme-toggling/theme-toggling.provider.ts @@ -0,0 +1,27 @@ +import { + PanelController, + IPanelItemProvider, + PanelItemController, +} from '@ibiz-template/runtime'; +import { IPanelItem } from '@ibiz/model-core'; +import { ThemeTogglingController } from './theme-toggling.controller'; + +/** + * @description 主题切换适配器 + * @export + * @class ThemeTogglingProvider + * @implements {IPanelItemProvider} + */ +export class ThemeTogglingProvider implements IPanelItemProvider { + component: string = 'IBizThemeToggling'; + + async createController( + panelItem: IPanelItem, + panel: PanelController, + parent: PanelItemController | undefined, + ): Promise { + const c = new ThemeTogglingController(panelItem, panel, parent); + await c.init(); + return c; + } +} diff --git a/src/panel-component/theme-toggling/theme-toggling.scss b/src/panel-component/theme-toggling/theme-toggling.scss new file mode 100644 index 00000000000..43dba44269c --- /dev/null +++ b/src/panel-component/theme-toggling/theme-toggling.scss @@ -0,0 +1,13 @@ +@include b(theme-toggling) { + @include e(item) { + &.van-cell { + padding: getCssVar(spacing, tight) getCssVar(spacing, base); + font-size: getCssVar(font-size, regular); + color: getCssVar(color, text-0); + background-color: getCssVar(color, bg-2); + } + } + @include e(icon) { + color: getCssVar(color, primary, active); + } +} \ No newline at end of file diff --git a/src/panel-component/theme-toggling/theme-toggling.state.ts b/src/panel-component/theme-toggling/theme-toggling.state.ts new file mode 100644 index 00000000000..ba3b5bfcb79 --- /dev/null +++ b/src/panel-component/theme-toggling/theme-toggling.state.ts @@ -0,0 +1,16 @@ +import { PanelItemState } from '@ibiz-template/runtime'; + +/** + * @description 主题切换状态 + * @export + * @class ThemeTogglingState + * @extends {PanelItemState} + */ +export class ThemeTogglingState extends PanelItemState { + /** + * @description 主题 + * @type {('light' | 'dark' | 'auto' | string)} + * @memberof ThemeTogglingState + */ + theme: 'light' | 'dark' | 'auto' | string = ''; +} diff --git a/src/panel-component/theme-toggling/theme-toggling.tsx b/src/panel-component/theme-toggling/theme-toggling.tsx new file mode 100644 index 00000000000..045bb1c524e --- /dev/null +++ b/src/panel-component/theme-toggling/theme-toggling.tsx @@ -0,0 +1,78 @@ +import { PropType, defineComponent } from 'vue'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import { IPanelRawItem } from '@ibiz/model-core'; +import { ThemeTogglingController } from './theme-toggling.controller'; +import './theme-toggling.scss'; + +export const ThemeToggling = defineComponent({ + name: 'IBizThemeToggling', + props: { + /** + * @description 首页导航占位模型数据 + */ + modelData: { + type: Object as PropType, + required: true, + }, + /** + * @description 首页导航占位控制器 + */ + controller: { + type: Object as PropType, + required: true, + }, + }, + setup(props) { + const c = props.controller; + const ns = useNamespace('theme-toggling'); + + const themeList = [ + { + title: '跟随系统', + value: 'auto', + }, + { + title: '亮色主题', + value: 'light', + }, + { + title: '暗色主题', + value: 'dark', + }, + ]; + + return { ns, c, themeList }; + }, + render() { + return ( + + {this.themeList.map(theme => { + return ( + this.c.switchTheme(theme.value)} + > + {{ + 'right-icon': () => { + return this.c.state.theme === theme.value ? ( + + ) : null; + }, + }} + + ); + })} + + ); + }, +}); -- Gitee From 6bb374856cea8fd6ad2a579d0c08aefd8308e448 Mon Sep 17 00:00:00 2001 From: ShineKOT <1917095344@qq.com> Date: Wed, 26 Nov 2025 18:08:15 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E4=B8=BB=E9=A2=98=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=9B=BD=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locale/en/index.ts | 5 +++++ src/locale/zh-CN/index.ts | 5 +++++ src/panel-component/theme-toggling/theme-toggling.tsx | 6 +++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/locale/en/index.ts b/src/locale/en/index.ts index 302a7f78840..af264caaed5 100644 --- a/src/locale/en/index.ts +++ b/src/locale/en/index.ts @@ -320,6 +320,11 @@ export default { onlyShowUnread: 'Only show unread', }, }, + themeToggling: { + auto: 'Follow system', + light: 'Light', + dark: 'Dark', + } }, // 工具 util: { diff --git a/src/locale/zh-CN/index.ts b/src/locale/zh-CN/index.ts index cd53e400a0f..dcad276a9c1 100644 --- a/src/locale/zh-CN/index.ts +++ b/src/locale/zh-CN/index.ts @@ -307,6 +307,11 @@ export default { onlyShowUnread: '只显示未读', }, }, + themeToggling: { + auto: '跟随系统', + light: '亮色主题', + dark: '暗色主题' + } }, // 工具 util: { diff --git a/src/panel-component/theme-toggling/theme-toggling.tsx b/src/panel-component/theme-toggling/theme-toggling.tsx index 045bb1c524e..216663c7f54 100644 --- a/src/panel-component/theme-toggling/theme-toggling.tsx +++ b/src/panel-component/theme-toggling/theme-toggling.tsx @@ -28,15 +28,15 @@ export const ThemeToggling = defineComponent({ const themeList = [ { - title: '跟随系统', + title: ibiz.i18n.t('panelComponent.themeToggling.auto'), value: 'auto', }, { - title: '亮色主题', + title: ibiz.i18n.t('panelComponent.themeToggling.light'), value: 'light', }, { - title: '暗色主题', + title: ibiz.i18n.t('panelComponent.themeToggling.dark'), value: 'dark', }, ]; -- Gitee