gaoluyang
2026-06-24 bfdc0e0e6d5e47aa501f9b6fadd143d9c97cf00a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
 * 组件注册
 *
 * 组件规范:每个子目录就是一个独立的组件,每个目录包括以下三个文件:
 *  1. config.ts:组件配置,必选,用于定义组件、组件默认的属性、定义属性的类型
 *  2. index.vue:组件展示,用于展示组件的渲染效果。可以不提供,如 Page(页面设置),只需要属性配置表单即可
 *  3. property.vue:组件属性表单,用于配置组件,必选,
 *
 * 注:
 * 组件 ID 以 config.ts 中配置的 id 为准,与组件目录的名称无关,但还是建议组件目录的名称与组件 ID 保持一致
 */
import { defineAsyncComponent } from 'vue';
 
const viewModules: Record<string, any> = import.meta.glob('./*/*.vue'); // 导入组件界面模块
const configModules: Record<string, any> = import.meta.glob('./*/config.ts', {
  eager: true,
}); // 导入配置模块
 
const components: Record<string, any> = {}; // 界面模块
const componentConfigs: Record<string, any> = {}; // 组件配置模块
 
type ViewType = 'index' | 'property'; // 组件界面的类型
 
/**
 * 注册组件的界面模块
 *
 * @param componentId 组件ID
 * @param configPath 配置模块的文件路径
 * @param viewType 组件界面的类型
 */
const registerComponentViewModule = (
  componentId: string,
  configPath: string,
  viewType: ViewType,
) => {
  const viewPath = configPath.replace('config.ts', `${viewType}.vue`);
  const viewModule = viewModules[viewPath];
  if (viewModule) {
    // 定义异步组件
    components[componentId] = defineAsyncComponent(viewModule);
  }
};
 
// 注册
Object.keys(configModules).forEach((modulePath: string) => {
  const component = configModules[modulePath].component;
  const componentId = component?.id;
  if (componentId) {
    // 注册组件
    componentConfigs[componentId] = component;
    // 注册预览界面
    registerComponentViewModule(componentId, modulePath, 'index');
    // 注册属性配置表单
    registerComponentViewModule(
      `${componentId}Property`,
      modulePath,
      'property',
    );
  }
});
 
export { componentConfigs, components };