This commit is contained in:
wfz
2026-01-20 21:53:09 +08:00
parent 4a90340ab3
commit bfa4e3107f
23 changed files with 2154 additions and 592 deletions

View File

@@ -6,9 +6,12 @@
import express from 'express'
import cors from 'cors'
import { moveElement } from './services/templateService.js'
import { moveElement, insertElement, parseElementTree, parseComponentProps, updateComponentProps, deleteElement } from './services/templateService.js'
import { readFile, writeFile } from 'fs/promises'
import path from 'path'
import { fileURLToPath } from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const app = express()
const PORT = 3001
@@ -20,6 +23,9 @@ app.use(express.json())
// Vue源码目录相对于服务根目录
const VUE_SOURCE_DIR = path.resolve('../draggable-panels/src/views')
// 设计组件模板目录
const DESIGN_COMPONENTS_DIR = path.resolve('../draggable-panels/src/fauto/designComponents')
/**
* API: 执行元素移动操作
*
@@ -127,8 +133,276 @@ app.get('/api/health', (req, res) => {
})
})
/**
* API: 插入设计组件
*
* POST /api/insert-component
* Body: {
* pagePath: string, // Vue文件路径
* componentId: string, // 设计组件ID
* targetPath: string, // 目标元素路径
* direction: string // 插入方向
* }
*/
app.post('/api/insert-component', async (req, res) => {
try {
const { pagePath, componentId, targetPath, direction } = req.body
console.log('[API] 收到插入请求:', {
pagePath,
componentId,
targetPath,
direction
})
// 验证参数
if (!pagePath || !componentId || !targetPath || !direction) {
return res.status(400).json({
success: false,
error: '缺少必要参数'
})
}
// 构建完整文件路径
let normalizedPath = pagePath
const viewsIndex = normalizedPath.indexOf('views/')
if (viewsIndex !== -1) {
normalizedPath = normalizedPath.substring(viewsIndex + 6)
}
const filePath = path.join(VUE_SOURCE_DIR, normalizedPath)
// 读取设计组件模板
const templatePath = path.join(DESIGN_COMPONENTS_DIR, componentId, 'template.html')
let componentTemplate
try {
componentTemplate = await readFile(templatePath, 'utf-8')
} catch (err) {
return res.status(404).json({
success: false,
error: `设计组件模板不存在: ${componentId}`
})
}
console.log('[API] 设计组件模板:', componentTemplate.substring(0, 100) + '...')
// 读取Vue文件
let vueContent
try {
vueContent = await readFile(filePath, 'utf-8')
} catch (err) {
return res.status(404).json({
success: false,
error: `文件不存在: ${pagePath}`
})
}
// 执行插入操作
const result = insertElement(vueContent, {
templateContent: componentTemplate.trim(),
targetPath,
direction
})
if (!result.success) {
return res.status(400).json({
success: false,
error: result.error
})
}
// 写回文件
await writeFile(filePath, result.content, 'utf-8')
console.log('[API] 插入成功')
res.json({
success: true,
message: `已将 ${componentId} 插入到 ${targetPath}${direction}方向`
})
} catch (error) {
console.error('[API] 错误:', error)
res.status(500).json({
success: false,
error: error.message
})
}
})
/**
* API: 获取页面元素结构树
*
* GET /api/element-tree?pagePath=xxx
*/
app.get('/api/element-tree', async (req, res) => {
try {
const { pagePath } = req.query
if (!pagePath) {
return res.status(400).json({
success: false,
error: '缺少pagePath参数'
})
}
// 构建完整文件路径
let normalizedPath = pagePath
const viewsIndex = normalizedPath.indexOf('views/')
if (viewsIndex !== -1) {
normalizedPath = normalizedPath.substring(viewsIndex + 6)
}
const filePath = path.join(VUE_SOURCE_DIR, normalizedPath)
console.log('[API] 获取结构树:', filePath)
// 读取Vue文件
let vueContent
try {
vueContent = await readFile(filePath, 'utf-8')
} catch (err) {
return res.status(404).json({
success: false,
error: `文件不存在: ${pagePath}`
})
}
// 解析结构树
const result = parseElementTree(vueContent)
if (!result.success) {
return res.status(400).json({
success: false,
error: result.error
})
}
res.json({
success: true,
tree: result.tree
})
} catch (error) {
console.error('[API] 错误:', error)
res.status(500).json({
success: false,
error: error.message
})
}
})
// 启动服务
app.listen(PORT, () => {
console.log(`🚀 Vue模板服务启动: http://localhost:${PORT}`)
console.log(`📁 源码目录: ${VUE_SOURCE_DIR}`)
})
/**
* API: 获取组件属性
* GET /api/component-props?pagePath=xxx&elementPath=xxx
*/
app.get('/api/component-props', async (req, res) => {
try {
const { pagePath, elementPath } = req.query
if (!pagePath || !elementPath) {
return res.status(400).json({
success: false,
error: '缺少参数'
})
}
let normalizedPath = pagePath
const viewsIndex = normalizedPath.indexOf('views/')
if (viewsIndex !== -1) {
normalizedPath = normalizedPath.substring(viewsIndex + 6)
}
const filePath = path.join(VUE_SOURCE_DIR, normalizedPath)
const vueContent = await readFile(filePath, 'utf-8')
const result = parseComponentProps(vueContent, elementPath)
if (!result.success) {
return res.status(400).json(result)
}
res.json(result)
} catch (error) {
res.status(500).json({ success: false, error: error.message })
}
})
/**
* API: 更新组件属性
* POST /api/update-props
*/
app.post('/api/update-props', async (req, res) => {
try {
const { pagePath, elementPath, updates } = req.body
if (!pagePath || !elementPath || !updates) {
return res.status(400).json({
success: false,
error: '缺少参数'
})
}
let normalizedPath = pagePath
const viewsIndex = normalizedPath.indexOf('views/')
if (viewsIndex !== -1) {
normalizedPath = normalizedPath.substring(viewsIndex + 6)
}
const filePath = path.join(VUE_SOURCE_DIR, normalizedPath)
const vueContent = await readFile(filePath, 'utf-8')
const result = updateComponentProps(vueContent, elementPath, updates)
if (!result.success) {
return res.status(400).json(result)
}
await writeFile(filePath, result.content, 'utf-8')
res.json({ success: true, message: '属性更新成功' })
} catch (error) {
res.status(500).json({ success: false, error: error.message })
}
})
/**
* API: 删除元素
* POST /api/delete-element
*/
app.post('/api/delete-element', async (req, res) => {
try {
const { pagePath, elementPath } = req.body
if (!pagePath || !elementPath) {
return res.status(400).json({
success: false,
error: '缺少参数'
})
}
let normalizedPath = pagePath
const viewsIndex = normalizedPath.indexOf('views/')
if (viewsIndex !== -1) {
normalizedPath = normalizedPath.substring(viewsIndex + 6)
}
const filePath = path.join(VUE_SOURCE_DIR, normalizedPath)
const vueContent = await readFile(filePath, 'utf-8')
const result = deleteElement(vueContent, elementPath)
if (!result.success) {
return res.status(400).json(result)
}
await writeFile(filePath, result.content, 'utf-8')
console.log(`[API] 删除成功: ${elementPath}`)
res.json({ success: true, message: '元素删除成功' })
} catch (error) {
res.status(500).json({ success: false, error: error.message })
}
})