feat: add settings dialog with render mode selection
- Add SettingDialogManager with radio-style render mode picker (simple/balance/advanced) - Add getRenderMode/setRenderMode API to Engine and EngineManager layers - Wire setting toolbar button to toggle the settings dialog - Add i18n keys for settings dialog (zh-CN/en-US) - Add version display at bottom-right of engine wrapper - Bump version to 1.1.7, rebuild and sync demo libs
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "iflow-engine",
|
||||
"version": "1.1.6",
|
||||
"version": "1.1.7",
|
||||
"description": "iFlow Engine SDK for Vue2, Vue3, React and HTML",
|
||||
"main": "./dist/iflow-engine.umd.js",
|
||||
"module": "./dist/iflow-engine.es.js",
|
||||
|
||||
@@ -22,3 +22,17 @@
|
||||
left: 20px !important;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
.bim-engine-version {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 10px;
|
||||
font-size: 11px;
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
z-index: 1;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
declare const __APP_VERSION__: string;
|
||||
import './bim-engine.css';
|
||||
import { ToolbarManager } from './managers/toolbar-manager';
|
||||
import { ButtonGroupManager } from './managers/button-group-manager';
|
||||
@@ -12,6 +13,7 @@ import { SectionAxisDialogManager } from './managers/section-axis-dialog-manager
|
||||
import { SectionBoxDialogManager } from './managers/section-box-dialog-manager';
|
||||
import { WalkControlManager } from './managers/walk-control-manager';
|
||||
import { EngineInfoDialogManager } from './managers/engine-info-dialog-manager';
|
||||
import { SettingDialogManager } from './managers/setting-dialog-manager';
|
||||
import { ComponentDetailManager } from './managers/component-detail-manager';
|
||||
import { AiChatManager } from './managers/ai-chat-manager';
|
||||
import type { EngineOptions, ModelLoadOptions } from './components/engine';
|
||||
@@ -44,6 +46,7 @@ export class BimEngine {
|
||||
public engineInfo: EngineInfoDialogManager | null = null;
|
||||
public componentDetail: ComponentDetailManager | null = null;
|
||||
public aiChat: AiChatManager | null = null;
|
||||
public setting: SettingDialogManager | null = null;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement | string,
|
||||
@@ -100,6 +103,11 @@ export class BimEngine {
|
||||
this.wrapper.className = 'bim-engine-wrapper';
|
||||
this.container.appendChild(this.wrapper);
|
||||
|
||||
const versionEl = document.createElement('div');
|
||||
versionEl.className = 'bim-engine-version';
|
||||
versionEl.textContent = `v${__APP_VERSION__}`;
|
||||
this.wrapper.appendChild(versionEl);
|
||||
|
||||
this.registry.container = this.container;
|
||||
this.registry.wrapper = this.wrapper;
|
||||
|
||||
@@ -141,6 +149,10 @@ export class BimEngine {
|
||||
this.registry.aiChat = this.aiChat;
|
||||
this.aiChat.init();
|
||||
|
||||
this.setting = new SettingDialogManager(this.registry);
|
||||
this.registry.setting = this.setting;
|
||||
this.setting.init();
|
||||
|
||||
this.updateTheme(themeManager.getTheme());
|
||||
themeManager.subscribe((theme) => {
|
||||
this.updateTheme(theme);
|
||||
@@ -166,6 +178,7 @@ export class BimEngine {
|
||||
this.sectionBox?.destroy();
|
||||
this.walkControl?.destroy();
|
||||
this.aiChat?.destroy();
|
||||
this.setting?.destroy();
|
||||
this.container.innerHTML = '';
|
||||
this.registry.reset();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ButtonConfig } from '../../../index.type';
|
||||
import { getIcon } from '../../../../../utils/icon-manager';
|
||||
import type { ManagerRegistry } from '../../../../../core/manager-registry';
|
||||
|
||||
export const createSettingButton = (_registry?: ManagerRegistry): ButtonConfig => {
|
||||
export const createSettingButton = (registry?: ManagerRegistry): ButtonConfig => {
|
||||
return {
|
||||
id: 'setting',
|
||||
groupId: 'group-2',
|
||||
@@ -10,8 +10,8 @@ export const createSettingButton = (_registry?: ManagerRegistry): ButtonConfig =
|
||||
label: 'toolbar.setting',
|
||||
icon: getIcon('设置'),
|
||||
keepActive: false,
|
||||
onClick: (button) => {
|
||||
console.log('设置按钮被点击:', button.id);
|
||||
onClick: (_button) => {
|
||||
registry?.setting?.toggle();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -557,6 +557,33 @@ export class Engine implements IBimComponent {
|
||||
|
||||
// ==================== 结束:剖切功能 ====================
|
||||
|
||||
// ==================== 渲染模式 ====================
|
||||
|
||||
/**
|
||||
* 获取当前渲染模式
|
||||
* @returns 'simple' | 'balance' | 'advanced'
|
||||
*/
|
||||
public getRenderMode(): string {
|
||||
if (!this._isInitialized || !this.engine?.engineModelModule) {
|
||||
return 'balance';
|
||||
}
|
||||
return this.engine.engineModelModule.getCurrentMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置渲染模式
|
||||
* @param mode 'simple'(性能模式) | 'balance'(平衡模式) | 'advanced'(效果模式)
|
||||
*/
|
||||
public setRenderMode(mode: 'simple' | 'balance' | 'advanced'): void {
|
||||
if (!this._isInitialized || !this.engine?.engineModelModule) {
|
||||
console.warn('[Engine] Cannot set render mode: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
this.engine.engineModelModule.setMode(mode);
|
||||
}
|
||||
|
||||
// ==================== 结束:渲染模式 ====================
|
||||
|
||||
// ==================== 漫游功能 ====================
|
||||
|
||||
/** 漫游模式是否激活 */
|
||||
|
||||
@@ -20,6 +20,7 @@ import type { SectionBoxDialogManager } from '../managers/section-box-dialog-man
|
||||
import type { WalkPathDialogManager } from '../managers/walk-path-dialog-manager';
|
||||
import type { WalkPlanViewDialogManager } from '../managers/walk-plan-view-dialog-manager';
|
||||
import type { EngineInfoDialogManager } from '../managers/engine-info-dialog-manager';
|
||||
import type { SettingDialogManager } from '../managers/setting-dialog-manager';
|
||||
import type { ComponentDetailManager } from '../managers/component-detail-manager';
|
||||
import type { AiChatManager } from '../managers/ai-chat-manager';
|
||||
|
||||
@@ -69,6 +70,8 @@ export class ManagerRegistry {
|
||||
public componentDetail: ComponentDetailManager | null = null;
|
||||
/** AI 聊天管理器 */
|
||||
public aiChat: AiChatManager | null = null;
|
||||
/** 设置对话框管理器 */
|
||||
public setting: SettingDialogManager | null = null;
|
||||
|
||||
constructor() {}
|
||||
|
||||
@@ -93,6 +96,7 @@ export class ManagerRegistry {
|
||||
this.engineInfo = null;
|
||||
this.componentDetail = null;
|
||||
this.aiChat = null;
|
||||
this.setting = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -209,5 +209,14 @@ export const enUS: TranslationDictionary = {
|
||||
other: 'Other',
|
||||
otherPlaceholder: 'Enter custom answer',
|
||||
submit: 'Submit'
|
||||
},
|
||||
setting: {
|
||||
dialogTitle: 'Settings',
|
||||
renderMode: 'Render Mode',
|
||||
modes: {
|
||||
simple: 'Performance',
|
||||
balance: 'Balanced',
|
||||
advanced: 'Quality',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -231,6 +231,15 @@ export interface TranslationDictionary {
|
||||
otherPlaceholder: string;
|
||||
submit: string;
|
||||
};
|
||||
setting: {
|
||||
dialogTitle: string;
|
||||
renderMode: string;
|
||||
modes: {
|
||||
simple: string;
|
||||
balance: string;
|
||||
advanced: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -209,5 +209,14 @@ export const zhCN: TranslationDictionary = {
|
||||
other: '其他',
|
||||
otherPlaceholder: '请输入自定义答案',
|
||||
submit: '提交'
|
||||
},
|
||||
setting: {
|
||||
dialogTitle: '设置',
|
||||
renderMode: '渲染模式',
|
||||
modes: {
|
||||
simple: '性能模式',
|
||||
balance: '平衡模式',
|
||||
advanced: '效果模式',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -685,6 +685,26 @@ export class EngineManager extends BaseManager {
|
||||
|
||||
// ==================== 结束:构件操作 ====================
|
||||
|
||||
// ==================== 渲染模式 ====================
|
||||
|
||||
/**
|
||||
* 获取当前渲染模式
|
||||
* @returns 'simple' | 'balance' | 'advanced'
|
||||
*/
|
||||
public getRenderMode(): string {
|
||||
return this.engineInstance?.getRenderMode() ?? 'balance';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置渲染模式
|
||||
* @param mode 'simple' | 'balance' | 'advanced'
|
||||
*/
|
||||
public setRenderMode(mode: 'simple' | 'balance' | 'advanced'): void {
|
||||
this.engineInstance?.setRenderMode(mode);
|
||||
}
|
||||
|
||||
// ==================== 结束:渲染模式 ====================
|
||||
|
||||
/** 销毁引擎管理器 */
|
||||
public destroy(): void {
|
||||
if (this.engineInstance) {
|
||||
|
||||
107
src/managers/setting-dialog-manager.ts
Normal file
107
src/managers/setting-dialog-manager.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { ManagerRegistry } from '../core/manager-registry';
|
||||
import { t } from '../services/locale';
|
||||
|
||||
type RenderMode = 'simple' | 'balance' | 'advanced';
|
||||
|
||||
export class SettingDialogManager extends BaseDialogManager {
|
||||
protected get dialogId() { return 'setting-dialog'; }
|
||||
protected get dialogTitle() { return 'setting.dialogTitle'; }
|
||||
protected get dialogWidth() { return 280; }
|
||||
|
||||
constructor(registry: ManagerRegistry) {
|
||||
super(registry);
|
||||
}
|
||||
|
||||
public init(): void {}
|
||||
|
||||
protected getDialogPosition() {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 100, y: 100 };
|
||||
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
|
||||
return {
|
||||
x: (containerWidth - this.dialogWidth) / 2,
|
||||
y: (containerHeight - 200) / 2
|
||||
};
|
||||
}
|
||||
|
||||
protected createContent(): HTMLElement {
|
||||
const currentMode = this.registry.engine3d?.getRenderMode() ?? 'balance';
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.style.cssText = 'padding: 16px;';
|
||||
|
||||
// 渲染模式标题
|
||||
const label = document.createElement('div');
|
||||
label.style.cssText = 'font-size: 13px; color: var(--bim-text-secondary, #94a3b8); margin-bottom: 12px;';
|
||||
label.textContent = t('setting.renderMode');
|
||||
content.appendChild(label);
|
||||
|
||||
// 三个模式选项
|
||||
const modes: { key: RenderMode; labelKey: string }[] = [
|
||||
{ key: 'simple', labelKey: 'setting.modes.simple' },
|
||||
{ key: 'balance', labelKey: 'setting.modes.balance' },
|
||||
{ key: 'advanced', labelKey: 'setting.modes.advanced' },
|
||||
];
|
||||
|
||||
const group = document.createElement('div');
|
||||
group.style.cssText = 'display: flex; flex-direction: column; gap: 4px;';
|
||||
|
||||
for (const mode of modes) {
|
||||
const item = document.createElement('div');
|
||||
item.style.cssText = `
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 10px 12px; border-radius: 6px; cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
background: ${mode.key === currentMode ? 'var(--bim-primary, #3b82f6)' : 'transparent'};
|
||||
color: ${mode.key === currentMode ? 'var(--bim-text-inverse, #fff)' : 'var(--bim-text-primary, #fff)'};
|
||||
`;
|
||||
|
||||
// 圆点指示器
|
||||
const dot = document.createElement('div');
|
||||
dot.style.cssText = `
|
||||
width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0;
|
||||
border: 2px solid ${mode.key === currentMode ? 'var(--bim-text-inverse, #fff)' : 'var(--bim-text-tertiary, #64748b)'};
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
`;
|
||||
if (mode.key === currentMode) {
|
||||
const inner = document.createElement('div');
|
||||
inner.style.cssText = 'width: 8px; height: 8px; border-radius: 50%; background: var(--bim-text-inverse, #fff);';
|
||||
dot.appendChild(inner);
|
||||
}
|
||||
|
||||
const text = document.createElement('span');
|
||||
text.style.cssText = 'font-size: 14px; font-weight: 500;';
|
||||
text.textContent = t(mode.labelKey);
|
||||
|
||||
item.appendChild(dot);
|
||||
item.appendChild(text);
|
||||
|
||||
item.addEventListener('mouseenter', () => {
|
||||
if (mode.key !== currentMode) {
|
||||
item.style.background = 'var(--bim-floating-btn-bg, rgba(255,255,255,0.08))';
|
||||
}
|
||||
});
|
||||
item.addEventListener('mouseleave', () => {
|
||||
if (mode.key !== currentMode) {
|
||||
item.style.background = 'transparent';
|
||||
}
|
||||
});
|
||||
|
||||
item.addEventListener('click', () => {
|
||||
this.registry.engine3d?.setRenderMode(mode.key);
|
||||
// 重新渲染弹窗内容
|
||||
this.hide();
|
||||
this.show();
|
||||
});
|
||||
|
||||
group.appendChild(item);
|
||||
}
|
||||
|
||||
content.appendChild(group);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { defineConfig } from 'vite';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import { resolve } from 'path';
|
||||
import cssInjectedByJs from 'vite-plugin-css-injected-by-js';
|
||||
import pkg from './package.json';
|
||||
|
||||
export default defineConfig(() => {
|
||||
return {
|
||||
@@ -25,6 +26,9 @@ export default defineConfig(() => {
|
||||
open: '/demo/index.html',
|
||||
allowedHosts: true,
|
||||
},
|
||||
define: {
|
||||
__APP_VERSION__: JSON.stringify(pkg.version),
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'src/index.ts'),
|
||||
|
||||
Reference in New Issue
Block a user