fix: 修复渲染器无法调用 project 内定义的 api

This commit is contained in:
wangxuefeng
2025-02-25 11:39:45 +08:00
parent e695a4bf4a
commit 11018965bd
14 changed files with 199 additions and 17966 deletions

View File

@@ -1,10 +1,7 @@
import { createApp } from 'vue';
import router from './router';
import App from './App.vue';
import ElementPlus from 'element-plus';
import './style/index.scss';
const app = createApp(App);
app.use(router);
app.use(ElementPlus);
app.mount('#app');

View File

@@ -4,12 +4,22 @@ const routes = [
{
path: '/',
name: 'home',
component: () => import('./views/index.vue')
component: () => import('@/views/index.vue')
},
{
path: '/preview/:id',
name: 'preview',
component: () => import('./views/preview.vue')
component: () => import('@/views/preview.vue')
},
{
path: '/unauthorized',
name: 'Unauthorized',
component: () => import('@/views/unauthorized.vue')
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/views/not-found.vue')
}
];

View File

@@ -1,19 +0,0 @@
import { createRouter, createWebHashHistory } from 'vue-router';
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/unauthorized',
name: 'Unauthorized',
component: () => import('@/views/unauthorized.vue')
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/views/not-found.vue')
}
]
});
export default router;

View File

