From 4bc58460b424b626beea20a9c68dfb07bb0ba749 Mon Sep 17 00:00:00 2001 From: abearxiong Date: Mon, 26 Jan 2026 03:01:29 +0800 Subject: [PATCH] remove old apps --- src/db/drizzle/schema.ts | 1 - src/old-apps/container/index.ts | 1 - src/old-apps/container/list.ts | 108 ------ src/old-apps/container/models/index.ts | 101 ------ .../container/module/get-container-file.ts | 11 - src/old-apps/container/type.ts | 3 - src/old-apps/page/index.ts | 3 - src/old-apps/page/list.ts | 312 ------------------ src/old-apps/page/models/index.ts | 88 ----- src/old-apps/page/module/cache-file.ts | 193 ----------- src/old-apps/page/module/file-template.ts | 102 ------ src/old-apps/page/module/get-container.ts | 143 -------- src/old-apps/page/publish.ts | 89 ----- src/routes/index.ts | 1 + src/routes/light-code/list.ts | 151 +++++++++ 15 files changed, 152 insertions(+), 1155 deletions(-) delete mode 100644 src/old-apps/container/index.ts delete mode 100644 src/old-apps/container/list.ts delete mode 100644 src/old-apps/container/models/index.ts delete mode 100644 src/old-apps/container/module/get-container-file.ts delete mode 100644 src/old-apps/container/type.ts delete mode 100644 src/old-apps/page/index.ts delete mode 100644 src/old-apps/page/list.ts delete mode 100644 src/old-apps/page/models/index.ts delete mode 100644 src/old-apps/page/module/cache-file.ts delete mode 100644 src/old-apps/page/module/file-template.ts delete mode 100644 src/old-apps/page/module/get-container.ts delete mode 100644 src/old-apps/page/publish.ts create mode 100644 src/routes/light-code/list.ts diff --git a/src/db/drizzle/schema.ts b/src/db/drizzle/schema.ts index 3d6e6ae..3e56ca5 100644 --- a/src/db/drizzle/schema.ts +++ b/src/db/drizzle/schema.ts @@ -253,7 +253,6 @@ export const kvContainer = pgTable("kv_container", { createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), uid: uuid(), - publish: json().default({}), tags: json().default([]), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), hash: text().default(''), diff --git a/src/old-apps/container/index.ts b/src/old-apps/container/index.ts deleted file mode 100644 index 83ec5cd..0000000 --- a/src/old-apps/container/index.ts +++ /dev/null @@ -1 +0,0 @@ -import './list.ts'; diff --git a/src/old-apps/container/list.ts b/src/old-apps/container/list.ts deleted file mode 100644 index afa5b06..0000000 --- a/src/old-apps/container/list.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { CustomError } from '@kevisual/router'; -import { app } from '../../app.ts'; -import { ContainerModel, ContainerData, Container } from './models/index.ts'; - -app - .route({ - path: 'container', - key: 'list', - middleware: ['auth'], - }) - .define(async (ctx) => { - const tokenUser = ctx.state.tokenUser; - const list = await ContainerModel.findAll({ - order: [['updatedAt', 'DESC']], - where: { - uid: tokenUser.id, - }, - attributes: { exclude: ['code'] }, - }); - ctx.body = list; - return ctx; - }) - .addTo(app); - -app - .route({ - path: 'container', - key: 'get', - middleware: ['auth'], - }) - .define(async (ctx) => { - const tokenUser = ctx.state.tokenUser; - const id = ctx.query.id; - if (!id) { - throw new CustomError('id is required'); - } - const container = await ContainerModel.findByPk(id); - if (!container) { - throw new CustomError('container not found'); - } - if (container.uid !== tokenUser.id) { - throw new CustomError('container not found'); - } - ctx.body = container; - return ctx; - }) - .addTo(app); - -app - .route({ - path: 'container', - key: 'update', - middleware: ['auth'], - }) - .define(async (ctx) => { - const tokenUser = ctx.state.tokenUser; - const data = ctx.query.data; - const { id, ...container } = data; - let containerModel: ContainerModel | null = null; - if (id) { - containerModel = await ContainerModel.findByPk(id); - if (containerModel) { - containerModel.update({ - ...container, - publish: { - ...containerModel.publish, - ...container.publish, - }, - }); - await containerModel.save(); - } - } else { - try { - containerModel = await ContainerModel.create({ - ...container, - uid: tokenUser.id, - }); - } catch (e) { - console.log('error', e); - } - console.log('containerModel', container); - } - ctx.body = containerModel; - return ctx; - }) - .addTo(app); - -app - .route({ - path: 'container', - key: 'delete', - middleware: ['auth'], - }) - .define(async (ctx) => { - const tokenUser = ctx.state.tokenUser; - const id = ctx.query.id; - const container = await ContainerModel.findByPk(id); - if (!container) { - throw new CustomError('container not found'); - } - if (container.uid !== tokenUser.id) { - throw new CustomError('container not found'); - } - await container.destroy(); - ctx.body = container; - return ctx; - }) - .addTo(app); diff --git a/src/old-apps/container/models/index.ts b/src/old-apps/container/models/index.ts deleted file mode 100644 index 6e4ccb8..0000000 --- a/src/old-apps/container/models/index.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { sequelize } from '../../../modules/sequelize.ts'; -import { DataTypes, Model } from 'sequelize'; -import crypto from 'crypto'; -export interface ContainerData {} -export type ContainerPublish = { - key: string; - title?: string; - description?: string; - fileName?: string; - version?: string; -}; -export type Container = Partial>; - -/** - * 用户代码容器 - */ -export class ContainerModel extends Model { - declare id: string; - // 标题 - declare title: string; - // 描述 - declare description: string; - // 类型 - declare type: string; - // 标签 - declare tags: string[]; - // 代码 - declare code: string; - // hash 值 - declare hash: string; - // 数据 - declare data: ContainerData; - // 发布 - declare publish: ContainerPublish; - // 用户 id - declare uid: string; - declare updatedAt: Date; - declare createdAt: Date; - createHash() { - const { code } = this; - const hash = crypto.createHash('md5'); - hash.update(code); - this.hash = hash.digest('hex'); - } -} -ContainerModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - comment: 'id', - }, - title: { - type: DataTypes.TEXT, - defaultValue: '', - }, - description: { - type: DataTypes.TEXT, - defaultValue: '', - }, - tags: { - type: DataTypes.JSON, - defaultValue: [], - }, - type: { - type: DataTypes.STRING, // 代码类型, html, js, render-js - defaultValue: 'render-js', - }, - code: { - type: DataTypes.TEXT, - defaultValue: '', - }, - hash: { - type: DataTypes.TEXT, - defaultValue: '', - }, - data: { - type: DataTypes.JSON, - defaultValue: {}, - }, - publish: { - type: DataTypes.JSON, - defaultValue: {}, - }, - - uid: { - type: DataTypes.UUID, - allowNull: true, - }, - }, - { - sequelize, - tableName: 'kv_container', - paranoid: true, - }, -); - -// ContainerModel.sync({ alter: true, logging: false }).catch((e) => { -// console.error('ContainerModel sync', e); -// }); diff --git a/src/old-apps/container/module/get-container-file.ts b/src/old-apps/container/module/get-container-file.ts deleted file mode 100644 index fe973fc..0000000 --- a/src/old-apps/container/module/get-container-file.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ContainerModel } from '../models/index.ts'; - -export const getContainerById = async (id: string) => { - const container = await ContainerModel.findByPk(id); - const code = container?.code; - return { - code, - id: container?.id, - updatedAt: new Date(container?.updatedAt).getTime(), - }; -}; diff --git a/src/old-apps/container/type.ts b/src/old-apps/container/type.ts deleted file mode 100644 index caa8919..0000000 --- a/src/old-apps/container/type.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ContainerData } from './models/index.ts'; - -export { ContainerData }; diff --git a/src/old-apps/page/index.ts b/src/old-apps/page/index.ts deleted file mode 100644 index 47ca30f..0000000 --- a/src/old-apps/page/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import './list.ts' - -import './publish.ts' \ No newline at end of file diff --git a/src/old-apps/page/list.ts b/src/old-apps/page/list.ts deleted file mode 100644 index 212ed69..0000000 --- a/src/old-apps/page/list.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { CustomError } from '@kevisual/router'; -import { app } from '../../app.ts'; -import { PageModel } from './models/index.ts'; -import { nanoid, customAlphabet } from 'nanoid' -import { ContainerModel } from '../container/models/index.ts'; -import { Op } from 'sequelize'; -import { getDeck } from './module/cache-file.ts'; -export const clearBlank = (newStyle: any) => { - for (let key in newStyle) { - if (newStyle[key] === '' || newStyle[key] === undefined || newStyle[key] === null) { - delete newStyle[key]; - } - } -}; -const uuidv4 = () => { - const alphabet = '0123456789abcdef'; - const nanoidCustom = customAlphabet(alphabet, 36); - return nanoidCustom(); -} -app - .route({ - path: 'page', - key: 'get', - }) - .define(async (ctx) => { - const id = ctx.query.id; - if (!id) { - throw new CustomError('id is required'); - } - try { - const page = await PageModel.findByPk(id); - ctx.body = page; - } catch (e) { - console.log('error', e); - throw new CustomError(e.message || 'get error'); - } - }) - .addTo(app); - -app - .route({ - path: 'page', - key: 'list', - middleware: ['auth'], - }) - .define(async (ctx) => { - const tokenUser = ctx.state.tokenUser; - ctx.body = await PageModel.findAll({ - order: [['updatedAt', 'DESC']], - where: { - uid: tokenUser.id, - }, - }); - return ctx; - }) - .addTo(app); - -app - .route({ - path: 'page', - key: 'update', - middleware: ['auth'], - }) - .define(async (ctx) => { - const { data, id, publish, ...rest } = ctx.query.data; - const tokenUser = ctx.state.tokenUser; - let needUpdate = { ...rest }; - if (data) { - needUpdate = { ...needUpdate, data }; - } - if (publish) { - needUpdate = { ...needUpdate, publish }; - } - - if (id) { - const page = await PageModel.findByPk(id); - // if (!page?.publish && publish) { - // needUpdate = { ...needUpdate, publish }; - // } - if (page) { - const newPage = await page.update({ ...needUpdate }); - ctx.body = newPage; - } else { - throw new CustomError('page not found'); - } - } else if (data) { - const page = await PageModel.create({ ...needUpdate, uid: tokenUser.id }); - ctx.body = page; - } - }) - .addTo(app); -app - .route('page', 'updateNode') - .define(async (ctx) => { - const { id, nodeData } = ctx.query.data; - const force = ctx.query.force; - if (!id) { - throw new CustomError('id is required'); - } - const page = await PageModel.findByPk(id); - if (!page) { - throw new CustomError('page not found'); - } - const { data } = page; - const { nodes = [] } = data; - let flag = false; - const newNodes = nodes.map((item) => { - const nodeItem = nodeData; - if (item.id === nodeItem.id) { - flag = true; - const { data, ...rest } = nodeItem; - const { style, ...restData } = data || {}; - let newStyle = force ? { ...style } : { ...item?.data?.style, ...style }; - clearBlank(newStyle); - console.log('newStyle', newStyle); - const newNodeItem = { - ...item, - ...rest, - data: { - ...item?.data, - ...restData, - style: newStyle, - }, - }; - console.log('newNodeItem', newNodeItem); - return newNodeItem; - } - return item; - }); - if (!flag) { - newNodes.push(nodeData); - } - const newData = { ...data, nodes: newNodes }; - const newPage = await page.update({ data: newData }); - ctx.body = newPage; - - return ctx; - }) - .addTo(app); -app - .route({ - path: 'page', - key: 'delete', - }) - .define(async (ctx) => { - const id = ctx.query.id; - const page = await PageModel.findByPk(id); - if (page) { - await page.destroy(); - } - ctx.body = page; - return ctx; - }) - .addTo(app); - -app - .route({ - path: 'page', - key: 'addDemo', - }) - .define(async (ctx) => { - const id = uuidv4(); - const data = { - // id: 'container-1', - id, - title: 'demo', - description: 'demo', - type: 'conainer', - data: { - edges: [ - { - id: 'e1', - // source: 'container-1', - source: id, - target: 'container-2', - }, - { - id: 'e2', - // source: 'container-1', - source: id, - target: 'container-3', - }, - { - id: 'e3', - source: 'container-2', - target: 'container-4', - }, - ], - nodes: [ - { - // id: 'container-1', - id, - type: 'container', - data: { - label: '开始', - title: 'demo-hello-world', - cid: 'a6652ce0-82fb-432a-a6b0-2033a655b02c', - root: true, - style: { - border: '1px solid black', - }, - }, - position: { - x: 50, - y: 125, - }, - }, - { - id: 'container-2', - type: 'container', - data: { - label: '容器', - title: 'demo-child-01', - cid: '67e5b2ff-98dc-43ab-8ad9-9b062096f8eb', - style: { - color: 'green', - position: 'absolute', - border: '1px solid black', - top: '100px', - left: '100px', - width: '200px', - height: '200px', - }, - shadowRoot: true, - }, - position: { - x: 350, - y: 125, - }, - }, - { - id: 'container-3', - type: 'container', - data: { - label: '容器', - title: 'demo-child-03', - cid: '208c3e36-dc7d-46af-b2f0-81d5f43c974d', - style: { - color: 'green', - position: 'absolute', - border: '1px solid green', - top: '100px', - left: '100px', - width: '200px', - height: '200px', - }, - }, - position: { - x: 350, - y: 325, - }, - }, - { - id: 'container-4', - type: 'container', - data: { - label: '容器', - title: 'demo-child-04', - cid: '170c0b55-8c13-4d6e-bf35-3f935d979a0d', - style: { - color: 'green', - position: 'absolute', - border: '1px solid green', - top: '100px', - left: '400px', - width: '200px', - height: '200px', - }, - }, - position: { - x: 650, - y: 125, - }, - }, - ], - viewport: {}, - }, - }; - try { - const page = await PageModel.create(data); - ctx.body = page; - } catch (e) { - console.log('error', e); - throw new CustomError('addDemo error'); - } - }) - .addTo(app); - -app - .route({ - path: 'page', - key: 'getDeck', - }) - .define(async (ctx) => { - const id = ctx.query.id; - if (!id) { - throw new CustomError('id is required'); - } - - try { - const page = await PageModel.findByPk(id); - if (!page) { - throw new CustomError(404, 'panel not found'); - } - const pageData = await getDeck(page); - ctx.body = pageData; - } catch (e) { - console.log('error', e); - throw new CustomError(e.message || 'get error'); - } - }) - .addTo(app); diff --git a/src/old-apps/page/models/index.ts b/src/old-apps/page/models/index.ts deleted file mode 100644 index c1b0e62..0000000 --- a/src/old-apps/page/models/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { sequelize } from '../../../modules/sequelize.ts'; -import { DataTypes, Model } from 'sequelize'; - -type PageNodeData = { - id: string; - type: string; - data: { - label?: string; // 容器 开始 结束 - root?: boolean; // 是否是根节点 - - // 容器上的属性 - cid?: string; // 容器id - style?: { [key: string]: string }; - className?: string; - showChild?: boolean; - shadowRoot?: boolean; - }; - - [key: string]: any; -}; - -export interface PageData { - edges: any[]; - nodes: PageNodeData[]; - viewport: any; - [key: string]: any; -} -export type Publish = { - id?: string; // resource id - description?: string; - key?: string; - version?: string; -}; -/** - * 页面数据 - */ -export class PageModel extends Model { - declare id: string; - declare title: string; - declare description: string; - declare type: string; - declare data: PageData; - declare publish: Publish; - declare uid: string; -} -PageModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - comment: 'id', - }, - title: { - type: DataTypes.STRING, - defaultValue: '', - }, - description: { - type: DataTypes.TEXT, - defaultValue: '', - }, - type: { - type: DataTypes.STRING, - defaultValue: '', - }, - data: { - type: DataTypes.JSON, - defaultValue: {}, - }, - publish: { - type: DataTypes.JSON, - defaultValue: {}, - }, - uid: { - type: DataTypes.UUID, - allowNull: true, - }, - }, - { - sequelize, - tableName: 'kv_page', - paranoid: true, - }, -); - -// PageModel.sync({ alter: true, logging: false }).catch((e) => { -// console.error('PageModel sync', e); -// }); diff --git a/src/old-apps/page/module/cache-file.ts b/src/old-apps/page/module/cache-file.ts deleted file mode 100644 index 75f9218..0000000 --- a/src/old-apps/page/module/cache-file.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { useFileStore } from '@kevisual/use-config'; -import { PageModel } from '../models/index.ts'; -import { ContainerModel } from '@/old-apps/container/models/index.ts'; -import { Op } from 'sequelize'; -import { getContainerData } from './get-container.ts'; -import path from 'node:path'; -import fs from 'node:fs'; -import { getHTML, getDataJs, getOneHTML } from './file-template.ts'; -import { minioClient } from '@/app.ts'; -import { bucketName } from '@/modules/minio.ts'; -import { getContentType } from '@/utils/get-content-type.ts'; -import archiver from 'archiver'; -import { CustomError } from '@kevisual/router'; -import { nanoid } from 'nanoid'; - -export const cacheFile = useFileStore('cache-file', { - needExists: true, -}); - -export const getDeck = async (page: PageModel) => { - const { data } = page; - const { nodes = [], edges } = data; - const containerList = nodes - .map((item) => { - const { data } = item; - return data?.cid; - }) - .filter((item) => item); - const quchong = Array.from(new Set(containerList)); - const containers = await ContainerModel.findAll({ - where: { - id: { - [Op.in]: quchong, - }, - }, - }); - - const pageData = { - page, - containerList: containers, - }; - return pageData; -}; - -export const cachePage = async (page: PageModel, opts: { tokenUser: any; key; version }) => { - const _result = await getDeck(page); - const result = getContainerData(_result); - const key = 'data-' + nanoid(6); - const html = getHTML({ rootId: page.id, title: page?.publish?.key, dataKey: key }); - const dataJs = getDataJs(result); - const htmlPath = path.resolve(cacheFile, `${page.id}.html`); - const dataJsPath = path.resolve(cacheFile, `${page.id}.js`); - fs.writeFileSync(htmlPath, html); - fs.writeFileSync(dataJsPath, dataJs); - const minioHTML = await uploadMinio({ ...opts, path: `index.html`, filePath: htmlPath }); - const minioData = await uploadMinio({ ...opts, path: `${key || 'data'}.js`, filePath: dataJsPath }); - return [ - { - name: 'index.html', - path: minioHTML, - }, - { - name: `${key || 'data'}.js`, - path: minioData, - }, - ]; -}; -export const uploadMinioContainer = async ({ tokenUser, key, version, code, filePath, saveHTML }) => { - if ((filePath as string).includes('..')) { - throw new CustomError('file path is invalid'); - } - const uploadFiles = []; - const minioKeyVersion = `${tokenUser.username}/${key}/${version}`; - const minioPath = path.join(minioKeyVersion, filePath); - const minioFileName = path.basename(minioPath); - if (!minioFileName.endsWith('.js')) { - saveHTML = false; - } - console.log('minioPath', minioPath); - // const isHTML = filePath.endsWith('.html'); - const name = minioPath.replace(minioKeyVersion + '/', ''); - await minioClient.putObject(bucketName, minioPath, code, code.length, { - 'Content-Type': getContentType(filePath), - 'app-source': 'user-app', - 'Cache-Control': 'no-cache', // no-cache - }); - uploadFiles.push({ - name, - path: minioPath, - }); - if (saveHTML) { - const htmlPath = minioPath.replace('.js', '.html'); - const code = getOneHTML({ title: 'Kevisual', file: minioFileName.replace('.js', '') }); - await minioClient.putObject(bucketName, htmlPath, code, code.length, { - 'Content-Type': 'text/html', - 'app-source': 'user-app', - 'Cache-Control': 'max-age=31536000, immutable', - }); - uploadFiles.push({ - name: 'index.html', - path: htmlPath, - }); - } - return uploadFiles; -}; -export const uploadMinio = async ({ tokenUser, key, version, path, filePath }) => { - const minioPath = `${tokenUser.username}/${key}/${version}/${path}`; - const isHTML = filePath.endsWith('.html'); - await minioClient.fPutObject(bucketName, minioPath, filePath, { - 'Content-Type': getContentType(filePath), - 'app-source': 'user-app', - 'Cache-Control': isHTML ? 'no-cache' : 'max-age=31536000, immutable', // 缓存一年 - }); - fs.unlinkSync(filePath); // 删除临时文件 - return minioPath; -}; -export const uploadMinioTemp = async ({ tokenUser, filePath, path }) => { - const minioPath = `${tokenUser.username}/temp/${path}`; - const isHTML = filePath.endsWith('.html'); - await minioClient.fPutObject(bucketName, minioPath, filePath, { - 'Content-Type': getContentType(filePath), - 'app-source': 'user-app', - 'Cache-Control': isHTML ? 'no-cache' : 'max-age=31536000, immutable', // 缓存一年 - }); - fs.unlinkSync(filePath); // 删除临时文件 - return minioPath; -}; -export const getZip = async (page: PageModel, opts: { tokenUser: any }) => { - const _result = await getDeck(page); - const result = getContainerData(_result); - const html = getHTML({ rootId: page.id, title: page?.publish?.key }); - const dataJs = getDataJs(result); - const zip = archiver('zip', { - zlib: { level: 9 }, - }); - // 创建 zip 文件的输出流 - const zipCache = path.join(cacheFile, `${page.id}.zip`); - if (checkFileExistsSync(zipCache)) { - throw new CustomError('page is on uploading'); - } - return await new Promise((resolve, reject) => { - const output = fs.createWriteStream(zipCache); - // 监听事件 - output.on('close', async () => { - console.log(`Zip file has been created successfully. Total size: ${zip.pointer()} bytes.`); - let time = (new Date().getTime() / 1000).toFixed(0); - const name = page.title || page.id; - const minioPath = await uploadMinioTemp({ ...opts, filePath: zipCache, path: `${name + '-' + time}.zip` }); - resolve(minioPath); - }); - - output.on('end', () => { - console.log('Data has been drained.'); // 数据已被耗尽 - throw new CustomError('Data has been drained.'); - }); - - zip.on('warning', (err) => { - if (err.code === 'ENOENT') { - console.warn('File not found:', err); - } else { - throw err; - } - }); - - zip.on('error', (err) => { - throw err; - }); - - // 通过管道将 zip 数据流输出到指定文件 - zip.pipe(output); - - // 添加 HTML 字符串作为文件到 zip 中 - zip.append(html, { name: 'index.html' }); - - // 添加 JavaScript 字符串作为文件到 zip 中 - zip.append(dataJs, { name: 'data.js' }); - zip.append(JSON.stringify(page), { name: 'app.config.json' }); - // 可以继续添加更多内容,文件或目录等 - // zip.append('Another content', { name: 'other.txt' }); - - // 结束归档(必须调用,否则 zip 文件无法完成) - zip.finalize(); - }); -}; -export const checkFileExistsSync = (filePath: string) => { - try { - // 使用 F_OK 检查文件或目录是否存在 - fs.accessSync(filePath, fs.constants.F_OK); - return true; - } catch (err) { - return false; - } -}; diff --git a/src/old-apps/page/module/file-template.ts b/src/old-apps/page/module/file-template.ts deleted file mode 100644 index f35689c..0000000 --- a/src/old-apps/page/module/file-template.ts +++ /dev/null @@ -1,102 +0,0 @@ -type HTMLOptions = { - title?: string; - rootId: string; - dataKey?: string; -}; -/** - * data list - * @param opts - * @returns - */ -export const getHTML = (opts: HTMLOptions) => { - return ` - - - - - - ${opts.title || 'Kevisual'} - - - - - -
- - - -`; -}; - -export const getDataJs = (result: any) => { - return 'export const data=' + JSON.stringify(result); -}; - -type OneHTMLOptions = { - title?: string; - file: string; -} -/** - * one data - * @param opts - * @returns - */ -export const getOneHTML = (opts: OneHTMLOptions) => { - return ` - - - - - - ${opts.title || 'Kevisual'} - - - - - -
- - - -`; -}; diff --git a/src/old-apps/page/module/get-container.ts b/src/old-apps/page/module/get-container.ts deleted file mode 100644 index 46a2bf6..0000000 --- a/src/old-apps/page/module/get-container.ts +++ /dev/null @@ -1,143 +0,0 @@ -// import { RenderData } from '@abearxiong/container'; -type RenderData = any; - -type Page = { - data: { - edges: { id: string; source: string; target: string }[]; - nodes: { id: string; type: string; position: { x: number; y: number }; data: any }[]; - }; - id: string; - type: string; - [key: string]: any; -}; -type Container = { - code: string; - id: string; - [key: string]: any; -}; -type PageEditData = { - page: Page; - containerList: Container[]; -}; -export const getContainerData = (pageEditData: any) => { - const { page, containerList } = pageEditData; - const containerObj = containerList.reduce((acc, container) => { - acc[container.id] = container; - return acc; - }, {}); - - const { edges, nodes } = page.data; - const nodesObj = nodes.reduce((acc, node) => { - acc[node.id] = node; - return acc; - }, {}); - const treeArray = getTreeFromEdges(edges); - const floatNodes = nodes.filter((node) => !treeArray.find((item) => item.id === node.id)); - const treeNodes = nodes.filter((node) => treeArray.find((item) => item.id === node.id)); - const renderData: RenderData[] = []; - for (let tree of treeArray) { - const node = nodesObj[tree.id]; - const container = containerObj[node.data?.cid]; - const style = node.data?.style ?? { - position: 'absolute', - width: 100, - height: 100, - }; - const data = { - node: { ...node }, - container: { ...container }, - }; - renderData.push({ - id: node.id, - children: tree.children, - parents: tree.parents, - code: container?.code || '', - codeId: container?.id, - data: data || {}, - className: node.data?.className, - shadowRoot: node.data?.shadowRoot, - showChild: node.data?.showChild, - style, - }); - } - for (let node of floatNodes) { - const container = containerObj[node.data?.cid]; - const style = node.data?.style ?? { - position: 'absolute', - width: 100, - height: 100, - }; - const data = { - node: { ...node }, - container: { ...container }, - }; - renderData.push({ - id: node.id, - children: [], - parents: [], - code: container?.code || '', - codeId: container?.id, - data: data || {}, - className: node.data?.className, - shadowRoot: node.data?.shadowRoot, - showChild: node.data?.showChild, - style, - }); - } - return renderData; -}; -const getTreeFromEdges = ( - edges: { id: string; source: string; target: string }[], -): { - id: string; - parents: string[]; - children: string[]; -}[] => { - // 构建树形结构 - function buildNodeTree(edges) { - const nodeMap = {}; - - // 初始化每个节点的子节点列表和父节点列表 - edges.forEach((edge) => { - if (!nodeMap[edge.source]) { - nodeMap[edge.source] = { id: edge.source, parents: [], children: [] }; - } - if (!nodeMap[edge.target]) { - nodeMap[edge.target] = { id: edge.target, parents: [], children: [] }; - } - - // 连接父节点和子节点 - nodeMap[edge.source].children.push(nodeMap[edge.target]); - nodeMap[edge.target].parents.push(nodeMap[edge.source]); - }); - - return nodeMap; - } - - const nodeTree = buildNodeTree(edges); - - // 递归获取所有父节点,按顺序 - function getAllParents(node) { - const parents: string[] = []; - function traverseParents(currentNode) { - if (currentNode.parents.length > 0) { - currentNode.parents.forEach((parent: any) => { - parents.push(parent.id); - traverseParents(parent); - }); - } - } - traverseParents(node); - return parents.reverse(); // 确保顺序从最顶层到直接父节点 - } - - function getNodeInfo(nodeMap) { - return Object.values(nodeMap).map((node: any) => ({ - id: node.id, - parents: getAllParents(node), - children: node.children.map((child) => child.id), - })); - } - const result = getNodeInfo(nodeTree); - return result; -}; diff --git a/src/old-apps/page/publish.ts b/src/old-apps/page/publish.ts deleted file mode 100644 index 5bc6474..0000000 --- a/src/old-apps/page/publish.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { CustomError } from '@kevisual/router'; -import { app } from '../../app.ts'; -import { PageModel } from './models/index.ts'; -import { AppListModel, AppModel } from '../../routes/app-manager/index.ts'; -import { cachePage, getZip } from './module/cache-file.ts'; -import { uniqBy } from 'es-toolkit'; -import semver from 'semver'; - -app - .route({ - path: 'page', - key: 'publish', - middleware: ['auth'], - }) - .define(async (ctx) => { - const tokenUser = ctx.state.tokenUser; - const { data, id, publish, ...rest } = ctx.query.data; - let needUpdate = { ...rest }; - if (data) { - needUpdate = { ...needUpdate, data }; - } - if (publish) { - needUpdate = { ...needUpdate, publish }; - } - if (!id) { - throw new CustomError('id is required'); - } - const page = await PageModel.findByPk(id); - if (!page) { - throw new CustomError('page not found'); - } - await page.update(needUpdate); - - const _publish = page.publish || {}; - if (!_publish.key) { - throw new CustomError('publish key is required'); - } - try { - const { key, description } = _publish; - const version = _publish.version || '0.0.0'; - let app = await AppModel.findOne({ where: { key, uid: tokenUser.id } }); - if (!app) { - app = await AppModel.create({ title: key, key, uid: tokenUser.id, description, user: tokenUser.username }); - } - const _version = semver.inc(version, 'patch'); - let appList = await AppListModel.findOne({ where: { key, version: _version, uid: tokenUser.id } }); - if (!appList) { - appList = await AppListModel.create({ key, version: _version, uid: tokenUser.id, data: {} }); - } - // 上传文件 - const res = await cachePage(page, { tokenUser, key, version: _version }); - const appFiles = appList?.data?.files || []; - const newFiles = uniqBy([...appFiles, ...res], (item) => item.name); - appList.data = { - ...appList?.data, - files: newFiles, - }; - await appList.save(); - await page.update({ publish: { ..._publish, id: app.id, version: _version } }); - ctx.body = page; - } catch (e) { - console.log('error', e); - throw new CustomError(e.message || 'publish error'); - } - }) - .addTo(app); - -app - .route({ - path: 'page', - key: 'download', - middleware: ['auth'], - }) - .define(async (ctx) => { - const tokenUser = ctx.state.tokenUser; - const { id } = ctx.query; - const page = await PageModel.findByPk(id); - if (!page) { - throw new CustomError('page not found'); - } - try { - const files = await getZip(page, { tokenUser }); - ctx.body = files; - } catch (e) { - console.log('error', e); - throw new CustomError(e.message || 'download error'); - } - }) - .addTo(app); diff --git a/src/routes/index.ts b/src/routes/index.ts index 58c16cf..14076f8 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -10,6 +10,7 @@ import './config/index.ts'; // import './file-listener/index.ts'; +import './light-code/index.ts'; import './ai/index.ts'; diff --git a/src/routes/light-code/list.ts b/src/routes/light-code/list.ts new file mode 100644 index 0000000..5983bcd --- /dev/null +++ b/src/routes/light-code/list.ts @@ -0,0 +1,151 @@ +import { eq, desc, and, like, or } from 'drizzle-orm'; +import { CustomError } from '@kevisual/router'; +import { app, db, schema } from '../../app.ts'; + +app + .route({ + path: 'light-code', + key: 'list', + description: `获取轻代码列表,参数 + type: 代码类型light-code, ts`, + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const { type, search } = ctx.query || {}; + const conditions = [eq(schema.kvContainer.uid, tokenUser.id)]; + if (type) { + conditions.push(eq(schema.kvContainer.type, type as string)); + } + if (search) { + const searchTerm = `%${search}%`; + conditions.push( + or( + like(schema.kvContainer.title, searchTerm), + like(schema.kvContainer.description, searchTerm), + ), + ); + } + const list = await db + .select({ + id: schema.kvContainer.id, + title: schema.kvContainer.title, + description: schema.kvContainer.description, + type: schema.kvContainer.type, + tags: schema.kvContainer.tags, + data: schema.kvContainer.data, + uid: schema.kvContainer.uid, + createdAt: schema.kvContainer.createdAt, + updatedAt: schema.kvContainer.updatedAt, + hash: schema.kvContainer.hash, + }) + .from(schema.kvContainer) + .where(and(...conditions)) + .orderBy(desc(schema.kvContainer.updatedAt)); + ctx.body = list; + return ctx; + }) + .addTo(app); + +app + .route({ + path: 'light-code', + key: 'get', + description: '获取轻代码详情', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const id = ctx.query.id; + if (!id) { + throw new CustomError('id is required'); + } + const result = await db + .select() + .from(schema.kvContainer) + .where(eq(schema.kvContainer.id, id)) + .limit(1); + const container = result[0]; + if (!container) { + ctx.throw('未发现该代码内容'); + } + if (container.uid !== tokenUser.id) { + ctx.throw('没有权限访问该代码内容'); + } + ctx.body = container; + }) + .addTo(app); + +app + .route({ + path: 'light-code', + key: 'update', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const data = ctx.query.data; + const { id, ...container } = data; + if (id) { + const result = await db + .select() + .from(schema.kvContainer) + .where(eq(schema.kvContainer.id, id)) + .limit(1); + const existing = result[0]; + if (existing) { + await db + .update(schema.kvContainer) + .set({ + ...container, + updatedAt: new Date().toISOString(), + }) + .where(eq(schema.kvContainer.id, id)); + const updated = await db + .select() + .from(schema.kvContainer) + .where(eq(schema.kvContainer.id, id)) + .limit(1); + ctx.body = updated[0]; + } else { + ctx.body = null; + } + } else { + const [created] = await db + .insert(schema.kvContainer) + .values({ + ...container, + uid: tokenUser.id, + }) + .returning(); + ctx.body = created; + } + return ctx; + }) + .addTo(app); + +app + .route({ + path: 'container', + key: 'delete', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const id = ctx.query.id; + const result = await db + .select() + .from(schema.kvContainer) + .where(eq(schema.kvContainer.id, id)) + .limit(1); + const container = result[0]; + if (!container) { + ctx.throw('未发现该容器'); + } + if (container.uid !== tokenUser.id) { + ctx.throw('没有权限访问该容器'); + } + await db.delete(schema.kvContainer).where(eq(schema.kvContainer.id, id)); + ctx.body = container; + }) + .addTo(app);