feat: 低代码文件编辑历史记录 crud 功能完成

This commit is contained in:
wangxuefeng 2025-03-01 15:38:53 +08:00
parent 5c4aa42ecf
commit e052752694
11 changed files with 161 additions and 64 deletions

View File

@ -2,10 +2,10 @@ import instance from './instance';
import { type HistorySchema } from '@vtj/core'; import { type HistorySchema } from '@vtj/core';
export type LowCodeHistorySchema = { export type LowCodeHistorySchema = {
project_id: string; project_id: number;
id: string; file_id: string;
page_id?: string; history_id: string;
block_id?: string; id?: string;
dsl?: HistorySchema; dsl?: HistorySchema;
}; };
@ -15,8 +15,40 @@ function transformHistoryData(data: LowCodeHistorySchema) {
dsl: JSON.stringify(data.dsl || {}) dsl: JSON.stringify(data.dsl || {})
}; };
} }
export const getHistories = async () => {
const response = await instance.get('/api/v1/histories'); 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; return response.data;
}; };

View File

@ -23,9 +23,9 @@ import {
updateHistory as updateLowCodeHistory, updateHistory as updateLowCodeHistory,
deleteHistory as deleteLowCodeHistory, deleteHistory as deleteLowCodeHistory,
getHistories as getLowCodeHistories, getHistories as getLowCodeHistories,
createHistory as createLowCodeHistory createHistory as createLowCodeHistory,
getHistories
} from '@/io'; } from '@/io';
import { isNumeric } from 'licia-es';
const storage = new Storage({ const storage = new Storage({
type: 'local', type: 'local',
expired: 0 expired: 0
@ -41,7 +41,7 @@ const stringifyFields = [
'meta' 'meta'
]; ];
export class StorageService extends BaseService { export class LowCodeService extends BaseService {
public async init(project: ProjectSchema): Promise<ProjectSchema> { public async init(project: ProjectSchema): Promise<ProjectSchema> {
const remoteProject = await getProject('2'); const remoteProject = await getProject('2');
const model = new ProjectModel(remoteProject); const model = new ProjectModel(remoteProject);
@ -81,7 +81,6 @@ export class StorageService extends BaseService {
} }
public async saveFile(file: BlockSchema): Promise<boolean> { public async saveFile(file: BlockSchema): Promise<boolean> {
console.log('saveFile', file);
if (file.id) { if (file.id) {
const existFile = await getLowCodeFile(file.id); const existFile = await getLowCodeFile(file.id);
if (existFile.file_id) { if (existFile.file_id) {
@ -115,7 +114,6 @@ export class StorageService extends BaseService {
} }
public async getFile(id: string): Promise<BlockSchema> { public async getFile(id: string): Promise<BlockSchema> {
console.log('getFile', id);
return getLowCodeFile(id).then((lowCodeFile) => { return getLowCodeFile(id).then((lowCodeFile) => {
if (lowCodeFile.dsl) { if (lowCodeFile.dsl) {
return Promise.resolve(lowCodeFile.dsl as BlockSchema); return Promise.resolve(lowCodeFile.dsl as BlockSchema);
@ -130,14 +128,6 @@ export class StorageService extends BaseService {
} }
public async saveHistory(history: HistorySchema): Promise<boolean> { public async saveHistory(history: HistorySchema): Promise<boolean> {
console.log('saveHistory', history);
// const existHistory = await getLowCodeHistory(history.id);
// if (existHistory.history_id) {
// await updateLowCodeHistory(history.id, history);
// } else {
// await createLowCodeHistory(history);
// }
storage.save(`history_${history.id}`, history);
return Promise.resolve(true); return Promise.resolve(true);
} }
@ -150,40 +140,52 @@ export class StorageService extends BaseService {
console.log('uploader', file, projectId); console.log('uploader', file, projectId);
return Promise.resolve(true); return Promise.resolve(true);
}; };
// TODO: 做成数据库存储后没啥用,保留就行
public removeHistory(id: string): Promise<boolean> { public removeHistory(id: string): Promise<boolean> {
return deleteLowCodeHistory(id).then((res) => { console.log('removeHistory', id);
console.log('removeHistory', res);
return Promise.resolve(true);
});
}
public async 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);
// const histories = await getLowCodeHistories(id);
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(fileId: string, item: HistoryItem): Promise<boolean> {
console.log('saveHistoryItem', fileId, item);
storage.save(`history_${fileId}_${item.id}`, item);
return Promise.resolve(true); return Promise.resolve(true);
} }
public removeHistoryItem(fId: string, ids: string[]): Promise<boolean> { public async getHistory(fileId: string): Promise<HistorySchema> {
ids.forEach((id) => { const histories = await getHistories({
storage.remove(`history_${fId}_${id}`); project_id: 2,
console.log('removeHistoryItem', fId, 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> {
const saveHistory = await createLowCodeHistory({
project_id: 2,
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); return Promise.resolve(true);
} }
public publish(project: ProjectSchema): Promise<boolean> { public publish(project: ProjectSchema): Promise<boolean> {

View File

@ -10,16 +10,16 @@ import {
// type ProjectModel // type ProjectModel
} from '@vtj/pro'; } from '@vtj/pro';
import { StorageService } from '@/service'; import { LowCodeService } from '@/service';
const container = ref(); const container = ref();
const service = new StorageService(); const service = new LowCodeService();
const engine = new Engine({ const engine = new Engine({
container, container,
service, service,
project: { project: {
id: 'test', id: '2',
name: '测试' name: '测试'
} }
}); });

View File

@ -5,14 +5,13 @@
import { ref, getCurrentInstance } from 'vue'; import { ref, getCurrentInstance } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { createProvider, ContextMode } from '@vtj/pro'; import { createProvider, ContextMode } from '@vtj/pro';
import { StorageService } from '@/service'; import { LowCodeService } from '@/service';
const service = new StorageService(); const service = new LowCodeService();
const { provider, onReady } = createProvider({ const { provider, onReady } = createProvider({
mode: ContextMode.Runtime, mode: ContextMode.Runtime,
service, service,
project: { project: {
id: 'test', id: '2'
name: '测试'
}, },
dependencies: { dependencies: {
Vue: () => import('vue'), Vue: () => import('vue'),

View File

@ -2,10 +2,14 @@
import { onMounted, computed, watch } from 'vue'; import { onMounted, computed, watch } from 'vue';
import { ElLoading } from 'element-plus'; import { ElLoading } from 'element-plus';
import Postmate from 'postmate'; import Postmate from 'postmate';
import { createRenderer } from '@vtj/renderer' import { createRenderer, createProvider } from '@vtj/renderer'
import { getFile } from './io';
import { useQuery } from '@tanstack/vue-query'; import { useQuery } from '@tanstack/vue-query';
import { LowCodeService } from './service'
import { getFile } from './io';
const lowCodeService = new LowCodeService();
onMounted(() => { onMounted(() => {
const handshake = new Postmate.Model({}); const handshake = new Postmate.Model({});
@ -16,12 +20,10 @@ handshake.then(parent => {
}); });
const { data: file, isFetching } = useQuery({ const { data: file, isFetching } = useQuery({
queryKey: ['file', '45tncm34d'], queryKey: ['getFile'],
queryFn: async () => { queryFn: async () => {
return getFile('45tncm34d'); return getFile('45tnbgeme');
}, },
retry: 3,
retryDelay: 2000,
}); });
watch(isFetching, (newVal) => { watch(isFetching, (newVal) => {
@ -34,6 +36,19 @@ watch(isFetching, (newVal) => {
} }
}); });
const { provider, onReady } = createProvider({
// runtime: 'web',
service: lowCodeService,
project: {
id: '2'
},
});
onReady(() => {
console.log('onReady');
});
const renderer = computed(() => { const renderer = computed(() => {
console.log(file?.value?.dsl.id); console.log(file?.value?.dsl.id);
if (file?.value?.dsl) { if (file?.value?.dsl) {

View File

@ -2,7 +2,6 @@ import { createApp } from "vue";
import "@sy/web-vitals"; import "@sy/web-vitals";
import { IconsPlugin } from "@vtj/icons"; import { IconsPlugin } from "@vtj/icons";
import { VueQueryPlugin } from "@tanstack/vue-query"; import { VueQueryPlugin } from "@tanstack/vue-query";
// import "@sy/low-code-shared/styles/reset.css";
import App from "./App.vue"; import App from "./App.vue";
import ElementPlus from "element-plus"; import ElementPlus from "element-plus";

View File

@ -1 +1,2 @@
export * from "./file"; export * from "./file";
export * from "./project";

View File

@ -0,0 +1,6 @@
import instance from "./instance";
export const getProject = async (id: string) => {
const response = await instance.get(`/api/v1/projects/${id}`);
return response.data;
};

View File

@ -0,0 +1,40 @@
// @ts-nocheck
import { type ProjectSchema, type BlockSchema, ProjectModel } from "@vtj/core";
import { BaseService } from "@vtj/renderer";
import { getProject, getFile as getLowCodeFile } from "@/io";
export class LowCodeService extends BaseService {
public async init(project: ProjectSchema) {
console.log("init", project);
const remoteProject = await getProject("2");
const model = new ProjectModel(remoteProject);
const dsl = model.toDsl();
return Promise.resolve(dsl);
}
public 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)])
),
};
updateProject("2", newProject);
const model = new ProjectModel(project);
storage.save(`project_${model.id}`, model.toDsl());
return Promise.resolve(true);
}
public async getFile(id: string): Promise<BlockSchema> {
console.log("getFile", id);
return getLowCodeFile(id).then((lowCodeFile) => {
if (lowCodeFile.dsl) {
return Promise.resolve(lowCodeFile.dsl as BlockSchema);
} else {
return Promise.reject(null);
}
});
}
}

View File

@ -1,7 +1,5 @@
{ {
"extends": "./node_modules/@vtj/cli/config/tsconfig.web.json",
"compilerOptions": { "compilerOptions": {
"lib": ["es2015", "dom"],
"noUnusedLocals": false, "noUnusedLocals": false,
"noUnusedParameters": false, "noUnusedParameters": false,
"baseUrl": "./", "baseUrl": "./",

View File

@ -8,4 +8,9 @@ export default defineConfig({
port: 10010, port: 10010,
}, },
plugins: [http2Proxy(), mkcert(), VuePlugin()], plugins: [http2Proxy(), mkcert(), VuePlugin()],
esbuild: {
supported: {
"top-level-await": true,
},
},
}); });