Skip to content

Commit

Permalink
feat:route code output (opentiny#937)
Browse files Browse the repository at this point in the history
* feat: 调整路由出码结构

* feat: 添加RouterView组件出码测试

* feat:路由出码忽略文件夹

* fix:去掉注释

* feat: 调整路由出码递归方式

* fix: 调整格式

* fix:修复路由component出码为字符串问题
  • Loading branch information
lichunn authored Dec 23, 2024
1 parent 15d9400 commit 3ac010b
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 40 deletions.
22 changes: 22 additions & 0 deletions packages/canvas/render/src/builtin/CanvasRouterView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<component :is="tag" v-bind="$attrs">
<slot>
<canvas-placeholder :placeholder="$attrs.placeholder"></canvas-placeholder>
</slot>
</component>
</template>

<script>
import CanvasPlaceholder from './CanvasPlaceholder.vue'
export default {
components: {
CanvasPlaceholder
},
props: {
tag: {
type: String,
default: 'div'
}
}
}
</script>
68 changes: 68 additions & 0 deletions packages/canvas/render/src/builtin/builtin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,63 @@
"data": {
"materials": {
"components": [
{
"icon": "Box",
"name": {
"zh_CN": "RouterView"
},
"component": "RouterView",
"schema": {
"slots": {},
"properties": [
{
"label": {
"zh_CN": "基础信息"
},
"description": {
"zh_CN": "基础信息"
},
"collapse": {
"number": 6,
"text": {
"zh_CN": "显示更多"
}
},
"content": []
}
],
"events": {
"onClick": {
"label": {
"zh_CN": "点击事件"
},
"description": {
"zh_CN": "点击时触发的回调函数"
},
"type": "event",
"functionInfo": {
"params": [],
"returns": {}
},
"defaultValue": ""
}
},
"shortcuts": {
"properties": []
},
"contentMenu": {
"actions": []
}
},
"configure": {
"loop": true,
"isContainer": true,
"nestingRule": {
"childWhitelist": [],
"descendantBlacklist": []
}
}
},
{
"icon": "Box",
"name": {
Expand Down Expand Up @@ -458,6 +515,17 @@
"zh_CN": "基础元素"
},
"children": [
{
"name": {
"zh_CN": "RouterView"
},
"icon": "Box",
"screenshot": "",
"snippetName": "RouterView",
"schema": {
"componentName": "RouterView"
}
},
{
"name": {
"zh_CN": "文本"
Expand Down
12 changes: 11 additions & 1 deletion packages/canvas/render/src/builtin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,15 @@ import CanvasIcon from './CanvasIcon.vue'
import CanvasSlot from './CanvasSlot.vue'
import CanvasImg from './CanvasImg.vue'
import CanvasPlaceholder from './CanvasPlaceholder.vue'
import CanvasRouterView from './CanvasRouterView.vue'

export { CanvasText, CanvasBox, CanvasCollection, CanvasIcon, CanvasSlot, CanvasImg, CanvasPlaceholder }
export {
CanvasText,
CanvasBox,
CanvasCollection,
CanvasIcon,
CanvasSlot,
CanvasImg,
CanvasPlaceholder,
CanvasRouterView
}
6 changes: 4 additions & 2 deletions packages/canvas/render/src/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import {
CanvasText,
CanvasSlot,
CanvasImg,
CanvasPlaceholder
CanvasPlaceholder,
CanvasRouterView
} from './builtin'

const { BROADCAST_CHANNEL } = constants
Expand Down Expand Up @@ -69,7 +70,8 @@ const Mapper = {
CanvasRow,
CanvasCol,
CanvasRowColContainer,
CanvasPlaceholder
CanvasPlaceholder,
CanvasRouterView
}

const { post } = useBroadcastChannel({ name: BROADCAST_CHANNEL.Notify })
Expand Down
129 changes: 92 additions & 37 deletions packages/vue-generator/src/plugins/genRouterPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,98 @@ const defaultOption = {
path: './src/router'
}

const parseSchema = (schema) => {
const { pageSchema } = schema
const flattenRoutes = (routes, parentPath = '') => {
return routes.reduce((acc, route) => {
const fullPath = `${parentPath}${route.path}`

if (route.path !== '/') {
if (route.component) {
// 如果存在 component,则直接添加路由
const newRoute = {
path: fullPath,
component: route.component,
children: flattenRoutes(route.children)
}
const redirectChild = route.children.find((item) => item.isDefault)

if (route.children && redirectChild) {
newRoute.redirect = `${fullPath}/${redirectChild.path}`
}

acc.push(newRoute)
} else if (route.children && route.children.length > 0) {
// 如果不存在 component 但有 children,则递归处理 children
const children = flattenRoutes(route.children, fullPath + '/')
// 将处理后的 children 合并到上一层存在 component 的路由中
acc.push(...children)
}
// 如果既没有 component 也没有 children,则不做任何处理
} else {
acc.push(route)
}

return acc
}, [])
}

const convertToNestedRoutes = (schema) => {
const pageSchema = schema.pageSchema?.sort((a, b) => a.meta?.router?.length - b.meta?.router?.length)
const result = []
let home = {}
let isGetHome = false

pageSchema.forEach((item) => {
if ((item.meta.isHome || item.meta.isDefault) && !isGetHome) {
home = {
path: '/',
redirect: `/${item.meta.router}`
}
isGetHome = true
}

const parts = item.meta?.router?.split('/').filter(Boolean)
let curretnLevel = result

const routes = pageSchema.map(({ meta: { isHome = false, router = '' } = {}, fileName, path }) => ({
filePath: `@/views${path ? `/${path}` : ''}/${fileName}.vue`,
fileName,
isHome,
path: router?.startsWith?.('/') ? router : `/${router}`
}))
parts.forEach((part, index) => {
let found = false

const hasRoot = routes.some(({ path }) => path === '/')
for (let i = 0; i < curretnLevel.length; i++) {
if (curretnLevel[i].path === part) {
// 如果已经存在该路径部分,则进入下一层级
curretnLevel = curretnLevel[i].children
found = true
break
}
}

if (!found) {
// 如果不存在该路径部分,创建一个新节点
const newNode = {
path: part,
children: []
}
// 如果路径是最后一步,则设置组件和属性
if (index === parts.length - 1) {
newNode.component = `() => import('@/views${item.path ? `/${item.path}` : ''}/${item.fileName}.vue')`
newNode.isDefault = item.meta.isDefault
}

if (!hasRoot && routes.length) {
const { path: homePath } = routes.find(({ isHome }) => isHome) || { path: routes[0].path }
curretnLevel.push(newNode)
curretnLevel = newNode.children
}
})
})

routes.unshift({ path: '/', redirect: homePath })
if (home.path) {
result.unshift(home)
}

return routes
return flattenRoutes(result)
}

// 示例路由数组
function genRouterPlugin(options = {}) {
const realOptions = mergeOptions(defaultOption, options)

const { path, fileName } = realOptions

return {
Expand All @@ -40,34 +108,21 @@ function genRouterPlugin(options = {}) {
* @returns
*/
run(schema) {
const routesList = parseSchema(schema)
const routesList = convertToNestedRoutes(schema)
const resultStr = JSON.stringify(routesList, null, 2).replace(
/("component":\s*)"(.*?)"/g,
(match, p1, p2) => p1 + p2
)

// TODO: 支持 hash 模式、history 模式
const importSnippet = "import { createRouter, createWebHashHistory } from 'vue-router'"
const exportSnippet = `
export default createRouter({
history: createWebHashHistory(),
routes
})`
const routes = routesList.map(({ fileName, path, redirect, filePath }) => {
let pathAttr = `path: '${path}'`
let redirectAttr = ''
let componentAttr = ''

if (redirect) {
redirectAttr = `redirect: '${redirect}'`
}

if (fileName) {
componentAttr = `component: () => import('${filePath}')`
}

const res = [pathAttr, redirectAttr, componentAttr].filter((item) => Boolean(item)).join(',')

return `{${res}}`
})
export default createRouter({
history: createWebHashHistory(),
routes
})`

const routeSnippets = `const routes = [${routes.join(',')}]`
const routeSnippets = `const routes = ${resultStr}`

const res = {
fileType: 'js',
Expand Down

0 comments on commit 3ac010b

Please sign in to comment.