新增 AutoRDO 需求清洗工作台与消息中枢,迭代 OneOS V2 设计规范及租赁合同/工作台/车辆等原型,同步云效技能与导航注册;并归档一批 legacy 原型快照。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
/**
|
||||
* OneOS 浅色 / 暗色主题(localStorage + 跨 iframe postMessage)
|
||||
* OneOS 浅色 / 暗色主题 & RuoYi 偏好设置(localStorage + 跨 iframe postMessage)
|
||||
* 暗色参照原型导航页(VoltAgent 深色画布)。
|
||||
* 不对「旧 ONEOS」目录下原型生效。
|
||||
*/
|
||||
|
||||
import './oneos-theme-content.css';
|
||||
import {
|
||||
type RuoYiSettings,
|
||||
readStoredRuoYiSettings,
|
||||
persistRuoYiSettings,
|
||||
DEFAULT_RUOYI_SETTINGS,
|
||||
} from './RuoYiSettingsDrawer';
|
||||
|
||||
export type OneOsTheme = 'light' | 'dark';
|
||||
|
||||
@@ -30,29 +36,101 @@ export function isLegacyOneOsPrototype(id?: string | null): boolean {
|
||||
}
|
||||
|
||||
export function readStoredOneOsTheme(): OneOsTheme {
|
||||
if (typeof window === 'undefined') return 'light';
|
||||
try {
|
||||
const v = window.localStorage.getItem(ONEOS_THEME_STORAGE_KEY);
|
||||
if (v === 'dark' || v === 'light') return v;
|
||||
} catch {
|
||||
/* ignore */
|
||||
const settings = readStoredRuoYiSettings();
|
||||
if (settings.themeMode === 'dark') return 'dark';
|
||||
if (settings.themeMode === 'light') return 'light';
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
}
|
||||
return 'light';
|
||||
}
|
||||
|
||||
export function applyOneOsTheme(theme: OneOsTheme, root: HTMLElement = document.documentElement) {
|
||||
root.setAttribute(ONEOS_THEME_ATTR, theme);
|
||||
if (root === document.documentElement) {
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
export function applyRuoYiSettingsToDocument(
|
||||
doc: Document = document,
|
||||
settings?: Partial<RuoYiSettings>,
|
||||
) {
|
||||
if (!doc || !doc.documentElement) return;
|
||||
const currentSettings: RuoYiSettings = {
|
||||
...readStoredRuoYiSettings(),
|
||||
...settings,
|
||||
};
|
||||
|
||||
const isDark =
|
||||
currentSettings.themeMode === 'dark' ||
|
||||
(currentSettings.themeMode === 'system' &&
|
||||
typeof window !== 'undefined' &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
|
||||
const themeValue = isDark ? 'dark' : 'light';
|
||||
|
||||
doc.documentElement.setAttribute('data-oneos-theme', themeValue);
|
||||
doc.documentElement.setAttribute('data-ds-mode', themeValue);
|
||||
doc.documentElement.setAttribute('data-oneos-theme-mode', themeValue);
|
||||
|
||||
if (isDark) {
|
||||
doc.documentElement.classList.add('dark');
|
||||
if (doc.body) doc.body.classList.add('dark');
|
||||
} else {
|
||||
doc.documentElement.classList.remove('dark');
|
||||
if (doc.body) doc.body.classList.remove('dark');
|
||||
}
|
||||
|
||||
// 注入或更新主题 CSS 变量覆盖节点
|
||||
let styleEl = doc.getElementById('oneos-ruoyi-theme-style-override') as HTMLStyleElement | null;
|
||||
if (!styleEl) {
|
||||
styleEl = doc.createElement('style');
|
||||
styleEl.id = 'oneos-ruoyi-theme-style-override';
|
||||
doc.head?.appendChild(styleEl);
|
||||
}
|
||||
|
||||
const primary = currentSettings.primaryColor || '#533AFD';
|
||||
const radius = `${Math.round((currentSettings.borderRadius ?? 0.5) * 16)}px`;
|
||||
const fontSize = `${currentSettings.fontSize || 14}px`;
|
||||
|
||||
styleEl.textContent = `
|
||||
:root, html, body, [data-oneos-theme], [data-ds-mode] {
|
||||
--oneos-primary: ${primary} !important;
|
||||
--ln-primary: ${primary} !important;
|
||||
--el-color-primary: ${primary} !important;
|
||||
--ln-primary-hover: ${primary} !important;
|
||||
--ln-primary-focus: ${primary} !important;
|
||||
--ruoyi-menu-active-text: ${primary} !important;
|
||||
--oneos-radius: ${radius} !important;
|
||||
--ln-radius: ${radius} !important;
|
||||
font-size: ${fontSize} !important;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
export function persistOneOsTheme(theme: OneOsTheme) {
|
||||
try {
|
||||
window.localStorage.setItem(ONEOS_THEME_STORAGE_KEY, theme);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
export function syncRuoYiSettingsToAllIframes(settings: RuoYiSettings) {
|
||||
if (typeof document === 'undefined') return;
|
||||
const frames = document.querySelectorAll('iframe');
|
||||
frames.forEach((frame) => {
|
||||
try {
|
||||
if (frame.contentDocument) {
|
||||
applyRuoYiSettingsToDocument(frame.contentDocument, settings);
|
||||
}
|
||||
} catch {
|
||||
/* ignore cross-origin */
|
||||
}
|
||||
|
||||
try {
|
||||
const isDark =
|
||||
settings.themeMode === 'dark' ||
|
||||
(settings.themeMode === 'system' &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
frame.contentWindow?.postMessage(
|
||||
{
|
||||
type: ONEOS_THEME_MESSAGE,
|
||||
theme: isDark ? 'dark' : 'light',
|
||||
settings,
|
||||
},
|
||||
'*',
|
||||
);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function broadcastOneOsTheme(theme: OneOsTheme) {
|
||||
@@ -63,20 +141,24 @@ export function broadcastOneOsTheme(theme: OneOsTheme) {
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
const frames = document.querySelectorAll('iframe');
|
||||
frames.forEach((frame) => {
|
||||
try {
|
||||
frame.contentWindow?.postMessage({ type: ONEOS_THEME_MESSAGE, theme }, '*');
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
});
|
||||
const settings = readStoredRuoYiSettings();
|
||||
syncRuoYiSettingsToAllIframes({ ...settings, themeMode: theme });
|
||||
}
|
||||
|
||||
export function applyOneOsTheme(theme: OneOsTheme, root: HTMLElement = document.documentElement) {
|
||||
const current = readStoredRuoYiSettings();
|
||||
const nextSettings: RuoYiSettings = {
|
||||
...current,
|
||||
themeMode: theme,
|
||||
};
|
||||
persistRuoYiSettings(nextSettings);
|
||||
applyRuoYiSettingsToDocument(root.ownerDocument || document, nextSettings);
|
||||
}
|
||||
|
||||
export function setOneOsTheme(theme: OneOsTheme) {
|
||||
applyOneOsTheme(theme);
|
||||
persistOneOsTheme(theme);
|
||||
broadcastOneOsTheme(theme);
|
||||
const settings = readStoredRuoYiSettings();
|
||||
syncRuoYiSettingsToAllIframes({ ...settings, themeMode: theme });
|
||||
}
|
||||
|
||||
export function toggleOneOsTheme(current?: OneOsTheme): OneOsTheme {
|
||||
@@ -87,7 +169,6 @@ export function toggleOneOsTheme(current?: OneOsTheme): OneOsTheme {
|
||||
|
||||
type BootstrapOptions = {
|
||||
prototypeId?: string;
|
||||
/** 强制跳过(如旧 ONEOS) */
|
||||
skip?: boolean;
|
||||
};
|
||||
|
||||
@@ -98,25 +179,24 @@ export function bootstrapOneOsTheme(options: BootstrapOptions = {}) {
|
||||
if (typeof window === 'undefined') return;
|
||||
if (options.skip || isLegacyOneOsPrototype(options.prototypeId)) return;
|
||||
|
||||
const fromQuery = new URLSearchParams(window.location.search).get('oneosTheme');
|
||||
const initial: OneOsTheme =
|
||||
fromQuery === 'dark' || fromQuery === 'light' ? fromQuery : readStoredOneOsTheme();
|
||||
|
||||
applyOneOsTheme(initial);
|
||||
persistOneOsTheme(initial);
|
||||
const currentSettings = readStoredRuoYiSettings();
|
||||
applyRuoYiSettingsToDocument(document, currentSettings);
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
const data = event.data;
|
||||
if (!data || data.type !== ONEOS_THEME_MESSAGE) return;
|
||||
if (data.theme !== 'dark' && data.theme !== 'light') return;
|
||||
applyOneOsTheme(data.theme);
|
||||
persistOneOsTheme(data.theme);
|
||||
|
||||
if (data.settings) {
|
||||
applyRuoYiSettingsToDocument(document, data.settings);
|
||||
} else if (data.theme === 'dark' || data.theme === 'light') {
|
||||
applyRuoYiSettingsToDocument(document, { themeMode: data.theme });
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('storage', (event) => {
|
||||
if (event.key !== ONEOS_THEME_STORAGE_KEY) return;
|
||||
if (event.newValue === 'dark' || event.newValue === 'light') {
|
||||
applyOneOsTheme(event.newValue);
|
||||
if (event.key === RUOYI_SETTINGS_STORAGE_KEY) {
|
||||
const nextSettings = readStoredRuoYiSettings();
|
||||
applyRuoYiSettingsToDocument(document, nextSettings);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user