@@ -4,27 +4,41 @@ import {
type HistorySchema,
type HistoryItem,
type MaterialDescription,
type ExtensionConfig,
type PageFile,
type BlockFile,
ProjectModel,
HistoryModel
} from '@vtj/core';
import { Storage, mapToObject } from '@vtj/utils';
import { BaseService } from '@vtj/renderer';
import { debounce } from 'licia-es';
const storage = new Storage({
type: 'local',
expired: 0,
prefix: '__VTJ_'
expired: 0
// prefix: '__VTJ_'
});
export class StorageService extends BaseService {
public init(project: ProjectSchema): Promise<ProjectSchema> {
console.log('init-project', project);
const model = new ProjectModel(project);
// console.log('init-project-model', model);
const match = storage.get(`project_${model.id}`);
console.log('init-project-match', match);
const dsl = Object.assign(model.toDsl(), match || {});
console.log('init-project-dsl', dsl);
storage.save(`project_${model.id}`, dsl);
return Promise.resolve(dsl);
}
public getExtension(): Promise<ExtensionConfig | undefined> {
const extension = storage.get('extension');
console.log('ExtensionConfig', extension);
return Promise.resolve(extension as ExtensionConfig | undefined);
}
public saveProject(project: ProjectSchema): Promise<boolean> {
const model = new ProjectModel(project);
storage.save(`project_${model.id}`, model.toDsl());
@@ -36,16 +50,19 @@ export class StorageService extends BaseService {
materials: Map<string, MaterialDescription>
): Promise<boolean> {
storage.save(`materials_${project.id}`, mapToObject(materials));
console.log('saveMaterials', materials);
return Promise.resolve(true);
}
public saveFile(file: BlockSchema): Promise<boolean> {
storage.save(`file_${file.id}`, file);
console.log('saveFile', file);
return Promise.resolve(true);
}
public getFile(id: string): Promise<BlockSchema> {
const dsl = storage.get(`file_${id}`);
console.log('getFile', id, dsl);
if (dsl) {
return Promise.resolve(dsl as BlockSchema);
} else {
@@ -55,14 +72,26 @@ export class StorageService extends BaseService {
public removeFile(id: string): Promise<boolean> {
storage.remove(`file_${id}`);
console.log('removeFile', id);
return Promise.resolve(true);
}
public saveHistory(history: HistorySchema): Promise<boolean> {
storage.save(`history_${history.id}`, history);
// console.log('saveHistory', history);
return Promise.resolve(true);
}
public api = (type: string, data: any): Promise<any> => {
console.log('api', type, data);
return Promise.resolve(true);
};
protected uploader = (file: File, projectId: string): Promise<any> => {
console.log('uploader', file, projectId);
return Promise.resolve(true);
};
public removeHistory(id: string): Promise<boolean> {
const history = storage.get(`history_${id}`) as HistorySchema;
if (history) {
@@ -70,6 +99,7 @@ export class StorageService extends BaseService {
const ids = items.map((item) => item.id);
this.removeHistoryItem(id, ids);
storage.remove(`history_${id}`);
console.log('removeHistory', history);
}
return Promise.resolve(true);
@@ -77,16 +107,20 @@ export class StorageService extends BaseService {
public getHistory(id: string): Promise<HistorySchema> {
const dsl = storage.get(`history_${id}`);
console.log('getHistoryDSL', dsl);
const history = new HistoryModel(dsl || { id });
console.log('getHistory', dsl, id, history);
return Promise.resolve(history.toDsl());
}
public getHistoryItem(fId: string, id: string): Promise<HistoryItem> {
const item = storage.get(`history_${fId}_${id}`);
console.log('getHistoryItem', item);
return Promise.resolve(item);
}
public saveHistoryItem(fId: string, item: HistoryItem): Promise<boolean> {
console.log('saveHistoryItem', fId, item);
storage.save(`history_${fId}_${item.id}`, item);
return Promise.resolve(true);
}
@@ -94,7 +128,20 @@ export class StorageService extends BaseService {
public removeHistoryItem(fId: string, ids: string[]): Promise<boolean> {
ids.forEach((id) => {
storage.remove(`history_${fId}_${id}`);
console.log('removeHistoryItem', fId, id);
});
return Promise.resolve(true);
}
public publish(project: ProjectSchema): Promise<boolean> {
console.log('整站发布 project', project);
return Promise.resolve(true);
}
public publishFile(
project: ProjectSchema,
file: PageFile | BlockFile
): Promise<boolean> {
console.log('发布页面', project, file);
return Promise.resolve(true);
}
}

View File

@@ -0,0 +1,81 @@
import * as Vue from 'vue';
import * as core from '@vtj/core';
import * as VtjUtils from '@vtj/utils';
import * as VtjUI from '@vtj/ui';
import * as designer from '@vtj/designer';
import * as renderer from '@vtj/renderer';
import * as VtjIcons from '@vtj/icons';
import * as ElementPlus from 'element-plus';
import type { ExtensionConfig } from '@vtj/core';
import type { EngineOptions } from '@vtj/designer';
export type ExtensionOptions = ExtensionConfig;
export type ExtensionFactory = (
config: ExtensionConfig
) => Partial<EngineOptions> | void;
export interface ExtensionOutput {
options: Partial<EngineOptions>;
adapters: Record<string, any>;
}
export class Extension {
private urls: string[] = [];
private library: string = '';
private params: any[] = [];
private __BASE_PATH__: string = '/';
private __adapters__: Record<string, any> = {};
constructor(private options: ExtensionOptions) {
const __VTJ_PRO__ = {
...core,
...designer,
...renderer
};
(window as any).Vue = Vue;
(window as any).__VTJ_PRO__ = __VTJ_PRO__;
(window as any).VtjUtils = VtjUtils;
(window as any).VtjIcons = VtjIcons;
(window as any).VtjUI = VtjUI;
(window as any).ElementPlus = ElementPlus;
const {
urls = [],
library,
params = [],
__BASE_PATH__ = '/',
__adapters__ = {}
} = options || {};
this.urls = urls;
this.library = library;
this.params = params;
this.__BASE_PATH__ = __BASE_PATH__;
this.__adapters__ = __adapters__;
}
async load(): Promise<ExtensionOutput> {
let options: Partial<EngineOptions> = {};
if (this.library) {
const base = this.__BASE_PATH__;
const css = this.urls
.filter((n) => renderer.isCSSUrl(n))
.map((n) => `${base}${n}`);
const scripts: string[] = this.urls
.filter((n) => renderer.isJSUrl(n))
.map((n) => `${base}${n}`);
renderer.loadCssUrl(css);
if (scripts.length) {
const output = await renderer
.loadScriptUrl(scripts, this.library)
.catch(() => null);
if (output && typeof output === 'function') {
options = output.call(output, this.options, this.params);
} else {
options = output || {};
}
}
}
return {
options,
adapters: this.__adapters__
};
}
}

View File

@@ -0,0 +1,10 @@
import 'element-plus/theme-chalk/dark/css-vars.css';
import 'element-plus/theme-chalk/index.css';
// import 'vxe-table/es/style.min.css';
import '@vtj/ui/dist/style.css';
import '@vtj/icons/dist/style.css';
export * from '@vtj/core';
export * from '@vtj/designer';
export * from '@vtj/renderer';
export * from './extension';

View File

@@ -6,9 +6,7 @@
import { ref } from 'vue';
import {
Engine,
widgetManager,
LocalService,
MemoryService
widgetManager
// type ProjectModel
} from '@vtj/pro';
@@ -16,7 +14,6 @@ import { StorageService } from '@/service';
const container = ref();
const service = new StorageService();
// const service = new StorageService();
const engine = new Engine({
container,
@@ -30,7 +27,6 @@ const engine = new Engine({
widgetManager.set('Previewer', {
props: {
path: (block: any) => {
console.log('block', block);
const pathname = location.pathname;
return `${pathname}#/preview/${block.id}`;
}

View File

@@ -1,36 +1,33 @@
<script setup lang="ts">
import { createRenderer } from '@vtj/renderer';
<template>
<component v-if="renderer" :is="renderer"></component>
</template>
<script lang="ts" setup>
import { ref, getCurrentInstance } from 'vue';
import { useRoute } from 'vue-router';
import { createProvider, ContextMode } from '@vtj/pro';
import { StorageService } from '@/service';
import { getCurrentInstance } from 'vue';
const route = useRoute();
const service = new StorageService();
const { provider, onReady } = createProvider({
mode: ContextMode.Runtime,
service,
project: {
id: 'test',
name: '测试'
},
dependencies: {
Vue: () => import('vue'),
VueRouter: () => import('vue-router'),
ElementPlus: () => import('element-plus')
}
});
const route = useRoute();
const renderer = ref();
const instance = getCurrentInstance();
const app = instance?.appContext.app;
const file = await service.getFile(route.params.id.toString());
console.log('file', file);
Object.assign(route.meta, file.meta);
const el = app?._container;
if (file?.type === 'page') {
el.classList.add('is-page');
}
const isPure = file?.pure;
if (isPure) {
el.classList.add('is-pure');
}
const { renderer } = createRenderer({
dsl: file
onReady(async () => {
instance?.appContext.app.use(provider);
renderer.value = await provider.getRenderComponent(
route.params.id.toString()
);
});
</script>
<template>
<component :is="renderer" />
</template>