Compare commits

...

20 Commits

Author SHA1 Message Date
yaoyun8 76c23b767b
fix(script): translate log (#549)
* fix: translate log

* Update scripts/connection.mjs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update scripts/connection.mjs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update scripts/connection.mjs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-08-24 21:46:45 +08:00
Gene c218724543
fix: 隐藏画布根节点的包裹元素的操作选项 (#492) 2024-08-24 21:43:53 +08:00
chilingling 871463f185
feat(cdn): change cdn from onmicrosoft to unpkg (#750) 2024-08-24 20:46:37 +08:00
wenmine 59eaf035bb
fix(download): Optimize download logic and adapt to iframe (#739)
* fix(download): Optimize download logic and adapt to iframe
2024-08-16 10:30:47 +08:00
chilingling 1ed91983b0
fix: abaolute canvas init inlineStyle should be string (#730) 2024-08-13 10:14:56 +08:00
Hexqi a442108e2b
docs: update milestone (#728)
* docs: update milestone

* fix: tab
2024-08-07 09:42:28 +08:00
wenmine 3a204624af
feat(download-code): support download zip for not support browsers (#703)
* feat(download-code): support download zip for not support browsers

* feat(download-code): support download zip for not support browsers - review

* feat(download-code): support download zip for not support browsers - review
2024-08-06 14:54:32 +08:00
chilingling 0d36f2d344
fix(setting): fix bindEvent dialog visible can't work on tinyvue 3.17 (#715) 2024-07-29 14:36:18 +08:00
chilingling a383421c38
fix(material): add missing componentsMap to mockServer (#701) 2024-07-23 19:10:35 +08:00
chilingling fd164a1cd2
fix(preview): multiple nested blocks cannot preview #663 (#665) 2024-07-22 16:28:30 +08:00
chilingling fec563dda3
fix: esbuild install failed on nodev16 (#671)
* fix: esbuild install failed on nodev16

* fix: esbuild install failed on nodev16

* fix: remove deps on root pkg.json
2024-07-22 16:14:26 +08:00
chilingling 732bed9795
fix: builtin components can't generate import statement with genSFCWithDefaultPlugin method (#656) 2024-07-22 15:17:17 +08:00
chilingling 2c27f9141a
fix: esbuild install failed on node v16 (#668)
* fix: esbuild install failed on nodev16

* fix: esbuild install failed on nodev16
2024-07-22 10:55:37 +08:00
yeser 66268d3ec3
fix: 修复onMouseover拼写错误 (#662) 2024-07-19 17:45:52 +08:00
chilingling e651dffa2b
fix: slot params missing double quote (#605)
* fix: slot params missing double quote

* fix: exclude nodemodule test case
2024-07-05 17:36:09 +08:00
chilingling 91d3ae108c
fix(material): add componentsMap to app Schema after material build (#527) 2024-07-05 14:03:32 +08:00
chilingling 277be2f11e
fix(vue-generator): fix globalstate codegen error (#547) 2024-07-05 11:06:11 +08:00
chilingling 2c478ce391
fix(metaComp): fix bug where metaHtmlText could set value to incorret schema children (#473) 2024-06-27 20:41:07 +08:00
chilingling c341f4c2c5
fix(style): fix render error caused by inline style breaks (#526) 2024-06-27 20:40:51 +08:00
chilingling 858e178af6
fix(mockServer): mockServer page preview can't render element-plus element (#503) 2024-05-27 19:19:29 +08:00
36 changed files with 585 additions and 113 deletions

View File

@ -88,9 +88,9 @@ gantt
dateFormat YYYY-MM-DD
axisFormat %Y-%m-%d
1.0.0-beta.x version :active,2023-09-25, 2024-03-31
1.0.0-rc version : 2024-04-01, 2024-06-30
1.0.0 version : 2024-07-01, 2024-07-31
1.0.0-beta.x version : 2023-09-25, 2024-05-20
1.0.0-rc version(refactor version) : 2024-10-01
1.0.0 version : 2024-11-01
```

View File

@ -84,13 +84,13 @@ pnpm run build:alpha 或 build:prod
## 里程碑
```mermaid
gantt
gantt
dateFormat YYYY-MM-DD
axisFormat %Y-%m-%d
1.0.0-beta.x version :active,2023-09-25, 2024-03-31
1.0.0-rc version : 2024-04-01, 2024-06-30
1.0.0 version : 2024-07-01, 2024-07-31
1.0.0-beta.x version : 2023-09-25, 2024-05-20
1.0.0-rc version(refactor version) : 2024-10-01
1.0.0 version : 2024-11-01
```

View File

@ -1918,6 +1918,13 @@
"destructuring": true,
"version": "0.1.17"
},
{
"componentName": "TinyCheckbox",
"package": "@opentiny/vue",
"exportName": "Checkbox",
"destructuring": true,
"version": "3.14.0"
},
{
"componentName": "TinySelect",
"package": "@opentiny/vue",
@ -1974,6 +1981,76 @@
"destructuring": true,
"version": "0.1.16"
},
{
"componentName": "TinyCollapse",
"package": "@opentiny/vue",
"exportName": "Collapse",
"destructuring": true,
"version": "3.14.0"
},
{
"componentName": "TinyCollapseItem",
"package": "@opentiny/vue",
"exportName": "CollapseItem",
"destructuring": true,
"version": "3.14.0"
},
{
"componentName": "TinyBreadcrumb",
"package": "@opentiny/vue",
"exportName": "Breadcrumb",
"destructuring": true,
"version": "3.14.0"
},
{
"componentName": "TinyBreadcrumbItem",
"package": "@opentiny/vue",
"exportName": "BreadcrumbItem",
"destructuring": true,
"version": "3.14.0"
},
{
"componentName": "ElInput",
"package": "element-plus",
"exportName": "ElInput",
"destructuring": true,
"version": "2.4.2"
},
{
"componentName": "ElButton",
"package": "element-plus",
"exportName": "ElButton",
"destructuring": true,
"version": "2.4.2"
},
{
"componentName": "ElForm",
"package": "element-plus",
"exportName": "ElForm",
"destructuring": true,
"version": "2.4.2"
},
{
"componentName": "ElFormItem",
"package": "element-plus",
"exportName": "ElFormItem",
"destructuring": true,
"version": "2.4.2"
},
{
"componentName": "ElTable",
"package": "element-plus",
"exportName": "ElTable",
"destructuring": true,
"version": "2.4.2"
},
{
"componentName": "ElTableColumn",
"package": "element-plus",
"exportName": "ElTableColumn",
"destructuring": true,
"version": "2.4.2"
},
{
"componentName": "PortalHome",
"main": "common/components/home",

View File

@ -25,8 +25,6 @@
},
"devDependencies": {
"@babel/eslint-parser": "^7.21.3",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@types/node": "^18.0.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.1.0",

View File

@ -43,7 +43,7 @@ export default defineConfig(({ command, mode }) => {
}
const vuePluginConfig = {}
const styleLinks = ['https://npm.onmicrosoft.cn/@opentiny/vue-theme@3.14/index.css']
const styleLinks = ['https://unpkg.com/@opentiny/vue-theme@3.14/index.css']
config.publicDir = false

View File

@ -229,7 +229,10 @@ export default {
}
const showAction = computed(() => {
const { parent } = getCurrent()
const { schema, parent } = getCurrent()
if (schema?.props?.['data-id'] === 'root-container') {
return false
}
return !props.resize && parent && parent?.type !== 'JSSlot'
})

View File

@ -716,11 +716,7 @@ export const onMouseUp = () => {
if (absolute) {
targetNode.node = getSchema()
data.props = data.props || {}
data.props.style = {
position: 'absolute',
top: dragState.mouse.y + 'px',
left: dragState.mouse.x + 'px'
}
data.props.style = `position: absolute; top: ${dragState.mouse.y}px; left: ${dragState.mouse.x}px`
}
insertNode(targetNode, position)

View File

@ -379,7 +379,8 @@ export default {
// 渲染画布增加根节点,与出码和预览保持一致
const rootChildrenSchema = {
componentName: 'div',
props: schema.props,
// 手动添加一个唯一的属性后续在画布选中此节点时方便处理额外的逻辑。由于没有修改schema不会影响出码
props: { ...schema.props, 'data-id': 'root-container' },
children: schema.children
}

View File

@ -558,7 +558,7 @@ const getBindProps = (schema, scope) => {
...parseData(schema.props, scope),
[DESIGN_UIDKEY]: id,
[DESIGN_TAGKEY]: componentName,
onMoseover: stopEvent,
onMouseover: stopEvent,
onFocus: stopEvent
}
if (scope) {

View File

@ -10,7 +10,7 @@
</div>
</div>
<div class="head-content">
<meta-input v-model="state.text" type="textarea" @change="change"></meta-input>
<meta-input v-model="state.text" type="textarea" @update:modelValue="change"></meta-input>
</div>
</template>
<script>

View File

@ -1,7 +1,7 @@
# alpha mode, used by the "build:alpha" script
NODE_ENV=production
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
VITE_CDN_DOMAIN=https://unpkg.com
VITE_LOCAL_IMPORT_MAPS=false
VITE_LOCAL_BUNDLE_DEPS=false
# VITE_ORIGIN=

View File

@ -1,7 +1,7 @@
# development mode, used by the "vite" command
NODE_ENV=development
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
VITE_CDN_DOMAIN=https://unpkg.com
VITE_LOCAL_IMPORT_MAPS=false
VITE_LOCAL_BUNDLE_DEPS=false
# request data via alpha service

View File

@ -1,7 +1,7 @@
# prod mode, used by the "build:prod" script
NODE_ENV=production
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
VITE_CDN_DOMAIN=https://unpkg.com
VITE_LOCAL_IMPORT_MAPS=false
VITE_LOCAL_BUNDLE_DEPS=false
#VITE_ORIGIN=

View File

@ -89,7 +89,6 @@
"eslint-linter-browserify": "8.57.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
"jszip": "^3.10.1",
"monaco-editor": "0.33.0",
"prettier": "2.7.1",
"sortablejs": "^1.14.0",
@ -107,6 +106,7 @@
"assert": "^2.0.0",
"buffer": "^6.0.3",
"cross-env": "^7.0.3",
"esbuild": "^0.21.5",
"esbuild-plugin-copy": "^2.1.1",
"eslint": "^8.38.0",
"eslint-plugin-vue": "^8.0.0",

View File

@ -20,10 +20,11 @@
"npm": {
"package": "element-plus",
"version": "2.4.2",
"script": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.css",
"script": "https://unpkg.com/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://unpkg.com/element-plus@2.4.2/dist/index.css",
"dependencies": null,
"exportName": "ElInput"
"exportName": "ElInput",
"destructuring": true
},
"group": "表单组件",
"category": "element-plus",
@ -300,10 +301,11 @@
"npm": {
"package": "element-plus",
"version": "2.4.2",
"script": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.css",
"script": "https://unpkg.com/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://unpkg.com/element-plus@2.4.2/dist/index.css",
"dependencies": null,
"exportName": "ElButton"
"exportName": "ElButton",
"destructuring": true
},
"group": "基础组件",
"category": "element-plus",
@ -621,9 +623,10 @@
"npm": {
"package": "element-plus",
"version": "2.4.2",
"script": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.css",
"script": "https://unpkg.com/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://unpkg.com/element-plus@2.4.2/dist/index.css",
"dependencies": null,
"destructuring": true,
"exportName": "ElForm"
},
"group": "表单组件",
@ -1078,9 +1081,10 @@
"npm": {
"package": "element-plus",
"version": "2.4.2",
"script": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.css",
"script": "https://unpkg.com/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://unpkg.com/element-plus@2.4.2/dist/index.css",
"dependencies": null,
"destructuring": true,
"exportName": "ElFormItem"
},
"group": "表单组件",
@ -1428,9 +1432,10 @@
"npm": {
"package": "element-plus",
"version": "2.4.2",
"script": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.css",
"script": "https://unpkg.com/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://unpkg.com/element-plus@2.4.2/dist/index.css",
"dependencies": null,
"destructuring": true,
"exportName": "ElTable"
},
"group": "数据展示",
@ -2666,9 +2671,10 @@
"npm": {
"package": "element-plus",
"version": "2.4.2",
"script": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://npm.onmicrosoft.cn/element-plus@2.4.2/dist/index.css",
"script": "https://unpkg.com/element-plus@2.4.2/dist/index.full.mjs",
"css": "https://unpkg.com/element-plus@2.4.2/dist/index.css",
"dependencies": null,
"destructuring": true,
"exportName": "ElTableColumn"
},
"group": "表单组件",
@ -8901,7 +8907,7 @@
"devMode": "proCode",
"npm": {
"package": "@opentiny/vue",
"exportName": "Select",
"exportName": "Breadcrumb",
"version": "",
"destructuring": true
},
@ -14007,20 +14013,10 @@
"schema": {
"componentName": "TinyBreadcrumb",
"props": {
"options": [
{
"to": "{ path: '/' }",
"label": "首页"
},
{
"to": "{ path: '/breadcrumb' }",
"label": "产品"
},
{
"replace": "true",
"label": "软件"
}
]
"options": {
"type": "JSExpression",
"value": "[{to: { path: '/' },label: '首页'},{to: { path: '/breadcrumb' },label: '产品'},{'replace': true,'label': '软件'}]"
}
}
}
},
@ -14275,7 +14271,7 @@
"schema": {
"componentName": "TinyTimeLine",
"props": {
"active": "2",
"active": 2,
"data": [
{
"name": "已下单"

View File

@ -86,11 +86,17 @@ export default {
.map((name) => fetchBlockSchema(name))
const schemaList = await Promise.allSettled(promiseList)
const extraList = []
schemaList.forEach((item) => {
if (item.status === 'fulfilled' && item.value?.[0]?.content) {
res.push(item.value[0].content)
res.push(...getBlocksSchema(item.value[0].content, blockSet))
extraList.push(getBlocksSchema(item.value[0].content, blockSet))
}
})
;(await Promise.allSettled(extraList)).forEach((item) => {
if (item.status === 'fulfilled' && item.value) {
res.push(...item.value)
}
})
@ -136,11 +142,10 @@ export default {
},
...(blocks || []).map((blockSchema) => {
return {
panelName: blockSchema.fileName,
panelName: `${blockSchema.fileName}.vue`,
panelValue:
genSFCWithDefaultPlugin(blockSchema, appData?.componentsMap || [], { blockRelativePath: './' }) || '',
panelType: 'vue',
index: true
panelType: 'vue'
}
})
]

View File

@ -1,6 +1,6 @@
<template>
<tiny-dialog-box
v-show="dialogVisible"
:visible="dialogVisible"
title="事件绑定"
width="50%"
:append-to-body="true"

View File

@ -69,7 +69,6 @@ import { ref, watch } from 'vue'
import { Collapse, CollapseItem, Input } from '@opentiny/vue'
import { useHistory, useCanvas, useProperties } from '@opentiny/tiny-engine-controller'
import { MetaCodeEditor, MetaBindVariable } from '@opentiny/tiny-engine-common'
import { formatString } from '@opentiny/tiny-engine-controller/js/ast'
import {
SizeGroup,
LayoutGroup,
@ -128,7 +127,7 @@ export default {
const { getSchema: getCanvasPageSchema, updateRect } = useCanvas().canvasApi.value
const pageSchema = getCanvasPageSchema()
const schema = getSchema() || pageSchema
const styleString = formatString(styleStrRemoveRoot(content), 'css')
const styleString = styleStrRemoveRoot(content)
const currentSchema = getCurrentSchema() || pageSchema
state.styleContent = content

View File

@ -30,7 +30,9 @@
"vite": "^4.3.7",
"vitest": "^1.4.0"
},
"dependencies": {},
"dependencies": {
"jszip": "^3.10.1"
},
"peerDependencies": {
"@opentiny/vue-renderless": "^3.14.0",
"vue": "^3.4.15"

View File

@ -0,0 +1,67 @@
/**
* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
// browser File System Access API encapsulation
import JSZIP from 'jszip'
/**
* 下载文件到本地
* @param {Blob} blobData 文件二进制数据
* @param {string} fileName 文件名
*/
export function saveAs(blobData, fileName) {
const downloadLink = document.createElement('a')
downloadLink.download = fileName
downloadLink.style.display = 'none'
downloadLink.href = URL.createObjectURL(blobData)
document.body.appendChild(downloadLink)
downloadLink.click()
document.body.removeChild(downloadLink)
}
/**
* 创建一个zip
*/
export const createZip = () => {
return new JSZIP()
}
/**
* 往zip里面写入文件夹和文件
* @param {Array<FileInfo>} filesInfo 文件信息
* FileInfo.filePath 文件相对路径'/'相连
* FileInfo.fileContent 文件内容
* @param {ZipExtraInfo} ZipExtraInfo zip额外信息
* {string} zipName 打出来的zip名称
* {JSZIP} zipHandle 创建好的zip句柄可以不传不传就用新的
*/
export const writeZip = (filesInfo, { zipHandle, zipName } = {}) => {
let zip = zipHandle
if (!zipHandle) {
zip = createZip()
}
filesInfo.forEach(({ filePath, fileContent }) => {
const file = filePath.split('/')
const fileName = file.pop()
const path = file.join('/')
if (path) {
zip.folder(path).file(fileName, fileContent)
} else {
zip.file(fileName, fileContent)
}
})
// 把打包的内容异步转成blob二进制格式
return zip.generateAsync({ type: 'blob' }).then((content) => {
// content就是blob数据
saveAs(content, `${zipName}.zip`)
})
}

View File

@ -1,17 +1,23 @@
/**
* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
// browser File System Access API encapsulation
import { createZip, writeZip } from './fszip'
// 支持file system api的条件存在这个方法 && 不处于iframe中
export const isSupportFileSystemAccess =
Object.prototype.hasOwnProperty.call(window, 'showDirectoryPicker') && window.self === window.top
/**
* 获取用户选择并授权的文件夹根路径
* @param {*} options
@ -19,8 +25,8 @@
* @returns dirHandle 目录句柄
*/
export const getUserBaseDirHandle = async (options = {}) => {
if (!window.showOpenFilePicker) {
throw new Error('不支持的浏览器!')
if (!isSupportFileSystemAccess) {
return createZip()
}
const dirHandle = await window.showDirectoryPicker({ mode: 'readwrite', ...options })
return dirHandle
@ -75,8 +81,8 @@ export async function getFileHandle(baseDirHandle, filePath, { create = false }
* @returns fileHandle 文件句柄
*/
export const getUserFileHandle = async (options = {}) => {
if (!window.showOpenFilePicker) {
throw new Error('不支持的浏览器!')
if (!isSupportFileSystemAccess) {
throw new Error('不支持的浏览器或处于iframe中')
}
const [fileHandle] = await window.showOpenFilePicker({ mode: 'readwrite', ...options })
return fileHandle
@ -166,16 +172,29 @@ export const writeFile = async (handle, { filePath, fileContent }) => {
* @param {Array<FileInfo>} filesInfo 文件信息
* FileInfo.filePath 文件相对路径
* FileInfo.fileContent 文件内容
* @param {Boolean} supportZipCache 是否支持zip缓存zip缓存可能会导致文件不能及时更新默认不缓存
*
*/
export const writeFiles = async (baseDirHandle, filesInfo) => {
export const writeFiles = async (
baseDirHandle,
filesInfo,
zipName = 'tiny-engine-generate-code',
supportZipCache = false
) => {
if (!filesInfo?.length) {
return
}
if (!isSupportFileSystemAccess) {
const zipInfo = { zipName, zipHandle: supportZipCache && baseDirHandle }
await writeZip(filesInfo, zipInfo)
return
}
let directoryHandle = baseDirHandle
if (!directoryHandle) {
directoryHandle = await window.showDirectoryPicker({ mode: 'readwrite' })
}
await Promise.all(filesInfo.map((fileInfo) => writeFile(baseDirHandle, fileInfo)))
await Promise.all(filesInfo.map((fileInfo) => writeFile(directoryHandle, fileInfo)))
}

View File

@ -47,7 +47,7 @@
"fs-extra": "^10.0.1",
"prettier": "^2.6.1",
"vite": "^4.3.7",
"vite-plugin-static-copy": "^1.0.4",
"vite-plugin-static-copy": "^0.16.0",
"vitest": "^1.4.0",
"winston": "^3.10.0"
},

View File

@ -1,3 +1,4 @@
import { BUILTIN_COMPONENTS_MAP } from '@/constant'
import { getImportMap } from './parseImport'
import {
genTemplateByHook,
@ -259,7 +260,10 @@ export const genSFCWithDefaultPlugin = (schema, componentsMap, config = {}) => {
}
}
return generateSFCFile(schema, componentsMap, newConfig)
// 兼容单独调用的场景,单独调用时,这里会默认加上 builtInComponents
const compsMapWithBuiltIn = [...componentsMap, ...BUILTIN_COMPONENTS_MAP]
return generateSFCFile(schema, compsMapWithBuiltIn, newConfig)
}
export default generateSFCFile

View File

@ -229,7 +229,7 @@ export const handleSlotBindAttrHook = (schemaData) => {
let paramsValue = ''
if (Array.isArray(params)) {
paramsValue = `={ ${params.join(',')} }`
paramsValue = `="{ ${params.join(',')} }"`
} else if (typeof params === 'string') {
paramsValue = `="${params}"`
}

View File

@ -44,8 +44,8 @@ function genDependenciesPlugin(options = {}) {
.map((item) => {
let [key, value] = item
if (value === '') {
value = "''"
if (typeof value === 'string') {
value = `'${value}'`
}
if (value && typeof value === 'object') {
@ -57,19 +57,19 @@ function genDependenciesPlugin(options = {}) {
.join(',')} })`
const getterExpression = Object.entries(getters)
.filter((item) => item.value?.type === 'JSFunction')
.filter((item) => item[1]?.type === 'JSFunction')
.map(([key, value]) => `${key}: ${value.value}`)
.join(',')
const actionExpressions = Object.entries(actions)
.filter((item) => item.value?.type === 'JSFunction')
.filter((item) => item[1]?.type === 'JSFunction')
.map(([key, value]) => `${key}: ${value.value}`)
.join(',')
const storeFiles = `
${importStatement}
export const ${id} = defineStore({
id: ${id},
id: '${id}',
state: ${stateExpression},
getters: { ${getterExpression} },
actions: { ${actionExpressions} }

View File

@ -0,0 +1 @@
export { testState } from './testState'

View File

@ -0,0 +1,27 @@
import { defineStore } from 'pinia'
export const testState = defineStore({
id: 'testState',
state: () => ({
name: 'testName',
license: '',
age: 18,
food: ['apple', 'orange', 'banana', 19],
desc: { description: 'hello world', money: 100, other: '', rest: ['a', 'b', 'c', 20] }
}),
getters: {
getAge: function getAge() {
return this.age
},
getName: function getName() {
return this.name
}
},
actions: {
setAge: function setAge(age) {
this.age = age
},
setName: function setName(name) {
this.name = name
}
}
})

View File

@ -676,7 +676,43 @@ export const appSchemaDemo01 = {
value: 'function dataHanlder(res){\n return res;\n}'
}
},
globalState: [],
globalState: [
{
id: 'testState',
state: {
name: 'testName',
license: '',
age: 18,
food: ['apple', 'orange', 'banana', 19],
desc: {
description: 'hello world',
money: 100,
other: '',
rest: ['a', 'b', 'c', 20]
}
},
getters: {
getAge: {
type: 'JSFunction',
value: 'function getAge() {\n return this.age \n}'
},
getName: {
type: 'JSFunction',
value: 'function getName() {\n return this.name \n}'
}
},
actions: {
setAge: {
type: 'JSFunction',
value: 'function setAge(age) {\n this.age = age; \n}'
},
setName: {
type: 'JSFunction',
value: 'function setName(name) {\n this.name = name; \n}'
}
}
}
],
utils: [
{
name: 'axios',

View File

@ -0,0 +1,12 @@
import { expect, test } from 'vitest'
import { genSFCWithDefaultPlugin } from '@/generator/vue/sfc'
import schema from './page.schema.json'
import componentsMap from './components-map.json'
import { formatCode } from '@/utils/formatCode'
test('should generate slot declaration correctly', async () => {
const res = genSFCWithDefaultPlugin(schema, componentsMap)
const formattedCode = formatCode(res, 'vue')
await expect(formattedCode).toMatchFileSnapshot('./expected/slotTest.vue')
})

View File

@ -0,0 +1,9 @@
[
{
"componentName": "TinyTree",
"exportName": "Tree",
"package": "@opentiny/vue",
"version": "^3.10.0",
"destructuring": true
}
]

View File

@ -0,0 +1,54 @@
<template>
<div>
<tiny-tree
:data="[
{ label: '一级 1', children: [{ label: '二级 1-1', children: [{ label: '三级 1-1-1' }] }] },
{
label: '一级 2',
children: [
{ label: '二级 2-1', children: [{ label: '三级 2-1-1' }] },
{ label: '二级 2-2', children: [{ label: '三级 2-2-1' }] }
]
}
]"
>
<template #default="{ data }">
<span>{{ data.label }}</span></template
></tiny-tree
>
<tiny-tree
:data="[
{ label: '一级 1', children: [{ label: '二级 1-1', children: [{ label: '三级 1-1-1' }] }] },
{
label: '一级 2',
children: [
{ label: '二级 2-1', children: [{ label: '三级 2-1-1' }] },
{ label: '二级 2-2', children: [{ label: '三级 2-2-1' }] }
]
}
]"
>
<template #default="data">
<span>{{ data.label }}</span></template
></tiny-tree
>
</div>
</template>
<script setup>
import { Tree as TinyTree } from '@opentiny/vue'
import * as vue from 'vue'
import { defineProps, defineEmits } from 'vue'
import { I18nInjectionKey } from 'vue-i18n'
const props = defineProps({})
const emit = defineEmits([])
const { t, lowcodeWrap, stores } = vue.inject(I18nInjectionKey).lowcode()
const wrap = lowcodeWrap(props, { emit })
wrap({ stores })
const state = vue.reactive({})
wrap({ state })
</script>
<style scoped></style>

View File

@ -0,0 +1,143 @@
{
"state": {},
"methods": {},
"componentName": "Page",
"fileName": "createVm",
"css": "",
"props": {},
"lifeCycles": {},
"children": [
{
"componentName": "TinyTree",
"props": {
"data": [
{
"label": "一级 1",
"children": [
{
"label": "二级 1-1",
"children": [
{
"label": "三级 1-1-1"
}
]
}
]
},
{
"label": "一级 2",
"children": [
{
"label": "二级 2-1",
"children": [
{
"label": "三级 2-1-1"
}
]
},
{
"label": "二级 2-2",
"children": [
{
"label": "三级 2-2-1"
}
]
}
]
}
]
},
"id": "33f52342",
"children": [
{
"componentName": "Template",
"props": {
"slot": {
"name": "default",
"params": ["data"]
}
},
"children": [
{
"componentName": "Text",
"props": {
"text": {
"type": "JSExpression",
"value": "data.label"
}
},
"id": "c225d165"
}
],
"id": "415d5f65"
}
]
},
{
"componentName": "TinyTree",
"props": {
"data": [
{
"label": "一级 1",
"children": [
{
"label": "二级 1-1",
"children": [
{
"label": "三级 1-1-1"
}
]
}
]
},
{
"label": "一级 2",
"children": [
{
"label": "二级 2-1",
"children": [
{
"label": "三级 2-1-1"
}
]
},
{
"label": "二级 2-2",
"children": [
{
"label": "三级 2-2-1"
}
]
}
]
}
]
},
"id": "33f52342",
"children": [
{
"componentName": "Template",
"props": {
"slot": {
"name": "default",
"params": "data"
}
},
"children": [
{
"componentName": "Text",
"props": {
"text": {
"type": "JSExpression",
"value": "data.label"
}
},
"id": "c225d165"
}
],
"id": "415d5f65"
}
]
}
]
}

View File

@ -17,7 +17,7 @@ import { viteStaticCopy } from 'vite-plugin-static-copy'
// https://vitejs.dev/config/
export default defineConfig({
test: {
exclude: ['**/result/**'],
exclude: ['**/result/**', 'node_modules'],
watchExclude: ['**/result/**']
},
resolve: {

View File

@ -12,7 +12,10 @@ const materialsDir = 'materials'
const bundlePath = path.join(process.cwd(), '/packages/design-core/public/mock/bundle.json')
// mockServer应用数据
const appInfoPath = path.join(process.cwd(), '/mockServer/src/services/appinfo.json')
const appSchemaPath = path.join(process.cwd(), 'mockServer/src/mock/get/app-center/v1/apps/schema/918.json')
const appInfo = fsExtra.readJSONSync(appInfoPath)
const appSchema = fsExtra.readJSONSync(appSchemaPath)
const connection = new MysqlConnection()
@ -22,6 +25,7 @@ const connection = new MysqlConnection()
const write = (bundle) => {
fsExtra.outputJSONSync(bundlePath, bundle, { spaces: 2 })
fsExtra.outputJSONSync(appInfoPath, appInfo, { spaces: 2 })
fsExtra.outputJSONSync(appSchemaPath, appSchema, { spaces: 2 })
}
/**
@ -36,13 +40,13 @@ const validateComponent = (file, component) => {
const requiredList = requiredFields.filter((field) => !fields.includes(field))
if (requiredList.length) {
logger.error(`组件文件 ${file} 缺少必要字段:${requiredList.join('、')}`)
logger.error(`missing required fields: ${requiredList.join(',')} at ${file}.`)
return false
}
if (!component.npm) {
logger.warn(`组件文件 ${file} 缺少 npm 字段出码时将不能通过import语句导入组件。`)
logger.warn(`missing the \`npm\` field, and it cannot be imported when coding at ${file}.`)
return false
}
@ -62,7 +66,7 @@ const validateBlock = (file, block) => {
const requiredList = requiredFields.filter((field) => !fields.includes(field))
if (requiredList.length) {
logger.error(`区块文件 ${file} 缺少必要字段:${requiredList.join('、')}`)
logger.error(`missing required fields: ${requiredList.join(',')} at ${file}.`)
return false
}
@ -80,7 +84,7 @@ const generateComponents = () => {
try {
fg([`${materialsDir}/**/*.json`]).then((files) => {
if (!files.length) {
logger.warn('物料文件夹为空,请先执行`pnpm splitMaterials`命令拆分物料资产包')
logger.warn('please execute `pnpm splitMaterials` first to split the materials.')
}
const bundle = {
@ -95,6 +99,7 @@ const generateComponents = () => {
}
const { components = [], snippets = [], blocks = [] } = bundle.data.materials
const componentsMap = []
const packagesMap = []
const appInfoBlocksLabels = appInfo.blockHistories.map((item) => item.label)
files.forEach((file) => {
@ -103,7 +108,7 @@ const generateComponents = () => {
if (!material) {
const fileFullPath = path.join(process.cwd(), file)
logger.error(`文件格式有误 (${fileFullPath})`)
logger.error(`incorrect file format at ${fileFullPath}.`)
return
}
@ -151,13 +156,31 @@ const generateComponents = () => {
appInfo.materialHistory.components = componentsMap
write(bundle)
const { package: packageName = '', version = '', exportName = '' } = npm || {}
const mapItem = {
componentName: component,
package: packageName,
version,
exportName
}
if (typeof npm.destructuring === 'boolean') {
mapItem.destructuring = npm.destructuring
}
if (npm.package) {
packagesMap.push(mapItem)
}
})
appSchema.data.componentsMap = packagesMap
write(bundle)
})
logger.success('物料资产包构建成功')
logger.success('materials built.')
} catch (error) {
logger.error(`物料资产包构建失败:${error}`)
logger.error(`failed to build materials: ${error}.`)
}
}
@ -166,13 +189,13 @@ const watcher = chokidar.watch(`${materialsDir}/**/*.json`, { ignoreInitial: tru
watcher.on('all', (event, file) => {
const eventMap = {
add: '新增',
change: '更新',
unlink: '删除'
add: 'added',
change: 'changed',
unlink: 'deleted'
}
const fileFullPath = path.join(process.cwd(), file)
logger.info(`${eventMap[event]}组件文件 (${fileFullPath})`)
logger.info(`${fileFullPath} ${eventMap[event]}, rebuilding materials...`)
// 监听物料文件变化,更新物料资产包
generateComponents()

View File

@ -38,10 +38,10 @@ class MysqlConnection {
return new Promise((resolve, reject) => {
this.connection.connect((error) => {
if (error) {
logger.warn('未能连接到数据库,请查看数据库配置是否正确')
logger.warn('unable to connect to the database, please check the database configuration is correct.')
reject()
} else {
logger.success('数据库连接成功')
logger.success('database connected.')
this.connected = true
resolve()
}
@ -100,11 +100,11 @@ class MysqlConnection {
* @returns boolean 校验组件字段是否失败false-有字段出错
*/
isValid(component, file) {
const longtextFields = ['name', 'npm', 'snippets', 'schema_fragment', 'configure', 'component_metadata']
const longTextFields = ['name', 'npm', 'snippets', 'schema_fragment', 'configure', 'component_metadata']
return Object.entries(component).every(([key, value]) => {
if (longtextFields.includes(key) && value !== null && typeof value !== 'object') {
logger.error(`"${key}" 的值不是有效的JSON (${file})`)
if (longTextFields.includes(key) && value !== null && typeof value !== 'object') {
logger.error(`the value of "${key}" is not valid JSON at ${file}.`)
return false
}
@ -193,10 +193,10 @@ class MysqlConnection {
this.query(sqlContent, component.component)
.then(() => {
logger.success(`组件 ${component.component} 数据更新成功`)
logger.success(`${component.component} updated.`)
})
.catch((error) => {
logger.error(`组件 ${component.component} 数据更新失败 ${error}`)
logger.error(`failed to update ${component.component}: ${error}.`)
})
}
@ -322,11 +322,11 @@ class MysqlConnection {
.then((result) => {
const id = result.insertId
logger.success(`组件 ${component.component} 数据新增成功`)
logger.success(`${component.component} added.`)
this.relationMaterialHistory(id)
})
.catch((error) => {
logger.success(`组件 ${component.component} 数据新增失败:${error}`)
logger.error(`add ${component.component} failed${error}.`)
})
}
@ -344,7 +344,7 @@ class MysqlConnection {
}
})
.catch((error) => {
logger.success(`查询组件 ${component.component} 失败:${error}`)
logger.error(`query ${component.component} failed${error}.`)
})
}
@ -395,11 +395,11 @@ class MysqlConnection {
return new Promise((resolve, reject) => {
this.query(sqlContent)
.then((result) => {
logger.success(`${componentsTableName} 创建成功`)
logger.success(`table ${componentsTableName} created.`)
resolve(result)
})
.catch((error) => {
logger.success(`${componentsTableName} 创建失败:${error}`)
logger.error(`create table ${componentsTableName} failed${error}.`)
reject(error)
})
})

View File

@ -51,9 +51,9 @@ const splitMaterials = () => {
fs.outputJsonSync(blockPath, block, { spaces: 2 })
})
logger.success('拆分物料资产包完成')
logger.success('materials splitted.')
} catch (error) {
logger.error(`拆分物料资产包失败: ${error}`)
logger.error(`failed to split materials: ${error}.`)
}
}