chore: 容器框架升级,修复项目命令行异常问题
This commit is contained in:
12
apps/designer/src/App.vue
Normal file
12
apps/designer/src/App.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<el-config-provider :locale="zhCn">
|
||||
<Suspense>
|
||||
<router-view></router-view>
|
||||
</Suspense>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElConfigProvider } from 'element-plus';
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
</script>
|
||||
BIN
apps/designer/src/assets/logo.png
Normal file
BIN
apps/designer/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
1
apps/designer/src/assets/logo.svg
Normal file
1
apps/designer/src/assets/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1711803009570" class="icon" viewBox="0 0 1280 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1500" width="320" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M557.85 1023l-122-35.4c-12.8-3.6-20-17-16.4-29.8L692.45 17.4c3.6-12.8 17-20 29.8-16.4l122 35.4c12.8 3.6 20 17 16.4 29.8L587.65 1006.6c-3.8 12.8-17 20.2-29.8 16.4z m-228-224.4l87-92.8c9.2-9.8 8.6-25.4-1.6-34.4L234.05 512l181.2-159.4c10.2-9 11-24.6 1.6-34.4l-87-92.8c-9-9.6-24.2-10.2-34-1L7.65 494.4c-10.2 9.4-10.2 25.6 0 35l288.2 270.2c9.8 9.2 25 8.8 34-1z m654.4 1.2l288.2-270.2c10.2-9.4 10.2-25.6 0-35L984.25 224.2c-9.6-9-24.8-8.6-34 1L863.25 318c-9.2 9.8-8.6 25.4 1.6 34.4L1046.05 512l-181.2 159.4c-10.2 9-11 24.6-1.6 34.4l87 92.8c9 9.8 24.2 10.2 34 1.2z" fill="#0157fe" p-id="1501"></path></svg>
|
||||
|
After Width: | Height: | Size: 931 B |
88
apps/designer/src/auto-imports.d.ts
vendored
Normal file
88
apps/designer/src/auto-imports.d.ts
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const createPinia: typeof import('pinia')['createPinia']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const defineStore: typeof import('pinia')['defineStore']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const getActivePinia: typeof import('pinia')['getActivePinia']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const mapActions: typeof import('pinia')['mapActions']
|
||||
const mapGetters: typeof import('pinia')['mapGetters']
|
||||
const mapState: typeof import('pinia')['mapState']
|
||||
const mapStores: typeof import('pinia')['mapStores']
|
||||
const mapWritableState: typeof import('pinia')['mapWritableState']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
||||
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const setActivePinia: typeof import('pinia')['setActivePinia']
|
||||
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const storeToRefs: typeof import('pinia')['storeToRefs']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const toValue: typeof import('vue')['toValue']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useId: typeof import('vue')['useId']
|
||||
const useLink: typeof import('vue-router')['useLink']
|
||||
const useModel: typeof import('vue')['useModel']
|
||||
const useRoute: typeof import('vue-router')['useRoute']
|
||||
const useRouter: typeof import('vue-router')['useRouter']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
2
apps/designer/src/constants/env.ts
Normal file
2
apps/designer/src/constants/env.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
// @ts-ignore
|
||||
export const currentEnv = __APP_ENV__;
|
||||
1
apps/designer/src/constants/index.ts
Normal file
1
apps/designer/src/constants/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './env';
|
||||
1
apps/designer/src/contants.ts
Normal file
1
apps/designer/src/contants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const ACCESS_STORAGE_KEY = 'RRO_IDE_ACCESS_STORAGE__';
|
||||
28
apps/designer/src/env.d.ts
vendored
Normal file
28
apps/designer/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue';
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
[key: string]: any;
|
||||
}
|
||||
}
|
||||
|
||||
declare module global {
|
||||
interface Window {}
|
||||
}
|
||||
|
||||
declare module 'vue' {
|
||||
interface ComponentCustomProperties {
|
||||
$uploader: any;
|
||||
$reqeust: any;
|
||||
$apis: any;
|
||||
$libs: any;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
21
apps/designer/src/io/api.ts
Normal file
21
apps/designer/src/io/api.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import instance from './instance';
|
||||
|
||||
export const getApiList = async () => {
|
||||
const response = await instance.get('/api/v1/api');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createApi = async (data: any) => {
|
||||
const response = await instance.post('/api/v1/api', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateApi = async (id: string, data: any) => {
|
||||
const response = await instance.put(`/api/v1/api/${id}`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteApi = async (id: string) => {
|
||||
const response = await instance.delete(`/api/v1/api/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
21
apps/designer/src/io/application.ts
Normal file
21
apps/designer/src/io/application.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import instance from './instance';
|
||||
|
||||
export const getApplicationList = async () => {
|
||||
const response = await instance.get('/api/v1/applications');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createApplication = async (data: any) => {
|
||||
const response = await instance.post('/api/v1/applications', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateApplication = async (id: string, data: any) => {
|
||||
const response = await instance.put(`/api/v1/applications/${id}`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteApplication = async (id: string) => {
|
||||
const response = await instance.delete(`/api/v1/applications/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
21
apps/designer/src/io/block.ts
Normal file
21
apps/designer/src/io/block.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import instance from './instance';
|
||||
|
||||
export const getBlockList = async () => {
|
||||
const response = await instance.get('/api/v1/blocks');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createBlock = async (data: any) => {
|
||||
const response = await instance.post('/api/v1/blocks', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateBlock = async (id: string, data: any) => {
|
||||
const response = await instance.put(`/api/v1/blocks/${id}`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteBlock = async (id: string) => {
|
||||
const response = await instance.delete(`/api/v1/blocks/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
91
apps/designer/src/io/file.ts
Normal file
91
apps/designer/src/io/file.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { type BlockSchema } from '@vtj/core';
|
||||
import instance from './instance';
|
||||
import { fi } from 'element-plus/es/locale/index.mjs';
|
||||
|
||||
export type LowCodeFileSchema = {
|
||||
project_id: number;
|
||||
publish: boolean;
|
||||
active: boolean;
|
||||
dsl: BlockSchema;
|
||||
file_path?: string;
|
||||
file_id?: string;
|
||||
};
|
||||
|
||||
function transformFile(file: LowCodeFileSchema): LowCodeFileSchema {
|
||||
return {
|
||||
project_id: file.project_id,
|
||||
publish: file.publish,
|
||||
active: file.active,
|
||||
// @ts-ignore
|
||||
dsl: JSON.stringify(file.dsl),
|
||||
file_path: file.file_path,
|
||||
file_id: file.file_id
|
||||
};
|
||||
}
|
||||
|
||||
export const getFileList = async () => {
|
||||
const response = await instance.get('/api/v1/files');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getFile = async (id: string) => {
|
||||
const response = await instance.get(`/api/v1/files/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createFile = async (data: LowCodeFileSchema) => {
|
||||
const response = await instance.post('/api/v1/files', transformFile(data));
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateFile = async (id: string, data: LowCodeFileSchema) => {
|
||||
const response = await instance.put(
|
||||
`/api/v1/files/${id}`,
|
||||
transformFile(data)
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
type PublishResponse = {
|
||||
code: string;
|
||||
data: object;
|
||||
id?: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export const deleteFile = async (id: string) => {
|
||||
const response = await instance.delete(`/api/v1/files/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 发布指定项目的所有文件
|
||||
* @param {number} projectId - 需要发布的项目ID
|
||||
* @returns {Promise<any>} 包含发布操作结果的Promise对象
|
||||
* @example
|
||||
* // 发布项目ID为123的所有文件
|
||||
* await publishAllFile(123)
|
||||
*/
|
||||
export const publishAllFile = async (
|
||||
projectId: number
|
||||
): Promise<PublishResponse> => {
|
||||
const response = await instance.post('/api/v1/files/publish', {
|
||||
project_id: projectId
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 发布单个文件
|
||||
* @param {string} fileId - 需要发布的文件ID
|
||||
* @returns {Promise<any>} 包含发布操作结果的Promise对象
|
||||
* @example
|
||||
* // 发布文件ID为45tnbgeme的文件
|
||||
* await publishFile('45tnbgeme')
|
||||
*/
|
||||
export const publishFile = async (fileId: string): Promise<PublishResponse> => {
|
||||
const response = await instance.post('/api/v1/files/publish-file', {
|
||||
file_id: fileId
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
76
apps/designer/src/io/history.ts
Normal file
76
apps/designer/src/io/history.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import instance from './instance';
|
||||
import { type HistorySchema } from '@vtj/core';
|
||||
|
||||
export type LowCodeHistorySchema = {
|
||||
project_id: number;
|
||||
file_id: string;
|
||||
history_id: string;
|
||||
id?: string;
|
||||
dsl?: HistorySchema;
|
||||
};
|
||||
|
||||
function transformHistoryData(data: LowCodeHistorySchema) {
|
||||
return {
|
||||
...data,
|
||||
dsl: JSON.stringify(data.dsl || {})
|
||||
};
|
||||
}
|
||||
|
||||
export type HistoriesResponse = {
|
||||
code: number;
|
||||
data: {
|
||||
list: Array<{
|
||||
id: number;
|
||||
project_id: number;
|
||||
file_id: string;
|
||||
history_id: string;
|
||||
dsl: Record<string, any>;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}>;
|
||||
total: number;
|
||||
};
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type GetHistoriesParams = {
|
||||
project_id: number;
|
||||
file_id: string;
|
||||
page?: number;
|
||||
per_page?: number;
|
||||
};
|
||||
|
||||
export const getHistories = async (params: GetHistoriesParams) => {
|
||||
const response = await instance.get<HistoriesResponse>('/api/v1/histories', {
|
||||
params: {
|
||||
project_id: params.project_id,
|
||||
file_id: params.file_id,
|
||||
...(params.page && { page: params.page }),
|
||||
...(params.per_page && { per_page: params.per_page })
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getHistory = async (id: string) => {
|
||||
const response = await instance.get(`/api/v1/histories/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createHistory = async (data: LowCodeHistorySchema) => {
|
||||
const response = await instance.post(
|
||||
'/api/v1/histories',
|
||||
transformHistoryData(data)
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateHistory = async (id: string, data: any) => {
|
||||
const response = await instance.put(`/api/v1/histories/${id}`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteHistory = async (id: string) => {
|
||||
const response = await instance.delete(`/api/v1/histories/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
7
apps/designer/src/io/index.ts
Normal file
7
apps/designer/src/io/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export * from './api';
|
||||
export * from './block';
|
||||
export * from './file';
|
||||
export * from './materials';
|
||||
export * from './project';
|
||||
export * from './application';
|
||||
export * from './history';
|
||||
30
apps/designer/src/io/instance.ts
Normal file
30
apps/designer/src/io/instance.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const apiBase = import.meta.env.VITE_BASE_API_URL;
|
||||
|
||||
// 创建独立实例
|
||||
const instance = axios.create({
|
||||
baseURL: apiBase // 基础URL直接放在实例配置中
|
||||
});
|
||||
|
||||
// 请求拦截器改为使用实例
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
// 可在此处添加统一请求头等配置
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
instance.interceptors.response.use(
|
||||
(response) => {
|
||||
return response.data;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
// 导出实例
|
||||
export default instance;
|
||||
112
apps/designer/src/io/materials.ts
Normal file
112
apps/designer/src/io/materials.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { type MaterialDescription } from '@vtj/core';
|
||||
|
||||
import instance from './instance';
|
||||
|
||||
// 定义响应类型
|
||||
interface MaterialResponse {
|
||||
code: number;
|
||||
data: MaterialData | MaterialData[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
/** 创建物料请求参数 */
|
||||
interface CreateMaterialRequest {
|
||||
project_id: number;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/** 创建物料响应类型 */
|
||||
interface CreateMaterialResponse {
|
||||
code: number;
|
||||
data: { id: string };
|
||||
message: string;
|
||||
}
|
||||
|
||||
/** 删除物料响应类型 */
|
||||
interface DeleteMaterialResponse {
|
||||
code: number;
|
||||
data: { id: string };
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物料列表
|
||||
* @param params 查询参数
|
||||
* @returns 物料列表
|
||||
*/
|
||||
export const getMaterialsList = async (
|
||||
params?: Record<string, any>
|
||||
): Promise<MaterialResponse> => {
|
||||
const response = await instance.get('/api/v1/materials', { params });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据ID获取单个物料
|
||||
* @param id 物料ID
|
||||
* @returns 物料详情
|
||||
*/
|
||||
export const getMaterials = async (id: number): Promise<MaterialResponse> => {
|
||||
const response = await instance.get(`/api/v1/materials/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
type MaterialData = {
|
||||
project_id: number;
|
||||
value: Record<string, MaterialDescription>;
|
||||
// 从原interface合并的字段
|
||||
id?: number;
|
||||
name?: string;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
};
|
||||
|
||||
function transformMaterialData(data: MaterialData) {
|
||||
return {
|
||||
...data,
|
||||
value: JSON.stringify(data.value)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新物料
|
||||
* @param data 物料数据(注意 value 需要是 JSON 字符串)
|
||||
* @example
|
||||
* postMaterials({ project_id: 1, value: '{"Authorization": "Bearer token"}' })
|
||||
*/
|
||||
export const postMaterials = async (
|
||||
data: MaterialData
|
||||
): Promise<CreateMaterialResponse> => {
|
||||
const response = await instance.post(
|
||||
'/api/v1/materials',
|
||||
transformMaterialData(data)
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新物料
|
||||
* @param data 物料数据
|
||||
* @returns 更新操作结果
|
||||
*/
|
||||
export const updateMaterials = async (data: MaterialData): Promise<any> => {
|
||||
const response = await instance.put(
|
||||
'/api/v1/materials',
|
||||
transformMaterialData(data)
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除指定物料
|
||||
* @param project_id 要删除的物料所属项目ID
|
||||
* @returns 删除操作结果
|
||||
* @example
|
||||
* deleteMaterial('123').then(() => console.log('删除成功'))
|
||||
*/
|
||||
export const deleteMaterials = async (
|
||||
project_id: number
|
||||
): Promise<DeleteMaterialResponse> => {
|
||||
const response = await instance.delete(`/api/v1/materials/${project_id}`);
|
||||
return response.data;
|
||||
};
|
||||
28
apps/designer/src/io/project.ts
Normal file
28
apps/designer/src/io/project.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import instance from './instance';
|
||||
|
||||
export const getProjectList = async (data?: Record<string, any>) => {
|
||||
const response = await instance.get('/api/v1/projects', {
|
||||
params: data
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getProject = async (id: string) => {
|
||||
const response = await instance.get(`/api/v1/projects/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createProject = async (data: any) => {
|
||||
const response = await instance.post('/api/v1/projects', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateProject = async (id: string, data: any) => {
|
||||
const response = await instance.put(`/api/v1/projects/${id}`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteProject = async (id: string) => {
|
||||
const response = await instance.delete(`/api/v1/projects/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
20
apps/designer/src/main.ts
Normal file
20
apps/designer/src/main.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createApp } from 'vue';
|
||||
import { createPersistedState } from 'pinia-plugin-persistedstate';
|
||||
|
||||
import router from './router';
|
||||
import App from './App.vue';
|
||||
import './style/index.scss';
|
||||
import { pinia } from './store';
|
||||
|
||||
// 添加持久化插件
|
||||
pinia.use(
|
||||
createPersistedState({
|
||||
auto: true, // 自动持久化所有 store
|
||||
storage: localStorage
|
||||
})
|
||||
);
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(router);
|
||||
app.use(pinia);
|
||||
app.mount('#app');
|
||||
31
apps/designer/src/router.ts
Normal file
31
apps/designer/src/router.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: () => import('@/views/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/preview/:id',
|
||||
name: 'preview',
|
||||
component: () => import('@/views/preview.vue')
|
||||
},
|
||||
{
|
||||
path: '/unauthorized',
|
||||
name: 'Unauthorized',
|
||||
component: () => import('@/views/unauthorized.vue')
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'NotFound',
|
||||
component: () => import('@/views/not-found.vue')
|
||||
}
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes
|
||||
});
|
||||
|
||||
export default router;
|
||||
249
apps/designer/src/service/index.ts
Normal file
249
apps/designer/src/service/index.ts
Normal file
@@ -0,0 +1,249 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
type ProjectSchema,
|
||||
type BlockSchema,
|
||||
type HistorySchema,
|
||||
type HistoryItem,
|
||||
type MaterialDescription,
|
||||
type ExtensionConfig,
|
||||
type PageFile,
|
||||
type BlockFile,
|
||||
type NodeFromPlugin,
|
||||
ProjectModel,
|
||||
HistoryModel
|
||||
} from '@vtj/core';
|
||||
import { mapToObject, Storage } from '@vtj/utils';
|
||||
import { BaseService } from '@vtj/renderer';
|
||||
import { isEmpty } from 'licia-es';
|
||||
import {
|
||||
getProject,
|
||||
updateProject,
|
||||
createFile,
|
||||
updateFile as updateLowCodeFile,
|
||||
getFile as getLowCodeFile,
|
||||
deleteFile as deleteLowCodeFile,
|
||||
getHistory as getLowCodeHistory,
|
||||
deleteHistory as deleteLowCodeHistory,
|
||||
createHistory as createLowCodeHistory,
|
||||
getHistories as getLowCodeHistories,
|
||||
publishFile as publishLowCodeFile,
|
||||
publishAllFile as publishLowCodeAllFile,
|
||||
getMaterials as getLowCodeMaterials,
|
||||
postMaterials as postLowCodeMaterials,
|
||||
updateMaterials as updateLowCodeMaterials,
|
||||
deleteMaterials as deleteLowCodeMaterials
|
||||
} from '@/io';
|
||||
const storage = new Storage({
|
||||
type: 'local',
|
||||
expired: 0
|
||||
});
|
||||
|
||||
const stringifyFields = [
|
||||
'config',
|
||||
'pages',
|
||||
'dependencies',
|
||||
'blocks',
|
||||
'apis',
|
||||
'meta'
|
||||
];
|
||||
|
||||
let initProject: ProjectSchema;
|
||||
|
||||
export class LowCodeService extends BaseService {
|
||||
public async init(project: ProjectSchema): Promise<ProjectSchema> {
|
||||
console.log('init', project);
|
||||
initProject = project;
|
||||
const remoteProject = await getProject(initProject.id);
|
||||
const arrayFields = ['pages', 'blocks', 'apis', 'meta', 'dependencies'];
|
||||
arrayFields.forEach((field) => {
|
||||
if (isEmpty(remoteProject[field])) {
|
||||
remoteProject[field] = [];
|
||||
}
|
||||
});
|
||||
console.log('remoteProject', remoteProject);
|
||||
const model = new ProjectModel(remoteProject);
|
||||
console.log('model', model || { id: initProject.id });
|
||||
const dsl = model.toDsl();
|
||||
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 async saveProject(project: ProjectSchema): Promise<boolean> {
|
||||
const newProject = {
|
||||
...project,
|
||||
...Object.fromEntries(
|
||||
Object.entries(project)
|
||||
.filter(([key]) => stringifyFields.includes(key))
|
||||
.map(([key, value]) => [key, JSON.stringify(value)])
|
||||
)
|
||||
};
|
||||
// 剔除引擎自行添加的 id,避免接口更新冲突报错
|
||||
Reflect.deleteProperty(newProject, 'id');
|
||||
await updateProject(initProject.id, newProject);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
public getPluginMaterial(
|
||||
from: NodeFromPlugin
|
||||
): Promise<MaterialDescription | null> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
// TODO: 物料存储只有在发布为其他端 (比如 uinapp) 时才有用,当前版本时不需要的,暂且保留
|
||||
public async saveMaterials(
|
||||
project: ProjectSchema,
|
||||
materials: Map<string, MaterialDescription>
|
||||
): Promise<boolean> {
|
||||
const materialData = mapToObject(materials);
|
||||
// storage.save(`materials_${project.id}`, materialData);
|
||||
// console.log('saveMaterials', materialData);
|
||||
// @ts-ignore
|
||||
const existMaterials = await getLowCodeMaterials(project?.id);
|
||||
if (existMaterials) {
|
||||
// 更新物料
|
||||
await updateLowCodeMaterials({
|
||||
project_id: project?.id,
|
||||
value: materialData
|
||||
});
|
||||
} else {
|
||||
// 创建物料
|
||||
await postLowCodeMaterials({
|
||||
project_id: project?.id,
|
||||
value: materialData
|
||||
});
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
// await deleteLowCodeMaterials(project.id);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
public async saveFile(file: BlockSchema): Promise<boolean> {
|
||||
console.log('saveFile', file);
|
||||
if (file.id) {
|
||||
const existFile = await getLowCodeFile(file.id);
|
||||
if (existFile.file_id) {
|
||||
return updateLowCodeFile(file.id, {
|
||||
...existFile,
|
||||
dsl: file
|
||||
})
|
||||
.then(() => {
|
||||
return Promise.resolve(true);
|
||||
})
|
||||
.catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
} else {
|
||||
return createFile({
|
||||
project_id: initProject.id,
|
||||
publish: false,
|
||||
active: true,
|
||||
dsl: file,
|
||||
file_id: file.id
|
||||
})
|
||||
.then(() => {
|
||||
return Promise.resolve(true);
|
||||
})
|
||||
.catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
public async getFile(id: string): Promise<BlockSchema> {
|
||||
return getLowCodeFile(id).then((lowCodeFile) => {
|
||||
if (lowCodeFile.dsl) {
|
||||
return Promise.resolve(lowCodeFile.dsl as BlockSchema);
|
||||
} else {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async removeFile(id: string): Promise<boolean> {
|
||||
return deleteLowCodeFile(id).then(() => Promise.resolve(true));
|
||||
}
|
||||
|
||||
public async saveHistory(history: HistorySchema): Promise<boolean> {
|
||||
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);
|
||||
};
|
||||
// TODO: 做成数据库存储后没啥用,保留就行
|
||||
public removeHistory(id: string): Promise<boolean> {
|
||||
// console.log('removeHistory', id);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
public async getHistory(fileId: string): Promise<HistorySchema> {
|
||||
const histories = await getLowCodeHistories({
|
||||
project_id: initProject.id,
|
||||
file_id: fileId,
|
||||
per_page: 50
|
||||
});
|
||||
const formatDsl = {
|
||||
id: histories.list[0].file_id,
|
||||
items: histories.list.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
id: item.history_id,
|
||||
label: item.created_at
|
||||
};
|
||||
})
|
||||
};
|
||||
const history = new HistoryModel(formatDsl);
|
||||
return Promise.resolve(history.toDsl());
|
||||
}
|
||||
|
||||
public async getHistoryItem(fId: string, id: string): Promise<HistoryItem> {
|
||||
const history = await getLowCodeHistory(id);
|
||||
return Promise.resolve(history);
|
||||
}
|
||||
|
||||
public async saveHistoryItem(
|
||||
fileId: string,
|
||||
historyItem: HistoryItem
|
||||
): Promise<boolean> {
|
||||
await createLowCodeHistory({
|
||||
project_id: initProject.id,
|
||||
file_id: fileId,
|
||||
history_id: historyItem.id,
|
||||
dsl: historyItem.dsl as HistorySchema
|
||||
});
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
public async removeHistoryItem(fId: string, ids: string[]): Promise<boolean> {
|
||||
await Promise.all(ids.map((id) => deleteLowCodeHistory(id)));
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
public publish(project: ProjectSchema): Promise<boolean> {
|
||||
return publishLowCodeAllFile(Number(project.id)).then((res) => {
|
||||
return Promise.resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
public publishFile(
|
||||
project: ProjectSchema,
|
||||
file: PageFile | BlockFile
|
||||
): Promise<boolean> {
|
||||
return publishLowCodeFile(file.id).then((res) => {
|
||||
return Promise.resolve(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
60
apps/designer/src/store/index.ts
Normal file
60
apps/designer/src/store/index.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { ref, computed } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { createPinia, defineStore } from 'pinia';
|
||||
|
||||
// 创建 pinia 实例
|
||||
export const pinia = createPinia();
|
||||
|
||||
// 用户模块 store
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
// 状态定义
|
||||
const token = ref<string>(localStorage.getItem('y-code-access-token') || '');
|
||||
const userProfile = ref<null>(null);
|
||||
|
||||
// getter 计算属性
|
||||
const isLoggedIn = computed(() => !!token.value);
|
||||
|
||||
// 同步 action
|
||||
const setToken = (newToken: string) => {
|
||||
token.value = newToken;
|
||||
localStorage.setItem('y-code-access-token', newToken);
|
||||
};
|
||||
|
||||
// 清理方法
|
||||
const logout = () => {
|
||||
token.value = '';
|
||||
userProfile.value = null;
|
||||
localStorage.removeItem('y-code-access-token');
|
||||
};
|
||||
|
||||
return {
|
||||
token,
|
||||
userProfile,
|
||||
isLoggedIn,
|
||||
setToken,
|
||||
logout
|
||||
};
|
||||
});
|
||||
|
||||
// 应用配置 store
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
const theme = ref<'light' | 'dark'>('light');
|
||||
const sidebarCollapsed = ref(false);
|
||||
|
||||
// 持久化配置
|
||||
const persist = {
|
||||
paths: ['theme', 'sidebarCollapsed'],
|
||||
storage: localStorage
|
||||
};
|
||||
|
||||
const toggleTheme = () => {
|
||||
theme.value = theme.value === 'light' ? 'dark' : 'light';
|
||||
};
|
||||
|
||||
return {
|
||||
theme,
|
||||
sidebarCollapsed,
|
||||
toggleTheme,
|
||||
persist
|
||||
};
|
||||
});
|
||||
15
apps/designer/src/style/index.scss
Normal file
15
apps/designer/src/style/index.scss
Normal file
@@ -0,0 +1,15 @@
|
||||
@use '@vtj/web/src/index.scss';
|
||||
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#vtjLink {
|
||||
display: none;
|
||||
}
|
||||
81
apps/designer/src/views/extension.ts
Normal file
81
apps/designer/src/views/extension.ts
Normal 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__
|
||||
};
|
||||
}
|
||||
}
|
||||
10
apps/designer/src/views/index.ts
Normal file
10
apps/designer/src/views/index.ts
Normal 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';
|
||||
74
apps/designer/src/views/index.vue
Normal file
74
apps/designer/src/views/index.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import Postmate from 'postmate';
|
||||
import { Engine, widgetManager } from '@vtj/pro';
|
||||
import { request, jsonp } from '@vtj/utils';
|
||||
import { useUserStore } from '@/store';
|
||||
import { LowCodeService } from '@/service';
|
||||
|
||||
const container = ref();
|
||||
const service = new LowCodeService();
|
||||
const userStore = useUserStore();
|
||||
|
||||
onMounted(async () => {
|
||||
// 数据模型
|
||||
const model = {
|
||||
name: '',
|
||||
url: '',
|
||||
applicationId: -1,
|
||||
projectId: -1,
|
||||
accessToken: ''
|
||||
};
|
||||
|
||||
const handshake = new Postmate.Model({});
|
||||
await handshake.then((parent) => {
|
||||
parent.emit('sync-context', 'y-code-designer is ready');
|
||||
Object.assign(model, parent.model);
|
||||
// console.log('get parent model', model);
|
||||
userStore.setToken(model.accessToken);
|
||||
request.useRequest((req) => {
|
||||
req.headers.set('Authorization', `Bearer ${model.accessToken}`);
|
||||
return req;
|
||||
});
|
||||
const engine = new Engine({
|
||||
container,
|
||||
service,
|
||||
project: {
|
||||
// @ts-ignore
|
||||
id: model.projectId,
|
||||
name: model.name
|
||||
},
|
||||
adapter: {
|
||||
request,
|
||||
jsonp
|
||||
}
|
||||
});
|
||||
widgetManager.set('Previewer', {
|
||||
props: {
|
||||
path: (block: any) => {
|
||||
const pathname = location.pathname;
|
||||
return `${pathname}#/preview/${block.id}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
widgetManager.set('Templates', {
|
||||
invisible: true
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="designer-container"
|
||||
ref="container"
|
||||
:token="userStore.token"></div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.designer-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
10
apps/designer/src/views/not-found.vue
Normal file
10
apps/designer/src/views/not-found.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<XContainer class="not-found" fit justify="center">
|
||||
<ElEmpty description="找不到页面【404】"></ElEmpty>
|
||||
</XContainer>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { XContainer } from '@vtj/web';
|
||||
import { ElEmpty } from 'element-plus';
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
46
apps/designer/src/views/preview.vue
Normal file
46
apps/designer/src/views/preview.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { LowCodeService } from '@/service';
|
||||
import { useUserStore } from '@/store';
|
||||
import { ContextMode, createProvider } from '@vtj/pro';
|
||||
import { jsonp, request } from '@vtj/utils';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const service = new LowCodeService();
|
||||
request.useRequest((req) => {
|
||||
req.headers.set('Authorization', `Bearer ${userStore.token}`);
|
||||
return req;
|
||||
});
|
||||
const { provider, onReady } = createProvider({
|
||||
mode: ContextMode.Runtime,
|
||||
service,
|
||||
project: {
|
||||
// @ts-ignore
|
||||
id: 4
|
||||
},
|
||||
adapter: {
|
||||
request,
|
||||
jsonp
|
||||
},
|
||||
dependencies: {
|
||||
Vue: () => import('vue'),
|
||||
VueRouter: () => import('vue-router'),
|
||||
ElementPlus: () => import('element-plus')
|
||||
}
|
||||
});
|
||||
const route = useRoute();
|
||||
const renderer = ref();
|
||||
const instance = getCurrentInstance();
|
||||
|
||||
onReady(async () => {
|
||||
instance?.appContext.app.use(provider);
|
||||
renderer.value = await provider.getRenderComponent(
|
||||
route.params.id.toString()
|
||||
);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<component v-if="renderer" :is="renderer" v-bind="$attrs" />
|
||||
</template>
|
||||
10
apps/designer/src/views/unauthorized.vue
Normal file
10
apps/designer/src/views/unauthorized.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<XContainer class="unauthorized" fit justify="center">
|
||||
<ElEmpty description="无权限访问该页面"></ElEmpty>
|
||||
</XContainer>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { XContainer } from '@vtj/ui';
|
||||
import { ElEmpty } from 'element-plus';
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
Reference in New Issue
Block a user