1254 lines
48 KiB
JavaScript
1254 lines
48 KiB
JavaScript
/**
|
||
* GERP.js - GERP 业务逻辑层
|
||
* 仅负责业务逻辑,所有 UI 操作通过 GERPUI 框架完成
|
||
*/
|
||
|
||
class GERP {
|
||
constructor(config = {}) {
|
||
this.Config = {
|
||
DefaultPage: config.DefaultPage || 'pages/dashboard.html',
|
||
DefaultTitle: config.DefaultTitle || '仪表盘',
|
||
Title: config.Title || 'GERP 管理系统',
|
||
...config
|
||
};
|
||
|
||
this.State = {
|
||
CurrentUser: null,
|
||
Notifications: [],
|
||
Permissions: [],
|
||
RoleScope: null, // {Type, TypeLabel, IsAdmin, IsDeptManager, IsWorkgroupLead, IsMember, DeptUUID, WorkgroupUUID}
|
||
IsAdmin: false
|
||
};
|
||
|
||
this.API = {
|
||
BaseURL: 'https://ugm.gvsds.com',
|
||
Request: this._ApiRequest.bind(this),
|
||
UserInfo: this._UserInfo.bind(this)
|
||
};
|
||
|
||
this.UI = null;
|
||
this.PopupManager = null;
|
||
this.Init();
|
||
}
|
||
|
||
async _ApiRequest(url, options = {}) {
|
||
const { method = 'GET', body = null, headers = {} } = options;
|
||
|
||
try {
|
||
const response = await fetch(url, {
|
||
method,
|
||
credentials: 'include',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
...headers
|
||
},
|
||
body: body ? JSON.stringify(body) : null
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.code === 0) {
|
||
return { success: true, data: result };
|
||
} else {
|
||
return { success: false, message: result.msg || '请求失败' };
|
||
}
|
||
} catch (error) {
|
||
return { success: false, message: error.message || '网络错误' };
|
||
}
|
||
}
|
||
|
||
_SetupTimezoneHeader() {
|
||
// 显示用户时区
|
||
const tzText = document.getElementById('GERPTZText');
|
||
if (tzText) {
|
||
const userTZ = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||
const offset = -new Date().getTimezoneOffset() / 60;
|
||
const offsetStr = offset >= 0 ? `+${offset}` : `${offset}`;
|
||
tzText.textContent = `UTC${offsetStr}`;
|
||
}
|
||
|
||
const originalFetch = window.fetch;
|
||
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||
const currentHost = window.location.hostname;
|
||
let _eltExpiredShown = false;
|
||
let _refreshing = null;
|
||
|
||
function _tryRefreshToken() {
|
||
if (_refreshing) return _refreshing;
|
||
_refreshing = originalFetch.call(window, 'https://ugm.gvsds.com/Auth/RefreshToken', {
|
||
method: 'POST',
|
||
credentials: 'include',
|
||
headers: { 'Content-Type': 'application/json' }
|
||
}).then(res => res.json()).then(result => {
|
||
_refreshing = null;
|
||
return result.code === 0;
|
||
}).catch(() => {
|
||
_refreshing = null;
|
||
return false;
|
||
});
|
||
return _refreshing;
|
||
}
|
||
|
||
window.fetch = function(url, options = {}) {
|
||
if (typeof url === 'string') {
|
||
let isSameOrigin = url.startsWith('/API/') || url.startsWith('/');
|
||
if (!isSameOrigin) {
|
||
try {
|
||
const u = new URL(url);
|
||
isSameOrigin = u.hostname === currentHost;
|
||
} catch(e) {}
|
||
}
|
||
if (isSameOrigin) {
|
||
options.headers = options.headers || {};
|
||
if (options.headers instanceof Headers) {
|
||
if (!options.headers.has('X-User-Timezone')) {
|
||
options.headers.set('X-User-Timezone', userTimezone);
|
||
}
|
||
} else {
|
||
options.headers['X-User-Timezone'] = options.headers['X-User-Timezone'] || userTimezone;
|
||
}
|
||
}
|
||
}
|
||
return originalFetch.call(this, url, options).then(response => {
|
||
if (!_eltExpiredShown && response.status === 401) {
|
||
return _tryRefreshToken().then(ok => {
|
||
if (ok) {
|
||
return originalFetch.call(this, url, options);
|
||
}
|
||
_eltExpiredShown = true;
|
||
GERP.ShowELTExpiredDialog();
|
||
return response;
|
||
});
|
||
}
|
||
if (!_eltExpiredShown && response.redirected) {
|
||
try {
|
||
const redirectUrl = new URL(response.url);
|
||
if (redirectUrl.pathname.includes('login') || redirectUrl.pathname.includes('Login')) {
|
||
_eltExpiredShown = true;
|
||
GERP.ShowELTExpiredDialog();
|
||
}
|
||
} catch(e) {}
|
||
}
|
||
return response;
|
||
});
|
||
};
|
||
}
|
||
|
||
static ShowELTExpiredDialog() {
|
||
const existing = document.getElementById('GERPELTExpiredOverlay');
|
||
if (existing) return;
|
||
const overlay = document.createElement('div');
|
||
overlay.id = 'GERPELTExpiredOverlay';
|
||
overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:999999;display:flex;align-items:center;justify-content:center;';
|
||
const dialog = document.createElement('div');
|
||
dialog.style.cssText = 'background:var(--CardBackground,#fff);border-radius:12px;padding:32px;max-width:420px;width:90%;box-shadow:0 20px 60px rgba(0,0,0,0.3);text-align:center;';
|
||
dialog.innerHTML = `
|
||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(239,68,68,0.1);display:flex;align-items:center;justify-content:center;margin:0 auto 20px;">
|
||
<i class="fas fa-lock" style="font-size:28px;color:#ef4444;"></i>
|
||
</div>
|
||
<h3 style="margin:0 0 12px;font-size:18px;color:var(--TextPrimary,#1e293b);">登录已失效</h3>
|
||
<p style="margin:0 0 24px;font-size:14px;color:var(--TextSecondary,#64748b);line-height:1.6;">您的登录凭证已过期或无效,请重新登录以继续操作。</p>
|
||
<button id="GERPELTExpiredReloginBtn" style="width:100%;padding:12px;border:none;border-radius:8px;background:var(--PrimaryColor,#2563eb);color:#fff;font-size:15px;font-weight:500;cursor:pointer;transition:opacity 0.2s;">重新登录</button>
|
||
`;
|
||
overlay.appendChild(dialog);
|
||
document.body.appendChild(overlay);
|
||
document.getElementById('GERPELTExpiredReloginBtn').addEventListener('click', () => {
|
||
const currentUrl = window.location.href;
|
||
window.location.href = `https://www.gvsds.com/login.html?redirect=${encodeURIComponent(currentUrl)}`;
|
||
});
|
||
document.getElementById('GERPELTExpiredReloginBtn').addEventListener('mouseover', function() {
|
||
this.style.opacity = '0.9';
|
||
});
|
||
document.getElementById('GERPELTExpiredReloginBtn').addEventListener('mouseout', function() {
|
||
this.style.opacity = '1';
|
||
});
|
||
}
|
||
|
||
async _UserInfo() {
|
||
return await this.API.Request(`${this.API.BaseURL}/Query/GetELTUserInfo`);
|
||
}
|
||
|
||
Init() {
|
||
this._SetupTimezoneHeader();
|
||
|
||
// 等待 GERPUI 初始化完成
|
||
if (window.GERPUI) {
|
||
this.SetupUI();
|
||
} else {
|
||
document.addEventListener('GERPUIReady', () => this.SetupUI());
|
||
}
|
||
}
|
||
|
||
// 模型 i18n 已由后端 FormAPI 通过 verbose_name 直接提供(column.title),
|
||
// 不再需要单独加载 i18n/models/ 接口
|
||
|
||
SetupUI() {
|
||
this.UI = window.GERPUI;
|
||
|
||
// 应用用户设置
|
||
this.ApplySettings();
|
||
|
||
// 初始化弹出层管理器
|
||
this.InitPopupManager();
|
||
|
||
// 绑定 UI 事件到业务逻辑
|
||
this.BindUIEvents();
|
||
|
||
// 绑定导航按钮事件
|
||
this.BindNavEvents();
|
||
|
||
// 初始化菜单数据
|
||
this.InitMenuData();
|
||
|
||
// 打开默认页面
|
||
this.OpenDefaultTab();
|
||
|
||
// 加载用户数据
|
||
this.LoadUserData();
|
||
|
||
// 加载通知
|
||
this.LoadNotifications();
|
||
}
|
||
|
||
// 从服务器加载并应用用户设置
|
||
async ApplySettings() {
|
||
const defaultSettings = {
|
||
themeMode: 'default',
|
||
sidebarExpanded: true, maxTabs: 20,
|
||
allowDuplicate: false, confirmClose: false,
|
||
desktopNotify: true, notifySound: true,
|
||
animations: true, preload: true
|
||
};
|
||
|
||
let settings = defaultSettings;
|
||
|
||
// 优先从服务器加载
|
||
try {
|
||
const resp = await fetch('/API/Settings');
|
||
const result = await resp.json();
|
||
if (result.code === 0 && result.data && Object.keys(result.data).length > 0) {
|
||
settings = { ...defaultSettings, ...result.data };
|
||
}
|
||
} catch (e) {
|
||
// 网络异常时回退到本地存储
|
||
try {
|
||
const saved = localStorage.getItem('GERPSettings');
|
||
if (saved) settings = { ...defaultSettings, ...JSON.parse(saved) };
|
||
} catch (e2) {}
|
||
}
|
||
|
||
this._ApplySettingsData(settings);
|
||
}
|
||
|
||
// 应用设置数据到 DOM 和 UI 配置
|
||
_ApplySettingsData(settings) {
|
||
// 应用动画
|
||
if (!settings.animations) {
|
||
document.documentElement.style.setProperty('--TransitionSpeed', '0s');
|
||
document.documentElement.style.setProperty('--AnimationDuration', '0s');
|
||
document.body.classList.add('GERPNoAnimations');
|
||
}
|
||
|
||
// 应用到 UI 配置
|
||
if (this.UI) {
|
||
this.UI.Config.MaxTabs = settings.maxTabs;
|
||
}
|
||
|
||
// 应用侧边栏状态
|
||
if (this.UI && this.UI.SetSidebarCollapsed) {
|
||
this.UI.SetSidebarCollapsed(!settings.sidebarExpanded);
|
||
}
|
||
|
||
// 保存引用供子页面查询
|
||
this._Settings = settings;
|
||
}
|
||
|
||
// 初始化弹出层管理器
|
||
InitPopupManager() {
|
||
this.PopupManager = {
|
||
popups: new Set(),
|
||
rafId: null,
|
||
lastScrollY: window.scrollY,
|
||
lastScrollX: window.scrollX,
|
||
lastInnerHeight: window.innerHeight,
|
||
lastInnerWidth: window.innerWidth,
|
||
|
||
// 注册弹出层
|
||
register(popup) {
|
||
this.popups.add(popup);
|
||
this.startMonitoring();
|
||
},
|
||
|
||
// 注销弹出层
|
||
unregister(popup) {
|
||
this.popups.delete(popup);
|
||
if (this.popups.size === 0) {
|
||
this.stopMonitoring();
|
||
}
|
||
},
|
||
|
||
// 开始监控
|
||
startMonitoring() {
|
||
if (this.rafId) return;
|
||
|
||
const monitor = () => {
|
||
// 检测视口变化
|
||
const scrollY = window.scrollY;
|
||
const scrollX = window.scrollX;
|
||
const innerHeight = window.innerHeight;
|
||
const innerWidth = window.innerWidth;
|
||
|
||
const hasChange = (
|
||
scrollY !== this.lastScrollY ||
|
||
scrollX !== this.lastScrollX ||
|
||
innerHeight !== this.lastInnerHeight ||
|
||
innerWidth !== this.lastInnerWidth
|
||
);
|
||
|
||
if (hasChange) {
|
||
this.lastScrollY = scrollY;
|
||
this.lastScrollX = scrollX;
|
||
this.lastInnerHeight = innerHeight;
|
||
this.lastInnerWidth = innerWidth;
|
||
|
||
// 更新所有弹出层位置
|
||
this.updateAllPositions();
|
||
}
|
||
|
||
this.rafId = requestAnimationFrame(monitor);
|
||
};
|
||
|
||
this.rafId = requestAnimationFrame(monitor);
|
||
},
|
||
|
||
// 停止监控
|
||
stopMonitoring() {
|
||
if (this.rafId) {
|
||
cancelAnimationFrame(this.rafId);
|
||
this.rafId = null;
|
||
}
|
||
},
|
||
|
||
// 更新所有弹出层位置
|
||
updateAllPositions() {
|
||
this.popups.forEach(popup => {
|
||
if (popup && typeof popup.updatePosition === 'function') {
|
||
try {
|
||
popup.updatePosition();
|
||
} catch (e) {
|
||
// 忽略错误
|
||
}
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
// 监听 iframe 内容滚动(通过 postMessage)
|
||
window.addEventListener('message', (e) => {
|
||
if (e.data && e.data.type === 'IFRAME_SCROLL') {
|
||
this.PopupManager.updateAllPositions();
|
||
}
|
||
});
|
||
|
||
// 初始化主题管理器
|
||
this.InitThemeManager();
|
||
|
||
// 初始化全局主题同步(供子页面使用)
|
||
this.InitGlobalThemeSync();
|
||
}
|
||
|
||
// 初始化主题管理器
|
||
InitThemeManager() {
|
||
this.ThemeManager = {
|
||
themes: {
|
||
default: {
|
||
name: '默认主题',
|
||
colors: {
|
||
PrimaryColor: '#2563eb',
|
||
PrimaryHover: '#1d4ed8',
|
||
SecondaryColor: '#64748b',
|
||
SuccessColor: '#10b981',
|
||
WarningColor: '#f59e0b',
|
||
DangerColor: '#ef4444',
|
||
BackgroundColor: '#f1f5f9',
|
||
CardBackground: '#ffffff',
|
||
TextPrimary: '#1e293b',
|
||
TextSecondary: '#64748b',
|
||
TextMuted: '#94a3b8',
|
||
BorderColor: '#e2e8f0'
|
||
}
|
||
},
|
||
dark: {
|
||
name: '深色主题',
|
||
colors: {
|
||
PrimaryColor: '#3b82f6',
|
||
PrimaryHover: '#2563eb',
|
||
SecondaryColor: '#94a3b8',
|
||
SuccessColor: '#22c55e',
|
||
WarningColor: '#eab308',
|
||
DangerColor: '#ef4444',
|
||
BackgroundColor: '#0f172a',
|
||
CardBackground: '#1e293b',
|
||
TextPrimary: '#f1f5f9',
|
||
TextSecondary: '#94a3b8',
|
||
TextMuted: '#64748b',
|
||
BorderColor: '#334155'
|
||
}
|
||
},
|
||
light: {
|
||
name: '浅色主题',
|
||
colors: {
|
||
PrimaryColor: '#0ea5e9',
|
||
PrimaryHover: '#0284c7',
|
||
SecondaryColor: '#71717a',
|
||
SuccessColor: '#22c55e',
|
||
WarningColor: '#f59e0b',
|
||
DangerColor: '#ef4444',
|
||
BackgroundColor: '#fafafa',
|
||
CardBackground: '#ffffff',
|
||
TextPrimary: '#18181b',
|
||
TextSecondary: '#71717a',
|
||
TextMuted: '#a1a1aa',
|
||
BorderColor: '#e4e4e7'
|
||
}
|
||
},
|
||
green: {
|
||
name: '绿色主题',
|
||
colors: {
|
||
PrimaryColor: '#10b981',
|
||
PrimaryHover: '#059669',
|
||
SecondaryColor: '#6b7280',
|
||
SuccessColor: '#22c55e',
|
||
WarningColor: '#f59e0b',
|
||
DangerColor: '#ef4444',
|
||
BackgroundColor: '#f0fdf4',
|
||
CardBackground: '#ffffff',
|
||
TextPrimary: '#14532d',
|
||
TextSecondary: '#4b5563',
|
||
TextMuted: '#9ca3af',
|
||
BorderColor: '#d1fae5'
|
||
}
|
||
},
|
||
purple: {
|
||
name: '紫色主题',
|
||
colors: {
|
||
PrimaryColor: '#8b5cf6',
|
||
PrimaryHover: '#7c3aed',
|
||
SecondaryColor: '#6b7280',
|
||
SuccessColor: '#10b981',
|
||
WarningColor: '#f59e0b',
|
||
DangerColor: '#ef4444',
|
||
BackgroundColor: '#faf5ff',
|
||
CardBackground: '#ffffff',
|
||
TextPrimary: '#3b0764',
|
||
TextSecondary: '#4b5563',
|
||
TextMuted: '#9ca3af',
|
||
BorderColor: '#ede9fe'
|
||
}
|
||
},
|
||
red: {
|
||
name: '红色主题',
|
||
colors: {
|
||
PrimaryColor: '#ef4444',
|
||
PrimaryHover: '#dc2626',
|
||
SecondaryColor: '#6b7280',
|
||
SuccessColor: '#10b981',
|
||
WarningColor: '#f59e0b',
|
||
DangerColor: '#b91c1c',
|
||
BackgroundColor: '#fef2f2',
|
||
CardBackground: '#ffffff',
|
||
TextPrimary: '#450a0a',
|
||
TextSecondary: '#4b5563',
|
||
TextMuted: '#9ca3af',
|
||
BorderColor: '#fee2e2'
|
||
}
|
||
}
|
||
},
|
||
currentTheme: 'default',
|
||
|
||
// 切换主题
|
||
setTheme(themeName) {
|
||
if (!this.themes[themeName]) {
|
||
console.warn(`主题 ${themeName} 不存在,使用默认主题`);
|
||
themeName = 'default';
|
||
}
|
||
|
||
const theme = this.themes[themeName];
|
||
const root = document.documentElement;
|
||
|
||
// 应用主题颜色到 CSS 变量
|
||
Object.entries(theme.colors).forEach(([key, value]) => {
|
||
root.style.setProperty(`--${key}`, value);
|
||
});
|
||
|
||
// 保存到 localStorage
|
||
localStorage.setItem('gerp-theme', themeName);
|
||
localStorage.setItem('gerp-theme-colors', JSON.stringify(theme.colors));
|
||
|
||
// 更新当前主题
|
||
this.currentTheme = themeName;
|
||
|
||
// 触发主题切换事件
|
||
window.dispatchEvent(new CustomEvent('themeChange', {
|
||
detail: { theme: themeName, colors: theme.colors }
|
||
}));
|
||
|
||
// 通知所有子页面(iframe)更新主题
|
||
this.NotifyChildFrames(themeName, theme.colors);
|
||
|
||
// 通知父页面(如果存在)
|
||
if (window.parent && window.parent !== window) {
|
||
window.parent.postMessage({
|
||
type: 'THEME_CHANGE_FROM_CHILD',
|
||
theme: themeName,
|
||
colors: theme.colors
|
||
}, '*');
|
||
}
|
||
|
||
return theme;
|
||
},
|
||
|
||
// 通知所有子页面(iframe)更新主题
|
||
NotifyChildFrames(themeName, colors) {
|
||
const iframes = document.querySelectorAll('iframe');
|
||
iframes.forEach(iframe => {
|
||
try {
|
||
iframe.contentWindow.postMessage({
|
||
type: 'THEME_CHANGE',
|
||
theme: themeName,
|
||
colors: colors
|
||
}, '*');
|
||
} catch (e) {
|
||
console.warn('无法通知子页面:', e);
|
||
}
|
||
});
|
||
},
|
||
|
||
// 获取当前主题
|
||
getTheme() {
|
||
return this.themes[this.currentTheme];
|
||
},
|
||
|
||
// 获取所有主题
|
||
getAllThemes() {
|
||
return this.themes;
|
||
},
|
||
|
||
// 加载保存的主题
|
||
loadSavedTheme() {
|
||
const savedTheme = localStorage.getItem('gerp-theme');
|
||
if (savedTheme && this.themes[savedTheme]) {
|
||
this.setTheme(savedTheme);
|
||
} else {
|
||
this.setTheme('default');
|
||
}
|
||
}
|
||
};
|
||
|
||
// 页面加载时自动应用保存的主题
|
||
this.ThemeManager.loadSavedTheme();
|
||
|
||
// 监听主题变化并同步到子页面
|
||
window.addEventListener('message', (e) => {
|
||
if (e.data && e.data.type === 'THEME_CHANGE' && e.data.colors) {
|
||
const root = document.documentElement;
|
||
Object.entries(e.data.colors).forEach(([key, value]) => {
|
||
root.style.setProperty(`--${key}`, value);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// 初始化全局主题同步(供子页面使用)
|
||
InitGlobalThemeSync() {
|
||
// 提供给子页面使用的全局主题同步函数
|
||
window.GERPThemeSync = {
|
||
// 初始化主题同步
|
||
init() {
|
||
const root = document.documentElement;
|
||
|
||
// 从localStorage读取并应用保存的主题
|
||
this.applySavedTheme();
|
||
|
||
// 监听来自父页面的主题变化消息
|
||
window.addEventListener('message', (e) => {
|
||
const { type, data } = e.data || {};
|
||
|
||
if (type === 'THEME_CHANGE' && data && data.colors) {
|
||
Object.entries(data.colors).forEach(([key, value]) => {
|
||
root.style.setProperty(`--${key}`, value);
|
||
});
|
||
// 保存到localStorage
|
||
localStorage.setItem('gerp-theme', data.theme);
|
||
localStorage.setItem('gerp-theme-colors', JSON.stringify(data.colors));
|
||
}
|
||
|
||
if (type === 'THEME_RESPONSE' && data && data.colors) {
|
||
Object.entries(data.colors).forEach(([key, value]) => {
|
||
root.style.setProperty(`--${key}`, value);
|
||
});
|
||
// 保存到localStorage
|
||
localStorage.setItem('gerp-theme', data.theme);
|
||
localStorage.setItem('gerp-theme-colors', JSON.stringify(data.colors));
|
||
}
|
||
});
|
||
|
||
// 页面加载时向父页面请求当前主题
|
||
if (window.parent && window.parent !== window) {
|
||
window.parent.postMessage({ type: 'GET_THEME' }, '*');
|
||
}
|
||
},
|
||
|
||
// 应用保存的主题
|
||
applySavedTheme() {
|
||
const root = document.documentElement;
|
||
const themeColors = localStorage.getItem('gerp-theme-colors');
|
||
if (themeColors) {
|
||
try {
|
||
const colors = JSON.parse(themeColors);
|
||
Object.entries(colors).forEach(([key, value]) => {
|
||
root.style.setProperty(`--${key}`, value);
|
||
});
|
||
} catch (e) {
|
||
console.warn('无法解析主题颜色:', e);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
// 绑定 UI 框架事件
|
||
BindUIEvents() {
|
||
// 菜单点击 - 打开 Tab
|
||
this.UI.On('menuClick', (data) => {
|
||
const icon = this.UI.ExtractIconClass(
|
||
document.querySelector(`[data-id="${data.id}"] .GERPMenuIcon`)?.innerHTML
|
||
);
|
||
this.UI.OpenTab({
|
||
page: data.page,
|
||
title: data.title,
|
||
icon: icon
|
||
}, this.UI.State.ActivePanelId);
|
||
});
|
||
|
||
// Tab 激活 - 更新标题
|
||
this.UI.On('tabActivate', (data) => {
|
||
this.UI.SetTitle(data.tab.Title);
|
||
});
|
||
|
||
// Tab 关闭
|
||
this.UI.On('tabClose', (tab) => {
|
||
});
|
||
|
||
// Tab 为空
|
||
this.UI.On('tabEmpty', () => {
|
||
this.UI.LoadFrame('');
|
||
this.UI.SetTitle('');
|
||
});
|
||
|
||
// 侧边栏切换
|
||
this.UI.On('sidebarToggle', (state) => {
|
||
});
|
||
|
||
// 用户操作
|
||
this.UI.On('userAction', (action) => {
|
||
this.HandleUserAction(action);
|
||
});
|
||
}
|
||
|
||
// 绑定导航按钮事件
|
||
BindNavEvents() {
|
||
// 搜索按钮
|
||
this.UI.Elements.SearchBtn?.addEventListener('click', () => {
|
||
this.OpenSearch();
|
||
});
|
||
|
||
// 通知按钮 - hover 触发
|
||
let notifyTimeout;
|
||
this.UI.Elements.NotifyBtn?.addEventListener('mouseenter', () => {
|
||
notifyTimeout = setTimeout(() => this.OpenNotifyPanel(), 150);
|
||
});
|
||
this.UI.Elements.NotifyBtn?.addEventListener('mouseleave', () => {
|
||
clearTimeout(notifyTimeout);
|
||
});
|
||
|
||
// 设置按钮 - 统一打开设置页面
|
||
this.UI.Elements.SettingsBtn?.addEventListener('click', () => {
|
||
this.OpenSettingsPage();
|
||
});
|
||
|
||
// 侧边栏设置按钮 - 统一打开设置页面
|
||
this.UI.Elements.SidebarSettingsBtn?.addEventListener('click', () => {
|
||
this.OpenSettingsPage();
|
||
});
|
||
|
||
// 用户信息 - hover 触发
|
||
let userTimeout;
|
||
this.UI.Elements.UserInfo?.addEventListener('mouseenter', () => {
|
||
userTimeout = setTimeout(() => this.OpenUserDropdown(), 150);
|
||
});
|
||
this.UI.Elements.UserInfo?.addEventListener('mouseleave', () => {
|
||
clearTimeout(userTimeout);
|
||
});
|
||
|
||
// 侧边栏切换按钮
|
||
this.UI.Elements.ToggleBtn?.addEventListener('click', () => {
|
||
this.UI.ToggleSidebar();
|
||
});
|
||
|
||
// 遮罩层点击
|
||
this.UI.Elements.Overlay?.addEventListener('click', () => {
|
||
this.UI.CloseSidebar();
|
||
});
|
||
}
|
||
|
||
// 初始化菜单数据
|
||
async InitMenuData() {
|
||
// 先加载角色作用域(用于默认菜单差异化)
|
||
if (!this.State.RoleScope) {
|
||
await this.LoadRoleScope();
|
||
}
|
||
fetch('/API/MenuList', { credentials: 'include' })
|
||
.then(res => res.json())
|
||
.then(result => {
|
||
if (result.code === 0 && result.data && result.data.length > 0) {
|
||
this.UI.SetMenuData(result.data);
|
||
} else {
|
||
this.UI.SetMenuData(this._getDefaultMenuData());
|
||
}
|
||
})
|
||
.catch(() => {
|
||
this.UI.SetMenuData(this._getDefaultMenuData());
|
||
});
|
||
}
|
||
|
||
// 加载角色作用域(用于前端差异化显示)
|
||
async LoadRoleScope() {
|
||
try {
|
||
const res = await fetch('/API/FormAPI/CheckAdmin', { credentials: 'include' });
|
||
const result = await res.json();
|
||
if (result.code === 0 && result.data) {
|
||
this.State.RoleScope = result.data.role_scope || null;
|
||
this.State.IsAdmin = !!(result.data.is_admin || result.data.is_superuser);
|
||
}
|
||
} catch(e) {
|
||
this.State.RoleScope = null;
|
||
this.State.IsAdmin = false;
|
||
}
|
||
}
|
||
|
||
_getDefaultMenuData() {
|
||
const scope = this.State.RoleScope;
|
||
const scopeType = scope?.Type || 'member';
|
||
const isAdmin = scopeType === 'admin';
|
||
const isDeptManager = scopeType === 'dept_manager';
|
||
const isWorkgroupLead = scopeType === 'workgroup_lead';
|
||
const isOrgManager = isAdmin || isDeptManager || isWorkgroupLead;
|
||
|
||
// 仪表盘:所有角色都可见
|
||
const menus = [
|
||
{
|
||
Id: 'dashboard',
|
||
Title: '仪表盘',
|
||
Icon: '<i class="fas fa-chart-line"></i>',
|
||
Page: 'pages/dashboard.html'
|
||
}
|
||
];
|
||
|
||
// 公司资产:所有角色都可见(原"系统设置"改名,资产管理挪入此)
|
||
// admin 还包含租户/审计/支付/系统配置等系统层面设置
|
||
const companyAssetsChildren = [
|
||
{ Id: 'system-assets', Title: '资产管理', Icon: '<i class="fas fa-images"></i>', Page: 'pages/assets/manager.html' }
|
||
];
|
||
if (isAdmin) {
|
||
companyAssetsChildren.push(
|
||
{ Id: 'system-tenant', Title: '租户管理', Icon: '<i class="fas fa-layer-group"></i>', Page: 'pages/Company/tenant.html' },
|
||
{ Id: 'system-tenant-apply', Title: '租户入驻申请', Icon: '<i class="fas fa-key"></i>', Page: 'pages/system/tenant-create.html' },
|
||
{ Id: 'system-tenant-review', Title: '租户审核工作台', Icon: '<i class="fas fa-clipboard-check"></i>', Page: 'pages/system/tenant-review.html' },
|
||
{ Id: 'system-audit-log', Title: '操作审计日志', Icon: '<i class="fas fa-history"></i>', Page: 'pages/system/audit-log.html' },
|
||
{ Id: 'system-payment-config', Title: '支付网关配置', Icon: '<i class="fas fa-credit-card"></i>', Page: 'pages/system/payment-config.html' },
|
||
{ Id: 'system-config', Title: '系统配置', Icon: '<i class="fas fa-tools"></i>', Page: 'pages/system/settings.html' }
|
||
);
|
||
} else if (isDeptManager || isWorkgroupLead) {
|
||
companyAssetsChildren.push(
|
||
{ Id: 'system-tenant-apply', Title: '租户入驻申请', Icon: '<i class="fas fa-key"></i>', Page: 'pages/system/tenant-create.html' }
|
||
);
|
||
}
|
||
menus.push({
|
||
Id: 'company-assets',
|
||
Title: '公司资产',
|
||
Icon: '<i class="fas fa-boxes"></i>',
|
||
Expanded: false,
|
||
Children: companyAssetsChildren
|
||
});
|
||
|
||
// 业务管理:所有角色都可见(销售订单 + 产品管理)
|
||
menus.push({
|
||
Id: 'business',
|
||
Title: '业务管理',
|
||
Icon: '<i class="fas fa-briefcase"></i>',
|
||
Expanded: false,
|
||
Children: [
|
||
{ Id: 'sales-orders', Title: '销售订单', Icon: '<i class="fas fa-shopping-cart"></i>', Page: 'pages/sales/orders.html' },
|
||
{ Id: 'inventory-products', Title: '产品管理', Icon: '<i class="fas fa-box"></i>', Page: 'pages/inventory/products.html' }
|
||
]
|
||
});
|
||
|
||
// 组织管理:admin/dept_manager/workgroup_lead 可见
|
||
// 归集公司/部门/工作组/角色/成员/职务等组织相关功能
|
||
if (isOrgManager) {
|
||
const orgChildren = [];
|
||
if (isAdmin) {
|
||
orgChildren.push({ Id: 'org-company', Title: '公司管理', Icon: '<i class="fas fa-building"></i>', Page: 'pages/Company/company.html' });
|
||
}
|
||
orgChildren.push(
|
||
{ Id: 'org-department', Title: '部门管理', Icon: '<i class="fas fa-sitemap"></i>', Page: 'pages/Company/department.html' },
|
||
{ Id: 'org-workgroup', Title: '工作组管理', Icon: '<i class="fas fa-users-cog"></i>', Page: 'pages/Company/workgroup.html' },
|
||
{ Id: 'org-role', Title: '角色管理', Icon: '<i class="fas fa-shield-alt"></i>', Page: 'pages/Company/role.html' }
|
||
);
|
||
if (isAdmin) {
|
||
orgChildren.push({ Id: 'org-role-permissions', Title: '角色权限分配', Icon: '<i class="fas fa-sitemap"></i>', Page: 'pages/system/role-permissions.html' });
|
||
}
|
||
// 成员管理(pages/system/users.html 内置 role_scope 差异化:admin=用户管理/dept_manager=部门成员/workgroup_lead=工作组成员)
|
||
const memberMenuTitle = isAdmin ? '成员管理' :
|
||
(isDeptManager ? '部门成员' : '工作组成员');
|
||
orgChildren.push(
|
||
{ Id: 'org-employee', Title: memberMenuTitle, Icon: '<i class="fas fa-user"></i>', Page: 'pages/system/users.html' },
|
||
{ Id: 'org-position', Title: '职务管理', Icon: '<i class="fas fa-id-badge"></i>', Page: 'pages/system/dbtable.html?table=Position&title=职务管理' }
|
||
);
|
||
|
||
menus.push({
|
||
Id: 'org',
|
||
Title: '组织管理',
|
||
Icon: '<i class="fas fa-project-diagram"></i>',
|
||
Expanded: false,
|
||
Children: orgChildren
|
||
});
|
||
}
|
||
|
||
// 服务器管理:仅 admin 可见(含菜单编辑器)
|
||
if (isAdmin) {
|
||
menus.push({
|
||
Id: 'server',
|
||
Title: '服务器管理',
|
||
Icon: '<i class="fas fa-server"></i>',
|
||
Expanded: false,
|
||
Children: [
|
||
{ Id: 'server-database', Title: '数据库管理', Icon: '<i class="fas fa-database"></i>', Page: 'pages/system/database.html' },
|
||
{ Id: 'server-msync', Title: 'MSYNC 服务器', Icon: '<i class="fas fa-network-wired"></i>', Page: 'pages/system/msync-servers.html' },
|
||
{ Id: 'server-menu', Title: '菜单编辑器', Icon: '<i class="fas fa-bars"></i>', Page: 'pages/system/menu.html' }
|
||
]
|
||
});
|
||
}
|
||
// 普通组员:仅看到 仪表盘 + 公司资产(个人资料通过顶部头像菜单访问)
|
||
|
||
return menus;
|
||
}
|
||
|
||
// 打开默认 Tab(仅在主页时)
|
||
OpenDefaultTab() {
|
||
const currentPath = window.location.pathname;
|
||
const isHomePage = currentPath === '/' ||
|
||
currentPath === '/index.html' ||
|
||
currentPath === '/index';
|
||
|
||
if (!isHomePage) {
|
||
return;
|
||
}
|
||
|
||
this.UI.OpenTab({
|
||
page: this.Config.DefaultPage,
|
||
title: this.Config.DefaultTitle,
|
||
icon: 'fa-chart-line'
|
||
});
|
||
}
|
||
|
||
// 打开搜索
|
||
OpenSearch() {
|
||
const allMenuItems = this.FlattenMenu(this.UI.State.MenuData);
|
||
|
||
this.UI.OpenSearch({
|
||
placeholder: '搜索菜单、页面、功能...',
|
||
onSearch: (keyword) => {
|
||
if (!keyword.trim()) return [];
|
||
return allMenuItems
|
||
.filter(item => item.title.toLowerCase().includes(keyword.toLowerCase()))
|
||
.map(item => ({
|
||
id: item.id,
|
||
title: item.title,
|
||
path: item.path,
|
||
icon: this.UI.ExtractIconClass(item.icon)
|
||
}));
|
||
},
|
||
onSelect: (item) => {
|
||
if (item) {
|
||
this.UI.SetActiveMenu(item.id);
|
||
this.UI.OpenTab({
|
||
page: item.page,
|
||
title: item.title,
|
||
icon: this.UI.ExtractIconClass(item.icon)
|
||
});
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// 打开通知面板
|
||
OpenNotifyPanel() {
|
||
this.UI.OpenNotifyPanel({
|
||
notifications: this.State.Notifications,
|
||
onReadAll: () => {
|
||
fetch('/API/Message', {
|
||
method: 'PATCH',
|
||
credentials: 'include',
|
||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||
body: 'action=read_all'
|
||
}).then(r => r.json()).then(result => {
|
||
if (result.code === 0) {
|
||
this.State.UnreadCount = 0;
|
||
this.State.Notifications = [];
|
||
this.UpdateNotifyBadge();
|
||
}
|
||
});
|
||
},
|
||
onViewAll: () => {
|
||
this.UI.OpenTab({
|
||
page: 'pages/system/message.html',
|
||
title: '站内信',
|
||
icon: 'fa-envelope'
|
||
});
|
||
},
|
||
onItemClick: (msgId) => {
|
||
this.UI.OpenTab({
|
||
page: 'pages/system/message.html?id=' + msgId,
|
||
title: '站内信',
|
||
icon: 'fa-envelope'
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// 打开设置页面
|
||
OpenSettingsPage() {
|
||
this.UI.OpenTab({
|
||
page: 'pages/system/settings.html',
|
||
title: '系统设置',
|
||
icon: 'fa-cog'
|
||
});
|
||
}
|
||
|
||
// 打开用户下拉菜单
|
||
OpenUserDropdown() {
|
||
this.UI.OpenUserDropdown({
|
||
user: this.State.CurrentUser,
|
||
items: [
|
||
{ action: 'profile', label: '个人资料', icon: 'fa-user' },
|
||
{ action: 'password', label: '修改密码', icon: 'fa-key' },
|
||
{ action: 'logout', label: '退出登录', icon: 'fa-sign-out-alt', danger: true }
|
||
]
|
||
});
|
||
}
|
||
|
||
|
||
|
||
// 处理用户操作
|
||
HandleUserAction(action) {
|
||
switch (action) {
|
||
case 'profile':
|
||
this.UI.OpenTab({
|
||
page: 'pages/profile.html',
|
||
title: '个人资料',
|
||
icon: 'fa-user'
|
||
});
|
||
break;
|
||
case 'password':
|
||
this.ShowPasswordModal();
|
||
break;
|
||
case 'logout':
|
||
this.Logout();
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 显示修改密码弹窗
|
||
ShowPasswordModal() {
|
||
this.UI.OpenModal({
|
||
title: '修改密码',
|
||
content: `
|
||
<div style="padding: 20px;">
|
||
<div style="margin-bottom: 16px;">
|
||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">当前密码</label>
|
||
<input type="password" style="width: 100%; padding: 10px; border: 1px solid var(--BorderColor); border-radius: 8px;">
|
||
</div>
|
||
<div style="margin-bottom: 16px;">
|
||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">新密码</label>
|
||
<input type="password" style="width: 100%; padding: 10px; border: 1px solid var(--BorderColor); border-radius: 8px;">
|
||
</div>
|
||
<div style="margin-bottom: 16px;">
|
||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">确认新密码</label>
|
||
<input type="password" style="width: 100%; padding: 10px; border: 1px solid var(--BorderColor); border-radius: 8px;">
|
||
</div>
|
||
<button class="GERPBtn Primary" style="width: 100%;">确认修改</button>
|
||
</div>
|
||
`
|
||
});
|
||
}
|
||
|
||
// 退出登录
|
||
Logout() {
|
||
window.location.href = 'https://ugm.gvsds.com/Auth/DeleteAllCookies';
|
||
}
|
||
|
||
// 加载用户数据
|
||
async LoadUserData() {
|
||
const result = await this.API.UserInfo();
|
||
|
||
if (result.success) {
|
||
const user = result.data;
|
||
this.State.CurrentUser = {
|
||
uuid: user.UserUUID,
|
||
name: user.UserName,
|
||
gender: user.UserGender,
|
||
signature: user.UserPersonalSignature,
|
||
email: user.UserEmail,
|
||
tele: user.UserTele,
|
||
positionStatus: user.UserPositionStatus,
|
||
avatar: 'https://ugm.gvsds.com/Query/GetELTUserAvatar'
|
||
};
|
||
|
||
const userNameEl = document.querySelector('.GERPUserName');
|
||
if (userNameEl) {
|
||
userNameEl.textContent = user.UserName || '用户';
|
||
}
|
||
|
||
// 获取当前角色对应的公司名称,更新 Logo
|
||
this._UpdateLogoCompanyName();
|
||
} else {
|
||
console.error('加载用户信息失败:', result.message);
|
||
}
|
||
}
|
||
|
||
// 更新 Logo 显示当前角色所属公司名称
|
||
async _UpdateLogoCompanyName() {
|
||
try {
|
||
const res = await fetch('https://ugm.gvsds.com/Auth/GetUserRoles', {
|
||
method: 'GET',
|
||
credentials: 'include'
|
||
});
|
||
const result = await res.json();
|
||
if (result.code === 0 && result.data?.roles?.length) {
|
||
const activeRole = result.data.roles.find(r => r.active) || result.data.roles[0];
|
||
const logoText = document.querySelector('.GERPLogoText');
|
||
if (logoText && activeRole) {
|
||
const fullName = activeRole.CompanyName || '';
|
||
const shortName = activeRole.CompanyShort || '';
|
||
if (fullName && shortName) {
|
||
logoText.textContent = `${fullName}(${shortName})`;
|
||
} else {
|
||
logoText.textContent = fullName || shortName || activeRole.RoleName || '后台管理';
|
||
}
|
||
}
|
||
}
|
||
} catch (e) {
|
||
// 获取失败时保持默认文字
|
||
}
|
||
}
|
||
|
||
// 加载通知
|
||
LoadNotifications() {
|
||
fetch('/API/Message?action=unread_count', { credentials: 'include' })
|
||
.then(r => r.json())
|
||
.then(result => {
|
||
if (result.code === 0) {
|
||
this.State.UnreadCount = result.UnreadCount || 0;
|
||
this.State.Notifications = (result.RecentMessages || []).map(msg => ({
|
||
id: msg.MessageUUID,
|
||
icon: msg.MsgType === 0 ? 'fa-info-circle' : msg.MsgType === 1 ? 'fa-clipboard-check' : msg.MsgType === 2 ? 'fa-tools' : 'fa-envelope',
|
||
title: msg.Title,
|
||
text: msg.Content,
|
||
time: msg.CreateTime,
|
||
unread: true,
|
||
msgType: msg.MsgType,
|
||
sender: msg.SenderName
|
||
}));
|
||
this.UpdateNotifyBadge();
|
||
} else {
|
||
this.State.UnreadCount = 0;
|
||
this.State.Notifications = [];
|
||
this.UpdateNotifyBadge();
|
||
}
|
||
})
|
||
.catch(() => {
|
||
this.State.UnreadCount = 0;
|
||
this.State.Notifications = [];
|
||
this.UpdateNotifyBadge();
|
||
});
|
||
}
|
||
|
||
// 更新通知角标
|
||
UpdateNotifyBadge() {
|
||
const unreadCount = this.State.UnreadCount || 0;
|
||
const badge = this.UI.Elements.NotifyBtn?.querySelector('.GERPBadge');
|
||
if (badge) {
|
||
badge.textContent = unreadCount > 99 ? '99+' : unreadCount;
|
||
badge.style.display = unreadCount > 0 ? 'flex' : 'none';
|
||
}
|
||
}
|
||
|
||
// 扁平化菜单数据
|
||
FlattenMenu(items, path = '') {
|
||
let result = [];
|
||
items.forEach(item => {
|
||
const currentPath = path ? `${path} / ${item.Title}` : item.Title;
|
||
if (item.Page) {
|
||
result.push({
|
||
id: item.Id,
|
||
title: item.Title,
|
||
page: item.Page,
|
||
icon: item.Icon,
|
||
path: path
|
||
});
|
||
}
|
||
if (item.Children) {
|
||
result = result.concat(this.FlattenMenu(item.Children, currentPath));
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
|
||
// 静态方法:供子页面调用
|
||
static Navigate(page, title) {
|
||
if (window.parent !== window && window.parent.GERPApp && window.parent.GERPApp.UI) {
|
||
// 在 GERP 父框架内:通过 postMessage 通知父框架打开新标签页
|
||
window.parent.postMessage({ type: 'NAVIGATE', data: { page, title } }, '*');
|
||
} else {
|
||
// 非 GERP 父情况:在新标签页打开
|
||
window.open(page, '_blank');
|
||
}
|
||
}
|
||
|
||
static SetTitle(title) {
|
||
if (window.parent !== window && window.parent.GERPApp && window.parent.GERPApp.UI) {
|
||
window.parent.postMessage({ type: 'SET_TITLE', data: { title } }, '*');
|
||
} else {
|
||
document.title = title;
|
||
}
|
||
}
|
||
|
||
static Refresh() {
|
||
if (window.parent !== window && window.parent.GERPApp && window.parent.GERPApp.UI) {
|
||
window.parent.postMessage({ type: 'REFRESH' }, '*');
|
||
} else {
|
||
window.location.reload();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 自动初始化
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
window.GERPApp = new GERP();
|
||
});
|
||
|
||
// ==================== 全局主题同步功能 ===================
|
||
// 注意:GERPThemeSync.js 已提取为独立文件,供所有子页面使用
|
||
// 这里只处理父页面接收子页面主题变化的逻辑
|
||
|
||
// 全局主题监听器
|
||
window.addEventListener('message', (e) => {
|
||
const { type, data } = e.data || {};
|
||
|
||
// 处理来自子页面的主题请求
|
||
if (type === 'GET_THEME') {
|
||
const gerp = window.GERPApp;
|
||
if (gerp && gerp.ThemeManager) {
|
||
const theme = gerp.ThemeManager.getTheme();
|
||
const iframe = e.source;
|
||
if (iframe && theme) {
|
||
iframe.postMessage({
|
||
type: 'THEME_RESPONSE',
|
||
theme: gerp.ThemeManager.currentTheme,
|
||
colors: theme.colors
|
||
}, '*');
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 处理来自子页面的主题变化
|
||
if (type === 'THEME_CHANGE_FROM_CHILD') {
|
||
const gerp = window.GERPApp;
|
||
if (gerp && gerp.ThemeManager && data && data.colors) {
|
||
// 更新父页面的CSS变量
|
||
const root = document.documentElement;
|
||
Object.entries(data.colors).forEach(([key, value]) => {
|
||
root.style.setProperty(`--${key}`, value);
|
||
});
|
||
// 保存到localStorage
|
||
localStorage.setItem('gerp-theme', data.theme);
|
||
localStorage.setItem('gerp-theme-colors', JSON.stringify(data.colors));
|
||
// 通知其他子页面
|
||
gerp.ThemeManager.NotifyChildFrames(data.theme, data.colors);
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 处理来自设置页面的设置更新
|
||
if (type === 'SETTINGS_UPDATE') {
|
||
const gerp = window.GERPApp;
|
||
if (gerp && data) {
|
||
gerp._ApplySettingsData(data);
|
||
}
|
||
return;
|
||
}
|
||
});
|
||
|
||
// ==================== 监听 iframe 消息 ====================
|
||
window.addEventListener('message', (e) => {
|
||
const { type, data } = e.data || {};
|
||
const gerp = window.GERPApp;
|
||
|
||
if (!gerp || !gerp.UI) return;
|
||
|
||
switch (type) {
|
||
case 'NAVIGATE':
|
||
gerp.UI.OpenTab({
|
||
page: data.page,
|
||
title: data.title || '新页面'
|
||
});
|
||
break;
|
||
case 'SET_TITLE':
|
||
gerp.UI.SetTitle(data.title);
|
||
break;
|
||
case 'REFRESH':
|
||
gerp.UI.Elements.ContentFrame?.contentWindow.location.reload();
|
||
break;
|
||
}
|
||
});
|
||
|
||
/*
|
||
const styles = {
|
||
sysName: 'background: linear-gradient(90deg, #1c92d2, #f2fcfe); color: #fff; padding: 8px 15px; border-radius: 4px 0 0 4px; font-weight: bold; font-size: 14px; text-shadow: 1px 1px 2px #000;',
|
||
version: 'background: #00c6ff; background: -webkit-linear-gradient(to right, #0072ff, #00c6ff); background: linear-gradient(to right, #0072ff, #00c6ff); color: #fff; padding: 8px 15px; border-radius: 0 4px 4px 0; font-weight: bold; font-size: 14px;',
|
||
info: 'background: #f6ffed; color: #52c41a; padding: 5px 10px; border-left: 4px solid #52c41a; font-size: 12px; font-family: monospace;',
|
||
copyright: 'background: #333; color: #999; padding: 4px 10px; border-radius: 4px; font-size: 11px;',
|
||
warning: 'background: #fff2f0; color: #f5222d; padding: 5px 10px; border-left: 4px solid #f5222d; font-size: 12px; font-weight: bold;'
|
||
};
|
||
console.log("\n");
|
||
console.log(`%c GERP-GERP %c CORE V${this.version} `, styles.sysName, styles.version);
|
||
console.log(`%c GVSDS-GERP V${this.version} %c © 2026 GVSDS Inc.`, 'background:#35495e ; padding: 4px; border-radius: 3px 0 0 3px; color: #fff', 'background:#41b883 ; padding: 4px; border-radius: 0 3px 3px 0; color: #fff' );
|
||
console.log(`%c 银河锋锐ERP后台管理系统核心逻辑 | GVSDS TermiNexus Team `, styles.copyright);
|
||
console.log(`%c CORE INIT: LAYUI | JQUERY | MD5 | LAYER `, styles.info);
|
||
console.log(`%c ⚠️ LICENSE: INTERNAL USE ONLY. UNAUTHORIZED MODIFICATION OR DISTRIBUTION IS PROHIBITED. ⚠️ `, styles.warning);
|
||
console.log(
|
||
`%c 🚀 我们在招人,欢迎你来! ` +
|
||
`%c Quick Access %c https://invite.gvsds.com/`,
|
||
'background: linear-gradient(90deg, #FF512F 0%, #DD2476 100%); color: #fff; padding: 5px 10px; border-radius: 4px 0 0 4px; font-weight: bold.',
|
||
'background: #333; color: #fff; padding: 5px 10px; border-radius: 0 4px 4px 0;',
|
||
'color: #4CAF50; font-weight: bold; text-decoration: underline;'
|
||
);
|
||
console.log(`%c QQ 群: 1037453621`, styles.warning);
|
||
console.info( '%c System Check %c UserAgent: ' + navigator.userAgent, 'background: #00bcd4; color: white; padding: 4px; font-weight: bold;', 'color: #00bcd4; font-weight: bold;' );
|
||
console.log("\n");
|
||
|
||
window.GERPThemeSync.init();
|
||
*/ |