@chatbi-v/cli 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/.env +8 -0
- package/dist/app/.env.hbs +8 -0
- package/dist/app/README.md.hbs +16 -0
- package/dist/app/chatbi.config.ts.hbs +60 -0
- package/{templates/default/apps/main → dist/app}/index.html.hbs +3 -4
- package/dist/app/package.json.hbs +34 -0
- package/dist/app/src/App.tsx.hbs +92 -0
- package/dist/app/src/components/GlobalErrorBoundary.tsx.hbs +69 -0
- package/dist/app/src/components/GlobalSettingsModal.tsx.hbs +35 -0
- package/dist/app/src/components/LayoutSkeletons.tsx.hbs +79 -0
- package/dist/app/src/components/index.ts.hbs +2 -0
- package/dist/app/src/custom-antd.less.hbs +7 -0
- package/dist/app/src/features/settings/ConfigRenderStrategy.tsx.hbs +119 -0
- package/dist/app/src/features/settings/ExtensionSettings.tsx.hbs +52 -0
- package/dist/app/src/features/settings/PluginList.tsx.hbs +115 -0
- package/dist/app/src/features/settings/PluginSettings.tsx.hbs +123 -0
- package/dist/app/src/features/settings/SchemaSettingsRenderer.tsx.hbs +56 -0
- package/dist/app/src/hooks/useAppRoutes.ts.hbs +39 -0
- package/dist/app/src/hooks/usePluginLoader.ts.hbs +22 -0
- package/dist/app/src/hooks/usePluginSettings.ts.hbs +29 -0
- package/dist/app/src/hooks/useThemeSync.ts.hbs +108 -0
- package/dist/app/src/index.css.hbs +45 -0
- package/dist/app/src/layouts/BackgroundEffects.tsx.hbs +10 -0
- package/dist/app/src/layouts/MainContent.tsx.hbs +58 -0
- package/dist/app/src/layouts/SidebarNav.tsx.hbs +182 -0
- package/dist/app/src/main.tsx.hbs +43 -0
- package/dist/app/src/providers/AppProviders.tsx.hbs +36 -0
- package/dist/app/src/services/api/index.ts.hbs +37 -0
- package/dist/app/src/services/api/modules/auth.ts.hbs +18 -0
- package/dist/app/src/services/config-service.ts.hbs +48 -0
- package/dist/app/src/stores/storage-adapter.ts.hbs +29 -0
- package/dist/app/src/stores/useSessionStore.ts.hbs +22 -0
- package/dist/app/src/stores/useUIStore.ts.hbs +64 -0
- package/dist/app/tailwind.config.cjs.hbs +14 -0
- package/dist/app/tsconfig.json.hbs +26 -0
- package/dist/app/vite.config.ts.hbs +89 -0
- package/dist/index.js +5662 -4194
- package/{templates/default → dist/monorepo}/package.json.hbs +5 -0
- package/dist/monorepo/pnpm-workspace.yaml.hbs +10 -0
- package/dist/{default → monorepo}/tsconfig.json.hbs +3 -1
- package/{templates/default/plugins/demo-plugin → dist/plugin}/package.json.hbs +9 -3
- package/dist/plugin/src/index.tsx.hbs +90 -0
- package/dist/plugin/tsconfig.json.hbs +14 -0
- package/package.json +18 -6
- package/templates/app/.env.hbs +8 -0
- package/templates/app/README.md.hbs +16 -0
- package/templates/app/chatbi.config.ts.hbs +60 -0
- package/{dist/default/apps/main → templates/app}/index.html.hbs +3 -4
- package/templates/app/package.json.hbs +34 -0
- package/templates/app/src/App.tsx.hbs +92 -0
- package/templates/app/src/components/GlobalErrorBoundary.tsx.hbs +69 -0
- package/templates/app/src/components/GlobalSettingsModal.tsx.hbs +35 -0
- package/templates/app/src/components/LayoutSkeletons.tsx.hbs +79 -0
- package/templates/app/src/components/index.ts.hbs +2 -0
- package/templates/app/src/custom-antd.less.hbs +7 -0
- package/templates/app/src/features/settings/ConfigRenderStrategy.tsx.hbs +119 -0
- package/templates/app/src/features/settings/ExtensionSettings.tsx.hbs +52 -0
- package/templates/app/src/features/settings/PluginList.tsx.hbs +115 -0
- package/templates/app/src/features/settings/PluginSettings.tsx.hbs +123 -0
- package/templates/app/src/features/settings/SchemaSettingsRenderer.tsx.hbs +56 -0
- package/templates/app/src/hooks/useAppRoutes.ts.hbs +39 -0
- package/templates/app/src/hooks/usePluginLoader.ts.hbs +22 -0
- package/templates/app/src/hooks/usePluginSettings.ts.hbs +29 -0
- package/templates/app/src/hooks/useThemeSync.ts.hbs +108 -0
- package/templates/app/src/index.css.hbs +45 -0
- package/templates/app/src/layouts/BackgroundEffects.tsx.hbs +10 -0
- package/templates/app/src/layouts/MainContent.tsx.hbs +58 -0
- package/templates/app/src/layouts/SidebarNav.tsx.hbs +182 -0
- package/templates/app/src/main.tsx.hbs +43 -0
- package/templates/app/src/providers/AppProviders.tsx.hbs +36 -0
- package/templates/app/src/services/api/index.ts.hbs +37 -0
- package/templates/app/src/services/api/modules/auth.ts.hbs +18 -0
- package/templates/app/src/services/config-service.ts.hbs +48 -0
- package/templates/app/src/stores/storage-adapter.ts.hbs +29 -0
- package/templates/app/src/stores/useSessionStore.ts.hbs +22 -0
- package/templates/app/src/stores/useUIStore.ts.hbs +64 -0
- package/templates/app/tailwind.config.cjs.hbs +14 -0
- package/templates/app/tsconfig.json.hbs +26 -0
- package/templates/app/vite.config.ts.hbs +89 -0
- package/templates/monorepo/.gitignore.hbs +3 -0
- package/{dist/default → templates/monorepo}/package.json.hbs +5 -0
- package/templates/monorepo/pnpm-workspace.yaml.hbs +10 -0
- package/templates/{default → monorepo}/tsconfig.json.hbs +3 -1
- package/{dist/default/plugins/demo-plugin → templates/plugin}/package.json.hbs +9 -3
- package/templates/plugin/src/index.tsx.hbs +90 -0
- package/templates/plugin/tsconfig.json.hbs +14 -0
- package/dist/default/apps/main/package.json.hbs +0 -20
- package/dist/default/apps/main/src/App.tsx.hbs +0 -162
- package/dist/default/apps/main/src/components/NavIcon.tsx.hbs +0 -41
- package/dist/default/apps/main/src/hooks/usePluginLoader.ts.hbs +0 -25
- package/dist/default/apps/main/src/index.css.hbs +0 -8
- package/dist/default/apps/main/src/main.tsx.hbs +0 -13
- package/dist/default/apps/main/src/pages/Guide.tsx.hbs +0 -133
- package/dist/default/apps/main/tailwind.config.cjs.hbs +0 -17
- package/dist/default/apps/main/tsconfig.json.hbs +0 -10
- package/dist/default/apps/main/vite.config.ts.hbs +0 -16
- package/dist/default/plugins/demo-plugin/src/index.tsx.hbs +0 -44
- package/dist/default/plugins/demo-plugin/tsconfig.json.hbs +0 -10
- package/dist/default/pnpm-workspace.yaml.hbs +0 -3
- package/templates/default/apps/main/package.json.hbs +0 -20
- package/templates/default/apps/main/src/App.tsx.hbs +0 -162
- package/templates/default/apps/main/src/components/NavIcon.tsx.hbs +0 -41
- package/templates/default/apps/main/src/hooks/usePluginLoader.ts.hbs +0 -25
- package/templates/default/apps/main/src/index.css.hbs +0 -8
- package/templates/default/apps/main/src/main.tsx.hbs +0 -13
- package/templates/default/apps/main/src/pages/Guide.tsx.hbs +0 -133
- package/templates/default/apps/main/tailwind.config.cjs.hbs +0 -17
- package/templates/default/apps/main/tsconfig.json.hbs +0 -10
- package/templates/default/apps/main/vite.config.ts.hbs +0 -16
- package/templates/default/plugins/demo-plugin/src/index.tsx.hbs +0 -44
- package/templates/default/plugins/demo-plugin/tsconfig.json.hbs +0 -10
- package/templates/default/pnpm-workspace.yaml.hbs +0 -3
- /package/dist/{default/apps/main → app}/postcss.config.cjs.hbs +0 -0
- /package/{templates/default → dist/monorepo}/.gitignore.hbs +0 -0
- /package/dist/{default → monorepo}/README.md.hbs +0 -0
- /package/templates/{default/apps/main → app}/postcss.config.cjs.hbs +0 -0
- /package/templates/{default → monorepo}/README.md.hbs +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MenuFoldOutlined,
|
|
3
|
+
MenuUnfoldOutlined,
|
|
4
|
+
SettingOutlined,
|
|
5
|
+
ThunderboltOutlined,
|
|
6
|
+
} from '@ant-design/icons';
|
|
7
|
+
import { AvatarSkeleton,type PluginExtension, pluginManager, PluginSlot, SidebarIconSkeleton, Slot } from '@chatbi-v/core';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { useNavigate } from 'react-router-dom';
|
|
10
|
+
|
|
11
|
+
import { chatbiConfig } from '../../chatbi.config';
|
|
12
|
+
import { NavSkeleton } from '../components/LayoutSkeletons';
|
|
13
|
+
import { useUIStore } from '../stores/useUIStore';
|
|
14
|
+
|
|
15
|
+
// 导航图标组件
|
|
16
|
+
export const NavIcon = React.memo(({
|
|
17
|
+
icon,
|
|
18
|
+
active,
|
|
19
|
+
onClick,
|
|
20
|
+
title,
|
|
21
|
+
label,
|
|
22
|
+
expanded,
|
|
23
|
+
}: {
|
|
24
|
+
icon: React.ReactNode;
|
|
25
|
+
active?: boolean;
|
|
26
|
+
onClick?: () => void;
|
|
27
|
+
title?: string;
|
|
28
|
+
label?: string;
|
|
29
|
+
expanded?: boolean;
|
|
30
|
+
}) => (
|
|
31
|
+
<div
|
|
32
|
+
onClick={onClick}
|
|
33
|
+
title={title}
|
|
34
|
+
className={`flex items-center cursor-pointer transition-all duration-300 relative group
|
|
35
|
+
${expanded ? 'w-full' : 'w-12'} px-3 h-11 rounded-xl
|
|
36
|
+
${
|
|
37
|
+
active
|
|
38
|
+
? 'bg-primary/15 text-primary font-semibold shadow-sm ring-1 ring-primary/20 dark:bg-primary/20'
|
|
39
|
+
: 'text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-white/10 hover:text-slate-900 dark:hover:text-white hover:scale-105 active:scale-95'
|
|
40
|
+
}`}
|
|
41
|
+
>
|
|
42
|
+
<div className="w-6 h-6 flex items-center justify-center shrink-0">
|
|
43
|
+
<div className={`text-xl transition-transform duration-300 ${!expanded && active ? 'scale-110' : ''}`}>{icon}</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div className={`overflow-hidden whitespace-nowrap transition-all duration-300 ease-in-out ${
|
|
47
|
+
expanded ? 'w-auto opacity-100 ml-3' : 'w-0 opacity-0 ml-0'
|
|
48
|
+
}`}>
|
|
49
|
+
<span className="text-sm block">
|
|
50
|
+
{label}
|
|
51
|
+
</span>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
</div>
|
|
55
|
+
));
|
|
56
|
+
|
|
57
|
+
interface SidebarNavProps {
|
|
58
|
+
activeTab: string;
|
|
59
|
+
pluginsLoaded: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const SidebarNav: React.FC<SidebarNavProps> = React.memo(({
|
|
63
|
+
activeTab,
|
|
64
|
+
pluginsLoaded,
|
|
65
|
+
}) => {
|
|
66
|
+
const navigate = useNavigate();
|
|
67
|
+
const {
|
|
68
|
+
collapsed, setCollapsed,
|
|
69
|
+
setIsSettingsOpen, isMaximized
|
|
70
|
+
} = useUIStore();
|
|
71
|
+
|
|
72
|
+
const renderSidebarBottomItem = React.useCallback(({ key, extension }: { key: string, extension: PluginExtension }) => {
|
|
73
|
+
const Component = extension.component;
|
|
74
|
+
return (
|
|
75
|
+
<Component key={key} collapsed={collapsed} />
|
|
76
|
+
);
|
|
77
|
+
}, [collapsed]);
|
|
78
|
+
|
|
79
|
+
const renderSidebarSystemItem = React.useCallback(({ key, extension }: { key: string, extension: PluginExtension }) => {
|
|
80
|
+
const Component = extension.component;
|
|
81
|
+
return (
|
|
82
|
+
<div key={key} className={`flex items-center gap-3 transition-all duration-300 relative group
|
|
83
|
+
${collapsed ? 'w-12 justify-center' : 'w-full px-4'} rounded-xl`}
|
|
84
|
+
>
|
|
85
|
+
{Component ? <Component collapsed={collapsed} /> : null}
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}, [collapsed]);
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<nav className={`relative z-20 flex flex-col items-center py-4 gap-[var(--layout-gap)] transition-all duration-500 ease-[cubic-bezier(0.2,0,0,1)]
|
|
92
|
+
border-r border-slate-200/60 dark:border-white/10 backdrop-blur-xl bg-white/80 dark:bg-slate-900/80
|
|
93
|
+
${isMaximized ? 'w-0 overflow-hidden opacity-0 p-0 border-none' : (collapsed ? 'w-[72px]' : 'w-[var(--layout-sidebar-width)]')}
|
|
94
|
+
h-screen
|
|
95
|
+
`}>
|
|
96
|
+
{!pluginsLoaded ? (
|
|
97
|
+
<NavSkeleton />
|
|
98
|
+
) : (
|
|
99
|
+
<>
|
|
100
|
+
{/* 品牌标识 */}
|
|
101
|
+
<div className={`flex items-center gap-3 mb-6 transition-all duration-300 ${!collapsed ? 'w-full px-5' : 'justify-center'}`}>
|
|
102
|
+
<div className="w-12 h-12 rounded-2xl bg-gradient-to-tr from-primary to-secondary flex items-center justify-center shadow-lg shadow-primary/20 shrink-0 group cursor-pointer hover:scale-105 transition-transform duration-300">
|
|
103
|
+
<ThunderboltOutlined className="text-2xl text-white" />
|
|
104
|
+
</div>
|
|
105
|
+
{!collapsed && (
|
|
106
|
+
<div className="flex flex-col animate-in fade-in slide-in-from-left-4 duration-500">
|
|
107
|
+
<span className="font-bold text-xl leading-tight tracking-tight text-slate-800 dark:text-slate-100">{chatbiConfig.system.title}</span>
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
{/* 导航项 */}
|
|
113
|
+
<div className="flex-1 w-full flex flex-col gap-[var(--layout-gap)] overflow-y-auto no-scrollbar items-center transition-all duration-300 px-3 pt-2">
|
|
114
|
+
<PluginSlot
|
|
115
|
+
slot={Slot.Sidebar}
|
|
116
|
+
className="flex flex-col gap-[var(--layout-gap)] w-full items-center"
|
|
117
|
+
skeleton={
|
|
118
|
+
<div className="flex flex-col gap-[var(--layout-gap)] w-full items-center">
|
|
119
|
+
{[1, 2, 3].map(i => <SidebarIconSkeleton key={i} />)}
|
|
120
|
+
</div>
|
|
121
|
+
}
|
|
122
|
+
renderItem={({ key, extension }: { key: string, extension: PluginExtension }) => (
|
|
123
|
+
<NavIcon
|
|
124
|
+
key={key}
|
|
125
|
+
icon={extension.meta?.icon}
|
|
126
|
+
label={extension.meta?.label}
|
|
127
|
+
active={
|
|
128
|
+
// Support multi-level route matching
|
|
129
|
+
// e.g., activeTab='scene/10/tables' should match path='/scene'
|
|
130
|
+
// Remove leading slash for consistency
|
|
131
|
+
activeTab === (extension.meta?.path || extension.meta?.key)?.replace(/^\//, '') ||
|
|
132
|
+
activeTab.startsWith(((extension.meta?.path || extension.meta?.key)?.replace(/^\//, '') || '') + '/')
|
|
133
|
+
}
|
|
134
|
+
onClick={() => navigate(extension.meta?.path || '/')}
|
|
135
|
+
expanded={!collapsed}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
{/* 底部操作区 */}
|
|
142
|
+
<div className="w-full flex flex-col gap-[var(--layout-gap)] mt-auto mb-2 items-center transition-all duration-300 px-3">
|
|
143
|
+
<PluginSlot
|
|
144
|
+
slot={Slot.SidebarBottom}
|
|
145
|
+
className="w-full flex flex-col gap-[var(--layout-gap)]"
|
|
146
|
+
skeleton={<SidebarIconSkeleton />}
|
|
147
|
+
renderItem={renderSidebarBottomItem}
|
|
148
|
+
/>
|
|
149
|
+
<NavIcon
|
|
150
|
+
icon={<SettingOutlined />}
|
|
151
|
+
onClick={() => setIsSettingsOpen(true)}
|
|
152
|
+
title="系统设置"
|
|
153
|
+
label="设置"
|
|
154
|
+
expanded={!collapsed}
|
|
155
|
+
/>
|
|
156
|
+
|
|
157
|
+
<div className={`h-px bg-slate-200 dark:bg-white/10 my-2 transition-all duration-300 ${collapsed ? 'w-8' : 'w-full'}`} />
|
|
158
|
+
|
|
159
|
+
<PluginSlot
|
|
160
|
+
slot={Slot.SidebarSystem}
|
|
161
|
+
className={`w-full transition-all duration-300 ${collapsed ? 'flex justify-center' : ''}`}
|
|
162
|
+
skeleton={
|
|
163
|
+
<div className={`flex items-center gap-3 transition-all duration-300 ${collapsed ? 'w-12 justify-center' : 'w-full px-4'}`}>
|
|
164
|
+
<AvatarSkeleton />
|
|
165
|
+
</div>
|
|
166
|
+
}
|
|
167
|
+
renderItem={renderSidebarSystemItem}
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
<NavIcon
|
|
171
|
+
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
172
|
+
onClick={() => setCollapsed(!collapsed)}
|
|
173
|
+
title={collapsed ? "展开侧边栏" : "折叠侧边栏"}
|
|
174
|
+
label={collapsed ? "展开" : "折叠"}
|
|
175
|
+
expanded={!collapsed}
|
|
176
|
+
/>
|
|
177
|
+
</div>
|
|
178
|
+
</>
|
|
179
|
+
)}
|
|
180
|
+
</nav>
|
|
181
|
+
);
|
|
182
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import 'antd/dist/reset.css'
|
|
2
|
+
import './index.css'
|
|
3
|
+
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import ReactDOM from 'react-dom/client'
|
|
6
|
+
import { HashRouter } from 'react-router-dom'
|
|
7
|
+
|
|
8
|
+
import App from './App'
|
|
9
|
+
import { GlobalErrorBoundary } from './components'
|
|
10
|
+
import { api } from './services/api'
|
|
11
|
+
|
|
12
|
+
// 挂载全局 API 实例供插件使用
|
|
13
|
+
// 插件可以通过 window.chatbi.api 访问核心请求实例
|
|
14
|
+
declare global {
|
|
15
|
+
interface Window {
|
|
16
|
+
chatbi: {
|
|
17
|
+
api: typeof api;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
window.chatbi = {
|
|
23
|
+
api
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// API Mock 策略说明:
|
|
27
|
+
// Mock 逻辑已移至 services/api/index.ts 中统一处理
|
|
28
|
+
// 开启方式:
|
|
29
|
+
// 1. URL 参数: ?mock=true (优先级最高)
|
|
30
|
+
// 2. 环境变量: VITE_USE_MOCK=true (在 .env.development 中配置)
|
|
31
|
+
|
|
32
|
+
// 应用启动
|
|
33
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
34
|
+
<React.StrictMode>
|
|
35
|
+
{/* 全局错误边界,捕获渲染过程中的未处理异常 */}
|
|
36
|
+
<GlobalErrorBoundary>
|
|
37
|
+
{/* 路由模式:默认使用 HashRouter,如果需要 history 模式请改为 BrowserRouter */}
|
|
38
|
+
<HashRouter>
|
|
39
|
+
<App />
|
|
40
|
+
</HashRouter>
|
|
41
|
+
</GlobalErrorBoundary>
|
|
42
|
+
</React.StrictMode>,
|
|
43
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { XProvider } from '@ant-design/x';
|
|
2
|
+
import { ApiProvider, pluginManager, PluginProvider } from '@chatbi-v/core';
|
|
3
|
+
import { App as AntdApp, ConfigProvider } from 'antd';
|
|
4
|
+
import React, { ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
import { useThemeSync } from '../hooks/useThemeSync';
|
|
7
|
+
import { api } from '../services/api';
|
|
8
|
+
|
|
9
|
+
interface AppProvidersProps {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 应用全局 Providers
|
|
15
|
+
* @description 封装所有全局 Context Provider,包括 API, Plugin, Theme, Antd 等
|
|
16
|
+
* @note 使用 reduceRight 组合 Provider,避免嵌套地狱 (Provider Hell)
|
|
17
|
+
*/
|
|
18
|
+
export const AppProviders: React.FC<AppProvidersProps> = ({ children }) => {
|
|
19
|
+
const themeConfig = useThemeSync();
|
|
20
|
+
|
|
21
|
+
// 定义 Provider 列表,顺序从外到内
|
|
22
|
+
const providers: Array<[React.ComponentType<any>, Record<string, any>]> = [
|
|
23
|
+
// 核心服务
|
|
24
|
+
[ApiProvider, { api }],
|
|
25
|
+
[PluginProvider, { manager: pluginManager }],
|
|
26
|
+
// UI 主题配置
|
|
27
|
+
[ConfigProvider, { theme: themeConfig }],
|
|
28
|
+
[AntdApp, {}],
|
|
29
|
+
[XProvider, { theme: themeConfig }],
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
// 使用 reduceRight 从内向外包裹 children
|
|
33
|
+
return providers.reduceRight((acc, [Provider, props]) => {
|
|
34
|
+
return <Provider {...props}>{acc}</Provider>;
|
|
35
|
+
}, children);
|
|
36
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ApiEngine, AxiosAdapter, createLogger, isMockMode } from '@chatbi-v/core';
|
|
2
|
+
import { MockAdapter } from '@chatbi-v/mocks';
|
|
3
|
+
|
|
4
|
+
const logger = createLogger('Api');
|
|
5
|
+
|
|
6
|
+
// 从环境变量获取配置
|
|
7
|
+
const baseURL = import.meta.env.VITE_API_BASE_URL || '/api';
|
|
8
|
+
const timeout = Number(import.meta.env.VITE_API_TIMEOUT) || 10000;
|
|
9
|
+
|
|
10
|
+
// 统一 Mock 模式决策
|
|
11
|
+
const useMock = isMockMode();
|
|
12
|
+
|
|
13
|
+
if (useMock) {
|
|
14
|
+
logger.info(`⚠️ Mock 模式已启用 (基于核心库 isMockMode 判断)`);
|
|
15
|
+
} else {
|
|
16
|
+
logger.debug(`正在以真实模式运行`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 创建适配器 (根据 Mock 模式切换)
|
|
20
|
+
const adapter = useMock
|
|
21
|
+
? new MockAdapter(100) // 100ms 延迟模拟
|
|
22
|
+
: new AxiosAdapter(baseURL, timeout);
|
|
23
|
+
|
|
24
|
+
// 创建 API 引擎实例
|
|
25
|
+
export const api = new ApiEngine(adapter);
|
|
26
|
+
|
|
27
|
+
// 自动加载 ./modules 下的所有配置文件
|
|
28
|
+
// 使用 Vite 的 import.meta.glob 功能
|
|
29
|
+
const modules = import.meta.glob('./modules/*.ts', { eager: true });
|
|
30
|
+
|
|
31
|
+
Object.entries(modules).forEach(([path, module]: [string, any]) => {
|
|
32
|
+
// 从路径中提取模块名 (e.g., './modules/auth.ts' -> 'auth')
|
|
33
|
+
const name = path.match(/\.\/modules\/(.*)\.ts$/)?.[1];
|
|
34
|
+
if (name && module.default) {
|
|
35
|
+
api.register({ [name]: module.default });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
login: {
|
|
3
|
+
url: '/auth/login',
|
|
4
|
+
method: 'POST',
|
|
5
|
+
desc: '用户登录',
|
|
6
|
+
mock: true,
|
|
7
|
+
mockData: {
|
|
8
|
+
code: 0,
|
|
9
|
+
message: 'success',
|
|
10
|
+
data: { token: 'mock-token-123', user: { id: 1, name: 'Admin' } },
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
logout: {
|
|
14
|
+
url: '/auth/logout',
|
|
15
|
+
method: 'POST',
|
|
16
|
+
desc: '用户登出',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { pluginManager, dateUtils } from '@chatbi-v/core';
|
|
2
|
+
|
|
3
|
+
export const exportSystemConfig = () => {
|
|
4
|
+
const exportData: Record<string, any> = {
|
|
5
|
+
pluginStates: {},
|
|
6
|
+
configs: {},
|
|
7
|
+
timestamp: dateUtils.dayjs().toISOString(),
|
|
8
|
+
environment: {
|
|
9
|
+
userAgent: navigator.userAgent,
|
|
10
|
+
language: navigator.language,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// 1. Export Plugin States
|
|
15
|
+
const allPlugins = pluginManager.getPlugins();
|
|
16
|
+
allPlugins.forEach((p) => {
|
|
17
|
+
exportData.pluginStates[p.id] = pluginManager.getPluginState(p.id);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// 2. Export Configs (scan localStorage for plugin related keys)
|
|
21
|
+
// We look for keys starting with 'plugin:' and global config keys
|
|
22
|
+
const globalKeys = ['chatbi-theme', 'chatbi-layout'];
|
|
23
|
+
|
|
24
|
+
// Global configs
|
|
25
|
+
globalKeys.forEach(key => {
|
|
26
|
+
const val = localStorage.getItem(key);
|
|
27
|
+
if (val) exportData.configs[key] = val;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Plugin specific configs and System configs
|
|
31
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
32
|
+
const key = localStorage.key(i);
|
|
33
|
+
if (key && (key.startsWith('plugin:') || key.startsWith('system:'))) {
|
|
34
|
+
exportData.configs[key] = localStorage.getItem(key);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Create and download file
|
|
39
|
+
const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
|
|
40
|
+
const url = URL.createObjectURL(blob);
|
|
41
|
+
const a = document.createElement('a');
|
|
42
|
+
a.href = url;
|
|
43
|
+
a.download = `chatbi-config-${dateUtils.formatDate()}.json`;
|
|
44
|
+
document.body.appendChild(a);
|
|
45
|
+
a.click();
|
|
46
|
+
document.body.removeChild(a);
|
|
47
|
+
URL.revokeObjectURL(url);
|
|
48
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { pluginManager } from '@chatbi-v/core';
|
|
2
|
+
import { StateStorage } from 'zustand/middleware';
|
|
3
|
+
|
|
4
|
+
export const createZustandStorage = (scope: 'system' | 'shared' = 'system'): StateStorage => {
|
|
5
|
+
return {
|
|
6
|
+
getItem: (name: string): string | null => {
|
|
7
|
+
// Lazy access to ensure pluginManager is ready (though it's a singleton)
|
|
8
|
+
const storageManager = pluginManager.getStorageManager();
|
|
9
|
+
const storage = scope === 'system'
|
|
10
|
+
? storageManager.getSystemStorage()
|
|
11
|
+
: storageManager.getSharedStorage();
|
|
12
|
+
return storage.getItem(name);
|
|
13
|
+
},
|
|
14
|
+
setItem: (name: string, value: string): void => {
|
|
15
|
+
const storageManager = pluginManager.getStorageManager();
|
|
16
|
+
const storage = scope === 'system'
|
|
17
|
+
? storageManager.getSystemStorage()
|
|
18
|
+
: storageManager.getSharedStorage();
|
|
19
|
+
storage.setItem(name, value);
|
|
20
|
+
},
|
|
21
|
+
removeItem: (name: string): void => {
|
|
22
|
+
const storageManager = pluginManager.getStorageManager();
|
|
23
|
+
const storage = scope === 'system'
|
|
24
|
+
? storageManager.getSystemStorage()
|
|
25
|
+
: storageManager.getSharedStorage();
|
|
26
|
+
storage.removeItem(name);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { createJSONStorage,persist } from 'zustand/middleware';
|
|
3
|
+
|
|
4
|
+
import { createZustandStorage } from './storage-adapter';
|
|
5
|
+
|
|
6
|
+
export interface SessionState {
|
|
7
|
+
activeSession: string | null;
|
|
8
|
+
setActiveSession: (id: string | null) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const useSessionStore = create<SessionState>()(
|
|
12
|
+
persist(
|
|
13
|
+
(set) => ({
|
|
14
|
+
activeSession: null,
|
|
15
|
+
setActiveSession: (id) => set({ activeSession: id }),
|
|
16
|
+
}),
|
|
17
|
+
{
|
|
18
|
+
name: 'chatbi-session-storage',
|
|
19
|
+
storage: createJSONStorage(() => createZustandStorage('system')),
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { createJSONStorage,persist } from 'zustand/middleware';
|
|
3
|
+
|
|
4
|
+
import { createZustandStorage } from './storage-adapter';
|
|
5
|
+
|
|
6
|
+
export interface UIState {
|
|
7
|
+
collapsed: boolean;
|
|
8
|
+
toggleCollapsed: () => void;
|
|
9
|
+
setCollapsed: (v: boolean) => void;
|
|
10
|
+
|
|
11
|
+
isRightPanelOpen: boolean;
|
|
12
|
+
toggleRightPanel: () => void;
|
|
13
|
+
setIsRightPanelOpen: (v: boolean) => void;
|
|
14
|
+
|
|
15
|
+
isMaximized: boolean;
|
|
16
|
+
toggleMaximized: () => void;
|
|
17
|
+
setIsMaximized: (v: boolean) => void;
|
|
18
|
+
|
|
19
|
+
isSettingsOpen: boolean;
|
|
20
|
+
setIsSettingsOpen: (v: boolean) => void;
|
|
21
|
+
|
|
22
|
+
currentThemeId: string;
|
|
23
|
+
themeMode: 'dark' | 'light';
|
|
24
|
+
setThemeId: (id: string) => void;
|
|
25
|
+
setThemeMode: (mode: 'dark' | 'light') => void;
|
|
26
|
+
toggleThemeMode: () => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const useUIStore = create<UIState>()(
|
|
30
|
+
persist(
|
|
31
|
+
(set) => ({
|
|
32
|
+
collapsed: false,
|
|
33
|
+
toggleCollapsed: () => set((state) => ({ collapsed: !state.collapsed })),
|
|
34
|
+
setCollapsed: (v) => set({ collapsed: v }),
|
|
35
|
+
|
|
36
|
+
isRightPanelOpen: true,
|
|
37
|
+
toggleRightPanel: () => set((state) => ({ isRightPanelOpen: !state.isRightPanelOpen })),
|
|
38
|
+
setIsRightPanelOpen: (v) => set({ isRightPanelOpen: v }),
|
|
39
|
+
|
|
40
|
+
isMaximized: false,
|
|
41
|
+
toggleMaximized: () => set((state) => ({ isMaximized: !state.isMaximized })),
|
|
42
|
+
setIsMaximized: (v) => set({ isMaximized: v }),
|
|
43
|
+
|
|
44
|
+
isSettingsOpen: false,
|
|
45
|
+
setIsSettingsOpen: (v) => set({ isSettingsOpen: v }),
|
|
46
|
+
|
|
47
|
+
currentThemeId: 'default',
|
|
48
|
+
themeMode: 'dark',
|
|
49
|
+
setThemeId: (id) => set({ currentThemeId: id }),
|
|
50
|
+
setThemeMode: (mode) => set({ themeMode: mode }),
|
|
51
|
+
toggleThemeMode: () => set((state) => ({ themeMode: state.themeMode === 'light' ? 'dark' : 'light' })),
|
|
52
|
+
}),
|
|
53
|
+
{
|
|
54
|
+
name: 'chatbi-ui-storage',
|
|
55
|
+
storage: createJSONStorage(() => createZustandStorage('system')),
|
|
56
|
+
partialize: (state) => ({
|
|
57
|
+
currentThemeId: state.currentThemeId,
|
|
58
|
+
themeMode: state.themeMode,
|
|
59
|
+
collapsed: state.collapsed,
|
|
60
|
+
isRightPanelOpen: state.isRightPanelOpen
|
|
61
|
+
}),
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
presets: [
|
|
4
|
+
require('@chatbi-v/tailwind-config')
|
|
5
|
+
],
|
|
6
|
+
darkMode: 'class',
|
|
7
|
+
content: [
|
|
8
|
+
'./index.html',
|
|
9
|
+
'./src/**/*.{ts,tsx}',
|
|
10
|
+
'./.chatbi/core/src/**/*.{ts,tsx}',
|
|
11
|
+
'./.chatbi/plugin-*/**/*.{ts,tsx}'
|
|
12
|
+
],
|
|
13
|
+
plugins: []
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "{{tsconfigPath}}",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2020",
|
|
5
|
+
"useDefineForClassFields": true,
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"declaration": false,
|
|
15
|
+
"declarationMap": false,
|
|
16
|
+
"composite": false,
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
"types": ["vite/client", "node"],
|
|
19
|
+
"baseUrl": ".",
|
|
20
|
+
"paths": {
|
|
21
|
+
"@/*": ["./src/*"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"include": ["src"],
|
|
25
|
+
"references": []
|
|
26
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import react from '@vitejs/plugin-react';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { defineConfig, loadEnv } from 'vite';
|
|
5
|
+
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 分包策略函数
|
|
9
|
+
* 用于将依赖打包成独立的 chunk,利用浏览器缓存优化加载性能
|
|
10
|
+
*/
|
|
11
|
+
function manualChunks(id: string) {
|
|
12
|
+
// 1. ChatBI 核心层
|
|
13
|
+
if (id.includes('@chatbi-v/core')) return 'chatbi-core';
|
|
14
|
+
|
|
15
|
+
// 2. 第三方依赖 (Node Modules)
|
|
16
|
+
if (id.includes('node_modules')) {
|
|
17
|
+
// React 核心 (将 React 相关包分组)
|
|
18
|
+
if (
|
|
19
|
+
/[\\/]node_modules[\\/](react|react-dom|react-router|react-router-dom|scheduler)[\\/]/.test(
|
|
20
|
+
id,
|
|
21
|
+
)
|
|
22
|
+
) {
|
|
23
|
+
return 'react-vendor';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// UI 组件库 (Ant Design)
|
|
27
|
+
if (id.includes('antd') || id.includes('@ant-design')) {
|
|
28
|
+
return 'antd-vendor';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 其他通用依赖
|
|
32
|
+
return 'vendor';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// https://vitejs.dev/config/
|
|
37
|
+
export default defineConfig(({ mode }) => {
|
|
38
|
+
const env = loadEnv(mode, process.cwd(), '');
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
base: env.VITE_APP_BASE_URL || '/',
|
|
42
|
+
|
|
43
|
+
plugins: [
|
|
44
|
+
react(),
|
|
45
|
+
// 自动读取 tsconfig.json 中的 paths 配置,实现别名映射
|
|
46
|
+
tsconfigPaths(),
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
resolve: {
|
|
50
|
+
alias: {
|
|
51
|
+
'@': path.resolve(__dirname, './src'),
|
|
52
|
+
},
|
|
53
|
+
// 强制统一核心依赖实例,避免多副本导致的 Context 失效
|
|
54
|
+
dedupe: [
|
|
55
|
+
'react',
|
|
56
|
+
'react-dom',
|
|
57
|
+
'react-router',
|
|
58
|
+
'react-router-dom',
|
|
59
|
+
'antd',
|
|
60
|
+
'@ant-design/icons',
|
|
61
|
+
'@ant-design/x',
|
|
62
|
+
'@chatbi-v/core'
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// 开发服务器配置
|
|
67
|
+
server: {
|
|
68
|
+
host: true,
|
|
69
|
+
port: 3000,
|
|
70
|
+
// 增量配置:如果需要代理后端接口,可在此配置
|
|
71
|
+
// proxy: {
|
|
72
|
+
// '/api': {
|
|
73
|
+
// target: 'http://localhost:8080',
|
|
74
|
+
// changeOrigin: true,
|
|
75
|
+
// rewrite: (path) => path.replace(/^\/api/, '')
|
|
76
|
+
// }
|
|
77
|
+
// }
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
build: {
|
|
81
|
+
rollupOptions: {
|
|
82
|
+
output: {
|
|
83
|
+
manualChunks,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
chunkSizeWarningLimit: 1000,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
});
|