forked from opentiny/tiny-engine
Compare commits
167 Commits
feat/betaV
...
develop
| Author | SHA1 | Date |
|---|---|---|
|
|
e651dffa2b | |
|
|
91d3ae108c | |
|
|
277be2f11e | |
|
|
2c478ce391 | |
|
|
c341f4c2c5 | |
|
|
858e178af6 | |
|
|
4bfba8ca40 | |
|
|
07b0245fa0 | |
|
|
a0a4e293d8 | |
|
|
ffd0280877 | |
|
|
47c71d1129 | |
|
|
0d36df07a7 | |
|
|
6d9241ed6a | |
|
|
899d616f7e | |
|
|
3a66996fae | |
|
|
aa8d361bd2 | |
|
|
30cfeb19df | |
|
|
c271054870 | |
|
|
e9961aaba8 | |
|
|
c36cc66f59 | |
|
|
e98994f8d9 | |
|
|
0afdf2fcae | |
|
|
7bb3adfcba | |
|
|
3107621129 | |
|
|
50b62373a7 | |
|
|
0818d1656a | |
|
|
56907693f6 | |
|
|
4fd55d4261 | |
|
|
d613b4e8f6 | |
|
|
ade2d93331 | |
|
|
7d965fceee | |
|
|
4864fb66c5 | |
|
|
eafe3df2c6 | |
|
|
005f36af3c | |
|
|
a69082f518 | |
|
|
e54edca915 | |
|
|
681a6fa612 | |
|
|
259ef69ba3 | |
|
|
8e89cc47e7 | |
|
|
da8f58b0d9 | |
|
|
f7980d8c83 | |
|
|
e94b9674aa | |
|
|
c55397928a | |
|
|
852217f711 | |
|
|
e9d6d7e3f9 | |
|
|
0e6d30183a | |
|
|
68838ed5f9 | |
|
|
a010bfa4d6 | |
|
|
6c92ffefec | |
|
|
e961e0638f | |
|
|
8c09632e9c | |
|
|
e9a67b9de0 | |
|
|
6a59dacfd6 | |
|
|
d0241a9972 | |
|
|
13db22af27 | |
|
|
030497fbad | |
|
|
68637db8db | |
|
|
38c89a856c | |
|
|
99d0e47c29 | |
|
|
731a8536aa | |
|
|
913f40c4d2 | |
|
|
e88b254683 | |
|
|
7d967777d8 | |
|
|
bf2bc188a5 | |
|
|
683fc51d52 | |
|
|
96def94945 | |
|
|
52037fdf78 | |
|
|
491c01092e | |
|
|
9bccbfacb6 | |
|
|
34dfbc624e | |
|
|
3e1cb599d7 | |
|
|
5e43b79922 | |
|
|
4d247ef406 | |
|
|
f26456bbb5 | |
|
|
caeb540d19 | |
|
|
3875e16e87 | |
|
|
422c62dbdb | |
|
|
e79853cb09 | |
|
|
b726219668 | |
|
|
7ea6ebcbbd | |
|
|
f843d121fa | |
|
|
a192280fc4 | |
|
|
6ca84ee6f2 | |
|
|
93263b5298 | |
|
|
fb2e2f1207 | |
|
|
c3c2e2e714 | |
|
|
9e57be080c | |
|
|
28ee851b2a | |
|
|
dec9334eb8 | |
|
|
91ff6aed55 | |
|
|
9c72525db6 | |
|
|
35c7e91a4c | |
|
|
12b7a11280 | |
|
|
435f81708f | |
|
|
421dda28be | |
|
|
236445e7ff | |
|
|
3c2e14d4de | |
|
|
7b9ff6cfd5 | |
|
|
00160f92df | |
|
|
1cbecd2497 | |
|
|
9b96d10fb2 | |
|
|
2b5fe014f9 | |
|
|
38762017ff | |
|
|
fe477ad74c | |
|
|
47be96756c | |
|
|
919f06e89d | |
|
|
467d5a223a | |
|
|
e8b2e58c00 | |
|
|
93fcba0205 | |
|
|
2d3b380764 | |
|
|
b343220d77 | |
|
|
11767f2b64 | |
|
|
ec95df7c7d | |
|
|
f8390c0c89 | |
|
|
f87fa76335 | |
|
|
2cc1071e4d | |
|
|
021524c128 | |
|
|
0b83919fb5 | |
|
|
1b80dd3a35 | |
|
|
a3b43ec166 | |
|
|
422714e7a3 | |
|
|
069b051457 | |
|
|
394ab180bb | |
|
|
d3e75cecdd | |
|
|
11e302f1f9 | |
|
|
1d4c32e279 | |
|
|
588baaab07 | |
|
|
67e35395c4 | |
|
|
8474ddbc68 | |
|
|
699dc7b77f | |
|
|
af3989a02e | |
|
|
fd5baf1660 | |
|
|
0478258c87 | |
|
|
0cc2993eb2 | |
|
|
009a6d0754 | |
|
|
a8379f2bda | |
|
|
8ed61ca311 | |
|
|
3ae47c811b | |
|
|
1e72976c4c | |
|
|
a6232e5c92 | |
|
|
6a4de499a4 | |
|
|
6de244f098 | |
|
|
59074024d8 | |
|
|
68addea488 | |
|
|
f6981fd36e | |
|
|
5c2ea9c37d | |
|
|
7febb33d8d | |
|
|
d1dd2c56b5 | |
|
|
ac4b52ce13 | |
|
|
9911abe6de | |
|
|
9be6f31129 | |
|
|
1bc436530b | |
|
|
d13309f23b | |
|
|
ed0b8a3073 | |
|
|
aaa83ba162 | |
|
|
da0fbd1e28 | |
|
|
d1f0a35950 | |
|
|
4876571ed0 | |
|
|
4b0cfe6267 | |
|
|
213e7d80e8 | |
|
|
cb8414da9b | |
|
|
df244b588d | |
|
|
0958b0e51d | |
|
|
bf5d322b6d | |
|
|
8be11f2075 | |
|
|
364160f977 | |
|
|
7f79659f5b |
|
|
@ -8,4 +8,4 @@ tool_params:
|
|||
secsolar:
|
||||
source_dir: ./
|
||||
cmetrics:
|
||||
exclude: vite.config.js|package.json|index.js|mockServer/assets
|
||||
exclude: vite.config.js|package.json|index.js|mockServer/assets|packages/vue-generator/test
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
SQL_HOST=localhost
|
||||
SQL_PORT=3306
|
||||
SQL_USER=root
|
||||
SQL_PASSWORD=admin
|
||||
SQL_DATABASE=tiny_engine
|
||||
|
|
@ -5,3 +5,5 @@ package-lock.json
|
|||
**/node_modules/**
|
||||
tmp
|
||||
temp
|
||||
mockServer
|
||||
packages/vue-generator/**/output/**
|
||||
|
|
|
|||
|
|
@ -64,6 +64,14 @@ body:
|
|||
attributes:
|
||||
label: What is actually happening
|
||||
placeholder: Please Input
|
||||
- type: input
|
||||
id: project-name
|
||||
attributes:
|
||||
label: What is your project name
|
||||
description: We also welcome you to fill in more detailed project information in the following issue [#334](https://github.com/opentiny/tiny-engine/issues/334).
|
||||
placeholder: Please Input
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional-comments
|
||||
attributes:
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ blank_issues_enabled: true
|
|||
contact_links:
|
||||
- name: Questions or need help
|
||||
url: https://github.com/opentiny/tiny-engine/discussions
|
||||
about: Add this WeChat(opentiny), we will invite you to the WeChat discussion group later.
|
||||
about: Add this WeChat(opentiny-official), we will invite you to the WeChat discussion group later.
|
||||
|
|
|
|||
|
|
@ -21,3 +21,11 @@ body:
|
|||
placeholder: Please Input
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: project-name
|
||||
attributes:
|
||||
label: What is your project name
|
||||
description: We also welcome you to fill in more detailed project information in the following issue [#334](https://github.com/opentiny/tiny-engine/issues/334).
|
||||
placeholder: Please Input
|
||||
validations:
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
English | [简体中文](https://github.com/opentiny/tiny-engine/blob/develop/.github/PULL_REQUEST_TEMPLATE/PULL_REQUEST_TEMPLATE.zh-CN.md)
|
||||
|
||||
# PR
|
||||
|
||||
## PR Checklist
|
||||
|
|
@ -7,6 +9,7 @@ Please check if your PR fulfills the following requirements:
|
|||
- [ ] The commit message follows our [Commit Message Guidelines](https://github.com/opentiny/tiny-engine/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] Tests for the changes have been added (for bug fixes / features)
|
||||
- [ ] Docs have been added / updated (for bug fixes / features)
|
||||
- [ ] Built its own designer, fully self-validated
|
||||
|
||||
## PR Type
|
||||
|
||||
|
|
@ -23,13 +26,21 @@ What kind of change does this PR introduce?
|
|||
- [ ] Documentation content changes
|
||||
- [ ] Other... Please describe:
|
||||
|
||||
## What is the current behavior?
|
||||
## Background and solution
|
||||
<!--
|
||||
1. Describe the problem and the scenario.
|
||||
2. New features need to be described and attached with renderings.
|
||||
3. Screenshots or GIFs involving UI/Interaction changes/Bugfix before and after modification are required.
|
||||
-->
|
||||
|
||||
### What is the current behavior?
|
||||
|
||||
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
|
||||
|
||||
Issue Number: N/A
|
||||
|
||||
## What is the new behavior?
|
||||
### What is the new behavior?
|
||||
|
||||
|
||||
## Does this PR introduce a breaking change?
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
[English](https://github.com/opentiny/tiny-engine/blob/develop/.github/PULL_REQUEST_TEMPLATE.md) | 简体中文
|
||||
|
||||
# PR
|
||||
|
||||
## PR Checklist
|
||||
|
||||
请检查您的 PR 是否满足以下要求:
|
||||
|
||||
- [ ] commit message遵循我们的[提交贡献指南](https://github.com/opentiny/tiny-engine/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] 添加了更改内容的测试用例(用于bugfix/功能)
|
||||
- [ ] 文档已添加/更新(用于bugfix/功能)
|
||||
- [ ] 是否构建了自己的设计器,经过了充分的自验证
|
||||
|
||||
## PR 类型
|
||||
|
||||
这个PR的类型是?
|
||||
|
||||
- [ ] 日常 bug 修复
|
||||
- [ ] 新特性支持
|
||||
- [ ] 代码风格优化
|
||||
- [ ] 重构
|
||||
- [ ] 构建优化
|
||||
- [ ] 测试用例
|
||||
- [ ] 文档更新
|
||||
- [ ] 分支合并
|
||||
- [ ] 其他改动(请补充)
|
||||
|
||||
|
||||
## 需求背景和解决方案
|
||||
|
||||
<!--
|
||||
1. 要解决的具体问题。
|
||||
2. 新增特性,需要进行功能描述,并附上效果图。
|
||||
3. 涉及UI/交互变动/Bugfix需要有修改前&修改后截图或 GIF。
|
||||
-->
|
||||
|
||||
|
||||
Issue Number: N/A
|
||||
|
||||
### 修改前
|
||||
|
||||
|
||||
### 修改后
|
||||
|
||||
## 此PR是否含有 breaking change?
|
||||
|
||||
- [ ] 是
|
||||
- [ ] 否
|
||||
|
||||
<!-- 如果此 PR 包含breaking change,请在下面从用户角度描述具体变化和其他风险。-->
|
||||
|
||||
## Other information
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
name: Push And Create PR Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: []
|
||||
pull_request:
|
||||
branches: [develop,main]
|
||||
|
||||
jobs:
|
||||
push-check:
|
||||
runs-on: ubuntu-latest # windows-latest || macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install pnpm
|
||||
run: npm i -g pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm i
|
||||
|
||||
- name: Get changed files
|
||||
id: get_changed_files
|
||||
uses: tj-actions/changed-files@v41
|
||||
with:
|
||||
files: |
|
||||
**.js
|
||||
**.vue
|
||||
**.jsx
|
||||
- name: Run ESLint
|
||||
run: npx eslint ${{steps.get_changed_files.outputs.all_changed_files}}
|
||||
- name: Run Build
|
||||
run: pnpm run build:plugin && pnpm run build:alpha
|
||||
|
|
@ -5,6 +5,7 @@ package-lock.json
|
|||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
lerna-debug.log
|
||||
packages/design-core/bundle-deps
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
|
|
|
|||
|
|
@ -51,14 +51,11 @@ Local startup steps:
|
|||
git clone git@github.com:username/tiny-engine.git
|
||||
cd tiny-engine
|
||||
git remote add upstream git@github.com:opentiny/tiny-engine.git
|
||||
npm i
|
||||
pnpm i
|
||||
|
||||
# Start the project.
|
||||
$ npm run serve
|
||||
$ pnpm dev
|
||||
|
||||
# start another terminal
|
||||
$ cd mockServer
|
||||
$ npm run dev
|
||||
```
|
||||
|
||||
To submit a PR:
|
||||
|
|
@ -67,7 +64,7 @@ To submit a PR:
|
|||
- Local coding.
|
||||
- Submit according to [Commit Message Format](https://www.conventionalcommits.org/zh-hans/v1.0.0/) specification. PR that do not conform to the submission specification will not be merged.
|
||||
- Submit to remote repository: `git push origin branchName`.
|
||||
- (Optional) Synchronize upstream repository dev branch latest code: `git pull upstream dev`.
|
||||
- (Optional) Synchronize upstream repository dev branch latest code: `git pull upstream develop`.
|
||||
- Open the [Pull requests](https://github.com/opentiny/tiny-engine/pulls) link of the TinyEngine code repository and click the New pull request button to submit the PR.
|
||||
- Project Committer conducts Code Review and makes comments.
|
||||
- The PR author adjusts the code according to the opinion. Please note that when a branch initiates PR, the subsequent commit will be synchronized automatically, and there is no need to resubmit the PR.
|
||||
|
|
|
|||
|
|
@ -42,23 +42,18 @@
|
|||
|
||||
- 点击 [TinyEngine](https://github.com/opentiny/tiny-engine) 代码仓库右上角的 Fork 按钮,将上游仓库 Fork 到个人仓库
|
||||
- Clone 个人仓库到本地
|
||||
- 在 TinyEngine 根目录下运行 `npm install`, 安装依赖
|
||||
- 在 TinyEngine mockServer 运行 `npm install`, 安装依赖
|
||||
- 在 TinyEngine 根目录下运行 `npm run serve`,再到 mockServer 目录下运行 `npm run dev`,启动本地开发
|
||||
- 在 TinyEngine 根目录下运行 `pnpm i`, 安装依赖
|
||||
- 在 TinyEngine 根目录下运行 `pnpm dev`,启动本地开发
|
||||
|
||||
```shell
|
||||
# username 为用户名,执行前请替换
|
||||
git clone git@github.com:username/tiny-engine.git
|
||||
cd tiny-engine
|
||||
git remote add upstream git@github.com:opentiny/tiny-engine.git
|
||||
npm i
|
||||
pnpm i
|
||||
|
||||
# 启动项目
|
||||
$ npm run serve
|
||||
|
||||
# start another terminal
|
||||
$ cd mockServer
|
||||
$ npm run dev
|
||||
$ pnpm dev
|
||||
|
||||
```
|
||||
|
||||
|
|
@ -68,7 +63,7 @@ $ npm run dev
|
|||
- 本地编码
|
||||
- 遵循 Commit Message Format 规范进行提交,不符合提交规范的 PR 将不会被合并
|
||||
- 提交到远程仓库:git push origin branchName
|
||||
- (可选)同步上游仓库 dev 分支最新代码:git pull upstream dev
|
||||
- (可选)同步上游仓库 develop 分支最新代码:git pull upstream develop
|
||||
- 打开 TinyEngine 代码仓库的 [Pull requests](https://github.com/opentiny/tiny-engine/pulls) 链接,点击 New pull request 按钮提交 PR
|
||||
- 项目 Committer 进行 Code Review,并提出意见
|
||||
- PR 作者根据意见调整代码,请注意一个分支发起了 PR 后,后续的 commit 会自动同步,无需重新提交 PR
|
||||
|
|
@ -81,4 +76,4 @@ $ npm run dev
|
|||
如果你对我们的开源项目感兴趣,欢迎通过以下方式加入我们的开源社区。
|
||||
|
||||
- 添加官方小助手微信:opentiny-official,加入我们的技术交流群
|
||||
- 加入邮件列表:opentiny@googlegroups.com
|
||||
- 加入邮件列表:opentiny@googlegroups.com
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
<p align="center">
|
||||
<a href="https://opentiny.design/tiny-engine" target="_blank" rel="noopener noreferrer">
|
||||
<img alt="OpenTiny Logo" src="logo.svg" height="100" style="max-width:100%;">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">TinyEngine enables developers to customize low-code platforms, build low-bit platforms online in real time, and support secondary development or integration of low-bit platform capabilities.</p>
|
||||
|
||||
English | [简体中文](README.zh-CN.md)
|
||||
|
||||
🌈 Features:
|
||||
|
||||
- Cross-end cross-frame front-end components
|
||||
- Supports online real-time construction, secondary development, or being integrated.
|
||||
- Directly generate deployable source code without engine support.
|
||||
- Allows access to third-party components and customized extension plug-ins.
|
||||
- Supports high-code and low-code, and hybrid development and deployment of applications.
|
||||
- The platform accesses AI big model capabilities to help developers build applications.
|
||||
|
||||
## Development
|
||||
|
||||
### Dependencies required for installation
|
||||
|
||||
```sh
|
||||
$ pnpm install
|
||||
```
|
||||
|
||||
### Local development: Start the local mock server and use the mock data of the local mock server.
|
||||
|
||||
```sh
|
||||
$ pnpm dev
|
||||
```
|
||||
|
||||
Open a browser: `http://localhost:8080/?type=app&id=918&tenant=1&pageid=NTJ4MjvqoVj8OVsc`
|
||||
`url search` Parameters:
|
||||
|
||||
- `type=app` Application type
|
||||
- `id=xxx` Application ID
|
||||
- `tenant=xxx` Organization ID
|
||||
- `pageid=xxx` Page ID
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
# Build all plug-ins first
|
||||
pnpm build:plugin
|
||||
|
||||
# Build Designer
|
||||
pnpm build:alpha or build:prod
|
||||
|
||||
```
|
||||
|
||||
## 🤝 Participation and Contribution
|
||||
|
||||
If you are interested in our open source project, please join us! 🎉
|
||||
|
||||
Please read the [Contribution Guide](CONTRIBUTING.md) before participating in the contribution.
|
||||
|
||||
- Add official assistant WeChat opentiny-official and join the technical exchange group
|
||||
- Join the mailing list opentiny@googlegroups.com
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
44
README.md
44
README.md
|
|
@ -17,6 +17,12 @@ English | [简体中文](README.zh-CN.md)
|
|||
- Supports high-code and low-code, and hybrid development and deployment of applications.
|
||||
- The platform accesses AI big model capabilities to help developers build applications.
|
||||
|
||||
## Documentation
|
||||
|
||||
- intro:https://opentiny.design/tiny-engine#/home
|
||||
- tutorial:https://opentiny.design/tiny-engine#/help-center/course/engine
|
||||
- playground:https://opentiny.design/tiny-engine#/tiny-engine-editor
|
||||
|
||||
## Development
|
||||
|
||||
### Dependencies required for installation
|
||||
|
|
@ -31,6 +37,27 @@ $ pnpm install
|
|||
$ pnpm dev
|
||||
```
|
||||
|
||||
## Local development, directly connected to the local tiny-engine-webservice server
|
||||
|
||||
1. Start <a href="https://github.com/opentiny/tiny-engine-data-center/blob/main/README.md" target="_blank">tiny-engine-data-center</a>
|
||||
|
||||
2. Start <a href="https://github.com/opentiny/tiny-engine-webservice/blob/main/README.md" target="_blank">tiny-engine-webservice</a>
|
||||
|
||||
3. Modify the origin value in `vite.config.js` in the `packages/design-core/` directory of the tiny-engine project to be the address port of your local webService project (the webService port defaults to 7011), such as:
|
||||
|
||||
<img alt="Modify port" src="https://res.hc-cdn.com/lowcode-portal/1.1.55/img/docimg/backend_deploy_5.png">
|
||||
|
||||
|
||||
### Materials Synchronization [Solution](https://opentiny.design/tiny-engine#/help-center/course/engine/56)
|
||||
|
||||
```sh
|
||||
$ pnpm splitMaterials
|
||||
```
|
||||
|
||||
```sh
|
||||
$ pnpm buildMaterials
|
||||
```
|
||||
|
||||
Open a browser: `http://localhost:8080/?type=app&id=918&tenant=1&pageid=NTJ4MjvqoVj8OVsc`
|
||||
`url search` Parameters:
|
||||
|
||||
|
|
@ -48,6 +75,23 @@ pnpm build:plugin
|
|||
# Build Designer
|
||||
pnpm build:alpha or build:prod
|
||||
|
||||
```
|
||||
The folder where the product is located after building
|
||||
```
|
||||
tiny-engine/packages/design-core/dist/
|
||||
```
|
||||
|
||||
## Milestones
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```
|
||||
|
||||
## 🤝 Participation and Contribution
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@
|
|||
- 支持高代码与低代码,混合开发部署应用
|
||||
- 平台接入 AI 大模型能力,辅助开发者构建应用
|
||||
|
||||
## 文档
|
||||
|
||||
- 介绍:https://opentiny.design/tiny-engine#/home
|
||||
- 使用文档:https://opentiny.design/tiny-engine#/help-center/course/engine
|
||||
- 演示应用:https://opentiny.design/tiny-engine#/tiny-engine-editor
|
||||
|
||||
## 开发
|
||||
|
||||
### 安装所需的依赖
|
||||
|
|
@ -31,6 +37,27 @@ $ pnpm install
|
|||
$ pnpm dev
|
||||
```
|
||||
|
||||
### 本地开发,直连本地的tiny-engine-webservice服务端
|
||||
|
||||
1. 启动 <a href="https://github.com/opentiny/tiny-engine-data-center/blob/main/README.md" target="_blank">tiny-engine-data-center</a>
|
||||
|
||||
2. 启动 <a href="https://github.com/opentiny/tiny-engine-webservice/blob/main/README.md" target="_blank">tiny-engine-webservice</a>
|
||||
|
||||
3. 修改 tiny-engine 项目 `packages/design-core/` 目录下 `vite.config.js` 中origin的值为自己本地webService项目的地址端口(webService端口默认为7011),如:
|
||||
|
||||
<img alt="修改端口" src="https://res.hc-cdn.com/lowcode-portal/1.1.55/img/docimg/backend_deploy_5.png">
|
||||
|
||||
|
||||
### 物料同步[方案](https://opentiny.design/tiny-engine#/help-center/course/engine/56)
|
||||
|
||||
```sh
|
||||
$ pnpm splitMaterials
|
||||
```
|
||||
|
||||
```sh
|
||||
$ pnpm buildMaterials
|
||||
```
|
||||
|
||||
浏览器打开:`http://localhost:8080/?type=app&id=918&tenant=1&pageid=NTJ4MjvqoVj8OVsc`
|
||||
`url search`参数:
|
||||
|
||||
|
|
@ -48,6 +75,23 @@ pnpm run build:plugin
|
|||
# 构建设计器
|
||||
pnpm run build:alpha 或 build:prod
|
||||
|
||||
```
|
||||
构建后产物所在文件夹
|
||||
```
|
||||
tiny-engine/packages/design-core/dist/
|
||||
```
|
||||
|
||||
## 里程碑
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```
|
||||
|
||||
## 🤝 参与贡献
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const cacheStringFunction = (fn) => {
|
|||
}
|
||||
const hyphenateRE = /\B([A-Z])/g
|
||||
const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1').toLowerCase())
|
||||
var _export_sfc = (sfc, props) => {
|
||||
const _export_sfc = (sfc, props) => {
|
||||
const target = sfc.__vccOpts || sfc
|
||||
for (const [key, val] of props) {
|
||||
target[key] = val
|
||||
|
|
@ -73,7 +73,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|||
])
|
||||
)
|
||||
}
|
||||
var block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
const block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
['render', _sfc_render],
|
||||
['__file', 'D:/tmp/buildground/buildground_1673597935715/src/block/generated/components/PortalBlock.vue']
|
||||
])
|
||||
|
|
|
|||
|
|
@ -11,25 +11,27 @@
|
|||
*/
|
||||
|
||||
;(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined'
|
||||
? (module.exports = factory(
|
||||
require('@opentiny/tiny-engine-webcomponent-core'),
|
||||
require('vue'),
|
||||
require('vue-i18n'),
|
||||
require('@opentiny/vue-icon')
|
||||
))
|
||||
: typeof define === 'function' && define.amd
|
||||
? define(['@opentiny/tiny-engine-webcomponent-core', 'vue', 'vue-i18n', '@opentiny/vue-icon'], factory)
|
||||
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
|
||||
(global.TinyVueBlock = factory(global.TinyWebcomponentCore, global.Vue, global.VueI18n, global.TinyVueIcon)))
|
||||
})(this, function (tinyWebcomponentCore, vue, vueI18n, tinyVue3Icon) {
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
module.exports = factory(
|
||||
require('@opentiny/tiny-engine-webcomponent-core'),
|
||||
require('vue'),
|
||||
require('vue-i18n'),
|
||||
require('@opentiny/vue-icon')
|
||||
)
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(['@opentiny/tiny-engine-webcomponent-core', 'vue', 'vue-i18n', '@opentiny/vue-icon'], factory)
|
||||
} else {
|
||||
;(global = typeof globalThis !== 'undefined' ? globalThis : global || self),
|
||||
(global.TinyVueBlock = factory(global.TinyWebcomponentCore, global.Vue, global.VueI18n, global.TinyVueIcon))
|
||||
}
|
||||
})(this, (tinyWebcomponentCore, vue, vueI18n, tinyVue3Icon) => {
|
||||
function _interopNamespace(e) {
|
||||
if (e && e.__esModule) return e
|
||||
var n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } })
|
||||
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } })
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
Object.keys(e).forEach((k) => {
|
||||
if (k !== 'default') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k)
|
||||
const d = Object.getOwnPropertyDescriptor(e, k)
|
||||
Object.defineProperty(
|
||||
n,
|
||||
k,
|
||||
|
|
@ -45,10 +47,10 @@
|
|||
}
|
||||
})
|
||||
}
|
||||
n['default'] = e
|
||||
n.default = e
|
||||
return Object.freeze(n)
|
||||
}
|
||||
var vue__namespace = /* @__PURE__ */ _interopNamespace(vue)
|
||||
const vue__namespace = /* @__PURE__ */ _interopNamespace(vue)
|
||||
Object.freeze({})
|
||||
Object.freeze([])
|
||||
const cacheStringFunction = (fn) => {
|
||||
|
|
@ -60,7 +62,7 @@
|
|||
}
|
||||
const hyphenateRE = /\B([A-Z])/g
|
||||
const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1').toLowerCase())
|
||||
var _export_sfc = (sfc, props) => {
|
||||
const _export_sfc = (sfc, props) => {
|
||||
const target = sfc.__vccOpts || sfc
|
||||
for (const [key, val] of props) {
|
||||
target[key] = val
|
||||
|
|
@ -112,7 +114,7 @@
|
|||
])
|
||||
)
|
||||
}
|
||||
var block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
const block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
['render', _sfc_render],
|
||||
['__file', 'D:/tmp/buildground/buildground_1673597935715/src/block/generated/components/PortalBlock.vue']
|
||||
])
|
||||
|
|
|
|||
|
|
@ -76,6 +76,6 @@ const Mapper = {
|
|||
TinyDropdown: Dropdown,
|
||||
TinyChartHistogram: ChartHistogram
|
||||
}
|
||||
Mapper['TinyTabs'].isGroup = true
|
||||
Mapper['TinyGrid'].isGroup = true
|
||||
Mapper.TinyTabs.isGroup = true
|
||||
Mapper.TinyGrid.isGroup = true
|
||||
export { Mapper as default }
|
||||
|
|
|
|||
|
|
@ -1,23 +1,25 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
;(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined'
|
||||
? (module.exports = factory(require('@opentiny/vue')))
|
||||
: typeof define === 'function' && define.amd
|
||||
? define(['@opentiny/vue'], factory)
|
||||
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
|
||||
(global.TinyLowcodeComponent = factory(global.TinyVue)))
|
||||
})(this, function (tinyVue3) {
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
module.exports = factory(require('@opentiny/vue'))
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(['@opentiny/vue'], factory)
|
||||
} else {
|
||||
;(global = typeof globalThis !== 'undefined' ? globalThis : global || self),
|
||||
(global.TinyLowcodeComponent = factory(global.TinyVue))
|
||||
}
|
||||
})(this, (tinyVue3) => {
|
||||
'use strict'
|
||||
const Mapper = {
|
||||
TinyCarouselItem: tinyVue3.CarouselItem,
|
||||
|
|
@ -52,7 +54,7 @@
|
|||
TinyDropdown: tinyVue3.Dropdown,
|
||||
TinyChartHistogram: tinyVue3.ChartHistogram
|
||||
}
|
||||
Mapper['TinyTabs'].isGroup = true
|
||||
Mapper['TinyGrid'].isGroup = true
|
||||
Mapper.TinyTabs.isGroup = true
|
||||
Mapper.TinyGrid.isGroup = true
|
||||
return Mapper
|
||||
})
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ const cacheStringFunction = (fn) => {
|
|||
}
|
||||
const hyphenateRE = /\B([A-Z])/g
|
||||
const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1').toLowerCase())
|
||||
var _style_0 =
|
||||
const _style_0 =
|
||||
'\n.team-list-item.active[data-v-b66e3972] {\r\n border: 1px solid #38acff;\n}\n.toolbars-item[data-v-b66e3972]:hover {\r\n cursor: pointer;\r\n background-color: #f1f2f3;\n}\n.toolbars-item.active[data-v-b66e3972] {\r\n background-color: #e5e6e8;\n}\n'
|
||||
var _export_sfc = (sfc, props) => {
|
||||
const _export_sfc = (sfc, props) => {
|
||||
const target = sfc.__vccOpts || sfc
|
||||
for (const [key, val] of props) {
|
||||
target[key] = val
|
||||
|
|
@ -406,7 +406,7 @@ const _hoisted_22 = /* @__PURE__ */ _withScopeId(() =>
|
|||
)
|
||||
)
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
var _a
|
||||
let _a
|
||||
const _component_tiny_icon_setting = resolveComponent('tiny-icon-setting')
|
||||
const _component_tiny_tooltip = resolveComponent('tiny-tooltip')
|
||||
const _component_tiny_icon_check_out = resolveComponent('tiny-icon-check-out')
|
||||
|
|
@ -640,7 +640,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|||
])
|
||||
)
|
||||
}
|
||||
var block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
const block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
['render', _sfc_render],
|
||||
['styles', [_style_0]],
|
||||
['__scopeId', 'data-v-b66e3972'],
|
||||
|
|
|
|||
|
|
@ -11,36 +11,41 @@
|
|||
*/
|
||||
|
||||
;(function (global, factory) {
|
||||
typeof exports === 'object ' && typeof module !== 'undefined '
|
||||
? (module.exports = factory(
|
||||
require('@opentiny/tiny-engine-webcomponent-core '),
|
||||
require('vue '),
|
||||
require('vue-i18n '),
|
||||
require('@opentiny/vue-icon '),
|
||||
require('@opentiny/vue ')
|
||||
))
|
||||
: typeof define === 'function ' && define.amd
|
||||
? define(
|
||||
['@opentiny/tiny-engine-webcomponent-core ', 'vue ', 'vue-i18n ', '@opentiny/vue-icon ', '@opentiny/vue '],
|
||||
factory
|
||||
)
|
||||
: ((global = typeof globalThis !== 'undefined ' ? globalThis : global || self),
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
module.exports = factory(
|
||||
require('@opentiny/tiny-engine-webcomponent-core'),
|
||||
require('vue'),
|
||||
require('vue-i18n'),
|
||||
require('@opentiny/vue-icon'),
|
||||
require('@opentiny/vue')
|
||||
)
|
||||
} else if (typeof define === 'function ' && define.amd) {
|
||||
define([
|
||||
'@opentiny/tiny-engine-webcomponent-core',
|
||||
'vue',
|
||||
'vue-i18n',
|
||||
'@opentiny/vue-icon',
|
||||
'@opentiny/vue'
|
||||
], factory)
|
||||
} else {
|
||||
;(global = typeof globalThis !== 'undefined' ? globalThis : global || self),
|
||||
(global.TinyVueBlock = factory(
|
||||
global.TinyWebcomponentCore,
|
||||
global.Vue,
|
||||
global.VueI18n,
|
||||
global.TinyVueIcon,
|
||||
global.TinyVue
|
||||
)))
|
||||
})(this, function (tinyWebcomponentCore, vue, vueI18n, tinyVue3Icon, tinyVue3) {
|
||||
))
|
||||
}
|
||||
})(this, (tinyWebcomponentCore, vue, vueI18n, tinyVue3Icon, tinyVue3) => {
|
||||
'use strict '
|
||||
function _interopNamespace(e) {
|
||||
if (e && e.__esModule) return e
|
||||
var n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module ' } })
|
||||
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module ' } })
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
Object.keys(e).forEach((k) => {
|
||||
if (k !== 'default ') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k)
|
||||
const d = Object.getOwnPropertyDescriptor(e, k)
|
||||
Object.defineProperty(
|
||||
n,
|
||||
k,
|
||||
|
|
@ -59,7 +64,7 @@
|
|||
n['default '] = e
|
||||
return Object.freeze(n)
|
||||
}
|
||||
var vue__namespace = /* @__PURE__ */ _interopNamespace(vue)
|
||||
const vue__namespace = /* @__PURE__ */ _interopNamespace(vue)
|
||||
Object.freeze({})
|
||||
Object.freeze([])
|
||||
const cacheStringFunction = (fn) => {
|
||||
|
|
@ -71,9 +76,9 @@
|
|||
}
|
||||
const hyphenateRE = /\B([A-Z])/g
|
||||
const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1 ').toLowerCase())
|
||||
var _style_0 =
|
||||
const _style_0 =
|
||||
'\n.team-list-item.active[data-v-b66e3972] {\r\n border: 1px solid #38acff;\n}\n.toolbars-item[data-v-b66e3972]:hover {\r\n cursor: pointer;\r\n background-color: #f1f2f3;\n}\n.toolbars-item.active[data-v-b66e3972] {\r\n background-color: #e5e6e8;\n}\n '
|
||||
var _export_sfc = (sfc, props) => {
|
||||
const _export_sfc = (sfc, props) => {
|
||||
const target = sfc.__vccOpts || sfc
|
||||
for (const [key, val] of props) {
|
||||
target[key] = val
|
||||
|
|
@ -446,7 +451,7 @@
|
|||
)
|
||||
)
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
var _a
|
||||
let _a
|
||||
const _component_tiny_icon_setting = vue.resolveComponent('tiny-icon-setting ')
|
||||
const _component_tiny_tooltip = vue.resolveComponent('tiny-tooltip ')
|
||||
const _component_tiny_icon_check_out = vue.resolveComponent('tiny-icon-check-out ')
|
||||
|
|
@ -688,7 +693,7 @@
|
|||
])
|
||||
)
|
||||
}
|
||||
var block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
const block = /* @__PURE__ */ _export_sfc(_sfc_main, [
|
||||
['render ', _sfc_render],
|
||||
['styles ', [_style_0]],
|
||||
['__scopeId ', 'data-v-b66e3972 '],
|
||||
|
|
|
|||
|
|
@ -6065,7 +6065,7 @@
|
|||
"devMode": "proCode",
|
||||
"npm": {
|
||||
"package": "@opentiny/vue",
|
||||
"exportName": "TinyTabItem",
|
||||
"exportName": "TabItem",
|
||||
"version": "",
|
||||
"destructuring": true
|
||||
},
|
||||
|
|
@ -6314,7 +6314,7 @@
|
|||
"devMode": "proCode",
|
||||
"npm": {
|
||||
"package": "@opentiny/vue",
|
||||
"exportName": "TinyBreadcrumbItem",
|
||||
"exportName": "BreadcrumbItem",
|
||||
"version": "",
|
||||
"destructuring": true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
port: process.env.MOCK_PORT || 9090,
|
||||
env: process.env.NODE_ENV || 'development' // Current mode
|
||||
}
|
||||
|
|
@ -1,12 +1,21 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine-mock",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.3",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"description": "mock服务",
|
||||
"author": "opentiny",
|
||||
"license": "WTFPL",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentiny/tiny-engine",
|
||||
"directory": "mockServer"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/opentiny/tiny-engine/issues"
|
||||
},
|
||||
"author": "OpenTiny Team",
|
||||
"license": "MIT",
|
||||
"homepage": "https://opentiny.design/tiny-engine",
|
||||
"scripts": {
|
||||
"start": "gulp nodemon",
|
||||
"dev": "gulp",
|
||||
|
|
@ -16,7 +25,7 @@
|
|||
"lint": "eslint --fix ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@opentiny/tiny-engine-dsl-vue": "~1.0.0",
|
||||
"@opentiny/tiny-engine-dsl-vue": "^1.0.3",
|
||||
"@seald-io/nedb": "^4.0.2",
|
||||
"fs-extra": "^11.1.1",
|
||||
"glob": "^10.3.4",
|
||||
|
|
|
|||
|
|
@ -14,13 +14,12 @@ import Koa2 from 'koa'
|
|||
import KoaBody from 'koa-body'
|
||||
import KoaStatic from 'koa-static2'
|
||||
import path from 'path'
|
||||
import MainRoutes from './routes/main-routes'
|
||||
import { env, port } from '../config/config'
|
||||
import ErrorRoutesCatch from './middleware/ErrorRoutesCatch'
|
||||
import ErrorRoutes from './routes/error-routes'
|
||||
import MainRoutes from './routes/main-routes'
|
||||
|
||||
const app = new Koa2()
|
||||
const env = process.env.NODE_ENV || 'development' // Current mode
|
||||
const PORT = 9090
|
||||
app
|
||||
.use((ctx, next) => {
|
||||
ctx.set('Access-Control-Allow-Origin', '*')
|
||||
|
|
@ -57,6 +56,6 @@ if (env === 'development') {
|
|||
})
|
||||
}
|
||||
|
||||
app.listen(PORT)
|
||||
app.listen(port)
|
||||
|
||||
export default app
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@
|
|||
"type": "function",
|
||||
"content": {
|
||||
"type": "JSFunction",
|
||||
"value": "function util() {\r\n console.log(3211)\r\n}"
|
||||
"value": "function test() {\r\n return 'test'\r\n}"
|
||||
},
|
||||
"app": 918,
|
||||
"category": "utils",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,674 @@
|
|||
"gmt_modified": "2023-08-23 10:22:28"
|
||||
},
|
||||
"dataSource": {
|
||||
"list": [],
|
||||
"list": [
|
||||
{
|
||||
"id": 132,
|
||||
"name": "getAllComponent",
|
||||
"data": {
|
||||
"data": [],
|
||||
"type": "array"
|
||||
},
|
||||
"tpl": null,
|
||||
"app": "918",
|
||||
"desc": null,
|
||||
"created_at": "2022-06-28T06:26:26.000Z",
|
||||
"updated_at": "2022-06-28T07:02:30.000Z"
|
||||
},
|
||||
{
|
||||
"id": 133,
|
||||
"name": "getAllList",
|
||||
"data": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "test",
|
||||
"title": "测试",
|
||||
"field": "test",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "test1",
|
||||
"title": "测试1",
|
||||
"field": "test1",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"data": [
|
||||
{
|
||||
"test": "test1",
|
||||
"test1": "test1",
|
||||
"_id": "341efc48"
|
||||
},
|
||||
{
|
||||
"test": "test2",
|
||||
"test1": "test1",
|
||||
"_id": "b86b516c"
|
||||
},
|
||||
{
|
||||
"test": "test3",
|
||||
"test1": "test1",
|
||||
"_id": "f680cd78"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"uri": "",
|
||||
"method": "GET"
|
||||
},
|
||||
"dataHandler": {
|
||||
"type": "JSFunction",
|
||||
"value": "function dataHandler(data) { \n return data \n}"
|
||||
},
|
||||
"willFetch": {
|
||||
"type": "JSFunction",
|
||||
"value": "function willFetch(option) {\n return option \n}"
|
||||
},
|
||||
"shouldFetch": {
|
||||
"type": "JSFunction",
|
||||
"value": "function shouldFetch(option) {\n return true \n}"
|
||||
},
|
||||
"errorHandler": {
|
||||
"type": "JSFunction",
|
||||
"value": "function errorHandler(err) {}"
|
||||
}
|
||||
},
|
||||
"tpl": null,
|
||||
"app": "918",
|
||||
"desc": null,
|
||||
"created_at": "2022-06-28T07:32:16.000Z",
|
||||
"updated_at": "2023-01-19T03:29:11.000Z"
|
||||
},
|
||||
{
|
||||
"id": 135,
|
||||
"name": "getAllMaterialList",
|
||||
"data": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"title": "id",
|
||||
"field": "id",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"title": "name",
|
||||
"field": "name",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "framework",
|
||||
"title": "framework",
|
||||
"field": "framework",
|
||||
"type": "string",
|
||||
"format": {
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "components",
|
||||
"title": "components",
|
||||
"field": "components",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "content",
|
||||
"title": "content",
|
||||
"field": "content",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "url",
|
||||
"title": "url",
|
||||
"field": "url",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "published_at",
|
||||
"title": "published_at",
|
||||
"field": "published_at",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"title": "created_at",
|
||||
"field": "created_at",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "updated_at",
|
||||
"title": "updated_at",
|
||||
"field": "updated_at",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "published",
|
||||
"title": "published",
|
||||
"field": "published",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "last_build_info",
|
||||
"title": "last_build_info",
|
||||
"field": "last_build_info",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "tenant",
|
||||
"title": "tenant",
|
||||
"field": "tenant",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"title": "version",
|
||||
"field": "version",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"title": "description",
|
||||
"field": "description",
|
||||
"type": "string",
|
||||
"format": {}
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"data": [
|
||||
{
|
||||
"id": "f37123ec",
|
||||
"url": "",
|
||||
"name": "ng-material",
|
||||
"tenant": "",
|
||||
"content": "",
|
||||
"version": "1.0.0",
|
||||
"framework": "Angular",
|
||||
"published": "",
|
||||
"components": "",
|
||||
"created_at": "2021-11-02T11:32:22.000Z",
|
||||
"updated_at": "2021-11-02T11:32:22.000Z",
|
||||
"description": "angular组件库物料",
|
||||
"published_at": "2021-11-02T11:32:22.000Z",
|
||||
"last_build_info": "",
|
||||
"_id": "2a23e653"
|
||||
},
|
||||
{
|
||||
"id": "f37123ec",
|
||||
"url": "",
|
||||
"name": "ng-material",
|
||||
"tenant": "",
|
||||
"content": "",
|
||||
"version": "1.0.0",
|
||||
"framework": "Angular",
|
||||
"published": "",
|
||||
"components": "",
|
||||
"created_at": "2021-11-02T11:32:22.000Z",
|
||||
"updated_at": "2021-11-02T11:32:22.000Z",
|
||||
"description": "angular组件库物料",
|
||||
"published_at": "2021-11-02T11:32:22.000Z",
|
||||
"last_build_info": "",
|
||||
"_id": "06b253be"
|
||||
},
|
||||
{
|
||||
"id": "f37123ec",
|
||||
"url": "",
|
||||
"name": "ng-material",
|
||||
"tenant": "",
|
||||
"content": "",
|
||||
"version": "1.0.0",
|
||||
"framework": "Angular",
|
||||
"published": "",
|
||||
"components": "",
|
||||
"created_at": "2021-11-02T11:32:22.000Z",
|
||||
"updated_at": "2021-11-02T11:32:22.000Z",
|
||||
"description": "angular组件库物料",
|
||||
"published_at": "2021-11-02T11:32:22.000Z",
|
||||
"last_build_info": "",
|
||||
"_id": "c55a41ed"
|
||||
},
|
||||
{
|
||||
"id": "f37123ec",
|
||||
"url": "",
|
||||
"name": "ng-material",
|
||||
"tenant": "",
|
||||
"content": "",
|
||||
"version": "1.0.0",
|
||||
"framework": "Angular",
|
||||
"published": "",
|
||||
"components": "",
|
||||
"created_at": "2021-11-02T11:32:22.000Z",
|
||||
"updated_at": "2021-11-02T11:32:22.000Z",
|
||||
"description": "angular组件库物料",
|
||||
"published_at": "2021-11-02T11:32:22.000Z",
|
||||
"last_build_info": "",
|
||||
"_id": "f37123ec"
|
||||
},
|
||||
{
|
||||
"id": "7a63c1a2",
|
||||
"url": "",
|
||||
"name": "tiny-vue",
|
||||
"tenant": "",
|
||||
"content": "Tiny Vue物料",
|
||||
"version": "1.0.0",
|
||||
"framework": "Vue",
|
||||
"published": "",
|
||||
"components": "",
|
||||
"created_at": "",
|
||||
"updated_at": "",
|
||||
"description": "Tiny Vue物料",
|
||||
"published_at": "",
|
||||
"last_build_info": "",
|
||||
"_id": "7a63c1a2"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"uri": "",
|
||||
"method": "GET"
|
||||
},
|
||||
"willFetch": {
|
||||
"type": "JSFunction",
|
||||
"value": "function willFetch(option) {\n return option \n}"
|
||||
},
|
||||
"dataHandler": {
|
||||
"type": "JSFunction",
|
||||
"value": "function dataHandler(data) { \n return data \n}"
|
||||
},
|
||||
"shouldFetch": {
|
||||
"type": "JSFunction",
|
||||
"value": "function shouldFetch(option) {\n return true \n}"
|
||||
},
|
||||
"errorHandler": {
|
||||
"type": "JSFunction",
|
||||
"value": "function errorHandler(err) {}"
|
||||
}
|
||||
},
|
||||
"tpl": null,
|
||||
"app": "918",
|
||||
"desc": null,
|
||||
"created_at": "2022-06-29T00:57:50.000Z",
|
||||
"updated_at": "2023-05-15T02:37:12.000Z"
|
||||
},
|
||||
{
|
||||
"id": 139,
|
||||
"name": "treedata",
|
||||
"data": {
|
||||
"data": [
|
||||
{
|
||||
"label": "level111",
|
||||
"value": "111",
|
||||
"id": "f6609643",
|
||||
"pid": "",
|
||||
"_RID": "row_4"
|
||||
},
|
||||
{
|
||||
"label": "level1-son",
|
||||
"value": "111-1",
|
||||
"id": "af1f937f",
|
||||
"pid": "f6609643",
|
||||
"_RID": "row_5"
|
||||
},
|
||||
{
|
||||
"label": "level222",
|
||||
"value": "222",
|
||||
"id": "28e3709c",
|
||||
"pid": "",
|
||||
"_RID": "row_6"
|
||||
},
|
||||
{
|
||||
"label": "level2-son",
|
||||
"value": "222-1",
|
||||
"id": "6b571bef",
|
||||
"pid": "28e3709c",
|
||||
"_RID": "row_5"
|
||||
},
|
||||
{
|
||||
"id": "6317c2cc",
|
||||
"pid": "fdfa",
|
||||
"label": "fsdfaa",
|
||||
"value": "fsadf",
|
||||
"_RID": "row_6"
|
||||
},
|
||||
{
|
||||
"id": "9cce369f",
|
||||
"pid": "test",
|
||||
"label": "test1",
|
||||
"value": "001"
|
||||
}
|
||||
],
|
||||
"type": "tree"
|
||||
},
|
||||
"tpl": null,
|
||||
"app": "918",
|
||||
"desc": null,
|
||||
"created_at": "2022-06-30T06:13:57.000Z",
|
||||
"updated_at": "2022-07-29T03:14:55.000Z"
|
||||
},
|
||||
{
|
||||
"id": 150,
|
||||
"name": "componentList",
|
||||
"data": {
|
||||
"data": [
|
||||
{
|
||||
"_RID": "row_1",
|
||||
"name": "表单",
|
||||
"isSelected": "true",
|
||||
"description": "由按钮、输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据"
|
||||
},
|
||||
{
|
||||
"name": "按钮",
|
||||
"isSelected": "false",
|
||||
"description": "常用的操作按钮,提供包括默认按钮、图标按钮、图片按钮、下拉按钮等类型"
|
||||
},
|
||||
{
|
||||
"id": "490f8a00",
|
||||
"_RID": "row_3",
|
||||
"name": "表单项",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "Form 组件下的 FormItem 配置"
|
||||
},
|
||||
{
|
||||
"id": "c259b8b3",
|
||||
"_RID": "row_4",
|
||||
"name": "开关",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "关闭或打开"
|
||||
},
|
||||
{
|
||||
"id": "083ed9c7",
|
||||
"_RID": "row_5",
|
||||
"name": "互斥按钮组",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "以按钮组的方式出现,常用于多项类似操作"
|
||||
},
|
||||
{
|
||||
"id": "09136cea",
|
||||
"_RID": "row_6",
|
||||
"name": "提示框",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "Popover可通过对一个触发源操作触发弹出框,支持自定义弹出内容,延迟触发和渐变动画"
|
||||
},
|
||||
{
|
||||
"id": "a63b57d5",
|
||||
"_RID": "row_7",
|
||||
"name": "文字提示框",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "动态显示提示信息,一般通过鼠标事件进行响应;提供 warning、error、info、success 四种类型显示不同类别的信"
|
||||
},
|
||||
{
|
||||
"id": "a0f6e8a3",
|
||||
"_RID": "row_8",
|
||||
"name": "树",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "可进行展示有父子层级的数据,支持选择,异步加载等功能。但不推荐用它来展示菜单,展示菜单推荐使用树菜单"
|
||||
},
|
||||
{
|
||||
"id": "d1aa18fc",
|
||||
"_RID": "row_9",
|
||||
"name": "分页",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "当数据量过多时,使用分页分解数据,常用于 Grid 和 Repeater 组件"
|
||||
},
|
||||
{
|
||||
"id": "ca49cc52",
|
||||
"_RID": "row_10",
|
||||
"name": "表格",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "提供了非常强大数据表格功能,可以展示数据列表,可以对数据列表进行选择、编辑等"
|
||||
},
|
||||
{
|
||||
"id": "4e20ecc9",
|
||||
"name": "搜索框",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "指定条件对象进行搜索数据"
|
||||
},
|
||||
{
|
||||
"id": "6b093ee5",
|
||||
"name": "折叠面板",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "内容区可指定动态页面或自定义 html 等,支持展开收起操作"
|
||||
},
|
||||
{
|
||||
"id": "0a09abc0",
|
||||
"name": "对话框",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "模态对话框,在浮层中显示,引导用户进行相关操作"
|
||||
},
|
||||
{
|
||||
"id": "f814b901",
|
||||
"name": "标签页签项",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "tab页签"
|
||||
},
|
||||
{
|
||||
"id": "c5ae797c",
|
||||
"name": "单选",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "用于配置不同场景的选项,在一组备选项中进行单选"
|
||||
},
|
||||
{
|
||||
"id": "33d0c590",
|
||||
"_RID": "row_13",
|
||||
"name": "弹出编辑",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "该组件只能在弹出的面板中选择数据,不能手动输入数据;弹出面板中显示为 Tree 组件或者 Grid 组件"
|
||||
},
|
||||
{
|
||||
"id": "16711dfa",
|
||||
"_RID": "row_14",
|
||||
"name": "下拉框",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "Select 选择器是一种通过点击弹出下拉列表展示数据并进行选择的 UI 组件"
|
||||
},
|
||||
{
|
||||
"id": "a9fd190a",
|
||||
"_RID": "row_15",
|
||||
"name": "折叠面板项",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "内容区可指定动态页面或自定义 html 等,支持展开收起操作"
|
||||
},
|
||||
{
|
||||
"id": "a7dfa9ec",
|
||||
"_RID": "row_16",
|
||||
"name": "复选框",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "用于配置不同场景的选项,提供用户可在一组选项中进行多选"
|
||||
},
|
||||
{
|
||||
"id": "d4bb8330",
|
||||
"name": "输入框",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "通过鼠标或键盘输入字符"
|
||||
},
|
||||
{
|
||||
"id": "ced3dc83",
|
||||
"name": "时间线",
|
||||
"framework": "",
|
||||
"materials": "",
|
||||
"description": "时间线"
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"columns": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"field": "name",
|
||||
"title": "name",
|
||||
"format": {
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"dateTime": false,
|
||||
"required": false,
|
||||
"stringType": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"field": "description",
|
||||
"title": "description",
|
||||
"format": {
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"dateTime": false,
|
||||
"required": false,
|
||||
"stringType": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "isSelected",
|
||||
"type": "string",
|
||||
"field": "isSelected",
|
||||
"title": "isSelected",
|
||||
"format": {
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"dateTime": false,
|
||||
"required": false,
|
||||
"stringType": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"uri": "http://localhost:9090/assets/json/bundle.json",
|
||||
"method": "GET"
|
||||
},
|
||||
"willFetch": {
|
||||
"type": "JSFunction",
|
||||
"value": "function willFetch(option) {\n return option \n}"
|
||||
},
|
||||
"dataHandler": {
|
||||
"type": "JSFunction",
|
||||
"value": "function dataHandler(data) { \n return data \n}"
|
||||
},
|
||||
"shouldFetch": {
|
||||
"type": "JSFunction",
|
||||
"value": "function shouldFetch(option) {\n return true \n}"
|
||||
},
|
||||
"errorHandler": {
|
||||
"type": "JSFunction",
|
||||
"value": "function errorHandler(err) {}"
|
||||
}
|
||||
},
|
||||
"tpl": null,
|
||||
"app": "918",
|
||||
"desc": null,
|
||||
"created_at": "2022-07-04T02:20:07.000Z",
|
||||
"updated_at": "2022-07-04T06:25:29.000Z"
|
||||
},
|
||||
{
|
||||
"id": 151,
|
||||
"name": "selectedComponents",
|
||||
"data": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "name",
|
||||
"title": "name",
|
||||
"field": "name",
|
||||
"type": "string",
|
||||
"format": {
|
||||
"required": false,
|
||||
"stringType": "",
|
||||
"min": 0,
|
||||
"max": 0,
|
||||
"dateTime": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"title": "description",
|
||||
"field": "description",
|
||||
"type": "string",
|
||||
"format": {
|
||||
"required": false,
|
||||
"stringType": "",
|
||||
"min": 0,
|
||||
"max": 0,
|
||||
"dateTime": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "isSelected",
|
||||
"title": "isSelected",
|
||||
"field": "isSelected",
|
||||
"type": "string",
|
||||
"format": {
|
||||
"required": false,
|
||||
"stringType": "",
|
||||
"min": 0,
|
||||
"max": 0,
|
||||
"dateTime": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"data": [
|
||||
{
|
||||
"name": "标签页",
|
||||
"description": "分隔内容上有关联但属于不同类别的数据集合",
|
||||
"isSelected": "true",
|
||||
"_RID": "row_2"
|
||||
},
|
||||
{
|
||||
"name": "布局列",
|
||||
"description": "列配置信息",
|
||||
"isSelected": "true",
|
||||
"id": "76a7080a",
|
||||
"_RID": "row_4"
|
||||
},
|
||||
{
|
||||
"name": "日期选择器",
|
||||
"description": "用于设置/选择日期,包括年月/年月日/年月日时分/年月日时分秒日期格式",
|
||||
"isSelected": "true",
|
||||
"id": "76b20d73",
|
||||
"_RID": "row_1"
|
||||
},
|
||||
{
|
||||
"name": "走马灯",
|
||||
"description": "常用于一组图片或卡片轮播,当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现",
|
||||
"isSelected": "true",
|
||||
"id": "4c884c3d"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tpl": null,
|
||||
"app": "918",
|
||||
"desc": null,
|
||||
"created_at": "2022-07-04T03:04:05.000Z",
|
||||
"updated_at": "2022-07-04T03:43:40.000Z"
|
||||
}
|
||||
],
|
||||
"dataHandler": {
|
||||
"type": "JSFunction",
|
||||
"value": "function dataHanlder(res){\n return res;\n}"
|
||||
|
|
@ -102,7 +769,7 @@
|
|||
{
|
||||
"componentName": "TinyTimeLine",
|
||||
"props": {
|
||||
"active": "2",
|
||||
"active": 2,
|
||||
"data": [
|
||||
{
|
||||
"name": "基础配置"
|
||||
|
|
@ -858,7 +1525,7 @@
|
|||
{
|
||||
"componentName": "div",
|
||||
"props": {
|
||||
"style": "border-width: 1px; border-style: solid; border-color: #ffffff; padding-top: 10px; padding-left: 10px; padding-right: 10px; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px; background-color: #fff; position: fixed; inset: auto 0% 0% 0%; height: 80px; line-height: 80px; border-radius: 0px;"
|
||||
"style": "border-width: 1px;z-index:1;border-style: solid; border-color: #ffffff; padding-top: 10px; padding-left: 10px; padding-right: 10px; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px; background-color: #fff; position: fixed; inset: auto 0% 0% 0%; height: 80px; line-height: 80px; border-radius: 0px;"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
|
|
@ -883,7 +1550,7 @@
|
|||
{
|
||||
"componentName": "TinyCol",
|
||||
"props": {
|
||||
"span": "8"
|
||||
"span": 8
|
||||
},
|
||||
"id": "b9d051a5",
|
||||
"children": [
|
||||
|
|
@ -896,7 +1563,7 @@
|
|||
{
|
||||
"componentName": "TinyCol",
|
||||
"props": {
|
||||
"span": "5",
|
||||
"span": 5,
|
||||
"style": "display: flex;"
|
||||
},
|
||||
"id": "02352776",
|
||||
|
|
@ -930,7 +1597,7 @@
|
|||
{
|
||||
"componentName": "TinyCol",
|
||||
"props": {
|
||||
"span": "7"
|
||||
"span": 7
|
||||
},
|
||||
"id": "82b6c659",
|
||||
"children": [
|
||||
|
|
@ -998,7 +1665,7 @@
|
|||
{
|
||||
"componentName": "TinyCol",
|
||||
"props": {
|
||||
"span": "4",
|
||||
"span": 4,
|
||||
"style": "display: flex; flex-direction: row-reverse; border-radius: 0px; height: 100%; justify-content: flex-start; align-items: center;"
|
||||
},
|
||||
"id": "10b73009",
|
||||
|
|
@ -1023,7 +1690,7 @@
|
|||
],
|
||||
"fileName": "createVm",
|
||||
"meta": {
|
||||
"id": 1977,
|
||||
"id": "NTJ4MjvqoVj8OVsc",
|
||||
"parentId": "0",
|
||||
"group": "staticPages",
|
||||
"occupier": {
|
||||
|
|
@ -1120,7 +1787,7 @@
|
|||
},
|
||||
{
|
||||
"componentName": "TinyPlusFrozenPage",
|
||||
"package": "@opentiny/vuee",
|
||||
"package": "@opentiny/vue",
|
||||
"exportName": "FrozenPage",
|
||||
"destructuring": true,
|
||||
"version": "3.4.1"
|
||||
|
|
@ -1258,6 +1925,13 @@
|
|||
"destructuring": true,
|
||||
"version": "0.1.16"
|
||||
},
|
||||
{
|
||||
"componentName": "TinyButton",
|
||||
"package": "@opentiny/vue",
|
||||
"exportName": "Button",
|
||||
"destructuring": true,
|
||||
"version": "0.1.16"
|
||||
},
|
||||
{
|
||||
"componentName": "TinyButtonGroup",
|
||||
"package": "@opentiny/vue",
|
||||
|
|
@ -1300,6 +1974,48 @@
|
|||
"destructuring": true,
|
||||
"version": "0.1.16"
|
||||
},
|
||||
{
|
||||
"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",
|
||||
|
|
@ -1404,7 +2120,7 @@
|
|||
"type": "function",
|
||||
"content": {
|
||||
"type": "JSFunction",
|
||||
"value": "function util() {\r\n console.log(3211)\r\n}"
|
||||
"value": "function test() {\r\n return 'test'\r\n}"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import KoaRouter from 'koa-router'
|
||||
import * as glob from 'glob'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import * as glob from 'glob'
|
||||
import KoaRouter from 'koa-router'
|
||||
import path from 'path'
|
||||
import MockService from '../services/mockService'
|
||||
|
||||
import { getResponseData } from '../tool/Common'
|
||||
|
||||
const router = new KoaRouter()
|
||||
export const mockService = new MockService()
|
||||
const getJsonPathData = (jpath, method = 'get') => {
|
||||
|
|
@ -140,7 +140,9 @@ router.get('/material-center/api/block-groups/delete/:id', async (ctx) => {
|
|||
router.get('/material-center/api/block-groups', async (ctx) => {
|
||||
const result = await mockService.blockGroupService.find(ctx.query)
|
||||
let blockGroup
|
||||
if (result.data.length > 1) {
|
||||
if (result.data.length === 0) {
|
||||
ctx.body = result
|
||||
} else if (result.data.length > 1) {
|
||||
blockGroup = await Promise.all(
|
||||
result.data.map(async (group) => {
|
||||
group.blocks = await Promise.all(
|
||||
|
|
@ -153,7 +155,7 @@ router.get('/material-center/api/block-groups', async (ctx) => {
|
|||
})
|
||||
)
|
||||
ctx.body = getResponseData(blockGroup)
|
||||
} else {
|
||||
} else if (result.data.length === 1) {
|
||||
blockGroup = result.data[0]
|
||||
const blocks = await Promise.all(
|
||||
blockGroup.blocks.map(async (item) => {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default class AppService {
|
|||
// 拼装数据源
|
||||
const dataSource = {
|
||||
list: source,
|
||||
dataHandler: app['data_handler']
|
||||
dataHandler: app.data_handler
|
||||
}
|
||||
// 拼装工具类
|
||||
const utils = []
|
||||
|
|
@ -47,7 +47,7 @@ export default class AppService {
|
|||
const i18n = this.formatI18nEntrites(entriesData)
|
||||
return getResponseData({
|
||||
dataSource,
|
||||
globalState: app['global_state'],
|
||||
globalState: app.global_state,
|
||||
utils,
|
||||
i18n
|
||||
})
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -49,7 +49,7 @@ export default class BlockCategoryService {
|
|||
const categories = await this.db.findOneAsync({ _id: id })
|
||||
categories.blocks.push(params._id)
|
||||
await this.db.updateAsync({ _id: id }, { $set: categories })
|
||||
return
|
||||
return getResponseData(categories)
|
||||
}
|
||||
params.app = appinfo.app
|
||||
await this.db.updateAsync({ _id: id }, { $set: params })
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ export default class Schema2CodeServcice {
|
|||
return components.map((component) => {
|
||||
const {
|
||||
component: componentName,
|
||||
npm: { package: packageName, exportName, version, destructuring }
|
||||
npm: { package: packageName, exportName, version, destructuring } = {}
|
||||
} = component
|
||||
return {
|
||||
componentName,
|
||||
|
|
|
|||
21
package.json
21
package.json
|
|
@ -3,7 +3,7 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"dev": "concurrently 'pnpm:serve:backend' 'pnpm:serve:frontend'",
|
||||
"dev": "pnpm run setup && concurrently 'pnpm:serve:backend' 'pnpm:serve:frontend'",
|
||||
"dev:mock": "pnpm --filter @opentiny/tiny-engine dev",
|
||||
"serve:frontend": "pnpm --filter @opentiny/tiny-engine serve",
|
||||
"serve:backend": "pnpm --filter @opentiny/tiny-engine-mock dev",
|
||||
|
|
@ -18,7 +18,10 @@
|
|||
"pub:premajor": "pnpm run build:plugin && pnpm run build:alpha && pnpm lerna version premajor --preid beta --no-push --yes && lerna publish from-package --pre-dist-tag beta --yes",
|
||||
"pub:preminor": "pnpm run build:plugin && pnpm run build:alpha && pnpm lerna version preminor --preid beta --no-push --yes && lerna publish from-package --pre-dist-tag beta --yes",
|
||||
"pub:prepatch": "pnpm run build:plugin && pnpm run build:alpha && pnpm lerna version prepatch --preid beta --no-push --yes && lerna publish from-package --pre-dist-tag beta --yes",
|
||||
"pub:prerelease": "pnpm run build:plugin && pnpm run build:alpha && pnpm lerna version prerelease --preid beta --no-push --yes && lerna publish from-package --pre-dist-tag beta --yes"
|
||||
"pub:prerelease": "pnpm run build:plugin && pnpm run build:alpha && pnpm lerna version prerelease --preid beta --no-push --yes && lerna publish from-package --pre-dist-tag beta --yes",
|
||||
"setup": "node ./scripts/setup.js",
|
||||
"splitMaterials": "node ./scripts/splitMaterials.mjs",
|
||||
"buildMaterials": "node ./scripts/buildMaterials.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.21.3",
|
||||
|
|
@ -26,19 +29,24 @@
|
|||
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
||||
"@types/node": "^18.0.0",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^1.3.2",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"assert": "^2.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"chokidar": "^3.5.3",
|
||||
"concurrently": "^8.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^16.3.1",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-plugin-vue": "^8.0.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
"fs-extra": "^10.1.0",
|
||||
"husky": "^8.0.0",
|
||||
"concurrently": "^8.2.0",
|
||||
"lerna": "^7.2.0",
|
||||
"less": "^4.1.2",
|
||||
"lint-staged": "^13.2.0",
|
||||
"mysql": "^2.18.1",
|
||||
"path": "^0.12.7",
|
||||
"picocolors": "^1.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup-plugin-polyfill-node": "^0.12.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
|
|
@ -57,5 +65,10 @@
|
|||
"engines": {
|
||||
"node": ">=14",
|
||||
"pnpm": ">=7"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"@vue/repl@2.9.0": "patches/@vue__repl@2.9.0.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
# @opentiny/tiny-engine-blockToWebComponentTemplate
|
||||
|
||||
将区块转换成 webComponent,使得不同技术栈的区块可以统一在 vue 的画布上面运行
|
||||
|
||||
## 使用
|
||||
|
||||
- 后端拉取 template
|
||||
- 将区块 schema 转换成 高代码,并写入 src 文件夹中
|
||||
- 写入 lib.js,替换 BlockFileName 为实际出码的文件名
|
||||
- 执行 `pnpm install` 安装依赖
|
||||
- 运行 `pnpm run build:block` 命令
|
||||
- 得到 webcomponent 转换产物
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine-block-build",
|
||||
"version": "1.0.2",
|
||||
"description": "translate block to webcomponent template",
|
||||
"main": "./dist/web-components.es.js",
|
||||
"scripts": {
|
||||
"build:block": "vite build --mode block"
|
||||
},
|
||||
"keywords": [
|
||||
"vue",
|
||||
"vue3",
|
||||
"frontend",
|
||||
"opentiny",
|
||||
"lowcode",
|
||||
"tiny-engine",
|
||||
"webComponent"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentiny/tiny-engine",
|
||||
"directory": "packages/builtinComponent"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/opentiny/tiny-engine/issues"
|
||||
},
|
||||
"author": "OpenTiny Team",
|
||||
"license": "MIT",
|
||||
"homepage": "https://opentiny.design/tiny-engine",
|
||||
"dependencies": {
|
||||
"@opentiny/tiny-engine-i18n-host": "workspace:*",
|
||||
"@opentiny/tiny-engine-webcomponent-core": "workspace:*",
|
||||
"@opentiny/vue": "~3.14.0",
|
||||
"@opentiny/vue-icon": "~3.14.0",
|
||||
"@opentiny/vue-theme": "~3.14.0",
|
||||
"@vue/shared": "^3.3.11",
|
||||
"vue": "^3.4.15",
|
||||
"vue-i18n": "^9.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.5.2",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"vite": "^4.3.7"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-popover class="block-link-field" popper-class="option-popper block-new-attr-popover">
|
||||
<tiny-input placeholder="请输入字段名称"></tiny-input>
|
||||
</tiny-popover>
|
||||
<div>
|
||||
<slot name="menu" :title="state.title">
|
||||
<span>TinyEngine 前端可视化设计器,为设计器开发者提供定制服务,在线构建出自己专属的设计器。</span>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as vue from 'vue'
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
import { I18nInjectionKey } from 'vue-i18n'
|
||||
import { Input as TinyInput, Popover as TinyPopover } from '@opentiny/vue'
|
||||
|
||||
const props = defineProps({ testSlot: { type: Object, default: () => ({}) } })
|
||||
const emit = defineEmits([])
|
||||
|
||||
const { t, lowcodeWrap, stores } = vue.inject(I18nInjectionKey).lowcode()
|
||||
const wrap = lowcodeWrap(props, { emit }, t)
|
||||
|
||||
const state = vue.reactive({
|
||||
title: 'test slot params'
|
||||
})
|
||||
|
||||
wrap({
|
||||
stores,
|
||||
state
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
body {
|
||||
background-color: #fff;
|
||||
}
|
||||
.test {
|
||||
width: 100px;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
color: #191919;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { hyphenate } from '@vue/shared'
|
||||
import { defineCustomElement } from '@opentiny/tiny-engine-webcomponent-core'
|
||||
import block from './BlockFileName.vue'
|
||||
|
||||
window.TinyLowcodeResource = window.TinyLowcodeResource || {}
|
||||
|
||||
const blockName = hyphenate('BlockFileName')
|
||||
|
||||
if (customElements.get(blockName)) {
|
||||
if (window.TinyLowcodeResource[blockName]) {
|
||||
Object.assign(window.TinyLowcodeResource[blockName], block)
|
||||
}
|
||||
} else {
|
||||
block.links = process.env.VUE_APP_UI_LIB_FULL_STYLE_FILE_URL
|
||||
block.styles = ['svg { width: 10px; height: 10px;}', ...(block.styles || [])]
|
||||
window.TinyLowcodeResource[blockName] = block
|
||||
customElements.define(blockName, defineCustomElement(block))
|
||||
}
|
||||
|
||||
export default block
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import path from 'path'
|
||||
|
||||
const config = {
|
||||
define: {},
|
||||
resolve: {
|
||||
alias: {}
|
||||
},
|
||||
build: {
|
||||
cssCodeSplit: false,
|
||||
minify: false,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true
|
||||
},
|
||||
rollupOptions: {
|
||||
external: [
|
||||
'vue',
|
||||
'vue-i18n',
|
||||
'@opentiny/tiny-engine-i18n-host',
|
||||
'@opentiny/tiny-engine-webcomponent-core',
|
||||
'@opentiny/vue',
|
||||
'@opentiny/vue-icon'
|
||||
],
|
||||
output: {
|
||||
globals: {
|
||||
vue: 'Vue',
|
||||
'vue-i18n': 'VueI18n',
|
||||
'@opentiny/tiny-engine-i18n-host': 'TinyI18nHost',
|
||||
'@opentiny/tiny-engine-webcomponent-core': 'TinyWebcomponentCore',
|
||||
'@opentiny/vue': 'TinyVue',
|
||||
'@opentiny/vue-icon': 'TinyVueIcon'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
if (command !== 'build' || mode !== 'block') {
|
||||
return config
|
||||
}
|
||||
|
||||
const vuePluginConfig = {}
|
||||
const styleLinks = ['https://npm.onmicrosoft.cn/@opentiny/vue-theme@3.14/index.css']
|
||||
|
||||
config.publicDir = false
|
||||
|
||||
config.build.lib = {
|
||||
entry: path.resolve(__dirname, './src/lib.js'),
|
||||
name: 'TinyVueBlock',
|
||||
formats: ['umd', 'es'],
|
||||
fileName: (format) => `js/web-component.${format}.js`
|
||||
}
|
||||
|
||||
vuePluginConfig.customElement = true
|
||||
|
||||
config.plugins = [vue(vuePluginConfig), vueJsx()]
|
||||
|
||||
config.define['process.env'] = {
|
||||
VUE_APP_UI_LIB_FULL_STYLE_FILE_URL: styleLinks
|
||||
}
|
||||
|
||||
return config
|
||||
})
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# 内置组件
|
||||
|
||||
## 目前内置的组件
|
||||
|
||||
### CanvasRow
|
||||
|
||||
### CanvasCol
|
||||
|
||||
### CanvasRowColContainer
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export { default as CanvasCol } from './src/components/CanvasCol.vue'
|
||||
export { default as CanvasRow } from './src/components/CanvasRow.vue'
|
||||
export { default as CanvasRowColContainer } from './src/components/CanvasRowColContainer.vue'
|
||||
export { default as meta } from './src/meta'
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine-builtin-component",
|
||||
"version": "1.0.1",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentiny/tiny-engine",
|
||||
"directory": "packages/builtinComponent"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vite-plugin-css-injected-by-js": "^3.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"vite": "^4.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.4.15"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<div ref="colRef" class="canvas-col">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, defineProps } from 'vue'
|
||||
import { getStyleValue, alignMap, justAlignMap } from './helper'
|
||||
|
||||
const props = defineProps({
|
||||
flexBasis: {
|
||||
type: String,
|
||||
default: '0px'
|
||||
},
|
||||
rowGap: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
colGap: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
align: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
justAlign: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
grow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
shrink: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
widthType: {
|
||||
type: String,
|
||||
default: 'auto'
|
||||
}
|
||||
})
|
||||
|
||||
const getFlex = () => {
|
||||
const { flexBasis, grow, shrink, widthType } = props
|
||||
|
||||
if (widthType === 'fixed') {
|
||||
return `0 0 ${getStyleValue(flexBasis)}`
|
||||
}
|
||||
|
||||
return `${Number(grow)} ${Number(shrink)} ${getStyleValue(flexBasis)}`
|
||||
}
|
||||
|
||||
const styles = computed(() => ({
|
||||
flex: getFlex(props.flexBasis),
|
||||
rowGap: getStyleValue(props.rowGap),
|
||||
colGap: getStyleValue(props.colGap),
|
||||
align: alignMap[props.align] || 'stretch',
|
||||
justAlign: justAlignMap[props.justAlign] || 'flex-start'
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.canvas-col {
|
||||
display: flex;
|
||||
flex: v-bind('styles.flex');
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
row-gap: v-bind('styles.rowGap');
|
||||
column-gap: v-bind('styles.colGap');
|
||||
align-items: v-bind('styles.align');
|
||||
justify-content: v-bind('styles.justAlign');
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div class="canvas-row">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, defineProps } from 'vue'
|
||||
import { getStyleValue, alignMap, justAlignMap } from './helper'
|
||||
|
||||
const props = defineProps({
|
||||
minHeight: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
rowGap: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
colGap: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
align: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
justAlign: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const styles = computed(() => ({
|
||||
minHeight: getStyleValue(props.minHeight),
|
||||
rowGap: getStyleValue(props.rowGap),
|
||||
colGap: getStyleValue(props.colGap),
|
||||
align: alignMap[props.align] || 'stretch',
|
||||
justAlign: justAlignMap[props.justAlign] || 'flex-start'
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.canvas-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: v-bind('styles.justAlign');
|
||||
align-items: v-bind('styles.align');
|
||||
column-gap: v-bind('styles.rowGap');
|
||||
row-gap: v-bind('styles.colGap');
|
||||
min-height: v-bind('styles.minHeight');
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div class="row-col-container">
|
||||
<slot> </slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, defineProps } from 'vue'
|
||||
import { getStyleValue } from './helper'
|
||||
|
||||
const props = defineProps({
|
||||
rowGap: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const styles = computed(() => ({
|
||||
rowGap: getStyleValue(props.rowGap)
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.row-col-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: v-bind('styles.rowGap');
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
export const getStyleValue = (value) => {
|
||||
if (typeof value === 'number' || /^\d+\.?\d*$/.test(value)) {
|
||||
return `${value}px`
|
||||
}
|
||||
|
||||
if (/^\d+\.?\d*(px|%|pt|em|rem|vw|vh)$/.test(value)) {
|
||||
return value
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
export const alignMap = {
|
||||
'flex-start': 'flex-start',
|
||||
'flex-end': 'flex-end',
|
||||
center: 'center',
|
||||
stretch: 'stretch',
|
||||
start: 'start',
|
||||
end: 'end'
|
||||
}
|
||||
|
||||
export const justAlignMap = {
|
||||
'space-between': 'space-between',
|
||||
'space-around': 'space-around',
|
||||
'space-evenly': 'space-evenly',
|
||||
'flex-start': 'flex-start',
|
||||
'flex-end': 'flex-end',
|
||||
stretch: 'stretch',
|
||||
center: 'center',
|
||||
start: 'start',
|
||||
end: 'end',
|
||||
left: 'left',
|
||||
right: 'right'
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
{
|
||||
"components": {
|
||||
"icon": "Box",
|
||||
"name": {
|
||||
"zh_CN": "CanvasCol"
|
||||
},
|
||||
"component": "CanvasCol",
|
||||
"schema": {
|
||||
"slots": {},
|
||||
"properties": [
|
||||
{
|
||||
"label": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"collapse": {
|
||||
"number": 6,
|
||||
"text": {
|
||||
"zh_CN": "显示更多"
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"property": "widthType",
|
||||
"type": "String",
|
||||
"defaultValue": "auto",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "宽度类型"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaRadioGroup",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "label": "auto", "text": "自适应" },
|
||||
{ "label": "fixed", "text": "固定" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "flexBasis",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "固定宽度"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "rowGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "行间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "colGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "列间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "align",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "副轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "stretch", "label": "拉伸对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "justAlign",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "主轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "space-between", "label": "两端对齐" },
|
||||
{ "value": "space-evenly", "label": "均分对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "grow",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "增长"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSwitch",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "shrink",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "收缩"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSwitch",
|
||||
"props": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": {},
|
||||
"shortcuts": {
|
||||
"properties": []
|
||||
},
|
||||
"contentMenu": {
|
||||
"actions": []
|
||||
}
|
||||
},
|
||||
"configure": {
|
||||
"loop": true,
|
||||
"isContainer": true,
|
||||
"nestingRule": {
|
||||
"childWhitelist": [],
|
||||
"descendantBlacklist": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
{
|
||||
"components": {
|
||||
"icon": "Box",
|
||||
"name": {
|
||||
"zh_CN": "CanvasRow"
|
||||
},
|
||||
"component": "CanvasRow",
|
||||
"schema": {
|
||||
"slots": {},
|
||||
"properties": [
|
||||
{
|
||||
"label": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"collapse": {
|
||||
"number": 6,
|
||||
"text": {
|
||||
"zh_CN": "显示更多"
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"property": "minHeight",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "最小高度"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "rowGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "行间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "colGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "列间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "align",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "副轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "stretch", "label": "拉伸对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "justAlign",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "主轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "space-between", "label": "两端对齐" },
|
||||
{ "value": "space-evenly", "label": "均分对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": {},
|
||||
"shortcuts": {
|
||||
"properties": []
|
||||
},
|
||||
"contentMenu": {
|
||||
"actions": []
|
||||
}
|
||||
},
|
||||
"configure": {
|
||||
"loop": true,
|
||||
"isContainer": true,
|
||||
"nestingRule": {
|
||||
"childWhitelist": [],
|
||||
"descendantBlacklist": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"components": {
|
||||
"icon": "Box",
|
||||
"name": {
|
||||
"zh_CN": "行列容器"
|
||||
},
|
||||
"component": "CanvasRowColContainer",
|
||||
"schema": {
|
||||
"slots": {},
|
||||
"properties": [
|
||||
{
|
||||
"label": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"collapse": {
|
||||
"number": 6,
|
||||
"text": {
|
||||
"zh_CN": "显示更多"
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"property": "rowGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "行间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": {},
|
||||
"shortcuts": {
|
||||
"properties": []
|
||||
},
|
||||
"contentMenu": {
|
||||
"actions": []
|
||||
}
|
||||
},
|
||||
"configure": {
|
||||
"loop": true,
|
||||
"isContainer": true,
|
||||
"nestingRule": {
|
||||
"childWhitelist": [],
|
||||
"descendantBlacklist": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"snippets": {
|
||||
"name": {
|
||||
"zh_CN": "行列容器"
|
||||
},
|
||||
"screenshot": "",
|
||||
"snippetName": "CanvasRowColContainer",
|
||||
"icon": "Box",
|
||||
"schema": {
|
||||
"componentName": "CanvasRowColContainer",
|
||||
"props": {
|
||||
"rowGap": "20px"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "CanvasRow",
|
||||
"props": {
|
||||
"rowGap": "20px",
|
||||
"colGap": "20px"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "CanvasCol",
|
||||
"props": {
|
||||
"rowGap": "20px",
|
||||
"colGap": "20px",
|
||||
"grow": true,
|
||||
"shrink": true,
|
||||
"widthType": "auto"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import CanvasCol from './CanvasCol.json'
|
||||
import CanvasRow from './CanvasRow.json'
|
||||
import CanvasRowColContainer from './CanvasRowColContainer.json'
|
||||
|
||||
export default {
|
||||
components: [
|
||||
{
|
||||
group: '内置组件',
|
||||
children: [{ ...CanvasCol.components }, { ...CanvasRow.components }, { ...CanvasRowColContainer.components }]
|
||||
}
|
||||
],
|
||||
snippets: [
|
||||
{
|
||||
group: '内置组件',
|
||||
children: [{ ...CanvasRowColContainer.snippets }]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
import { defineConfig } from 'vite'
|
||||
import path from 'path'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import vitePluginCssInjectedByJs from 'vite-plugin-css-injected-by-js'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue(), vueJsx(), vitePluginCssInjectedByJs()],
|
||||
publicDir: false,
|
||||
build: {
|
||||
cssCodeSplit: false,
|
||||
lib: {
|
||||
entry: path.resolve(__dirname, './index.js'),
|
||||
name: 'builtinComponent',
|
||||
fileName: () => 'index.js',
|
||||
formats: ['es']
|
||||
},
|
||||
rollupOptions: {
|
||||
external: ['vue']
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine-canvas",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.3",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
|
@ -14,26 +14,39 @@
|
|||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentiny/tiny-engine",
|
||||
"directory": "packages/canvas"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/opentiny/tiny-engine/issues"
|
||||
},
|
||||
"author": "OpenTiny Team",
|
||||
"license": "MIT",
|
||||
"homepage": "https://opentiny.design/tiny-engine",
|
||||
"dependencies": {
|
||||
"@babel/core": "7.18.13",
|
||||
"@opentiny/tiny-engine-common": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-controller": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-i18n-host": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-utils": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-webcomponent-core": "workspace:^1.0.0",
|
||||
"@opentiny/vue": "~3.10.0",
|
||||
"@opentiny/vue-icon": "~3.10.0",
|
||||
"@opentiny/vue-renderless": "~3.10.0",
|
||||
"@opentiny/tiny-engine-builtin-component": "workspace:*",
|
||||
"@opentiny/tiny-engine-controller": "workspace:*",
|
||||
"@opentiny/tiny-engine-i18n-host": "workspace:*",
|
||||
"@opentiny/tiny-engine-utils": "workspace:*",
|
||||
"@opentiny/tiny-engine-webcomponent-core": "workspace:*",
|
||||
"@vue/babel-plugin-jsx": "1.1.1",
|
||||
"@vue/shared": "^3.3.4",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"vue": "3.2.45",
|
||||
"vue-i18n": "9.2.2"
|
||||
"@vueuse/core": "^9.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^1.3.10",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"vite": "^4.3.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentiny/vue": "^3.14.0",
|
||||
"@opentiny/vue-icon": "^3.14.0",
|
||||
"@opentiny/vue-renderless": "^3.14.0",
|
||||
"vue": "^3.4.15",
|
||||
"vue-i18n": "^9.9.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -432,399 +432,6 @@
|
|||
"configure": {
|
||||
"loop": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "Box",
|
||||
"name": {
|
||||
"zh_CN": "CanvasRow"
|
||||
},
|
||||
"component": "CanvasRow",
|
||||
"schema": {
|
||||
"slots": {},
|
||||
"properties": [
|
||||
{
|
||||
"label": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"collapse": {
|
||||
"number": 6,
|
||||
"text": {
|
||||
"zh_CN": "显示更多"
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"property": "minHeight",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "最小高度"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "rowGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "行间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "colGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "列间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "align",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "副轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "stretch", "label": "拉伸对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "justAlign",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "主轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "space-between", "label": "两端对齐" },
|
||||
{ "value": "space-evenly", "label": "均分对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": {},
|
||||
"shortcuts": {
|
||||
"properties": []
|
||||
},
|
||||
"contentMenu": {
|
||||
"actions": []
|
||||
}
|
||||
},
|
||||
"configure": {
|
||||
"loop": true,
|
||||
"isContainer": true,
|
||||
"nestingRule": {
|
||||
"childWhitelist": [],
|
||||
"descendantBlacklist": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "Box",
|
||||
"name": {
|
||||
"zh_CN": "CanvasCol"
|
||||
},
|
||||
"component": "CanvasCol",
|
||||
"schema": {
|
||||
"slots": {},
|
||||
"properties": [
|
||||
{
|
||||
"label": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"collapse": {
|
||||
"number": 6,
|
||||
"text": {
|
||||
"zh_CN": "显示更多"
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"property": "widthType",
|
||||
"type": "String",
|
||||
"defaultValue": "auto",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "宽度类型"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaRadioGroup",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "label": "auto", "text": "自适应" },
|
||||
{ "label": "fixed", "text": "固定" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "flexBasis",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "固定宽度"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "rowGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "行间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "colGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "列间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "align",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "副轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "stretch", "label": "拉伸对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "justAlign",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "主轴对齐"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSelect",
|
||||
"props": {
|
||||
"options": [
|
||||
{ "value": "flex-start", "label": "头部对齐" },
|
||||
{ "value": "center", "label": "中间对齐" },
|
||||
{ "value": "flex-end", "label": "尾端对齐" },
|
||||
{ "value": "space-between", "label": "两端对齐" },
|
||||
{ "value": "space-evenly", "label": "均分对齐" }
|
||||
],
|
||||
"type": "button"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "grow",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "增长"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSwitch",
|
||||
"props": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "shrink",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "收缩"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaSwitch",
|
||||
"props": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": {},
|
||||
"shortcuts": {
|
||||
"properties": []
|
||||
},
|
||||
"contentMenu": {
|
||||
"actions": []
|
||||
}
|
||||
},
|
||||
"configure": {
|
||||
"loop": true,
|
||||
"isContainer": true,
|
||||
"nestingRule": {
|
||||
"childWhitelist": [],
|
||||
"descendantBlacklist": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "Box",
|
||||
"name": {
|
||||
"zh_CN": "行列容器"
|
||||
},
|
||||
"component": "CanvasRowColContainer",
|
||||
"schema": {
|
||||
"slots": {},
|
||||
"properties": [
|
||||
{
|
||||
"label": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "基础信息"
|
||||
},
|
||||
"collapse": {
|
||||
"number": 6,
|
||||
"text": {
|
||||
"zh_CN": "显示更多"
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"property": "rowGap",
|
||||
"type": "String",
|
||||
"defaultValue": "",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "行间距"
|
||||
}
|
||||
},
|
||||
"cols": 12,
|
||||
"rules": [],
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": {},
|
||||
"shortcuts": {
|
||||
"properties": []
|
||||
},
|
||||
"contentMenu": {
|
||||
"actions": []
|
||||
}
|
||||
},
|
||||
"configure": {
|
||||
"loop": true,
|
||||
"isContainer": true,
|
||||
"nestingRule": {
|
||||
"childWhitelist": [],
|
||||
"descendantBlacklist": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -907,45 +514,9 @@
|
|||
"schema": {
|
||||
"componentName": "Img",
|
||||
"props": {
|
||||
"src": "img/webNova.jpg",
|
||||
"style": "width: 200px; height: 200px"
|
||||
"src": "https://tinyengine-assets.obs.cn-north-4.myhuaweicloud.com/files/designer-default-icon.jpg"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"zh_CN": "行列容器"
|
||||
},
|
||||
"screenshot": "",
|
||||
"snippetName": "CanvasRowColContainer",
|
||||
"icon": "Box",
|
||||
"schema": {
|
||||
"componentName": "CanvasRowColContainer",
|
||||
"props": {
|
||||
"rowGap": "20px"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "CanvasRow",
|
||||
"props": {
|
||||
"rowGap": "20px",
|
||||
"colGap": "20px"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "CanvasCol",
|
||||
"props": {
|
||||
"rowGap": "20px",
|
||||
"colGap": "20px",
|
||||
"grow": true,
|
||||
"shrink": true,
|
||||
"widthType": "auto"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import CanvasText from './CanvasText.vue'
|
||||
import CanvasBox from './CanvasBox.vue'
|
||||
|
|
@ -16,18 +16,6 @@ import CanvasCollection from './CanvasCollection.vue'
|
|||
import CanvasIcon from './CanvasIcon.vue'
|
||||
import CanvasSlot from './CanvasSlot.vue'
|
||||
import CanvasImg from './CanvasImg.vue'
|
||||
import CanvasRow from './CanvasRow.vue'
|
||||
import CanvasCol from './CanvasCol.vue'
|
||||
import CanvasRowColContainer from './CanvasRowColContainer.vue'
|
||||
import CanvasPlaceholder from './CanvasPlaceholder.vue'
|
||||
|
||||
export {
|
||||
CanvasText,
|
||||
CanvasBox,
|
||||
CanvasCollection,
|
||||
CanvasIcon,
|
||||
CanvasSlot,
|
||||
CanvasImg,
|
||||
CanvasRow,
|
||||
CanvasCol,
|
||||
CanvasRowColContainer
|
||||
}
|
||||
export { CanvasText, CanvasBox, CanvasCollection, CanvasIcon, CanvasSlot, CanvasImg, CanvasPlaceholder }
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
export const NODE_UID = 'data-uid'
|
||||
export const NODE_TAG = 'data-tag'
|
||||
|
|
@ -125,9 +125,10 @@ export const getClipboardSchema = (event) => translateStringToSchame(event.clipb
|
|||
*/
|
||||
export const dynamicImportComponents = async ({ package: pkg, script, components }) => {
|
||||
if (!script) return
|
||||
const scriptUrl = script.startsWith('.') ? new URL(script, location.href).href : script
|
||||
|
||||
if (!window.TinyComponentLibs[pkg]) {
|
||||
const modules = await import(/* @vite-ignore */ script)
|
||||
const modules = await import(/* @vite-ignore */ scriptUrl)
|
||||
|
||||
window.TinyComponentLibs[pkg] = modules
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,16 +27,48 @@
|
|||
</div>
|
||||
<!-- 绝对定位画布时调节元素大小 -->
|
||||
<template v-else>
|
||||
<div class="drag-resize resize-top" @mousedown.stop="onMousedown($event, 'center', 'start')"></div>
|
||||
<div class="drag-resize resize-bottom" @mousedown.stop="onMousedown($event, 'center', 'end')"></div>
|
||||
<div class="drag-resize resize-left" @mousedown.stop="onMousedown($event, 'start', 'center')"></div>
|
||||
<div class="drag-resize resize-right" @mousedown.stop="onMousedown($event, 'end', 'center')"></div>
|
||||
<div class="drag-resize resize-top-left" @mousedown.stop="onMousedown($event, 'start', 'start')"></div>
|
||||
<div class="drag-resize resize-top-right" @mousedown.stop="onMousedown($event, 'end', 'start')"></div>
|
||||
<div class="drag-resize resize-bottom-left" @mousedown.stop="onMousedown($event, 'start', 'end')"></div>
|
||||
<div class="drag-resize resize-bottom-right" @mousedown.stop="onMousedown($event, 'end', 'end')"></div>
|
||||
<div
|
||||
class="drag-resize resize-top"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'center', 'start')"
|
||||
></div>
|
||||
<div
|
||||
class="drag-resize resize-bottom"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'center', 'end')"
|
||||
></div>
|
||||
<div
|
||||
class="drag-resize resize-left"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'start', 'center')"
|
||||
></div>
|
||||
<div
|
||||
class="drag-resize resize-right"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'end', 'center')"
|
||||
></div>
|
||||
<div
|
||||
class="drag-resize resize-top-left"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'start', 'start')"
|
||||
></div>
|
||||
<div
|
||||
class="drag-resize resize-top-right"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'end', 'start')"
|
||||
></div>
|
||||
<div
|
||||
class="drag-resize resize-bottom-left"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'start', 'end')"
|
||||
></div>
|
||||
<div
|
||||
class="drag-resize resize-bottom-right"
|
||||
draggable="true"
|
||||
@mousedown.stop="onMousedown($event, 'end', 'end')"
|
||||
></div>
|
||||
</template>
|
||||
<div v-if="showAction" class="corner-mark-right" :style="fixStyle">
|
||||
<div v-if="showAction" ref="optionRef" class="corner-mark-right" :style="fixStyle">
|
||||
<template v-if="!isModal">
|
||||
<div v-if="showToParent" title="选择父级">
|
||||
<icon-chevron-left @click.stop="selectParent"></icon-chevron-left>
|
||||
|
|
@ -68,13 +100,13 @@
|
|||
<div v-show="hoverState.configure?.isContainer" class="corner-mark-bottom-right">拖放元素到容器内</div>
|
||||
</div>
|
||||
<div v-show="lineState.height && lineState.width" class="canvas-rect line">
|
||||
<div :class="['hover-line', lineState.position]">
|
||||
<div :class="['hover-line', lineState.position, { forbidden: lineState.forbidden }]">
|
||||
<div v-if="lineState.position === 'in' && hoverState.configure" class="choose-slots"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { watchPostEffect, ref, watch, computed } from 'vue'
|
||||
import { watchPostEffect, ref, watch, computed, nextTick } from 'vue'
|
||||
import {
|
||||
IconDel,
|
||||
IconSetting,
|
||||
|
|
@ -85,6 +117,7 @@ import {
|
|||
IconEyeclose
|
||||
} from '@opentiny/vue-icon'
|
||||
import {
|
||||
canvasState,
|
||||
getCurrent,
|
||||
removeNodeById,
|
||||
selectNode,
|
||||
|
|
@ -95,7 +128,7 @@ import {
|
|||
dragStart,
|
||||
getCurrentElement
|
||||
} from './container'
|
||||
import { useResource } from '@opentiny/tiny-engine-controller'
|
||||
import { useLayout, useResource } from '@opentiny/tiny-engine-controller'
|
||||
import { Popover } from '@opentiny/vue'
|
||||
import shortCutPopover from './shortCutPopover.vue'
|
||||
|
||||
|
|
@ -103,8 +136,6 @@ import shortCutPopover from './shortCutPopover.vue'
|
|||
const OPTION_BAR_HEIGHT = 24
|
||||
// 标签高度
|
||||
const LABEL_HEIGHT = 24
|
||||
// 操作条最大宽度
|
||||
const MAX_OPTION_WIDTH = 110
|
||||
|
||||
// 画布右边滚动条宽度
|
||||
const SCROLL_BAR_WIDTH = 8
|
||||
|
|
@ -112,6 +143,11 @@ const SCROLL_BAR_WIDTH = 8
|
|||
// 当工具操作条和标签高度并排显示时,需要的间距 6px
|
||||
const OPTION_SPACE = 6
|
||||
|
||||
// 选中框的边框宽度
|
||||
const SELECTION_BORDER_WIDTH = 2
|
||||
|
||||
const STYLE_UNSET = 'unset'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
IconDel: IconDel(),
|
||||
|
|
@ -204,6 +240,7 @@ export default {
|
|||
return config?.configure?.isModal
|
||||
})
|
||||
|
||||
const optionRef = ref(null)
|
||||
const fixStyle = ref('')
|
||||
|
||||
let showPopover = ref(false)
|
||||
|
|
@ -265,45 +302,188 @@ export default {
|
|||
const labelRef = ref(null)
|
||||
const labelStyle = ref('')
|
||||
|
||||
const bottomPanelHeight = ref(0)
|
||||
const topToolbarHeight = ref(0)
|
||||
|
||||
watchPostEffect(() => {
|
||||
if (!bottomPanelHeight.value) {
|
||||
bottomPanelHeight.value = document.querySelector('#tiny-bottom-panel')?.offsetHeight
|
||||
const positions = {
|
||||
LEFT: 'left',
|
||||
RIGHT: 'right',
|
||||
TOP: 'top',
|
||||
BOTTOM: 'bottom',
|
||||
isHorizontal(position) {
|
||||
return [this.LEFT, this.RIGHT].includes(position)
|
||||
},
|
||||
isVertical(position) {
|
||||
return [this.TOP, this.BOTTOM].includes(position)
|
||||
}
|
||||
if (!topToolbarHeight.value) {
|
||||
topToolbarHeight.value = document.querySelector('.tiny-engine-toolbar')?.offsetHeight
|
||||
}
|
||||
|
||||
class Align {
|
||||
alignLeft = false
|
||||
horizontalValue = 0
|
||||
alignTop = false
|
||||
verticalValue = 0
|
||||
|
||||
constructor({ alignLeft, horizontalValue, alignTop, verticalValue }) {
|
||||
this.alignLeft = alignLeft
|
||||
this.horizontalValue = horizontalValue
|
||||
this.alignTop = alignTop
|
||||
this.verticalValue = verticalValue
|
||||
}
|
||||
|
||||
const { left, top, width, height } = props.selectState
|
||||
align(position, value = 0) {
|
||||
if (positions.isHorizontal(position)) {
|
||||
this.alignLeft = position === positions.LEFT
|
||||
this.horizontalValue = value
|
||||
return this
|
||||
}
|
||||
if (positions.isVertical(position)) {
|
||||
this.alignTop = position === positions.TOP
|
||||
this.horizontalValue = value
|
||||
return this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
toStyleValue() {
|
||||
const styleObj = {}
|
||||
|
||||
if (this.alignLeft) {
|
||||
styleObj.left = this.horizontalValue
|
||||
styleObj.right = STYLE_UNSET
|
||||
} else {
|
||||
styleObj.right = this.horizontalValue
|
||||
styleObj.left = STYLE_UNSET
|
||||
}
|
||||
|
||||
if (this.alignTop) {
|
||||
styleObj.top = this.verticalValue
|
||||
styleObj.bottom = STYLE_UNSET
|
||||
} else {
|
||||
styleObj.bottom = this.verticalValue
|
||||
styleObj.top = STYLE_UNSET
|
||||
}
|
||||
|
||||
return this.styleObj2Str(styleObj)
|
||||
}
|
||||
|
||||
styleObj2Str = (styleObj) => {
|
||||
return Object.entries(styleObj)
|
||||
.map(([key, value]) => {
|
||||
const num = Number(value)
|
||||
|
||||
if (Number.isNaN(num)) {
|
||||
return `${key}:${value}`
|
||||
}
|
||||
|
||||
const val = positions.isHorizontal(key) ? num - SELECTION_BORDER_WIDTH : num
|
||||
return `${key}:${val}px`
|
||||
})
|
||||
.join(';')
|
||||
}
|
||||
}
|
||||
|
||||
const getStyleValues = (selectState, canvasSize, labelWidth, optionWidth) => {
|
||||
const { left, top, width, height, doc } = selectState
|
||||
const { width: canvasWidth, height: canvasHeight } = canvasSize
|
||||
// 标签宽度和工具操作条宽度之和加上间距
|
||||
const fullRectWidth = labelWidth + optionWidth + OPTION_SPACE
|
||||
|
||||
// 是否 将label 标签放置到底部,判断 top 距离
|
||||
const isLabelAtBottom = top <= topToolbarHeight.value + LABEL_HEIGHT
|
||||
const isLabelAtBottom = top < LABEL_HEIGHT
|
||||
const labelAlign = new Align({
|
||||
alignLeft: true,
|
||||
horizontalValue: 0,
|
||||
alignTop: !isLabelAtBottom,
|
||||
verticalValue: -LABEL_HEIGHT
|
||||
})
|
||||
|
||||
// 是否将操作栏放置到底部,判断当前选中组件底部与页面底部的距离。
|
||||
const isOptionAtBottom = window.innerHeight - top - height - bottomPanelHeight.value > OPTION_BAR_HEIGHT
|
||||
const isOptionAtBottom = canvasHeight - top - height >= OPTION_BAR_HEIGHT
|
||||
const optionAlign = new Align({
|
||||
alignLeft: false,
|
||||
horizontalValue: 0,
|
||||
alignTop: !isOptionAtBottom,
|
||||
verticalValue: -OPTION_BAR_HEIGHT
|
||||
})
|
||||
|
||||
// 选中组件需要最小的宽度,如果小于这个最小宽度,label 和 option 组件可能会重叠遮挡,labelRef.value.clientWidth:label 的宽度
|
||||
const minWidth = MAX_OPTION_WIDTH + labelRef.value?.clientWidth || 0
|
||||
let translateXDis = 0
|
||||
const scrollBarWidth = doc.documentElement.scrollHeight > doc.documentElement.clientHeight ? SCROLL_BAR_WIDTH : 0
|
||||
|
||||
const siteCanvas = document.querySelector('.site-canvas')
|
||||
const right = siteCanvas.getBoundingClientRect().right
|
||||
// 判断是否偏右,偏右且重叠的话,需要移动 label 的位移,不能移动 option 的位移,否则有可能被遮挡
|
||||
const isOverRight = right <= left + width + SCROLL_BAR_WIDTH
|
||||
if (width < fullRectWidth) {
|
||||
// 选中框宽度小于标签宽度和工具操作条宽度之和加上间距
|
||||
|
||||
// 如果选中组件宽度小于最小宽度要求,则需要位移
|
||||
if (width < minWidth) {
|
||||
translateXDis = MAX_OPTION_WIDTH - width + (labelRef.value?.clientWidth || 0) + OPTION_SPACE
|
||||
// 如果labe宽度大于选中框宽度,并且label右侧已经超出画布,则label对齐右侧
|
||||
const isLabelAlignRight = labelWidth > width && left + labelWidth + scrollBarWidth > canvasWidth
|
||||
if (isLabelAlignRight) {
|
||||
labelAlign.align(positions.RIGHT)
|
||||
}
|
||||
|
||||
// 如果option宽度大于选中框宽度,并且option左侧已经超出画布,则option对齐左侧
|
||||
const isOptionAlignLeft = optionWidth > width && left + width - optionWidth < 0
|
||||
if (isOptionAlignLeft) {
|
||||
optionAlign.align(positions.LEFT)
|
||||
}
|
||||
|
||||
if (isLabelAtBottom === isOptionAtBottom) {
|
||||
// 标签框和工具操作框都在顶部或者都在底部
|
||||
|
||||
if (left + fullRectWidth < canvasWidth) {
|
||||
// 都放在左侧
|
||||
labelAlign.align(positions.LEFT)
|
||||
optionAlign.align(positions.LEFT, labelWidth + OPTION_SPACE)
|
||||
} else {
|
||||
// 都放在右侧
|
||||
optionAlign.align(positions.RIGHT)
|
||||
labelAlign.align(positions.RIGHT, optionWidth + OPTION_SPACE)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (left < 0) {
|
||||
labelAlign.align(positions.LEFT, Math.min(-left, width - fullRectWidth))
|
||||
}
|
||||
|
||||
if (left + width + scrollBarWidth > canvasWidth) {
|
||||
optionAlign.align(
|
||||
positions.RIGHT,
|
||||
Math.min(left + width + scrollBarWidth - canvasWidth, width - fullRectWidth)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
labelStyle.value = `top: unset; ${isLabelAtBottom ? 'bottom' : 'top'}: -${LABEL_HEIGHT}px; ${
|
||||
isOverRight && isLabelAtBottom === isOptionAtBottom && `left: -${translateXDis}px;`
|
||||
}`
|
||||
return {
|
||||
labelStyleValue: labelAlign.toStyleValue(),
|
||||
optionStyleValue: optionAlign.toStyleValue()
|
||||
}
|
||||
}
|
||||
|
||||
fixStyle.value = `
|
||||
${translateXDis && !isOverRight ? `transform: translateX(${translateXDis}px);` : ''}
|
||||
${isOptionAtBottom ? 'bottom' : 'top'}: -${OPTION_BAR_HEIGHT}px;`
|
||||
watchPostEffect(async () => {
|
||||
const { left, top, width, height, doc } = props.selectState
|
||||
|
||||
// nextTick后ref才能获取到元素。需要把监听的依赖放在await之前,否则无法监听变化
|
||||
await nextTick()
|
||||
|
||||
if (labelRef.value && !optionRef.value) {
|
||||
// 选中body的情况
|
||||
labelStyle.value = `left: 0; right: unset; top: unset; bottom: 0`
|
||||
return
|
||||
}
|
||||
|
||||
if (!labelRef.value || !optionRef.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const scale = useLayout().getScale()
|
||||
const canvasRect = canvasState.iframe.getBoundingClientRect()
|
||||
const { width: labelWidth } = labelRef.value.getBoundingClientRect()
|
||||
const { width: optionWidth } = optionRef.value.getBoundingClientRect()
|
||||
|
||||
// canvas容器中,iframe以及iframe之外的元素clientRect的尺寸都是缩放过的,除以scale得到原始大小
|
||||
const { labelStyleValue, optionStyleValue } = getStyleValues(
|
||||
{ left, top, width, height, doc },
|
||||
{ width: canvasRect.width / scale, height: canvasRect.height / scale },
|
||||
labelWidth / scale,
|
||||
optionWidth / scale
|
||||
)
|
||||
|
||||
labelStyle.value = labelStyleValue
|
||||
fixStyle.value = optionStyleValue
|
||||
})
|
||||
|
||||
return {
|
||||
|
|
@ -313,6 +493,7 @@ export default {
|
|||
copy,
|
||||
hide,
|
||||
selectParent,
|
||||
optionRef,
|
||||
fixStyle,
|
||||
showAction,
|
||||
showPopover,
|
||||
|
|
@ -329,7 +510,7 @@ export default {
|
|||
|
||||
<style lang="less">
|
||||
.canvas-rect {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
border: 1px solid var(--ti-lowcode-canvas-rect-border-color);
|
||||
|
|
@ -392,11 +573,12 @@ export default {
|
|||
height: 100%;
|
||||
background: var(--ti-lowcode-canvas-hover-line-in-bg-color);
|
||||
}
|
||||
&.forbid {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
&.forbidden:not(.in) {
|
||||
background: var(--ti-lowcode-canvas-hover-line-forbid-bg-color);
|
||||
}
|
||||
&.forbidden.in {
|
||||
background: var(--ti-lowcode-canvas-hover-line-in-forbid-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
.choose-slots {
|
||||
|
|
@ -454,7 +636,6 @@ export default {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
right: -1px;
|
||||
height: 24px;
|
||||
padding: 0 4px;
|
||||
color: var(--ti-lowcode-canvas-corner-mark-right-color);
|
||||
|
|
@ -479,7 +660,6 @@ export default {
|
|||
.corner-mark-left {
|
||||
white-space: nowrap;
|
||||
pointer-events: all;
|
||||
left: -2px;
|
||||
color: var(--ti-lowcode-canvas-select-corner-mark-left-color);
|
||||
background: var(--ti-lowcode-canvas-select-corner-mark-left-bg-color);
|
||||
svg {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
:windowGetClickEventTarget="target"
|
||||
:resize="canvasState.type === 'absolute'"
|
||||
@select-slot="selectSlot"
|
||||
@setting="settingModle"
|
||||
@setting="settingModel"
|
||||
></canvas-action>
|
||||
<canvas-divider :selectState="selectState"></canvas-divider>
|
||||
<canvas-resize-border :iframe="iframe"></canvas-resize-border>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>
|
||||
import { onMounted, ref, computed, onUnmounted } from 'vue'
|
||||
import { iframeMonitoring } from '@opentiny/tiny-engine-common/js/monitor'
|
||||
import { iframeMonitoring } from '@opentiny/tiny-engine-controller/js/monitor'
|
||||
import { useTranslate, useCanvas, useResource } from '@opentiny/tiny-engine-controller'
|
||||
import CanvasAction from './CanvasAction.vue'
|
||||
import CanvasResize from './CanvasResize.vue'
|
||||
|
|
@ -50,12 +50,12 @@ import {
|
|||
updateRect,
|
||||
getElement,
|
||||
dragStart,
|
||||
getOffset,
|
||||
selectNode,
|
||||
initCanvas,
|
||||
clearLineState,
|
||||
querySelectById,
|
||||
getCurrent
|
||||
getCurrent,
|
||||
canvasApi
|
||||
} from './container'
|
||||
|
||||
export default {
|
||||
|
|
@ -71,7 +71,7 @@ export default {
|
|||
const insertPanel = ref(null)
|
||||
const insertPosition = ref(false)
|
||||
const loading = computed(() => useCanvas().isLoading())
|
||||
let showSettingModle = ref(false)
|
||||
let showSettingModel = ref(false)
|
||||
let target = ref(null)
|
||||
|
||||
const setCurrentNode = async (event) => {
|
||||
|
|
@ -100,11 +100,13 @@ export default {
|
|||
|
||||
// 如果是点击右键则打开右键菜单
|
||||
if (event.button === 2) {
|
||||
openMenu(getOffset(event.target), event)
|
||||
openMenu(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useCanvas().initCanvasApi(canvasApi)
|
||||
|
||||
const beforeCanvasReady = () => {
|
||||
if (iframe.value) {
|
||||
const win = iframe.value.contentWindow
|
||||
|
|
@ -123,8 +125,30 @@ export default {
|
|||
const doc = iframe.value.contentDocument
|
||||
const win = iframe.value.contentWindow
|
||||
|
||||
let isScrolling = false
|
||||
|
||||
// 以下是内部iframe监听的事件
|
||||
win.addEventListener('mousedown', (event) => {
|
||||
// html元素使用scroll和mouseup事件处理
|
||||
if (event.target === doc.documentElement) {
|
||||
isScrolling = false
|
||||
return
|
||||
}
|
||||
|
||||
insertPosition.value = false
|
||||
setCurrentNode(event)
|
||||
target.value = event.target
|
||||
})
|
||||
|
||||
win.addEventListener('scroll', () => {
|
||||
isScrolling = true
|
||||
})
|
||||
|
||||
win.addEventListener('mouseup', (event) => {
|
||||
if (event.target !== doc.documentElement || isScrolling) {
|
||||
return
|
||||
}
|
||||
|
||||
insertPosition.value = false
|
||||
setCurrentNode(event)
|
||||
target.value = event.target
|
||||
|
|
@ -156,8 +180,8 @@ export default {
|
|||
}
|
||||
}
|
||||
// 设置弹窗
|
||||
const settingModle = () => {
|
||||
showSettingModle.value = true
|
||||
const settingModel = () => {
|
||||
showSettingModel.value = true
|
||||
}
|
||||
|
||||
const updateI18n = (message) => {
|
||||
|
|
@ -194,7 +218,9 @@ export default {
|
|||
|
||||
onMounted(() => run(iframe))
|
||||
onUnmounted(() => {
|
||||
removeHostkeyEvent(iframe.value.contentDocument)
|
||||
if (iframe.value?.contentDocument) {
|
||||
removeHostkeyEvent(iframe.value.contentDocument)
|
||||
}
|
||||
window.removeEventListener('message', updateI18n, false)
|
||||
})
|
||||
|
||||
|
|
@ -212,9 +238,9 @@ export default {
|
|||
canvasState,
|
||||
insertComponent,
|
||||
insertPanel,
|
||||
settingModle,
|
||||
settingModel,
|
||||
target,
|
||||
showSettingModle,
|
||||
showSettingModel,
|
||||
insertPosition,
|
||||
loading
|
||||
}
|
||||
|
|
@ -223,16 +249,19 @@ export default {
|
|||
</script>
|
||||
<style lang="less" scoped>
|
||||
.insert-panel {
|
||||
z-index: 1;
|
||||
z-index: 4;
|
||||
position: fixed;
|
||||
top: 200px;
|
||||
left: 400px;
|
||||
width: 480px;
|
||||
:deep(.components-wrap) {
|
||||
& > .tiny-collapse {
|
||||
height: 300px;
|
||||
max-height: 300px;
|
||||
}
|
||||
}
|
||||
:deep(#pane-blocks) {
|
||||
max-height: 400px;
|
||||
}
|
||||
}
|
||||
.datainit-tip {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ const ROW_SNIPPET = {
|
|||
grow: true,
|
||||
shrink: true,
|
||||
widthType: 'auto'
|
||||
}
|
||||
},
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -103,16 +104,7 @@ export default {
|
|||
if (schema.componentName === 'CanvasCol') {
|
||||
// 当前组件为空组件,直接切成两行
|
||||
if (!schema.children?.length) {
|
||||
schema.children = [
|
||||
{
|
||||
...extend(true, {}, ROW_SNIPPET),
|
||||
children: [{ ...extend(true, {}, COL_SNIPPET) }]
|
||||
},
|
||||
{
|
||||
...extend(true, {}, ROW_SNIPPET),
|
||||
children: [{ ...extend(true, {}, COL_SNIPPET) }]
|
||||
}
|
||||
]
|
||||
schema.children = [extend(true, {}, ROW_SNIPPET), extend(true, {}, ROW_SNIPPET)]
|
||||
} else if (schema.children[0].componentName !== 'CanvasRow') {
|
||||
// 当前组件不为空组件且第一个孩子不为 row,则是第一次切割,切割成两行,需要将原来有的 children 放置到第一个 row 的 col
|
||||
schema.children = [
|
||||
|
|
@ -129,7 +121,7 @@ export default {
|
|||
]
|
||||
} else {
|
||||
// 已经切割过了,直接加一行
|
||||
schema.children.push(...extend(true, {}, ROW_SNIPPET))
|
||||
schema.children.push(extend(true, {}, ROW_SNIPPET))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +194,7 @@ export default {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.divider-wrapper {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -239,7 +231,7 @@ export default {
|
|||
}
|
||||
|
||||
.divider-line {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
border: 1px dashed var(--ti-lowcode-common-primary-color);
|
||||
z-index: 2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
<template>
|
||||
<div draggable="true" class="drag-item" @dragstart="dragstart">
|
||||
<div draggable="true" class="drag-item" @dragstart="dragstart" @click="handleClick">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { utils } from '@opentiny/tiny-engine-utils'
|
||||
import { dragStart } from './container'
|
||||
|
||||
const { deepClone } = utils
|
||||
|
||||
export default {
|
||||
props: {
|
||||
data: Object
|
||||
|
|
@ -13,9 +17,8 @@ export default {
|
|||
emits: ['click'],
|
||||
setup(props, { emit }) {
|
||||
const dragstart = (e) => {
|
||||
if (props.data && e.button === 0) {
|
||||
const data = JSON.parse(JSON.stringify(props.data))
|
||||
emit('click', data)
|
||||
if (props.data) {
|
||||
const data = deepClone(props.data)
|
||||
dragStart(data)
|
||||
|
||||
// 设置拖拽鼠标样式和设置拖拽预览图
|
||||
|
|
@ -24,8 +27,18 @@ export default {
|
|||
e.dataTransfer.setDragImage(target, 10, 10)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
if (props.data) {
|
||||
const data = deepClone(props.data)
|
||||
|
||||
emit('click', data)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dragstart
|
||||
dragstart,
|
||||
handleClick
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export default {
|
|||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: []
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
emits: ['click']
|
||||
|
|
@ -44,37 +44,23 @@ export default {
|
|||
li {
|
||||
width: unset !important;
|
||||
background: var(--ti-lowcode-breadcrumb-bg);
|
||||
a {
|
||||
.label {
|
||||
padding: 0 3px 0 16px;
|
||||
border-top: 0;
|
||||
color: var(--ti-lowcode-breadcrumb-color);
|
||||
transition: 0.3s;
|
||||
&::after {
|
||||
display: inline-block;
|
||||
right: -6px;
|
||||
border-left: 6px solid var(--ti-lowcode-breadcrumb-bg);
|
||||
transition: 0.3s;
|
||||
}
|
||||
&::before {
|
||||
display: inline-block;
|
||||
right: -7px;
|
||||
left: unset;
|
||||
border-left: 6px solid var(--ti-lowcode-breadcrumb-icon-color);
|
||||
transition: 0.3s;
|
||||
z-index: 1;
|
||||
}
|
||||
&:hover {
|
||||
background: var(--ti-lowcode-breadcrumb-hover-bg);
|
||||
cursor: pointer;
|
||||
&::after {
|
||||
border-left-color: var(--ti-lowcode-breadcrumb-hover-bg);
|
||||
border-left-color: var(--ti-steps-advanced-li-hover-bg-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
&:last-child a {
|
||||
&:last-child .label {
|
||||
border-right: 0px solid var(--ti-lowcode-breadcrumb-color);
|
||||
border-radius: 0;
|
||||
}
|
||||
&:first-child a {
|
||||
&:first-child .label {
|
||||
border-right: 0px solid var(--ti-lowcode-breadcrumb-color);
|
||||
border-radius: 0;
|
||||
border-left: unset;
|
||||
|
|
|
|||
|
|
@ -4,32 +4,37 @@
|
|||
<li
|
||||
v-for="(item, index) in menus"
|
||||
:key="index"
|
||||
:class="item.items ? 'li-item' : ''"
|
||||
:class="{
|
||||
'li-item': item.items,
|
||||
'li-item-disabled': actionDisabled(item)
|
||||
}"
|
||||
@click="doOperation(item)"
|
||||
@mouseover="current = item"
|
||||
@mouseover="onShowChildrenMenu(item)"
|
||||
>
|
||||
<div>
|
||||
<span>{{ item.name }}</span>
|
||||
<span v-if="item.items"><icon-right></icon-right></span>
|
||||
</div>
|
||||
<ul v-if="item.items && current === item" class="sub-menu menu-item">
|
||||
<ul v-if="item.items && current === item" class="sub-menu menu-item" :style="subMenuStyles">
|
||||
<template v-for="(subItem, subIndex) in item.items" :key="subIndex">
|
||||
<li v-if="subItem?.check?.() !== false" @click.stop="doOperation(subItem)">
|
||||
<li
|
||||
:class="[{ 'menu-item-disabled': subItem.check && !subItem.check?.() }]"
|
||||
@click.stop="doOperation(subItem)"
|
||||
>
|
||||
{{ subItem.name }}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<save-new-block :boxVisibility="boxVisibility" fromCanvas @close="close"></save-new-block>
|
||||
<SaveNewBlock :boxVisibility="boxVisibility" fromCanvas @close="close"></SaveNewBlock>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="jsx">
|
||||
import { ref, reactive, nextTick } from 'vue'
|
||||
import { getConfigure, getController, getCurrent, copyNode, removeNodeById } from './container'
|
||||
import { canvasState, getConfigure, getController, getCurrent, copyNode, removeNodeById } from './container'
|
||||
import { useLayout, useModal, useCanvas } from '@opentiny/tiny-engine-controller'
|
||||
import { SaveNewBlock } from '@opentiny/tiny-engine-common'
|
||||
import { iconRight } from '@opentiny/vue-icon'
|
||||
|
||||
const menuState = reactive({
|
||||
|
|
@ -40,27 +45,35 @@ const menuState = reactive({
|
|||
|
||||
const current = ref(null)
|
||||
const menuDom = ref(null)
|
||||
const subMenuStyles = ref(null)
|
||||
|
||||
export const closeMenu = () => {
|
||||
menuState.show = false
|
||||
current.value = null
|
||||
}
|
||||
|
||||
export const openMenu = (offset, event) => {
|
||||
const { x, y } = offset
|
||||
const { getScale } = useLayout()
|
||||
export const openMenu = (event) => {
|
||||
menuState.position = {
|
||||
// 位置处于画布右侧边缘时需要调整显示方向 TODO
|
||||
left: event.clientX * getScale() + x + 2 + 'px',
|
||||
top: event.clientY * getScale() + y + 'px'
|
||||
left: event.clientX + 2 + 'px',
|
||||
top: event.clientY + 'px'
|
||||
}
|
||||
menuState.show = sessionStorage.getItem('pageInfo') ? true : false
|
||||
|
||||
nextTick(() => {
|
||||
if (menuDom.value) {
|
||||
const { bottom, height, top } = menuDom.value.getBoundingClientRect()
|
||||
if (bottom > document.body?.clientHeight) {
|
||||
menuState.position.top = top - height + 'px'
|
||||
const { right, bottom, width, height } = menuDom.value.getBoundingClientRect()
|
||||
const canvasRect = canvasState.iframe.getBoundingClientRect()
|
||||
if (bottom > canvasRect.bottom) {
|
||||
menuState.position.top = `${parseInt(menuState.position.top) - height}px`
|
||||
}
|
||||
if (right > canvasRect.right) {
|
||||
menuState.position.left = `${parseInt(menuState.position.left) - width - 2}px`
|
||||
}
|
||||
// sub-menu样式width为100px,少于100宽度的空白区域则放置到左侧
|
||||
if (right + 100 < canvasRect.right) {
|
||||
subMenuStyles.value = { right: '-100px' }
|
||||
} else {
|
||||
subMenuStyles.value = { left: '-100px' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -68,7 +81,6 @@ export const openMenu = (offset, event) => {
|
|||
|
||||
export default {
|
||||
components: {
|
||||
SaveNewBlock,
|
||||
IconRight: iconRight()
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
|
|
@ -95,11 +107,13 @@ export default {
|
|||
items: [
|
||||
{ name: '文字提示', code: 'wrap', value: 'TinyTooltip' },
|
||||
{ name: '弹出框', code: 'wrap', value: 'TinyPopover' }
|
||||
]
|
||||
],
|
||||
code: 'addParent'
|
||||
},
|
||||
{ name: '删除', code: 'del' },
|
||||
{ name: '复制', code: 'copy' },
|
||||
{ name: '绑定事件', code: 'bindEvent' }
|
||||
{ name: '绑定事件', code: 'bindEvent' },
|
||||
{ name: '新建区块', code: 'createBlock' }
|
||||
])
|
||||
|
||||
const boxVisibility = ref(false)
|
||||
|
|
@ -108,10 +122,10 @@ export default {
|
|||
|
||||
const operations = {
|
||||
del() {
|
||||
removeNodeById(getCurrent().schema.id)
|
||||
removeNodeById(getCurrent().schema?.id)
|
||||
},
|
||||
copy() {
|
||||
copyNode(getCurrent().schema.id)
|
||||
copyNode(getCurrent().schema?.id)
|
||||
},
|
||||
config() {
|
||||
useLayout().activeSetting('props')
|
||||
|
|
@ -125,16 +139,56 @@ export default {
|
|||
wrap({ value, name }) {
|
||||
const componentName = value || name
|
||||
const { schema, parent } = getCurrent()
|
||||
const index = parent.children.indexOf(schema)
|
||||
const wrapSchema = {
|
||||
componentName,
|
||||
id: null,
|
||||
props: {},
|
||||
children: [schema]
|
||||
|
||||
if (!schema || !parent) {
|
||||
return
|
||||
}
|
||||
|
||||
const index = parent.children.findIndex(({ id }) => schema.id === id)
|
||||
let wrapSchema = {
|
||||
componentName,
|
||||
id: null,
|
||||
props: {
|
||||
content: '提示信息'
|
||||
},
|
||||
children: [schema]
|
||||
}
|
||||
// 需要对popover特殊处理
|
||||
if (value === 'TinyPopover') {
|
||||
wrapSchema = {
|
||||
componentName,
|
||||
props: {
|
||||
width: 200,
|
||||
title: '弹框标题',
|
||||
trigger: 'manual',
|
||||
modelValue: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
componentName: 'Template',
|
||||
props: {
|
||||
slot: 'reference'
|
||||
},
|
||||
children: [schema]
|
||||
},
|
||||
{
|
||||
componentName: 'Template',
|
||||
props: {
|
||||
slot: 'default'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
componentName: 'div',
|
||||
props: {
|
||||
placeholder: '提示内容'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
parent.children.splice(index, 1, wrapSchema)
|
||||
|
||||
getController().addHistory()
|
||||
},
|
||||
createBlock() {
|
||||
|
|
@ -149,12 +203,25 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
const actionDisabled = (actionItem) => {
|
||||
const actions = ['del', 'copy', 'addParent']
|
||||
return actions.includes(actionItem.code) && !getCurrent().schema?.id
|
||||
}
|
||||
|
||||
const onShowChildrenMenu = (menuItem) => {
|
||||
current.value = !actionDisabled(menuItem) ? menuItem : null
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
boxVisibility.value = false
|
||||
}
|
||||
const doOperation = (item) => {
|
||||
if ((item.check && !item.check?.()) || actionDisabled(item)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (item?.code) {
|
||||
operations[item.code](item)
|
||||
operations[item.code]?.(item)
|
||||
closeMenu()
|
||||
}
|
||||
}
|
||||
|
|
@ -166,7 +233,10 @@ export default {
|
|||
boxVisibility,
|
||||
close,
|
||||
current,
|
||||
menuDom
|
||||
menuDom,
|
||||
subMenuStyles,
|
||||
actionDisabled,
|
||||
onShowChildrenMenu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +244,7 @@ export default {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
.menu-item {
|
||||
|
|
@ -189,6 +259,10 @@ export default {
|
|||
.li-item {
|
||||
border-bottom: 1px solid var(--ti-lowcode-canvas-menu-border-color);
|
||||
}
|
||||
.li-item-disabled {
|
||||
cursor: not-allowed;
|
||||
color: var(--ti-lowcode-canvas-menu-item-disabled-color);
|
||||
}
|
||||
li {
|
||||
& > div {
|
||||
display: flex;
|
||||
|
|
@ -196,18 +270,21 @@ export default {
|
|||
justify-content: space-between;
|
||||
}
|
||||
font-size: 12px;
|
||||
color: var(--ti-lowcode-toolbar-breadcrumb-color);
|
||||
color: var(--ti-lowcode-canvas-menu-item-color);
|
||||
padding: 6px 15px;
|
||||
&:hover {
|
||||
color: var(--ti-lowcode-toolbar-icon-color);
|
||||
background: var(--ti-lowcode-canvas-menu-hover-color);
|
||||
&:not(.menu-item-disabled):hover {
|
||||
background: var(--ti-lowcode-canvas-menu-item-hover-bg-color);
|
||||
}
|
||||
position: relative;
|
||||
|
||||
&.menu-item-disabled {
|
||||
cursor: not-allowed;
|
||||
color: var(--ti-lowcode-canvas-menu-item-disabled-color);
|
||||
}
|
||||
}
|
||||
&.sub-menu {
|
||||
width: 100px;
|
||||
position: absolute;
|
||||
right: -100px;
|
||||
top: -2px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,26 +17,18 @@ import { canvasState } from './container'
|
|||
export default {
|
||||
setup() {
|
||||
const sizeStyle = computed(() => {
|
||||
const { width, maxWidth, minWidth, scale } = useLayout().getDimension()
|
||||
const { width, height, maxWidth, minWidth } = useLayout().getDimension()
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
maxWidth,
|
||||
minWidth,
|
||||
height: `${100 / scale}%`,
|
||||
transform: `scale(${scale}) translateY(-${(100 / scale - 100) / 2}%)`
|
||||
minWidth
|
||||
}
|
||||
})
|
||||
|
||||
const mouseDown = ref(false)
|
||||
const resizeDom = ref(null)
|
||||
|
||||
const onMouseMove = (event) => {
|
||||
if (mouseDown.value) {
|
||||
event.preventDefault()
|
||||
calculateSize(event)
|
||||
}
|
||||
}
|
||||
|
||||
const calculateSize = ({ movementX }) => {
|
||||
const dimension = useLayout().getDimension()
|
||||
const { maxWidth, minWidth, width } = dimension
|
||||
|
|
@ -48,6 +40,30 @@ export default {
|
|||
})
|
||||
}
|
||||
|
||||
const onMouseMove = (event) => {
|
||||
if (mouseDown.value) {
|
||||
event.preventDefault()
|
||||
calculateSize(event)
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseUp = () => {
|
||||
const iframe = canvasState.iframe
|
||||
|
||||
if (iframe) {
|
||||
iframe.style['pointer-events'] = 'auto'
|
||||
mouseDown.value = false
|
||||
|
||||
document.removeEventListener('mousemove', onMouseMove, { passive: false })
|
||||
document.removeEventListener('mouseup', onMouseUp)
|
||||
}
|
||||
}
|
||||
|
||||
const bindEvents = () => {
|
||||
document.addEventListener('mousemove', onMouseMove, { passive: false })
|
||||
document.addEventListener('mouseup', onMouseUp)
|
||||
}
|
||||
|
||||
const onMouseDown = () => {
|
||||
const iframe = canvasState.iframe
|
||||
|
||||
|
|
@ -58,44 +74,35 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
const onMouseUp = () => {
|
||||
const iframe = canvasState.iframe
|
||||
|
||||
if (iframe) {
|
||||
iframe.style['pointer-events'] = 'auto'
|
||||
mouseDown.value = false
|
||||
unbindEvents()
|
||||
}
|
||||
}
|
||||
|
||||
const bindEvents = () => {
|
||||
document.addEventListener('mousemove', onMouseMove, { passive: false })
|
||||
document.addEventListener('mouseup', onMouseUp)
|
||||
}
|
||||
|
||||
const unbindEvents = () => {
|
||||
document.removeEventListener('mousemove', onMouseMove, { passive: false })
|
||||
document.removeEventListener('mouseup', onMouseUp)
|
||||
}
|
||||
|
||||
const setScale = () => {
|
||||
useLayout().setDimension({ scale: 1 })
|
||||
nextTick(() => {
|
||||
const canvasWrap = document.querySelector('#canvas-wrap')
|
||||
|
||||
if (!canvasWrap) {
|
||||
return
|
||||
}
|
||||
|
||||
const rate = canvasWrap.offsetWidth / resizeDom.value.offsetWidth
|
||||
useLayout().setDimension({
|
||||
scale: rate > 1 ? 1 : rate
|
||||
scale: Math.min(rate, 1)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => useLayout().getDimension().width, setScale, { flush: 'post' })
|
||||
watch(() => useLayout().getDimension().width, setScale, { flush: 'post', immediate: true })
|
||||
|
||||
watch(() => useLayout().getPluginState().fixedPanels, setScale, { flush: 'post' })
|
||||
|
||||
watch(
|
||||
() => useLayout().getPluginState().render,
|
||||
(value) => !value && setScale(),
|
||||
(value) => {
|
||||
const currentFixed = useLayout().getPluginState().fixedPanels.includes(value)
|
||||
|
||||
if (!value || currentFixed) {
|
||||
setScale()
|
||||
}
|
||||
},
|
||||
{ flush: 'post' }
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<script>
|
||||
import { reactive, watch } from 'vue'
|
||||
import { useLayout } from '@opentiny/tiny-engine-controller'
|
||||
import { getCurrent, updateRect, selectState, querySelectById } from './container'
|
||||
|
||||
export default {
|
||||
|
|
@ -38,12 +39,17 @@ export default {
|
|||
}
|
||||
|
||||
const handleResize = (event, type) => {
|
||||
let { clientX, clientY } = event
|
||||
if (!props.iframe) {
|
||||
return
|
||||
}
|
||||
|
||||
if (type === 'iframe' && props.iframe) {
|
||||
const iframeRect = props.iframe.getBoundingClientRect()
|
||||
clientX += iframeRect.left
|
||||
clientY += iframeRect.top
|
||||
let { clientX, clientY } = event
|
||||
const iframeRect = props.iframe.getBoundingClientRect()
|
||||
const scale = useLayout().getScale()
|
||||
|
||||
if (type !== 'iframe') {
|
||||
clientX = (clientX - iframeRect.left) / scale
|
||||
clientY = (clientY - iframeRect.top) / scale
|
||||
}
|
||||
|
||||
const { parent, schema } = getCurrent()
|
||||
|
|
@ -65,14 +71,9 @@ export default {
|
|||
const parentWidth = parseInt(window.getComputedStyle(parentDomNode).width, 10)
|
||||
|
||||
// 最大宽度不能大于父组件宽度
|
||||
if (newWidth >= parentWidth) {
|
||||
newWidth = parentWidth
|
||||
}
|
||||
|
||||
newWidth = Math.min(newWidth, parentWidth)
|
||||
// 最小宽度32
|
||||
if (newWidth <= 32) {
|
||||
newWidth = 32
|
||||
}
|
||||
newWidth = Math.max(newWidth, 32)
|
||||
|
||||
schema.props.flexBasis = `${newWidth}px`
|
||||
schema.props.widthType = 'fixed'
|
||||
|
|
@ -186,7 +187,7 @@ export default {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.resize-border {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -20,15 +20,16 @@ import {
|
|||
NODE_LOOP
|
||||
} from '../common'
|
||||
import { useCanvas, useLayout, useResource, useTranslate } from '@opentiny/tiny-engine-controller'
|
||||
import { isVsCodeEnv } from '@opentiny/tiny-engine-controller/js/environments'
|
||||
import Builtin from '../builtin/builtin.json'
|
||||
|
||||
export const POSITION = Object.freeze({
|
||||
TOP: 'top',
|
||||
BOTTOM: 'bottom',
|
||||
LEFT: 'left',
|
||||
RIGHT: 'right',
|
||||
IN: 'in',
|
||||
FORBID: 'forbid'
|
||||
IN: 'in'
|
||||
})
|
||||
import { isVsCodeEnv } from '@opentiny/tiny-engine-common/js/environments'
|
||||
|
||||
const initialDragState = {
|
||||
keydown: false,
|
||||
|
|
@ -51,6 +52,28 @@ export const canvasState = shallowReactive({
|
|||
loopId: null
|
||||
})
|
||||
|
||||
export const getRenderer = () => canvasState.renderer
|
||||
|
||||
export const getController = () => canvasState.controller
|
||||
|
||||
export const getDocument = () => canvasState.iframe.contentDocument
|
||||
|
||||
export const getWindow = () => canvasState.iframe.contentWindow
|
||||
|
||||
export const getCurrent = () => {
|
||||
return {
|
||||
schema: canvasState.current,
|
||||
parent: canvasState.parent,
|
||||
loopId: canvasState.loopId
|
||||
}
|
||||
}
|
||||
|
||||
export const getGlobalState = () => getRenderer().getGlobalState()
|
||||
|
||||
export const getNode = (id, parent) => getRenderer()?.getNode(id, parent)
|
||||
|
||||
export const getSchema = () => getRenderer()?.getSchema()
|
||||
|
||||
export const getContext = () => {
|
||||
return getRenderer().getContext()
|
||||
}
|
||||
|
|
@ -76,8 +99,10 @@ const initialLineState = {
|
|||
width: 0,
|
||||
left: 0,
|
||||
position: '',
|
||||
forbidden: false,
|
||||
id: '',
|
||||
config: null
|
||||
config: null,
|
||||
doc: null
|
||||
}
|
||||
|
||||
// 选中画布中元素时的状态
|
||||
|
|
@ -95,6 +120,43 @@ export const lineState = reactive({
|
|||
...initialLineState
|
||||
})
|
||||
|
||||
export const clearHover = () => {
|
||||
Object.assign(hoverState, initialRectState, { slot: null })
|
||||
}
|
||||
|
||||
export const clearSelect = () => {
|
||||
canvasState.current = null
|
||||
canvasState.parent = null
|
||||
Object.assign(selectState, initialRectState)
|
||||
// 临时借用 remote 事件出发 currentSchema 更新
|
||||
canvasState?.emit?.('remove')
|
||||
}
|
||||
|
||||
const smoothScroll = {
|
||||
timmer: null,
|
||||
/**
|
||||
*
|
||||
* @param {*} up 方向
|
||||
* @param {*} step 每次滚动距离
|
||||
* @param {*} time 滚动延时(不得大于系统滚动时长,否则可能出现卡顿效果)
|
||||
*/
|
||||
start(up, step = 40, time = 100) {
|
||||
const dom = getDocument().documentElement
|
||||
const fn = () => {
|
||||
const top = up ? dom.scrollTop + step : dom.scrollTop - step
|
||||
|
||||
dom.scrollTo({ top, behavior: 'smooth' })
|
||||
this.timmer = setTimeout(fn, time)
|
||||
}
|
||||
|
||||
this.timmer || fn()
|
||||
},
|
||||
stop() {
|
||||
clearTimeout(this.timmer)
|
||||
this.timmer = null
|
||||
}
|
||||
}
|
||||
|
||||
export const dragStart = (
|
||||
data,
|
||||
element,
|
||||
|
|
@ -146,6 +208,12 @@ export const getElement = (element) => {
|
|||
if (element === element.ownerDocument.body) {
|
||||
return element
|
||||
}
|
||||
|
||||
// 如果当前元素是画布的html,返回画布的body
|
||||
if (element === element.ownerDocument.documentElement) {
|
||||
return element.ownerDocument.body
|
||||
}
|
||||
|
||||
if (!element || element.nodeType !== 1) {
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -159,6 +227,23 @@ export const getElement = (element) => {
|
|||
return undefined
|
||||
}
|
||||
|
||||
const getRect = (element) => {
|
||||
if (element === getDocument().body) {
|
||||
const { innerWidth: width, innerHeight: height } = getWindow()
|
||||
return {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: width,
|
||||
bottom: height,
|
||||
width,
|
||||
height,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
return element.getBoundingClientRect()
|
||||
}
|
||||
|
||||
const inserAfter = ({ parent, node, data }) => {
|
||||
const parentChildren = parent.children
|
||||
const index = parentChildren.indexOf(node)
|
||||
|
|
@ -205,113 +290,255 @@ export const removeNode = ({ parent, node }) => {
|
|||
}
|
||||
|
||||
export const removeNodeById = (id) => {
|
||||
if (!id) {
|
||||
return
|
||||
}
|
||||
|
||||
removeNode(getNode(id, true))
|
||||
clearSelect()
|
||||
getController().addHistory()
|
||||
canvasState.emit('remove')
|
||||
}
|
||||
|
||||
export const insertNode = (node, position = POSITION.IN, select = true) => {
|
||||
if (!node.parent) {
|
||||
insertInner({ node: canvasState.schema, data: node.data }, position)
|
||||
export const querySelectById = (id) => {
|
||||
let selector = `[${NODE_UID}="${id}"]`
|
||||
const doc = canvasState.iframe.contentDocument
|
||||
let element = doc.querySelector(selector)
|
||||
const loopId = element?.getAttribute('loop-id')
|
||||
if (element && loopId) {
|
||||
const currentLoopId = getCurrent().loopId
|
||||
selector = `[${NODE_UID}="${id}"][${NODE_LOOP}="${currentLoopId}"]`
|
||||
element = doc.querySelector(selector)
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
export const getCurrentElement = () => querySelectById(getCurrent().schema?.id)
|
||||
|
||||
// 滚动页面后,目标元素与页面边界至少保留的边距
|
||||
const SCROLL_MARGIN = 15
|
||||
|
||||
export const scrollToNode = (element) => {
|
||||
if (element) {
|
||||
const container = getDocument().documentElement
|
||||
const { clientWidth, clientHeight } = container
|
||||
const { left, right, top, bottom, width, height } = element.getBoundingClientRect()
|
||||
const option = {}
|
||||
|
||||
if (right < 0) {
|
||||
option.left = container.scrollLeft + left - SCROLL_MARGIN
|
||||
} else if (left > clientWidth) {
|
||||
option.left = container.scrollLeft + left - clientWidth + width + SCROLL_MARGIN
|
||||
}
|
||||
|
||||
if (bottom < 0) {
|
||||
option.top = container.scrollTop + top - SCROLL_MARGIN
|
||||
} else if (top > clientHeight) {
|
||||
option.top = container.scrollTop + top - clientHeight + height + SCROLL_MARGIN
|
||||
}
|
||||
|
||||
if (typeof option.left === 'number' || typeof option.top === 'number') {
|
||||
container.scrollTo(option)
|
||||
}
|
||||
}
|
||||
|
||||
return nextTick()
|
||||
}
|
||||
const setSelectRect = (element) => {
|
||||
element = element || getDocument().body
|
||||
|
||||
const { left, height, top, width } = getRect(element)
|
||||
const componentName = getCurrent().schema?.componentName || ''
|
||||
clearHover()
|
||||
Object.assign(selectState, {
|
||||
width,
|
||||
height,
|
||||
top,
|
||||
left,
|
||||
componentName,
|
||||
doc: getDocument()
|
||||
})
|
||||
}
|
||||
|
||||
export const updateRect = (id) => {
|
||||
id = (typeof id === 'string' && id) || getCurrent().schema?.id
|
||||
clearHover()
|
||||
|
||||
if (id) {
|
||||
setTimeout(() => setSelectRect(querySelectById(id)))
|
||||
} else {
|
||||
switch (position) {
|
||||
case POSITION.TOP:
|
||||
case POSITION.LEFT:
|
||||
insertBefore(node)
|
||||
break
|
||||
case POSITION.BOTTOM:
|
||||
case POSITION.RIGHT:
|
||||
inserAfter(node)
|
||||
break
|
||||
case POSITION.IN:
|
||||
insertInner(node)
|
||||
break
|
||||
default:
|
||||
insertInner(node)
|
||||
break
|
||||
// 如果选中的是body,不清除选中框
|
||||
if (!selectState.componentName && selectState.width > 0) {
|
||||
return
|
||||
}
|
||||
clearSelect()
|
||||
}
|
||||
}
|
||||
|
||||
export const getConfigure = (targetName) => {
|
||||
const material = getController().getMaterial(targetName)
|
||||
|
||||
// 这里如果是区块插槽,则返回标识为容器的对象
|
||||
if (targetName === 'Template') {
|
||||
return {
|
||||
isContainer: true
|
||||
}
|
||||
}
|
||||
|
||||
select && setTimeout(() => selectNode(node.data.id))
|
||||
|
||||
getController().addHistory()
|
||||
return material?.content?.configure || material.configure || {}
|
||||
}
|
||||
|
||||
export const addComponent = (data, position) => {
|
||||
const { schema, parent } = getCurrent()
|
||||
/**
|
||||
* 是否允许插入
|
||||
* @param {*} configure 当前放置目标的 configure,比如getConfigure(componentName)
|
||||
* @param {*} data 当前插入目标的schame数据
|
||||
* @returns
|
||||
*/
|
||||
export const allowInsert = (configure = hoverState.configure || {}, data = dragState.data || {}) => {
|
||||
const { nestingRule = {} } = configure
|
||||
const { childWhitelist = [], descendantBlacklist = [] } = nestingRule
|
||||
|
||||
insertNode({ node: schema, parent, data }, position)
|
||||
// 要插入的父节点必须是容器
|
||||
if (!configure.isContainer) {
|
||||
return false
|
||||
}
|
||||
|
||||
let flag = true
|
||||
// 白名单
|
||||
flag = childWhitelist.length ? childWhitelist.includes(data?.componentName) : true
|
||||
|
||||
// 黑名单
|
||||
if (descendantBlacklist.length) {
|
||||
flag = !descendantBlacklist.includes(data?.componentName)
|
||||
}
|
||||
|
||||
return flag
|
||||
}
|
||||
|
||||
export const copyNode = (id) => {
|
||||
const { node, parent } = getNode(id, true)
|
||||
const isAncestor = (ancestor, descendant) => {
|
||||
const ancestorId = typeof ancestor === 'string' ? ancestor : ancestor.id
|
||||
let descendantId = typeof descendant === 'string' ? descendant : descendant.id
|
||||
|
||||
inserAfter({ parent, node, data: copyObject(node) })
|
||||
getController().addHistory()
|
||||
while (descendantId) {
|
||||
const { parent } = getNode(descendantId, true) || {}
|
||||
|
||||
if (parent.id === ancestorId) {
|
||||
return true
|
||||
}
|
||||
|
||||
descendantId = parent.id
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export const onMouseUp = ({ target }) => {
|
||||
const { draging, data } = dragState
|
||||
const { position } = lineState
|
||||
const absolute = canvasState.type === 'absolute'
|
||||
const sourceId = data?.id
|
||||
const lineId = lineState.id
|
||||
const allowInsert = position !== POSITION.FORBID
|
||||
// 获取位置信息,返回状态
|
||||
const lineAbs = 20
|
||||
const getPosLine = (rect, configure) => {
|
||||
const mousePos = dragState.mouse
|
||||
const yAbs = Math.min(lineAbs, rect.height / 3)
|
||||
const xAbs = Math.min(lineAbs, rect.width / 3)
|
||||
let type
|
||||
let forbidden = false
|
||||
|
||||
if (draging && allowInsert) {
|
||||
const { parent, node } = getNode(lineId, true) || {} // target
|
||||
const targetNode = { parent, node, data: toRaw(data) }
|
||||
if (mousePos.y < rect.top + yAbs) {
|
||||
type = POSITION.TOP
|
||||
} else if (mousePos.y > rect.bottom - yAbs) {
|
||||
type = POSITION.BOTTOM
|
||||
} else if (mousePos.x < rect.left + xAbs) {
|
||||
type = POSITION.LEFT
|
||||
} else if (mousePos.x > rect.right - xAbs) {
|
||||
type = POSITION.RIGHT
|
||||
} else if (configure.isContainer) {
|
||||
type = POSITION.IN
|
||||
if (!allowInsert()) {
|
||||
forbidden = true
|
||||
}
|
||||
} else {
|
||||
type = POSITION.BOTTOM
|
||||
}
|
||||
|
||||
if (sourceId) {
|
||||
// 内部拖拽
|
||||
if (sourceId !== lineId && !absolute) {
|
||||
removeNode(getNode(sourceId, true))
|
||||
insertNode(targetNode, position)
|
||||
// 如果被拖拽的节点不是新增的,并且是放置的节点的祖先节点,则禁止插入
|
||||
const draggedId = dragState.data?.id
|
||||
if (draggedId && isAncestor(draggedId, lineState.id)) {
|
||||
forbidden = true
|
||||
}
|
||||
|
||||
return { type, forbidden }
|
||||
}
|
||||
|
||||
const isBodyEl = (element) => element.nodeName === 'BODY'
|
||||
|
||||
const setHoverRect = (element, data) => {
|
||||
if (!element) {
|
||||
return clearHover()
|
||||
}
|
||||
const componentName = element.getAttribute(NODE_TAG)
|
||||
const id = element.getAttribute(NODE_UID)
|
||||
const configure = getConfigure(componentName)
|
||||
const rect = getRect(element)
|
||||
const { left, height, top, width } = rect
|
||||
|
||||
hoverState.configure = configure
|
||||
|
||||
if (data) {
|
||||
let childEle = null
|
||||
lineState.id = id
|
||||
lineState.configure = configure
|
||||
const rectType = isBodyEl(element) ? POSITION.IN : getPosLine(rect, configure).type
|
||||
|
||||
// 如果拖拽经过的元素是body或者是带有容器属性的盒子,并且在元素内部插入,则需要特殊处理
|
||||
if ((isBodyEl(element) || configure?.isContainer) && rectType === POSITION.IN) {
|
||||
const { node } = isBodyEl(element) ? { node: getSchema() } : getNode(id, true) || {}
|
||||
const children = node?.children || []
|
||||
if (children.length > 0) {
|
||||
// 如果容器盒子有子节点,则以最后一个子节点为拖拽参照物
|
||||
const lastNode = children[children.length - 1]
|
||||
childEle = querySelectById(lastNode.id)
|
||||
const childComponentName = element.getAttribute(childEle)
|
||||
const Childconfigure = getConfigure(childComponentName)
|
||||
lineState.id = lastNode.id
|
||||
lineState.configure = Childconfigure
|
||||
}
|
||||
}
|
||||
|
||||
// 如果容器盒子有子元素
|
||||
if (childEle) {
|
||||
const childRect = getRect(childEle)
|
||||
const { left, height, top, width } = childRect
|
||||
const posLine = getPosLine(childRect, lineState.configure)
|
||||
Object.assign(lineState, {
|
||||
width,
|
||||
height,
|
||||
top,
|
||||
left,
|
||||
position: canvasState.type === 'absolute' || posLine.type,
|
||||
forbidden: posLine.forbidden
|
||||
})
|
||||
} else {
|
||||
// 从外部拖拽进来的无ID,insert
|
||||
if (absolute) {
|
||||
targetNode.node = getSchema()
|
||||
data.props = data.props || {}
|
||||
data.props.style = {
|
||||
position: 'absolute',
|
||||
top: dragState.mouse.y + 'px',
|
||||
left: dragState.mouse.x + 'px'
|
||||
}
|
||||
}
|
||||
|
||||
insertNode(targetNode, position)
|
||||
}
|
||||
}
|
||||
|
||||
// 重置拖拽状态
|
||||
dragEnd()
|
||||
}
|
||||
|
||||
const smoothScroll = {
|
||||
timmer: null,
|
||||
/**
|
||||
*
|
||||
* @param {*} up 方向
|
||||
* @param {*} step 每次滚动距离
|
||||
* @param {*} time 滚动延时(不得大于系统滚动时长,否则可能出现卡顿效果)
|
||||
*/
|
||||
start(up, step = 40, time = 100) {
|
||||
const dom = getDocument().documentElement
|
||||
const fn = () => {
|
||||
const top = up ? dom.scrollTop + step : dom.scrollTop - step
|
||||
|
||||
dom.scrollTo({ top, behavior: 'smooth' })
|
||||
this.timmer = setTimeout(fn, time)
|
||||
const posLine = getPosLine(rect, configure)
|
||||
Object.assign(lineState, {
|
||||
width,
|
||||
height,
|
||||
top,
|
||||
left,
|
||||
position: canvasState.type === 'absolute' || posLine.type,
|
||||
forbidden: posLine.forbidden
|
||||
})
|
||||
}
|
||||
|
||||
this.timmer || fn()
|
||||
},
|
||||
stop() {
|
||||
clearTimeout(this.timmer)
|
||||
this.timmer = null
|
||||
useLayout().closePlugin()
|
||||
}
|
||||
|
||||
// 设置元素hover状态
|
||||
Object.assign(hoverState, {
|
||||
width,
|
||||
height,
|
||||
top,
|
||||
left,
|
||||
componentName
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
|
||||
// 绝对布局
|
||||
|
|
@ -395,41 +622,6 @@ export const dragMove = (event, isHover) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const clearHover = () => {
|
||||
Object.assign(hoverState, initialRectState, { slot: null })
|
||||
}
|
||||
|
||||
export const clearSelect = () => {
|
||||
canvasState.current = null
|
||||
canvasState.parent = null
|
||||
Object.assign(selectState, initialRectState)
|
||||
}
|
||||
|
||||
export const querySelectById = (id, type = '') => {
|
||||
let selector = `[${NODE_UID}="${id}"]`
|
||||
const doc = canvasState.iframe.contentDocument
|
||||
let element = doc.querySelector(selector)
|
||||
const loopId = element?.getAttribute('loop-id')
|
||||
if (element && loopId) {
|
||||
const currentLoopId = getCurrent().loopId
|
||||
selector = `[${NODE_UID}="${id}"][${NODE_LOOP}="${currentLoopId}"]`
|
||||
element = doc.querySelector(selector)
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
export const getCurrentElement = () => querySelectById(getCurrent().schema?.id)
|
||||
|
||||
export const updateRect = (id) => {
|
||||
id = (typeof id === 'string' && id) || getCurrent().schema?.id
|
||||
clearHover()
|
||||
|
||||
if (id) {
|
||||
setTimeout(() => setSelectRect(querySelectById(id)))
|
||||
} else {
|
||||
clearSelect()
|
||||
}
|
||||
}
|
||||
// type == clickTree, 为点击大纲; type == loop-id=xxx ,为点击循环数据
|
||||
export const selectNode = async (id, type) => {
|
||||
if (type && type.indexOf('loop-id') > -1) {
|
||||
|
|
@ -459,174 +651,84 @@ export const hoverNode = (id, data) => {
|
|||
element && setHoverRect(element, data)
|
||||
}
|
||||
|
||||
export const scrollToNode = (element) => {
|
||||
if (element) {
|
||||
const container = getDocument().documentElement
|
||||
const h = container?.clientHeight
|
||||
const { y, height } = element.getBoundingClientRect()
|
||||
|
||||
if (y < 0) {
|
||||
container.scrollTo({ top: container.scrollTop + y - 15 })
|
||||
} else if (y > h) {
|
||||
container.scrollTo({ top: y + height - h + 15 })
|
||||
}
|
||||
}
|
||||
|
||||
return nextTick()
|
||||
}
|
||||
const setSelectRect = (element) => {
|
||||
element = element || getDocument().body
|
||||
|
||||
const { left, height, top, width } = element.getBoundingClientRect()
|
||||
const { x, y } = getOffset(element)
|
||||
const componentName = getCurrent().schema?.componentName || ''
|
||||
const scale = useLayout().getScale()
|
||||
clearHover()
|
||||
Object.assign(selectState, {
|
||||
width: width * scale,
|
||||
height: height * scale,
|
||||
top: top * scale + y,
|
||||
left: left * scale + x,
|
||||
componentName
|
||||
})
|
||||
}
|
||||
|
||||
const isBodyEl = (element) => element.nodeName === 'BODY'
|
||||
|
||||
const setHoverRect = (element, data) => {
|
||||
if (!element) {
|
||||
return clearHover()
|
||||
}
|
||||
const componentName = element.getAttribute(NODE_TAG)
|
||||
const id = element.getAttribute(NODE_UID)
|
||||
const configure = getConfigure(componentName)
|
||||
const rect = element.getBoundingClientRect()
|
||||
const { left, height, top, width } = rect
|
||||
const { x, y } = getOffset(element)
|
||||
const scale = useLayout().getScale()
|
||||
|
||||
hoverState.configure = configure
|
||||
|
||||
if (data) {
|
||||
let childEle = null
|
||||
lineState.id = id
|
||||
lineState.configure = configure
|
||||
const rectType = isBodyEl(element) ? POSITION.IN : getPosLine(rect, configure).type
|
||||
|
||||
// 如果拖拽经过的元素是body或者是带有容器属性的盒子,并且在元素内部插入,则需要特殊处理
|
||||
if ((isBodyEl(element) || configure?.isContainer) && rectType === POSITION.IN) {
|
||||
const { node } = isBodyEl(element) ? { node: getSchema() } : getNode(id, true) || {}
|
||||
const children = node?.children || []
|
||||
if (children.length > 0) {
|
||||
// 如果容器盒子有子节点,则以最后一个子节点为拖拽参照物
|
||||
const lastNode = children[children.length - 1]
|
||||
childEle = querySelectById(lastNode.id)
|
||||
const childComponentName = element.getAttribute(childEle)
|
||||
const Childconfigure = getConfigure(childComponentName)
|
||||
lineState.id = lastNode.id
|
||||
lineState.configure = Childconfigure
|
||||
}
|
||||
}
|
||||
|
||||
// 如果容器盒子有子元素
|
||||
if (childEle) {
|
||||
const childRect = childEle.getBoundingClientRect()
|
||||
const { left, height, top, width } = childRect
|
||||
const { x, y } = getOffset(childEle)
|
||||
Object.assign(lineState, {
|
||||
width: width * scale,
|
||||
height: height * scale,
|
||||
top: top * scale + y,
|
||||
left: left * scale + x,
|
||||
position: canvasState.type === 'absolute' || getPosLine(childRect, lineState.configure).type
|
||||
})
|
||||
} else {
|
||||
Object.assign(lineState, {
|
||||
width: width * scale,
|
||||
height: height * scale,
|
||||
top: top * scale + y,
|
||||
left: left * scale + x,
|
||||
position: canvasState.type === 'absolute' || getPosLine(rect, configure).type
|
||||
})
|
||||
}
|
||||
|
||||
useLayout().closePlugin()
|
||||
}
|
||||
|
||||
// 设置元素hover状态
|
||||
Object.assign(hoverState, {
|
||||
width: width * scale,
|
||||
height: height * scale,
|
||||
top: top * scale + y,
|
||||
left: left * scale + x,
|
||||
componentName
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否允许插入
|
||||
* @param {*} configure 当前放置目标的 configure,比如getConfigure(componentName)
|
||||
* @param {*} data 当前插入目标的schame数据
|
||||
* @returns
|
||||
*/
|
||||
export const allowInsert = (configure = hoverState.configure || {}, data = dragState.data || {}) => {
|
||||
const { nestingRule = {} } = configure
|
||||
const { childWhitelist = [], descendantBlacklist = [] } = nestingRule
|
||||
|
||||
// 要插入的父节点必须是容器
|
||||
if (!configure.isContainer) {
|
||||
return false
|
||||
}
|
||||
|
||||
let flag = true
|
||||
// 白名单
|
||||
flag = childWhitelist.length ? childWhitelist.includes(data?.componentName) : true
|
||||
|
||||
// 黑名单
|
||||
if (descendantBlacklist.length) {
|
||||
flag = !descendantBlacklist.includes(data?.componentName)
|
||||
}
|
||||
|
||||
return flag
|
||||
}
|
||||
|
||||
export const getConfigure = (targetName) => {
|
||||
const material = getController().getMaterial(targetName)
|
||||
|
||||
// 这里如果是区块插槽,则返回标识为容器的对象
|
||||
if (targetName === 'Template') {
|
||||
return {
|
||||
isContainer: true
|
||||
}
|
||||
}
|
||||
|
||||
return material?.content?.configure || material.configure || {}
|
||||
}
|
||||
|
||||
// 获取位置信息,返回状态
|
||||
const lineAbs = 20
|
||||
const getPosLine = (rect, configure) => {
|
||||
const mousePos = dragState.mouse
|
||||
const yAbs = Math.min(lineAbs, rect.height / 3)
|
||||
const xAbs = Math.min(lineAbs, rect.width / 3)
|
||||
let type
|
||||
|
||||
if (mousePos.y < rect.top + yAbs) {
|
||||
type = POSITION.TOP
|
||||
} else if (mousePos.y > rect.bottom - yAbs) {
|
||||
type = POSITION.BOTTOM
|
||||
} else if (mousePos.x < rect.left + xAbs) {
|
||||
type = POSITION.LEFT
|
||||
} else if (mousePos.x > rect.right - xAbs) {
|
||||
type = POSITION.RIGHT
|
||||
} else if (configure.isContainer) {
|
||||
type = allowInsert() ? POSITION.IN : POSITION.FORBID
|
||||
export const insertNode = (node, position = POSITION.IN, select = true) => {
|
||||
if (!node.parent) {
|
||||
insertInner({ node: canvasState.schema, data: node.data }, position)
|
||||
} else {
|
||||
type = POSITION.BOTTOM
|
||||
switch (position) {
|
||||
case POSITION.TOP:
|
||||
case POSITION.LEFT:
|
||||
insertBefore(node)
|
||||
break
|
||||
case POSITION.BOTTOM:
|
||||
case POSITION.RIGHT:
|
||||
inserAfter(node)
|
||||
break
|
||||
case POSITION.IN:
|
||||
insertInner(node)
|
||||
break
|
||||
default:
|
||||
insertInner(node)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return { type }
|
||||
select && setTimeout(() => selectNode(node.data.id))
|
||||
|
||||
getController().addHistory()
|
||||
}
|
||||
|
||||
export const addComponent = (data, position) => {
|
||||
const { schema, parent } = getCurrent()
|
||||
|
||||
insertNode({ node: schema, parent, data }, position)
|
||||
}
|
||||
|
||||
export const copyNode = (id) => {
|
||||
if (!id) {
|
||||
return
|
||||
}
|
||||
const { node, parent } = getNode(id, true)
|
||||
|
||||
inserAfter({ parent, node, data: copyObject(node) })
|
||||
getController().addHistory()
|
||||
}
|
||||
|
||||
export const onMouseUp = () => {
|
||||
const { draging, data } = dragState
|
||||
const { position, forbidden } = lineState
|
||||
const absolute = canvasState.type === 'absolute'
|
||||
const sourceId = data?.id
|
||||
const lineId = lineState.id
|
||||
|
||||
if (draging && !forbidden) {
|
||||
const { parent, node } = getNode(lineId, true) || {} // target
|
||||
const targetNode = { parent, node, data: toRaw(data) }
|
||||
|
||||
if (sourceId) {
|
||||
// 内部拖拽
|
||||
if (sourceId !== lineId && !absolute) {
|
||||
removeNode(getNode(sourceId, true))
|
||||
insertNode(targetNode, position)
|
||||
}
|
||||
} else {
|
||||
// 从外部拖拽进来的无ID,insert
|
||||
if (absolute) {
|
||||
targetNode.node = getSchema()
|
||||
data.props = data.props || {}
|
||||
data.props.style = {
|
||||
position: 'absolute',
|
||||
top: dragState.mouse.y + 'px',
|
||||
left: dragState.mouse.x + 'px'
|
||||
}
|
||||
}
|
||||
|
||||
insertNode(targetNode, position)
|
||||
}
|
||||
}
|
||||
|
||||
// 重置拖拽状态
|
||||
dragEnd()
|
||||
}
|
||||
|
||||
export const setPageCss = (css = '') => {
|
||||
|
|
@ -671,8 +773,16 @@ export const setState = (state) => {
|
|||
getRenderer().setState(state)
|
||||
}
|
||||
|
||||
export const setUtils = (utils) => {
|
||||
getRenderer().setUtils(utils)
|
||||
export const setUtils = (utils, clear, isForceRefresh) => {
|
||||
getRenderer().setUtils(utils, clear, isForceRefresh)
|
||||
}
|
||||
|
||||
export const updateUtils = (utils) => {
|
||||
getRenderer().updateUtils(utils)
|
||||
}
|
||||
|
||||
export const deleteUtils = (utils) => {
|
||||
getRenderer().deleteUtils(utils)
|
||||
}
|
||||
|
||||
export const deleteState = (variable) => {
|
||||
|
|
@ -684,26 +794,6 @@ export const setGlobalState = (state) => {
|
|||
getRenderer().setGlobalState(state)
|
||||
}
|
||||
|
||||
export const getGlobalState = () => getRenderer().getGlobalState()
|
||||
|
||||
export const getRenderer = () => canvasState.renderer
|
||||
|
||||
export const getController = () => canvasState.controller
|
||||
|
||||
export const getNode = (id, parent) => getRenderer()?.getNode(id, parent)
|
||||
|
||||
export const getDocument = () => canvasState.iframe.contentDocument
|
||||
|
||||
export const getWindow = () => canvasState.iframe.contentWindow
|
||||
|
||||
export const getCurrent = () => {
|
||||
return {
|
||||
schema: canvasState.current,
|
||||
parent: canvasState.parent,
|
||||
loopId: canvasState.loopId
|
||||
}
|
||||
}
|
||||
|
||||
export const getNodePath = (id, nodes = []) => {
|
||||
const { parent, node } = getNode(id, true) || {}
|
||||
|
||||
|
|
@ -726,8 +816,6 @@ export const setSchema = async (schema) => {
|
|||
return canvasState.schema
|
||||
}
|
||||
|
||||
export const getSchema = () => getRenderer()?.getSchema()
|
||||
|
||||
export const setConfigure = (configure) => {
|
||||
getRenderer().setConfigure(configure)
|
||||
}
|
||||
|
|
@ -760,6 +848,49 @@ export const canvasDispatch = (name, data, doc = getDocument()) => {
|
|||
doc.dispatchEvent(new CustomEvent(name, data))
|
||||
}
|
||||
|
||||
export const canvasApi = {
|
||||
dragStart,
|
||||
updateRect,
|
||||
getContext,
|
||||
getNodePath,
|
||||
dragMove,
|
||||
setLocales,
|
||||
setState,
|
||||
deleteState,
|
||||
getRenderer,
|
||||
clearSelect,
|
||||
selectNode,
|
||||
hoverNode,
|
||||
insertNode,
|
||||
removeNode,
|
||||
addComponent,
|
||||
setPageCss,
|
||||
addScript,
|
||||
addStyle,
|
||||
getNode,
|
||||
getCurrent,
|
||||
setSchema,
|
||||
setUtils,
|
||||
updateUtils,
|
||||
deleteUtils,
|
||||
getSchema,
|
||||
setI18n,
|
||||
getCanvasType,
|
||||
setCanvasType,
|
||||
setProps,
|
||||
setGlobalState,
|
||||
getGlobalState,
|
||||
getDocument,
|
||||
canvasDispatch,
|
||||
Builtin,
|
||||
setDataSourceMap: (...args) => {
|
||||
return canvasState.renderer.setDataSourceMap(...args)
|
||||
},
|
||||
getDataSourceMap: (...args) => {
|
||||
return canvasState.renderer.getDataSourceMap(...args)
|
||||
}
|
||||
}
|
||||
|
||||
export const initCanvas = ({ renderer, iframe, emit, controller }) => {
|
||||
const currentSchema = getSchema()
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
<icon-close class="icon-close" @click="closePanel"></icon-close>
|
||||
</span>
|
||||
</div>
|
||||
<config-group :group="propertiesList" :index="0">
|
||||
<ConfigGroup :group="propertiesList" :index="0">
|
||||
<template #item="{ data, propIndex }">
|
||||
<config-item
|
||||
<ConfigItem
|
||||
:key="propIndex"
|
||||
:property="data"
|
||||
:data-prop-index="propIndex"
|
||||
|
|
@ -22,22 +22,19 @@
|
|||
<template v-if="!data.noBinding" #suffix>
|
||||
<slot name="suffix" :data="data"></slot>
|
||||
</template>
|
||||
</config-item>
|
||||
</ConfigItem>
|
||||
</template>
|
||||
</config-group>
|
||||
</ConfigGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, ref } from 'vue'
|
||||
import { useResource, useProperties, useCanvas, useProperty } from '@opentiny/tiny-engine-controller'
|
||||
import { ConfigGroup, ConfigItem } from '@opentiny/tiny-engine-common'
|
||||
import { iconSetting, iconClose } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ConfigGroup,
|
||||
ConfigItem,
|
||||
IconSetting: iconSetting(),
|
||||
IconClose: iconClose()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -63,13 +63,13 @@ const setUtils = (data, clear, isForceRefresh) => {
|
|||
const utilsCollection = {}
|
||||
// 目前画布还不具备远程加载utils工具类的功能,目前只能加载TinyVue组件库中的组件工具
|
||||
data?.forEach((item) => {
|
||||
const util = window.TinyVue[item.name]
|
||||
const util = window.TinyVue[item.content.exportName]
|
||||
if (util) {
|
||||
utilsCollection[item.name] = util
|
||||
}
|
||||
|
||||
// 此处需要把工具类中的icon图标也加入utils上下文环境
|
||||
const utilIcon = window.TinyVueIcon[item.name]
|
||||
const utilIcon = window.TinyVueIcon[item.content.exportName]
|
||||
if (utilIcon) {
|
||||
utilsCollection[item.name] = utilIcon
|
||||
}
|
||||
|
|
@ -88,6 +88,19 @@ const setUtils = (data, clear, isForceRefresh) => {
|
|||
}
|
||||
}
|
||||
|
||||
const updateUtils = (data) => {
|
||||
setUtils(data, false, true)
|
||||
}
|
||||
|
||||
const deleteUtils = (data) => {
|
||||
data?.forEach((item) => {
|
||||
if (utils[item.name]) {
|
||||
delete utils[item.name]
|
||||
}
|
||||
})
|
||||
setUtils([], false, true)
|
||||
}
|
||||
|
||||
const setBridge = (data, clear) => {
|
||||
clear && reset(bridge)
|
||||
Object.assign(bridge, data)
|
||||
|
|
@ -363,6 +376,13 @@ export default {
|
|||
)
|
||||
},
|
||||
render() {
|
||||
// 渲染画布增加根节点,与出码和预览保持一致
|
||||
const rootChildrenSchema = {
|
||||
componentName: 'div',
|
||||
props: schema.props,
|
||||
children: schema.children
|
||||
}
|
||||
|
||||
return h(
|
||||
'tiny-i18n-host',
|
||||
{
|
||||
|
|
@ -371,9 +391,7 @@ export default {
|
|||
ref: 'page',
|
||||
className: 'design-page'
|
||||
},
|
||||
schema.children?.length
|
||||
? schema.children.map((child) => h(renderer, { schema: child, parent: schema }))
|
||||
: [h(CanvasEmpty)]
|
||||
schema.children?.length ? h(renderer, { schema: rootChildrenSchema, parent: schema }) : [h(CanvasEmpty)]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -381,6 +399,8 @@ export default {
|
|||
export const api = {
|
||||
getUtils,
|
||||
setUtils,
|
||||
updateUtils,
|
||||
deleteUtils,
|
||||
getBridge,
|
||||
setBridge,
|
||||
getMethods,
|
||||
|
|
@ -404,5 +424,3 @@ export const api = {
|
|||
setDataSourceMap,
|
||||
setGlobalState
|
||||
}
|
||||
|
||||
window.api = api
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { constants, utils } from '@opentiny/tiny-engine-utils'
|
|||
import babelPluginJSX from '@vue/babel-plugin-jsx'
|
||||
import { transformSync } from '@babel/core'
|
||||
import i18nHost from '@opentiny/tiny-engine-i18n-host'
|
||||
import { CanvasRow, CanvasCol, CanvasRowColContainer } from '@opentiny/tiny-engine-builtin-component'
|
||||
import { context, conditions, setNode } from './context'
|
||||
import {
|
||||
CanvasBox,
|
||||
|
|
@ -25,27 +26,33 @@ import {
|
|||
CanvasText,
|
||||
CanvasSlot,
|
||||
CanvasImg,
|
||||
CanvasRow,
|
||||
CanvasCol,
|
||||
CanvasRowColContainer
|
||||
CanvasPlaceholder
|
||||
} from '../builtin'
|
||||
import { NODE_UID as DESIGN_UIDKEY, NODE_TAG as DESIGN_TAGKEY, NODE_LOOP as DESIGN_LOOPID } from '../common'
|
||||
|
||||
const { BROADCAST_CHANNEL } = constants
|
||||
const { hyphenateRE } = utils
|
||||
const customElements = {}
|
||||
|
||||
const transformJSX = (code) =>
|
||||
transformSync(code, {
|
||||
const transformJSX = (code) => {
|
||||
const res = transformSync(code, {
|
||||
plugins: [
|
||||
[
|
||||
babelPluginJSX,
|
||||
{
|
||||
pragma: 'h',
|
||||
isCustomElement: (name) => custElements[name]
|
||||
isCustomElement: (name) => customElements[name]
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
return (res.code || '')
|
||||
.replace(/import \{.+\} from "vue";/, '')
|
||||
.replace(/h\(_?resolveComponent\((.*?)\)/g, `h(this.getComponent($1)`)
|
||||
.replace(/_?resolveComponent/g, 'h')
|
||||
.replace(/_?createTextVNode\((.*?)\)/g, '$1')
|
||||
.trim()
|
||||
}
|
||||
|
||||
export const blockSlotDataMap = reactive({})
|
||||
|
||||
|
|
@ -60,7 +67,8 @@ const Mapper = {
|
|||
Img: CanvasImg,
|
||||
CanvasRow,
|
||||
CanvasCol,
|
||||
CanvasRowColContainer
|
||||
CanvasRowColContainer,
|
||||
CanvasPlaceholder
|
||||
}
|
||||
|
||||
const { post } = useBroadcastChannel({ name: BROADCAST_CHANNEL.Notify })
|
||||
|
|
@ -131,18 +139,13 @@ const isObject = (data) => {
|
|||
export const isStateAccessor = (stateData) =>
|
||||
stateData?.accessor?.getter?.type === 'JSFunction' || stateData?.accessor?.setter?.type === 'JSFunction'
|
||||
|
||||
const parseI18n = (i18n, scope, ctx) => {
|
||||
return parseExpression(
|
||||
{
|
||||
type: 'JSExpression',
|
||||
value: `this.i18n('${i18n.key}')`
|
||||
},
|
||||
scope,
|
||||
{ i18n: i18nHost.global.t, ...ctx }
|
||||
)
|
||||
// 规避创建function eslint报错
|
||||
export const newFn = (...argv) => {
|
||||
const Fn = Function
|
||||
return new Fn(...argv)
|
||||
}
|
||||
|
||||
const parseExpression = (data, scope, ctx) => {
|
||||
const parseExpression = (data, scope, ctx, isJsx = false) => {
|
||||
try {
|
||||
if (data.value.indexOf('this.i18n') > -1) {
|
||||
ctx.i18n = i18nHost.global.t
|
||||
|
|
@ -150,16 +153,42 @@ const parseExpression = (data, scope, ctx) => {
|
|||
ctx.t = i18nHost.global.t
|
||||
}
|
||||
|
||||
return newFn('$scope', `with($scope || {}) { return ${data.value} }`).call(ctx, {
|
||||
const expression = isJsx ? transformJSX(data.value) : data.value
|
||||
return newFn('$scope', `with($scope || {}) { return ${expression} }`).call(ctx, {
|
||||
...ctx,
|
||||
...scope,
|
||||
slotScope: scope
|
||||
})
|
||||
} catch (err) {
|
||||
// 解析抛出异常,则再尝试解析 JSX 语法。如果解析 JSX 语法仍然出现错误,isJsx 变量会确保不会再次递归执行解析
|
||||
if (!isJsx) {
|
||||
return parseExpression(data, scope, ctx, true)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
const parseI18n = (i18n, scope, ctx) => {
|
||||
return parseExpression(
|
||||
{
|
||||
type: 'JSExpression',
|
||||
value: `this.i18n('${i18n.key}', ${JSON.stringify(i18n.params)})`
|
||||
},
|
||||
scope,
|
||||
{ i18n: i18nHost.global.t, ...ctx }
|
||||
)
|
||||
}
|
||||
|
||||
const renderDefault = (children, scope, parent) =>
|
||||
children.map?.((child) =>
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
h(renderer, {
|
||||
schema: child,
|
||||
scope,
|
||||
parent
|
||||
})
|
||||
)
|
||||
|
||||
const parseJSSlot = (data, scope) => {
|
||||
return ($scope) => renderDefault(data.value, { ...scope, ...$scope }, data)
|
||||
}
|
||||
|
|
@ -225,20 +254,111 @@ const parseFunctionString = (fnStr) => {
|
|||
return null
|
||||
}
|
||||
|
||||
// 规避创建function eslint报错
|
||||
export const newFn = (...argv) => {
|
||||
const Fn = Function
|
||||
return new Fn(...argv)
|
||||
const getPlainProps = (object = {}) => {
|
||||
const { slot, ...rest } = object
|
||||
const props = {}
|
||||
|
||||
if (slot) {
|
||||
rest.slot = slot.name || slot
|
||||
}
|
||||
|
||||
Object.entries(rest).forEach(([key, value]) => {
|
||||
let renderKey = key
|
||||
|
||||
// html 标签属性会忽略大小写,所以传递包含大写的 props 需要转换为 kebab 形式的 props
|
||||
if (!/on[A-Z]/.test(renderKey) && hyphenateRE.test(renderKey)) {
|
||||
renderKey = hyphenate(renderKey)
|
||||
}
|
||||
|
||||
if (['boolean', 'string', 'number'].includes(typeof value)) {
|
||||
props[renderKey] = value
|
||||
} else {
|
||||
// 如果传给webcomponent标签的是对象或者数组需要使用.prop修饰符,转化成h函数就是如下写法
|
||||
props[`.${renderKey}`] = value
|
||||
}
|
||||
})
|
||||
return props
|
||||
}
|
||||
|
||||
const generateCollection = (schema) => {
|
||||
if (schema.componentName === 'Collection' && schema.props?.dataSource && schema.children) {
|
||||
schema.children.forEach((item) => {
|
||||
const fetchData = item.props?.fetchData
|
||||
const methodMatch = fetchData?.value?.match(/this\.(.+?)}/)
|
||||
if (fetchData && methodMatch?.[1]) {
|
||||
const methodName = methodMatch[1].trim()
|
||||
// 缓存表格fetchData对应的数据源信息
|
||||
collectionMethodsMap[methodName] = schema.props.dataSource
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const generateBlockContent = (schema) => {
|
||||
if (schema?.componentName === 'Collection') {
|
||||
generateCollection(schema)
|
||||
}
|
||||
if (Array.isArray(schema?.children)) {
|
||||
schema.children.forEach((item) => {
|
||||
generateBlockContent(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const registerBlock = (componentName) => {
|
||||
getController()
|
||||
.registerBlock?.(componentName)
|
||||
.then((res) => {
|
||||
const blockSchema = res.content
|
||||
|
||||
// 拿到区块数据,建立区块中数据源的映射关系
|
||||
generateBlockContent(blockSchema)
|
||||
|
||||
// 如果区块的根节点有百分比高度,则需要特殊处理,把高度百分比传递下去,适配大屏应用
|
||||
if (/height:\s*?[\d|.]+?%/.test(blockSchema?.props?.style)) {
|
||||
const blockDoms = document.querySelectorAll(hyphenate(componentName))
|
||||
blockDoms.forEach((item) => {
|
||||
item.style.height = '100%'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const wrapCustomElement = (componentName) => {
|
||||
const material = getController().getMaterial(componentName)
|
||||
|
||||
if (!Object.keys(material).length) {
|
||||
registerBlock(componentName)
|
||||
}
|
||||
|
||||
customElements[componentName] = {
|
||||
name: componentName + '.ce',
|
||||
render() {
|
||||
return h(
|
||||
hyphenate(componentName),
|
||||
window.parent.TinyGlobalConfig.dslMode === 'Vue' ? getPlainProps(this.$attrs) : this.$attrs,
|
||||
this.$slots.default?.()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return customElements[componentName]
|
||||
}
|
||||
|
||||
export const getComponent = (name) => {
|
||||
return (
|
||||
Mapper[name] ||
|
||||
getNative(name) ||
|
||||
getBlock(name) ||
|
||||
customElements[name] ||
|
||||
(isHTMLTag(name) ? name : wrapCustomElement(name))
|
||||
)
|
||||
}
|
||||
|
||||
// 解析JSX字符串为可执行函数
|
||||
const parseJSXFunction = (data, ctx) => {
|
||||
try {
|
||||
const newValue = transformJSX(data.value)
|
||||
.code.replace(/import \{.+\} from "vue";/, '')
|
||||
.replace(/h\(_?resolveComponent\((.*?)\)/g, `h(this.getComponent($1)`)
|
||||
.replace(/_?resolveComponent/g, 'h')
|
||||
.replace(/_?createTextVNode\((.*?)\)/g, '$1')
|
||||
const fnInfo = parseFunctionString(newValue)
|
||||
if (!fnInfo) throw Error('函数解析失败,请检查格式。示例:function fnName() { }')
|
||||
|
||||
|
|
@ -297,6 +417,8 @@ const parseLoopArgs = (_loop) => {
|
|||
return undefined
|
||||
}
|
||||
|
||||
export const getIcon = (name) => window.TinyVueIcon?.[name]?.() || ''
|
||||
|
||||
const parseObjectData = (data, scope, ctx) => {
|
||||
if (!data) {
|
||||
return data
|
||||
|
|
@ -382,124 +504,36 @@ const stopEvent = (event) => {
|
|||
return false
|
||||
}
|
||||
|
||||
const getPlainProps = (object = {}) => {
|
||||
const { slot, ...rest } = object
|
||||
const props = {}
|
||||
|
||||
if (slot) {
|
||||
rest.slot = slot.name || slot
|
||||
}
|
||||
|
||||
Object.entries(rest).forEach(([key, value]) => {
|
||||
let renderKey = key
|
||||
|
||||
// html 标签属性会忽略大小写,所以传递包含大写的 props 需要转换为 kebab 形式的 props
|
||||
if (!/on[A-Z]/.test(renderKey) && hyphenateRE.test(renderKey)) {
|
||||
renderKey = hyphenate(renderKey)
|
||||
}
|
||||
|
||||
if (['boolean', 'string', 'number'].includes(typeof value)) {
|
||||
props[renderKey] = value
|
||||
} else {
|
||||
// 如果传给webcomponent标签的是对象或者数组需要使用.prop修饰符,转化成h函数就是如下写法
|
||||
props[`.${renderKey}`] = value
|
||||
}
|
||||
})
|
||||
return props
|
||||
}
|
||||
|
||||
const custElements = {}
|
||||
|
||||
const generateCollection = (schema) => {
|
||||
if (schema.componentName === 'Collection' && schema.props?.dataSource && schema.children) {
|
||||
schema.children.forEach((item) => {
|
||||
const fetchData = item.props?.fetchData
|
||||
const methodMatch = fetchData?.value?.match(/this\.(.+?)}/)
|
||||
if (fetchData && methodMatch?.[1]) {
|
||||
const methodName = methodMatch[1].trim()
|
||||
// 缓存表格fetchData对应的数据源信息
|
||||
collectionMethodsMap[methodName] = schema.props.dataSource
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const generateBlockContent = (schema) => {
|
||||
if (schema?.componentName === 'Collection') {
|
||||
generateCollection(schema)
|
||||
}
|
||||
if (Array.isArray(schema?.children)) {
|
||||
schema.children.forEach((item) => {
|
||||
generateBlockContent(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const registerBlock = (componentName) => {
|
||||
getController()
|
||||
.registerBlock?.(componentName)
|
||||
.then((res) => {
|
||||
const blockSchema = res.content
|
||||
|
||||
// 拿到区块数据,建立区块中数据源的映射关系
|
||||
generateBlockContent(blockSchema)
|
||||
|
||||
// 如果区块的根节点有百分比高度,则需要特殊处理,把高度百分比传递下去,适配大屏应用
|
||||
if (/height:\s*?[\d|.]+?%/.test(blockSchema?.props?.style)) {
|
||||
const blockDoms = document.querySelectorAll(hyphenate(componentName))
|
||||
blockDoms.forEach((item) => {
|
||||
item.style.height = '100%'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const wrapCustomElement = (componentName) => {
|
||||
const material = getController().getMaterial(componentName)
|
||||
|
||||
if (!Object.keys(material).length) {
|
||||
registerBlock(componentName)
|
||||
}
|
||||
|
||||
custElements[componentName] = {
|
||||
name: componentName + '.ce',
|
||||
render() {
|
||||
return h(
|
||||
hyphenate(componentName),
|
||||
window.parent.TinyGlobalConfig.dslMode === 'Vue' ? getPlainProps(this.$attrs) : this.$attrs,
|
||||
this.$slots.default?.()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return custElements[componentName]
|
||||
}
|
||||
|
||||
const goupSlot = (children, isCustElm) => {
|
||||
const slotGrup = {}
|
||||
const generateSlotGroup = (children, isCustomElm, schema) => {
|
||||
const slotGroup = {}
|
||||
|
||||
children.forEach((child) => {
|
||||
const { componentName, children, params = [], props } = child
|
||||
const slot = child.slot || props?.slot || 'default'
|
||||
const slot = child.slot || props?.slot?.name || props?.slot || 'default'
|
||||
const isNotEmptyTemplate = componentName === 'Template' && children.length
|
||||
|
||||
isCustElm && (child.props.slot = 'slot') // CE下需要给子节点加上slot标识
|
||||
slotGrup[slot] = slotGrup[slot] || {
|
||||
isCustomElm && (child.props.slot = 'slot') // CE下需要给子节点加上slot标识
|
||||
slotGroup[slot] = slotGroup[slot] || {
|
||||
value: [],
|
||||
params
|
||||
params,
|
||||
parent: isNotEmptyTemplate ? child : schema
|
||||
}
|
||||
slotGrup[slot].value.push(...(componentName === 'Template' ? children : [child])) // template 标签直接过滤掉
|
||||
|
||||
slotGroup[slot].value.push(...(isNotEmptyTemplate ? children : [child])) // template 标签直接过滤掉
|
||||
})
|
||||
|
||||
return slotGrup
|
||||
return slotGroup
|
||||
}
|
||||
|
||||
const renderSlot = (children, scope, schema, isCustElm) => {
|
||||
const renderSlot = (children, scope, schema, isCustomElm) => {
|
||||
if (children.some((a) => a.componentName === 'Template')) {
|
||||
const slotGrup = goupSlot(children, isCustElm)
|
||||
const slotGroup = generateSlotGroup(children, isCustomElm, schema)
|
||||
const slots = {}
|
||||
|
||||
Object.keys(slotGrup).forEach((slotName) => {
|
||||
slots[slotName] = ($scope) => renderDefault(slotGrup[slotName].value, { ...scope, ...$scope }, schema)
|
||||
Object.keys(slotGroup).forEach((slotName) => {
|
||||
const currentSlot = slotGroup[slotName]
|
||||
|
||||
slots[slotName] = ($scope) => renderDefault(currentSlot.value, { ...scope, ...$scope }, currentSlot.parent)
|
||||
})
|
||||
|
||||
return slots
|
||||
|
|
@ -508,18 +542,6 @@ const renderSlot = (children, scope, schema, isCustElm) => {
|
|||
return { default: () => renderDefault(children, scope, schema) }
|
||||
}
|
||||
|
||||
export const getComponent = (name) => {
|
||||
return (
|
||||
Mapper[name] ||
|
||||
getNative(name) ||
|
||||
getBlock(name) ||
|
||||
custElements[name] ||
|
||||
(isHTMLTag(name) ? name : wrapCustomElement(name))
|
||||
)
|
||||
}
|
||||
|
||||
export const getIcon = (name) => window.TinyVueIcon?.[name]?.() || ''
|
||||
|
||||
const checkGroup = (componentName) => configure[componentName]?.nestingRule?.childWhitelist?.length
|
||||
|
||||
const clickCapture = (componentName) => configure[componentName]?.clickCapture !== false
|
||||
|
|
@ -528,6 +550,10 @@ const getBindProps = (schema, scope) => {
|
|||
const { id, componentName } = schema
|
||||
const invalidity = configure[componentName]?.invalidity || []
|
||||
|
||||
if (componentName === 'CanvasPlaceholder') {
|
||||
return {}
|
||||
}
|
||||
|
||||
const bindProps = {
|
||||
...parseData(schema.props, scope),
|
||||
[DESIGN_UIDKEY]: id,
|
||||
|
|
@ -561,14 +587,30 @@ const getBindProps = (schema, scope) => {
|
|||
return bindProps
|
||||
}
|
||||
|
||||
const renderDefault = (children, scope, parent) =>
|
||||
children.map?.((child) =>
|
||||
h(renderer, {
|
||||
schema: child,
|
||||
scope,
|
||||
parent
|
||||
})
|
||||
)
|
||||
const getLoopScope = ({ scope, index, item, loopArgs }) => {
|
||||
return {
|
||||
...scope,
|
||||
...(parseLoopArgs({
|
||||
item,
|
||||
index,
|
||||
loopArgs
|
||||
}) || {})
|
||||
}
|
||||
}
|
||||
|
||||
const injectPlaceHolder = (componentName, children) => {
|
||||
const isEmptyArr = Array.isArray(children) && !children.length
|
||||
|
||||
if (configure[componentName]?.isContainer && (!children || isEmptyArr)) {
|
||||
return [
|
||||
{
|
||||
componentName: 'CanvasPlaceholder'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
const renderGroup = (children, scope, parent) => {
|
||||
return children.map?.((schema) => {
|
||||
|
|
@ -589,10 +631,14 @@ const renderGroup = (children, scope, parent) => {
|
|||
return null
|
||||
}
|
||||
|
||||
const renderChildren = injectPlaceHolder(componentName, children)
|
||||
|
||||
return h(
|
||||
getComponent(componentName),
|
||||
getBindProps(schema, mergeScope),
|
||||
Array.isArray(children) ? renderSlot(children, mergeScope, schema) : parseData(children, mergeScope)
|
||||
Array.isArray(renderChildren)
|
||||
? renderSlot(renderChildren, mergeScope, schema)
|
||||
: parseData(renderChildren, mergeScope)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -600,32 +646,25 @@ const renderGroup = (children, scope, parent) => {
|
|||
})
|
||||
}
|
||||
|
||||
const getLoopScope = ({ scope, index, item, loopArgs }) => {
|
||||
return {
|
||||
...scope,
|
||||
...(parseLoopArgs({
|
||||
item,
|
||||
index,
|
||||
loopArgs
|
||||
}) || {})
|
||||
}
|
||||
}
|
||||
|
||||
const getChildren = (schema, mergeScope) => {
|
||||
const { componentName, children } = schema
|
||||
const renderChildren = injectPlaceHolder(componentName, children)
|
||||
|
||||
const component = getComponent(componentName)
|
||||
const isNative = typeof component === 'string'
|
||||
const isCustElm = custElements[componentName]
|
||||
const isCustomElm = customElements[componentName]
|
||||
const isGroup = checkGroup(componentName)
|
||||
|
||||
if (Array.isArray(children)) {
|
||||
if (isNative || isCustElm) {
|
||||
return renderDefault(children, mergeScope, schema)
|
||||
if (Array.isArray(renderChildren)) {
|
||||
if (isNative || isCustomElm) {
|
||||
return renderDefault(renderChildren, mergeScope, schema)
|
||||
} else {
|
||||
return isGroup ? renderGroup(children, mergeScope, schema) : renderSlot(children, mergeScope, schema, isCustElm)
|
||||
return isGroup
|
||||
? renderGroup(renderChildren, mergeScope, schema)
|
||||
: renderSlot(renderChildren, mergeScope, schema, isCustomElm)
|
||||
}
|
||||
} else {
|
||||
return parseData(children, mergeScope)
|
||||
return parseData(renderChildren, mergeScope)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
import * as Vue from 'vue'
|
||||
import * as VueI18n from 'vue-i18n'
|
||||
import { addScript, addStyle, dynamicImportComponents, updateDependencies } from '../common'
|
||||
import TinyI18nHost, { I18nInjectionKey } from '@opentiny/tiny-engine-common/js/i18n'
|
||||
import TinyI18nHost, { I18nInjectionKey } from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
import * as TinyWebcomponentCore from '@opentiny/tiny-engine-webcomponent-core'
|
||||
import TinyVue from '@opentiny/vue'
|
||||
import * as TinyVueIcon from '@opentiny/vue-icon'
|
||||
|
|
@ -26,73 +26,77 @@ const dispatch = (name, data) => {
|
|||
window.parent.document.dispatchEvent(new CustomEvent(name, data))
|
||||
}
|
||||
|
||||
dispatch('beforeCanvasReady')
|
||||
const initRenderContext = () => {
|
||||
dispatch('beforeCanvasReady')
|
||||
|
||||
TinyI18nHost.lowcode = lowcode
|
||||
TinyI18nHost.lowcode = lowcode
|
||||
|
||||
// 目前先兼容老区块发布的代码,后期区块发布整改后再删除
|
||||
window.React = {}
|
||||
window.React.createElement = Vue.h
|
||||
// 目前先兼容老区块发布的代码,后期区块发布整改后再删除
|
||||
window.React = {}
|
||||
window.React.createElement = Vue.h
|
||||
|
||||
// 不能采用new Proxy代理Vue的方案,在编译后的vue会报错警告,采用一下方案扩展用于注入一些区块加载逻辑
|
||||
window.Vue = {
|
||||
...Vue,
|
||||
resolveComponent(...args) {
|
||||
// 此处先执行vue内部的解析组件的方法,如果可以拿到组件对象则直接返回,反之则去注册区块
|
||||
const component = Vue.resolveComponent(args[0])
|
||||
if (component && typeof component === 'string') {
|
||||
return getComponent(capitalize(camelize(args[0])))
|
||||
} else {
|
||||
return component
|
||||
}
|
||||
},
|
||||
// renderSlot方法第三个参数是作用域插槽传递的数据,格式{ data: vue.unref(state).componentData }
|
||||
renderSlot(...args) {
|
||||
// 获取当前vue的实例
|
||||
const instance = Vue.getCurrentInstance()
|
||||
|
||||
// 获取当前区块名称
|
||||
const blockName = instance.attrs.dataTag
|
||||
|
||||
const [, slotName, slotData] = args
|
||||
|
||||
// 如果是作用域插槽,则获取作用域插槽传递过来的参数
|
||||
if (slotData) {
|
||||
if (blockSlotDataMap[blockName]) {
|
||||
blockSlotDataMap[blockName][slotName] = slotData
|
||||
// 不能采用new Proxy代理Vue的方案,在编译后的vue会报错警告,采用一下方案扩展用于注入一些区块加载逻辑
|
||||
window.Vue = {
|
||||
...Vue,
|
||||
resolveComponent(...args) {
|
||||
// 此处先执行vue内部的解析组件的方法,如果可以拿到组件对象则直接返回,反之则去注册区块
|
||||
const component = Vue.resolveComponent(args[0])
|
||||
if (component && typeof component === 'string') {
|
||||
return getComponent(capitalize(camelize(args[0])))
|
||||
} else {
|
||||
blockSlotDataMap[blockName] = { [slotName]: slotData }
|
||||
return component
|
||||
}
|
||||
}
|
||||
},
|
||||
// renderSlot方法第三个参数是作用域插槽传递的数据,格式{ data: vue.unref(state).componentData }
|
||||
renderSlot(...args) {
|
||||
// 获取当前vue的实例
|
||||
const instance = Vue.getCurrentInstance()
|
||||
|
||||
/**
|
||||
* vue源码中的renderSlot会忽略default插槽的名称,所以这里必须手动添加args第三个参数的name值
|
||||
* vue源码如右所示:if (name !== 'default') props.name = name; return createVNode('slot', props, fallback && fallback());
|
||||
**/
|
||||
if (slotName === 'default') {
|
||||
args[2] = args[2] || {}
|
||||
args[2].name = slotName
|
||||
}
|
||||
// 获取当前区块名称
|
||||
const blockName = instance.attrs.dataTag
|
||||
|
||||
return Vue.renderSlot(...args)
|
||||
const [, slotName, slotData] = args
|
||||
|
||||
// 如果是作用域插槽,则获取作用域插槽传递过来的参数
|
||||
if (slotData) {
|
||||
if (blockSlotDataMap[blockName]) {
|
||||
blockSlotDataMap[blockName][slotName] = slotData
|
||||
} else {
|
||||
blockSlotDataMap[blockName] = { [slotName]: slotData }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vue源码中的renderSlot会忽略default插槽的名称,所以这里必须手动添加args第三个参数的name值
|
||||
* vue源码如右所示:if (name !== 'default') props.name = name; return createVNode('slot', props, fallback && fallback());
|
||||
**/
|
||||
if (slotName === 'default') {
|
||||
args[2] = args[2] || {}
|
||||
args[2].name = slotName
|
||||
}
|
||||
|
||||
return Vue.renderSlot(...args)
|
||||
}
|
||||
}
|
||||
|
||||
window.VueI18n = VueI18n
|
||||
window.TinyVue = TinyVue
|
||||
window.TinyVueIcon = TinyVueIcon
|
||||
window.TinyWebcomponentCore = TinyWebcomponentCore
|
||||
window.TinyI18nHost = TinyI18nHost
|
||||
window.TinyLowcodeComponent = {}
|
||||
window.TinyComponentLibs = {}
|
||||
|
||||
Object.entries(TinyVue).forEach(([_key, component]) => {
|
||||
const { name } = component
|
||||
if (name) {
|
||||
window.TinyLowcodeComponent[name] = component
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener('updateDependencies', updateDependencies)
|
||||
}
|
||||
|
||||
window.VueI18n = VueI18n
|
||||
window.TinyVue = TinyVue
|
||||
window.TinyVueIcon = TinyVueIcon
|
||||
window.TinyWebcomponentCore = TinyWebcomponentCore
|
||||
window.TinyI18nHost = TinyI18nHost
|
||||
window.TinyLowcodeComponent = {}
|
||||
window.TinyComponentLibs = {}
|
||||
|
||||
Object.entries(TinyVue).forEach(([_key, component]) => {
|
||||
const { name } = component
|
||||
if (name) {
|
||||
window.TinyLowcodeComponent[name] = component
|
||||
}
|
||||
})
|
||||
|
||||
let App = null
|
||||
|
||||
const renderer = {
|
||||
|
|
@ -111,11 +115,15 @@ const create = () => {
|
|||
|
||||
document.body.remove()
|
||||
document.body = document.createElement('body')
|
||||
const app = document.createElement('div')
|
||||
app.setAttribute('id', 'app')
|
||||
document.body.appendChild(app)
|
||||
|
||||
dispatch('canvasReady', { detail: renderer })
|
||||
|
||||
App = Vue.createApp(Main).use(TinyI18nHost).provide(I18nInjectionKey, TinyI18nHost)
|
||||
App.config.globalProperties.lowcodeConfig = window.parent.TinyGlobalConfig
|
||||
App.mount(document.body)
|
||||
App.mount(document.querySelector('#app'))
|
||||
|
||||
new ResizeObserver(() => {
|
||||
dispatch('canvasResize')
|
||||
|
|
@ -125,6 +133,7 @@ const create = () => {
|
|||
}
|
||||
|
||||
export const createRender = (config) => {
|
||||
initRenderContext()
|
||||
const { dslMode, canvasOptions } = config
|
||||
const { styles = [], scripts = [] } = canvasOptions[dslMode]
|
||||
const { styles: thirdStyles = [], scripts: thirdScripts = [] } = window.thirdPartyDeps || {}
|
||||
|
|
@ -134,5 +143,3 @@ export const createRender = (config) => {
|
|||
...scripts.map((src) => addScript(src)).concat([...thirdStyles, ...styles].map((src) => addStyle(src)))
|
||||
]).finally(create)
|
||||
}
|
||||
|
||||
document.addEventListener('updateDependencies', updateDependencies)
|
||||
|
|
|
|||
|
|
@ -10,89 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import CanvasContainer from './components/container/CanvasContainer.vue'
|
||||
import CanvasAction from './components/container/CanvasAction.vue'
|
||||
import CanvasDragItem from './components/container/CanvasDragItem.vue'
|
||||
import CanvasFooter from './components/container/CanvasFooter.vue'
|
||||
import CanvasResize from './components/container/CanvasResize.vue'
|
||||
import Builtin from './components/builtin/builtin.json'
|
||||
import RenderMain, { api as renderApi } from './components/render/RenderMain'
|
||||
import { createRender } from './components/render/runner'
|
||||
import {
|
||||
dragStart,
|
||||
updateRect,
|
||||
getContext,
|
||||
getNodePath,
|
||||
dragMove,
|
||||
setLocales,
|
||||
setState,
|
||||
deleteState,
|
||||
getRenderer,
|
||||
clearSelect,
|
||||
selectNode,
|
||||
hoverNode,
|
||||
insertNode,
|
||||
removeNode,
|
||||
addComponent,
|
||||
setPageCss,
|
||||
addScript,
|
||||
addStyle,
|
||||
getNode,
|
||||
getCurrent,
|
||||
setSchema,
|
||||
setUtils,
|
||||
getSchema,
|
||||
setI18n,
|
||||
getCanvasType,
|
||||
setCanvasType,
|
||||
setProps,
|
||||
setGlobalState,
|
||||
getGlobalState,
|
||||
getDocument,
|
||||
canvasDispatch
|
||||
} from './components/container/container'
|
||||
|
||||
export {
|
||||
CanvasContainer,
|
||||
CanvasAction,
|
||||
CanvasFooter,
|
||||
CanvasDragItem,
|
||||
CanvasResize,
|
||||
RenderMain,
|
||||
renderApi,
|
||||
Builtin,
|
||||
dragStart,
|
||||
dragMove,
|
||||
updateRect,
|
||||
getContext,
|
||||
getNodePath,
|
||||
getNode,
|
||||
getCurrent,
|
||||
setSchema,
|
||||
setUtils,
|
||||
getSchema,
|
||||
setLocales,
|
||||
setState,
|
||||
deleteState,
|
||||
setI18n,
|
||||
getRenderer,
|
||||
clearSelect,
|
||||
selectNode,
|
||||
insertNode,
|
||||
removeNode,
|
||||
hoverNode,
|
||||
addComponent,
|
||||
setPageCss,
|
||||
addScript,
|
||||
addStyle,
|
||||
getCanvasType,
|
||||
setCanvasType,
|
||||
setProps,
|
||||
setGlobalState,
|
||||
getGlobalState,
|
||||
getDocument,
|
||||
canvasDispatch,
|
||||
createRender
|
||||
}
|
||||
|
||||
export default CanvasContainer
|
||||
export { default as CanvasContainer } from './components/container/CanvasContainer.vue'
|
||||
export { default as CanvasDragItem } from './components/container/CanvasDragItem.vue'
|
||||
export { default as CanvasFooter } from './components/container/CanvasFooter.vue'
|
||||
export { createRender } from './components/render/runner'
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ export default defineConfig({
|
|||
'@': path.resolve(__dirname, 'src')
|
||||
}
|
||||
},
|
||||
define: {
|
||||
'process.env': {}
|
||||
},
|
||||
plugins: [
|
||||
vue({
|
||||
template: {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export default {
|
|||
const params = []
|
||||
const data = props?.data?.params || {}
|
||||
|
||||
curValue.replace(/\$\{(.+?)\}/g, (substr, key) => {
|
||||
curValue.replace(/\{(.+?)\}/g, (substr, key) => {
|
||||
key && params.push({ name: key, value: data[key] || '' })
|
||||
})
|
||||
paramsForm.value = params
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
:modal="false"
|
||||
:fullscreen="true"
|
||||
:append-to-body="true"
|
||||
title="Schema 本地与线上差异"
|
||||
title="Schema 线上与本地差异"
|
||||
>
|
||||
<vue-monaco
|
||||
v-if="state.compareVisible"
|
||||
|
|
@ -82,8 +82,8 @@ import {
|
|||
FormItem as TinyFormItem
|
||||
} from '@opentiny/vue'
|
||||
import { theme } from '@opentiny/tiny-engine-controller/adapter'
|
||||
import { useLayout } from '@opentiny/tiny-engine-controller'
|
||||
import { getSchema, setSchema } from '@opentiny/tiny-engine-canvas'
|
||||
import { useLayout, useNotify, useCanvas } from '@opentiny/tiny-engine-controller'
|
||||
import { constants } from '@opentiny/tiny-engine-utils'
|
||||
import VueMonaco from './VueMonaco.vue'
|
||||
|
||||
export default {
|
||||
|
|
@ -106,6 +106,7 @@ export default {
|
|||
},
|
||||
emits: ['update:visible'],
|
||||
setup(props, { emit, attrs }) {
|
||||
const { COMPONENT_NAME } = constants
|
||||
const formState = reactive({
|
||||
deployInfo: '',
|
||||
version: '',
|
||||
|
|
@ -186,9 +187,10 @@ export default {
|
|||
const remote = await api.getBlockById(block?.id)
|
||||
const originalObj = remote?.content || {}
|
||||
state.originalCode = JSON.stringify(originalObj, null, 2)
|
||||
const getSchema = useCanvas().canvasApi.value.getSchema
|
||||
|
||||
// 转为普通对象,和线上代码顺序保持一致
|
||||
const pageSchema = getSchema() || {}
|
||||
const pageSchema = getSchema?.() || {}
|
||||
if (pageSchema.componentName === 'Block') {
|
||||
state.code = JSON.stringify(pageSchema, null, 2)
|
||||
} else {
|
||||
|
|
@ -212,10 +214,21 @@ export default {
|
|||
}
|
||||
|
||||
const save = () => {
|
||||
const pageSchema = JSON.parse(state.newCode)
|
||||
setSchema(pageSchema)
|
||||
|
||||
close()
|
||||
if (!state.newCode) {
|
||||
close()
|
||||
return
|
||||
}
|
||||
try {
|
||||
const pageSchema = JSON.parse(state.newCode)
|
||||
const setSchema = useCanvas().canvasApi.value.setSchema
|
||||
setSchema?.({ ...pageSchema, componentName: COMPONENT_NAME.Block })
|
||||
close()
|
||||
} catch (err) {
|
||||
useNotify({
|
||||
type: 'error',
|
||||
message: '代码静态检查有错误,请先修改后再保存'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import { capitalize } from '@vue/shared'
|
|||
import { extend } from '@opentiny/vue-renderless/common/object'
|
||||
import { Input as TinyInput, Form as TinyForm, FormItem as TinyFormItem, Popover as TinyPopover } from '@opentiny/vue'
|
||||
import { useLayout, useModal, useCanvas, useBlock } from '@opentiny/tiny-engine-controller'
|
||||
import { getSchema, getCurrent } from '@opentiny/tiny-engine-canvas'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -38,7 +37,8 @@ export default {
|
|||
const { pageState } = useCanvas()
|
||||
const { addBlockEvent, removeEventLink, getCurrentBlock, appendEventEmit } = useBlock()
|
||||
const { PLUGIN_NAME, activePlugin } = useLayout()
|
||||
const { schema } = getSchema()
|
||||
|
||||
const { schema } = useCanvas().canvasApi.value?.getSchema?.() || {}
|
||||
const events = schema?.events || []
|
||||
const eventsList = Object.entries(events).map(([key, value]) => {
|
||||
return {
|
||||
|
|
@ -88,7 +88,7 @@ export default {
|
|||
|
||||
const {
|
||||
schema: { id, componentName }
|
||||
} = getCurrent()
|
||||
} = useCanvas().canvasApi.value?.getCurrent?.() || {}
|
||||
|
||||
const newEvent = extend(true, {}, data.metaEvent, {
|
||||
linked: {
|
||||
|
|
@ -117,7 +117,7 @@ export default {
|
|||
const editEvent = (item, data) => {
|
||||
const {
|
||||
schema: { id, componentName }
|
||||
} = getCurrent()
|
||||
} = useCanvas().canvasApi.value?.getCurrent?.() || {}
|
||||
|
||||
const oldEventName = data.linkedEventName
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import { reactive, computed } from 'vue'
|
|||
import { extend } from '@opentiny/vue-renderless/common/object'
|
||||
import { Input as TinyInput, Popover as TinyPopover } from '@opentiny/vue'
|
||||
import { useLayout, useModal, useCanvas, useBlock, useHistory } from '@opentiny/tiny-engine-controller'
|
||||
import { getSchema, getCurrent } from '@opentiny/tiny-engine-canvas'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -36,10 +35,10 @@ export default {
|
|||
},
|
||||
setup(props) {
|
||||
const { confirm } = useModal()
|
||||
const { pageState } = useCanvas()
|
||||
const { pageState, canvasApi } = useCanvas()
|
||||
const { addBlockProperty, removePropertyLink, getCurrentBlock, editBlockProperty } = useBlock()
|
||||
const { PLUGIN_NAME, activePlugin } = useLayout()
|
||||
const { schema } = getSchema()
|
||||
const { schema } = canvasApi.value.getSchema?.() || {}
|
||||
|
||||
const state = reactive({
|
||||
newPropertyName: ''
|
||||
|
|
@ -68,7 +67,7 @@ export default {
|
|||
exec() {
|
||||
const {
|
||||
schema: { id, componentName }
|
||||
} = getCurrent()
|
||||
} = canvasApi.value?.getCurrent?.() || {}
|
||||
const newProperty = extend(true, {}, property, {
|
||||
property: state.newPropertyName || `${property.property}${id}`,
|
||||
linked: {
|
||||
|
|
@ -87,7 +86,7 @@ export default {
|
|||
const editProperty = (property) => {
|
||||
const {
|
||||
schema: { id, componentName }
|
||||
} = getCurrent()
|
||||
} = canvasApi.value?.getCurrent?.() || {}
|
||||
|
||||
// 如果之前有关联关系,则需要去除关联
|
||||
if (props.data?.linked) {
|
||||
|
|
|
|||
|
|
@ -103,14 +103,14 @@ import { inject, computed, watch, ref, reactive, provide } from 'vue'
|
|||
import { Popover, Tooltip } from '@opentiny/vue'
|
||||
import { IconWriting, IconHelpCircle, IconPlusCircle } from '@opentiny/vue-icon'
|
||||
import { typeOf } from '@opentiny/vue-renderless/common/type'
|
||||
import i18n from '../js/i18n'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
import { MetaComponents } from '../index'
|
||||
import MetaBindVariable from './MetaBindVariable.vue'
|
||||
import MetaCodeEditor from './MetaCodeEditor.vue'
|
||||
import MultiTypeSelector from './MultiTypeSelector.vue'
|
||||
import { useHistory, useProperties, useResource, useLayout, useCanvas } from '@opentiny/tiny-engine-controller'
|
||||
import { generateFunction } from '@opentiny/tiny-engine-controller/utils'
|
||||
import { SCHEMA_DATA_TYPE, PAGE_STATUS, TYPES } from '../js/constants'
|
||||
import { SCHEMA_DATA_TYPE, PAGE_STATUS, TYPES } from '@opentiny/tiny-engine-controller/js/constants'
|
||||
|
||||
const hasRule = (required, rules) => {
|
||||
if (required) {
|
||||
|
|
@ -244,7 +244,7 @@ export default {
|
|||
})
|
||||
|
||||
const updateValue = (value) => {
|
||||
const { property } = props.property
|
||||
const { property, type } = props.property
|
||||
const { setProp } = useProperties()
|
||||
|
||||
// 是否双向绑定
|
||||
|
|
@ -283,7 +283,7 @@ export default {
|
|||
}
|
||||
|
||||
if (props.isTopLayer) {
|
||||
setProp(property, value)
|
||||
setProp(property, value, type)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,14 +78,13 @@
|
|||
<script lang="jsx">
|
||||
import { reactive, ref, watchEffect, onBeforeUnmount } from 'vue'
|
||||
import { Button, DialogBox, Popover, Search, Alert } from '@opentiny/vue'
|
||||
import { getGlobalConfig, useModal, usePage, useNotify } from '@opentiny/tiny-engine-controller'
|
||||
import { getGlobalConfig, useModal, usePage, useNotify, useCanvas } from '@opentiny/tiny-engine-controller'
|
||||
import { theme } from '@opentiny/tiny-engine-controller/adapter'
|
||||
import { getSchema } from '@opentiny/tiny-engine-canvas'
|
||||
import MetaListItems from './MetaListItems.vue'
|
||||
import { iconYes } from '@opentiny/vue-icon'
|
||||
import VueMonaco from './VueMonaco.vue'
|
||||
import { initCompletion } from '../js/completion'
|
||||
import { initLinter, lint } from '../js/linter'
|
||||
import { initCompletion } from '@opentiny/tiny-engine-controller/js/completion'
|
||||
import { initLinter, lint } from '@opentiny/tiny-engine-controller/js/linter'
|
||||
import { SvgButton } from '../index'
|
||||
|
||||
export default {
|
||||
|
|
@ -125,11 +124,12 @@ export default {
|
|||
bindLifeCycles: {},
|
||||
editorValue: '{}',
|
||||
hasError: false,
|
||||
linterWorker: null
|
||||
linterWorker: null,
|
||||
completionProvider: null
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
state.bindLifeCycles = props.bindLifeCycles || getSchema()?.lifeCycles || {}
|
||||
state.bindLifeCycles = props.bindLifeCycles || useCanvas().canvasApi.value?.getSchema()?.lifeCycles || {}
|
||||
})
|
||||
|
||||
const searchLifeCyclesList = (value) => {
|
||||
|
|
@ -141,7 +141,7 @@ export default {
|
|||
}
|
||||
|
||||
const syncLifeCycle = () => {
|
||||
const currentSchema = getSchema()
|
||||
const currentSchema = useCanvas().canvasApi.value?.getSchema?.()
|
||||
const pageContent = getPageContent()
|
||||
const { id, fileName } = pageContent
|
||||
if (id === currentSchema.id || fileName === currentSchema.fileName) {
|
||||
|
|
@ -164,7 +164,8 @@ export default {
|
|||
|
||||
const openLifeCyclesPanel = (item) => {
|
||||
state.title = item
|
||||
const bindLifeCycleSource = props.bindLifeCycles?.[item] || getSchema().lifeCycles?.[item]
|
||||
const bindLifeCycleSource =
|
||||
props.bindLifeCycles?.[item] || useCanvas().canvasApi.value?.getSchema?.()?.lifeCycles?.[item]
|
||||
state.editorValue =
|
||||
bindLifeCycleSource?.value ||
|
||||
`function ${item} (${item === 'setup' ? '{ props, state, watch, onMounted }' : ''}) {} `
|
||||
|
|
@ -210,7 +211,7 @@ export default {
|
|||
return
|
||||
}
|
||||
// Lowcode API 提示
|
||||
initCompletion(editorRef.value.getMonaco())
|
||||
state.completionProvider = initCompletion(editorRef.value.getMonaco(), editorRef.value.getEditor()?.getModel())
|
||||
|
||||
// 初始化 ESLint worker
|
||||
state.linterWorker = initLinter(editor, editorRef.value.getMonaco(), state)
|
||||
|
|
@ -226,6 +227,9 @@ export default {
|
|||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
state.completionProvider?.forEach?.((provider) => {
|
||||
provider.dispose()
|
||||
})
|
||||
// 终止 ESLint worker
|
||||
state.linterWorker?.terminate?.()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<a class="help-box" :href="href" target="_blank">
|
||||
<svg-button id="help-icon" :name="iconName" :tips="tips"></svg-button>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SvgButton from './SvgButton.vue'
|
||||
export default {
|
||||
components: {
|
||||
SvgButton
|
||||
},
|
||||
props: {
|
||||
href: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
tips: {
|
||||
type: String,
|
||||
default: '帮助'
|
||||
},
|
||||
iconName: {
|
||||
type: String,
|
||||
default: 'plugin-icon-plugin-help'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.help-box {
|
||||
width: 24px;
|
||||
height: 42px;
|
||||
|
||||
#help-icon {
|
||||
:deep(.svg-icon.icon-plugin-icon-plugin-help) {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
</slot>
|
||||
|
||||
<tiny-dialog-box
|
||||
v-if="dialogShouldInitialize"
|
||||
:visible="state.isVisible"
|
||||
title="变量绑定"
|
||||
width="48%"
|
||||
|
|
@ -123,15 +124,14 @@ import { reactive, ref, computed, nextTick, watch } from 'vue'
|
|||
import { camelize, capitalize } from '@vue/shared'
|
||||
import { Button, DialogBox, Search, Switch, Input, Tooltip, Alert } from '@opentiny/vue'
|
||||
import { useHttp } from '@opentiny/tiny-engine-http'
|
||||
import { getSchema, getGlobalState, setState, getNode, getCurrent } from '@opentiny/tiny-engine-canvas'
|
||||
import { useCanvas, useResource, useLayout, useApp, useProperties, useData } from '@opentiny/tiny-engine-controller'
|
||||
import { theme } from '@opentiny/tiny-engine-controller/adapter'
|
||||
import { constants } from '@opentiny/tiny-engine-utils'
|
||||
import SvgButton from './SvgButton.vue'
|
||||
import { parse, traverse, generate } from '../js/ast'
|
||||
import { DEFAULT_LOOP_NAME } from '../js/constants.js'
|
||||
import { parse, traverse, generate } from '@opentiny/tiny-engine-controller/js/ast'
|
||||
import { DEFAULT_LOOP_NAME } from '@opentiny/tiny-engine-controller/js/constants'
|
||||
import MonacoEditor from './VueMonaco.vue'
|
||||
import { formatString } from '../js/ast.js'
|
||||
import { formatString } from '@opentiny/tiny-engine-controller/js/ast'
|
||||
|
||||
const { EXPRESSION_TYPE } = constants
|
||||
|
||||
|
|
@ -149,6 +149,12 @@ const CONSTANTS = {
|
|||
}
|
||||
|
||||
const getJsSlot = () => {
|
||||
const { getNode, getCurrent } = useCanvas().canvasApi.value || {}
|
||||
|
||||
if (!getNode || !getCurrent) {
|
||||
return [false, {}]
|
||||
}
|
||||
|
||||
const jsSlot = getNode(getCurrent()?.parent?.id, true)?.parent
|
||||
|
||||
return [jsSlot?.type === 'JSSlot', jsSlot]
|
||||
|
|
@ -181,6 +187,10 @@ export default {
|
|||
modelValue: {
|
||||
type: [String, Number, Boolean, Array, Object, Date],
|
||||
default: ''
|
||||
},
|
||||
lazyLoad: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
|
|
@ -393,10 +403,10 @@ export default {
|
|||
const confirm = () => {
|
||||
let variableContent = state.isEditorEditMode ? editor.value?.getEditor().getValue() : state.variable
|
||||
|
||||
const { setSaved, canvasApi } = useCanvas()
|
||||
// 如果新旧值不一样就显示未保存状态
|
||||
if (oldValue !== variableContent) {
|
||||
const { pageState } = useCanvas()
|
||||
pageState.isSaved = false
|
||||
setSaved(false)
|
||||
variableContent = formatString(variableContent, 'javascript')
|
||||
}
|
||||
|
||||
|
|
@ -405,14 +415,14 @@ export default {
|
|||
|
||||
if (variableContent) {
|
||||
if (state.bindPrefix === CONSTANTS.DATASOUCEPREFIX) {
|
||||
const pageSchema = getSchema()
|
||||
const pageSchema = canvasApi.value.getSchema()
|
||||
const stateName = state.variable.replace(`${CONSTANTS.STATE}`, '')
|
||||
const staticData = state.variableContent.map(({ _id, ...other }) => other)
|
||||
|
||||
pageSchema.state[stateName] = staticData
|
||||
|
||||
// 设置画布上下文环境,让画布触发更新渲染
|
||||
setState({ [stateName]: staticData })
|
||||
canvasApi.value.setState({ [stateName]: staticData })
|
||||
|
||||
// 这里在setup生命周期函数内部处理用户真实环境中的数据源请求
|
||||
genRemoteMethodToLifeSetup(stateName, state.dataSouce, pageSchema)
|
||||
|
|
@ -441,11 +451,13 @@ export default {
|
|||
return ''
|
||||
}
|
||||
|
||||
const dialogShouldInitialize = ref(!props.lazyLoad)
|
||||
const open = () => {
|
||||
dialogShouldInitialize.value = true
|
||||
state.isVisible = true
|
||||
state.variableName = bindKey.value
|
||||
state.variable = getInitVariable()
|
||||
state.variables = getSchema()?.state || {}
|
||||
state.variables = useCanvas().canvasApi.value.getSchema()?.state || {}
|
||||
state.bindPrefix = CONSTANTS.STATE
|
||||
state.variableContent = state.variables[bindKey.value]
|
||||
nextTick(() => window.dispatchEvent(new Event('resize')))
|
||||
|
|
@ -453,6 +465,8 @@ export default {
|
|||
|
||||
const selectItem = (item) => {
|
||||
state.active = item.id
|
||||
const { canvasApi } = useCanvas()
|
||||
|
||||
if (item.id === 'function') {
|
||||
state.bindPrefix = CONSTANTS.THIS
|
||||
const { PLUGIN_NAME, getPluginApi } = useLayout()
|
||||
|
|
@ -468,7 +482,7 @@ export default {
|
|||
state.variables = bridge
|
||||
} else if (item.id === 'props') {
|
||||
state.bindPrefix = CONSTANTS.PROPS
|
||||
const properties = getSchema()?.schema?.properties
|
||||
const properties = canvasApi.value.getSchema()?.schema?.properties
|
||||
const bindProperties = {}
|
||||
properties?.forEach(({ content }) => {
|
||||
content.forEach(({ property }) => {
|
||||
|
|
@ -494,7 +508,7 @@ export default {
|
|||
state.bindPrefix = CONSTANTS.STORE
|
||||
state.variables = {}
|
||||
|
||||
const stores = getGlobalState()
|
||||
const stores = canvasApi.value.getGlobalState()
|
||||
stores.forEach(({ id, state: storeState = {}, getters = {} }) => {
|
||||
const loadProp = (prop) => {
|
||||
const propBinding = `${id}.${prop}`
|
||||
|
|
@ -515,7 +529,7 @@ export default {
|
|||
state.variables = params.reduce((variables, param) => ({ ...variables, [param]: param }), {})
|
||||
} else {
|
||||
state.bindPrefix = CONSTANTS.STATE
|
||||
state.variables = getSchema()?.[item.id]
|
||||
state.variables = canvasApi.value.getSchema()?.[item.id]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -526,6 +540,7 @@ export default {
|
|||
remove,
|
||||
cancel,
|
||||
confirm,
|
||||
dialogShouldInitialize,
|
||||
open,
|
||||
selectItem,
|
||||
state,
|
||||
|
|
@ -538,7 +553,7 @@ export default {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.icon {
|
||||
margin-left: 6px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.meta-bind-variable-dialog-box {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<script>
|
||||
import { ref, watchEffect } from 'vue'
|
||||
import { ButtonGroup } from '@opentiny/vue'
|
||||
import i18n from '../js/i18n'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
|
||||
export default {
|
||||
name: 'MetaButtonGroup',
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<script>
|
||||
import { ref, watchEffect } from 'vue'
|
||||
import { Cascader } from '@opentiny/vue'
|
||||
import i18n from '../js/i18n'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
|
||||
export default {
|
||||
name: 'MetaCascader',
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<script>
|
||||
import { ref, watchEffect, computed } from 'vue'
|
||||
import { CheckboxGroup } from '@opentiny/vue'
|
||||
import i18n from '../js/i18n'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
|
||||
export default {
|
||||
name: 'MetaCheckboxGroup',
|
||||
|
|
|
|||
|
|
@ -1,28 +1,29 @@
|
|||
<template>
|
||||
<div class="editor-wrap">
|
||||
<slot>
|
||||
<slot :open="open">
|
||||
<div v-if="buttonShowContent" :class="['full-width', { 'empty-color': value === '' }]" @click="open">
|
||||
<span>{{ value === '' ? buttonLabel : value?.slice(0, 30) }}</span>
|
||||
<svg-icon class="edit-icon" name="flow-edit"></svg-icon>
|
||||
<span class="text-content text-ellipsis-multiple">{{ value === '' ? buttonLabel : value }}</span>
|
||||
<svg-icon class="edit-icon" name="edit"></svg-icon>
|
||||
</div>
|
||||
<tiny-button v-else class="edit-btn" @click="open">
|
||||
{{ buttonLabel }}
|
||||
</tiny-button>
|
||||
</slot>
|
||||
<tiny-dialog-box
|
||||
v-model:visible="editorState.show"
|
||||
:title="titleLabel"
|
||||
width="50vw"
|
||||
class="meta-code-editor-dialog-box"
|
||||
append-to-body
|
||||
v-model:visible="editorState.show"
|
||||
:title="titleLabel"
|
||||
width="50vw"
|
||||
class="meta-code-editor-dialog-box"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="source-code">
|
||||
<div v-if="editorTipsTitle" class="header-tips-container">
|
||||
<span class="header-tips-title" :title="editorTipsTitle">{{ editorTipsTitle }}</span>
|
||||
<div
|
||||
v-if="editorTipsDemo"
|
||||
class="header-tips-showdemo"
|
||||
@click="editorState.showEditorDemo = !editorState.showEditorDemo"
|
||||
v-if="editorTipsDemo"
|
||||
class="header-tips-showdemo"
|
||||
@click="editorState.showEditorDemo = !editorState.showEditorDemo"
|
||||
>
|
||||
<span>{{ editorState.showEditorDemo ? $t('common.collapseExample') : $t('common.expandExample') }}</span>
|
||||
<icon-chevron-up v-if="editorState.showEditorDemo" class="collapse-icon"></icon-chevron-up>
|
||||
|
|
@ -35,22 +36,28 @@
|
|||
</div>
|
||||
</div>
|
||||
<monaco-editor
|
||||
ref="editor"
|
||||
class="source-code-content"
|
||||
:value="value"
|
||||
:options="options"
|
||||
@editorDidMount="editorDidMount"
|
||||
ref="editor"
|
||||
class="source-code-content"
|
||||
:value="value"
|
||||
:options="options"
|
||||
@editorDidMount="editorDidMount"
|
||||
></monaco-editor>
|
||||
<div v-if="showErrorMsg" class="error-msg">{{ editorState.errorMsg }}</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="btn-box">
|
||||
<tiny-button type="danger" v-if="language === 'json' && showFormatBtn" @click="formatCode">
|
||||
<tiny-button
|
||||
v-if="language === 'json' && showFormatBtn"
|
||||
class="format-btn"
|
||||
plain
|
||||
type="danger"
|
||||
@click="formatCode"
|
||||
>
|
||||
{{ $t('common.format') }}
|
||||
</tiny-button>
|
||||
<div>
|
||||
<tiny-button @click="close">{{ $t('common.cancel') }}</tiny-button>
|
||||
<tiny-button type="primary" @click="save">{{ $t('common.save') }}</tiny-button>
|
||||
<tiny-button @click="close">{{ $t('common.close') }}</tiny-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -63,8 +70,8 @@ import { reactive, ref, computed, watchEffect, nextTick } from 'vue'
|
|||
import { Button, DialogBox } from '@opentiny/vue'
|
||||
import { iconChevronDown, iconChevronUp } from '@opentiny/vue-icon'
|
||||
import VueMonaco from './VueMonaco.vue'
|
||||
import i18n from '../js/i18n'
|
||||
import { formatString } from '../js/ast.js'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
import { formatString } from '@opentiny/tiny-engine-controller/js/ast'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -139,7 +146,7 @@ export default {
|
|||
|
||||
watchEffect(() => {
|
||||
const { modelValue, dataType } = props
|
||||
const val = dataType ? modelValue?.value : modelValue
|
||||
const val = dataType ? modelValue?.value || '' : modelValue
|
||||
value.value = typeof val === 'string' ? val : JSON.stringify(val, null, 2)
|
||||
})
|
||||
|
||||
|
|
@ -269,19 +276,32 @@ export default {
|
|||
}
|
||||
.btn-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
&:has(.format-btn) {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
.full-width {
|
||||
border: 1px solid #adb0b8;
|
||||
border-radius: 2px;
|
||||
padding: 4px 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--ti-lowcode-meta-codeEditor-border-color);
|
||||
border-radius: 6px;
|
||||
&:hover {
|
||||
border-color: var(--ti-lowcode-meta-codeEditor-border-hover-color);
|
||||
}
|
||||
.text-content {
|
||||
--ellipsis-line: 1;
|
||||
}
|
||||
&.empty-color {
|
||||
color: var(--ti-lowcode-common-text-desc-color);
|
||||
}
|
||||
.edit-icon {
|
||||
margin-left: 4px;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
color: var(--ti-lowcode-common-text-main-color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<meta-list-items class="list" :optionsList="children">
|
||||
<meta-list-items class="list" :optionsList="children" @dragEnd="dragEnd">
|
||||
<template #content="{ data }">
|
||||
<div class="item-text">
|
||||
<div class="tiny-input">
|
||||
|
|
@ -67,7 +67,21 @@ export default {
|
|||
useHistory().addHistory()
|
||||
}
|
||||
|
||||
return { children, addChildren, delChildren }
|
||||
const dragEnd = (params = {}) => {
|
||||
const { oldIndex, newIndex } = params?.moved || {}
|
||||
|
||||
if (oldIndex === undefined || newIndex === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const list = schemaChildren
|
||||
const spliceItem = list.splice(oldIndex, 1)
|
||||
|
||||
list.splice(newIndex, 0, ...spliceItem)
|
||||
children.value = [...list]
|
||||
}
|
||||
|
||||
return { children, addChildren, delChildren, dragEnd }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -49,11 +49,12 @@
|
|||
<script>
|
||||
import { reactive, ref, watchEffect } from 'vue'
|
||||
import { useProperties, useResource } from '@opentiny/tiny-engine-controller'
|
||||
import { IconDel, IconEdit, IconClose } from '@opentiny/vue-icon'
|
||||
import { Form, FormItem, Input, Button, Popover } from '@opentiny/vue'
|
||||
import { IconDel, IconEdit, IconClose, IconPlus } from '@opentiny/vue-icon'
|
||||
import { Form, FormItem, Input, Button, Popover, Tooltip } from '@opentiny/vue'
|
||||
import { utils } from '@opentiny/tiny-engine-utils'
|
||||
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
components: {
|
||||
TinyForm: Form,
|
||||
TinyFormItem: FormItem,
|
||||
|
|
@ -62,7 +63,9 @@ export default {
|
|||
IconEdit: IconEdit(),
|
||||
IconDel: IconDel(),
|
||||
TinyPopover: Popover,
|
||||
IconClose: IconClose()
|
||||
IconClose: IconClose(),
|
||||
IconPlus: IconPlus(),
|
||||
TinyTooltip: Tooltip
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -19,6 +19,7 @@ import { useProperties } from '@opentiny/tiny-engine-controller'
|
|||
import MetaInput from './MetaInput.vue'
|
||||
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
components: {
|
||||
MetaInput
|
||||
},
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import { ref, inject, watchEffect, reactive } from 'vue'
|
|||
import { Input, Tooltip, Form, FormItem } from '@opentiny/vue'
|
||||
import { useProperties, useCanvas, useModal } from '@opentiny/tiny-engine-controller'
|
||||
import SvgICons from '@opentiny/vue-icon'
|
||||
import { verifyJsVarName } from '../js/verification'
|
||||
import { verifyJsVarName } from '@opentiny/tiny-engine-controller/js/verification'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -118,8 +118,8 @@ export default {
|
|||
emit('deleteItem', params)
|
||||
}
|
||||
|
||||
const dragEnd = () => {
|
||||
emit('changeItem')
|
||||
const dragEnd = (value) => {
|
||||
emit('dragEnd', value)
|
||||
}
|
||||
|
||||
const editItem = (params) => {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<script>
|
||||
import { ref, watchEffect, computed } from 'vue'
|
||||
import { RadioGroup, RadioButton } from '@opentiny/vue'
|
||||
import i18n from '../js/i18n'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
|
||||
export default {
|
||||
name: 'MetaRadioGroup',
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
<script>
|
||||
import { onMounted, ref, watchEffect } from 'vue'
|
||||
import { useMessage, useCanvas } from '@opentiny/tiny-engine-controller'
|
||||
import { getSchema } from '@opentiny/tiny-engine-canvas'
|
||||
import MetaCodeEditor from './MetaCodeEditor.vue'
|
||||
import MetaBindVariable from './MetaBindVariable.vue'
|
||||
|
||||
|
|
@ -91,7 +90,7 @@ export default {
|
|||
let newValue = value
|
||||
|
||||
if (value?.type === CONSTANT.JSEXPRESSION) {
|
||||
const pageSchema = getSchema()
|
||||
const pageSchema = useCanvas().canvasApi.value.getSchema()
|
||||
const stateName = value?.value?.replace(CONSTANT.STATE, '')
|
||||
newValue = pageSchema?.state?.[stateName]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
<script>
|
||||
import { computed, reactive, watchEffect } from 'vue'
|
||||
import { Select, Option, OptionGroup, Tooltip } from '@opentiny/vue'
|
||||
import i18n from '../js/i18n'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@
|
|||
<script>
|
||||
import { ref, watchEffect, nextTick } from 'vue'
|
||||
import { Popover } from '@opentiny/vue'
|
||||
import { useProperties, useResource, useModal } from '@opentiny/tiny-engine-controller'
|
||||
import { updateRect } from '@opentiny/tiny-engine-canvas'
|
||||
import { useProperties, useResource, useModal, useCanvas } from '@opentiny/tiny-engine-controller'
|
||||
import { iconHelpCircle } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
|
|
@ -121,7 +120,7 @@ export default {
|
|||
})
|
||||
}
|
||||
|
||||
updateRect()
|
||||
useCanvas().canvasApi.value.updateRect()
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<MetaArrayItem v-bind="$attrs" @update:modelValue="updateColumns"></MetaArrayItem>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick } from 'vue'
|
||||
import { useProperties, useResource, useCanvas } from '@opentiny/tiny-engine-controller'
|
||||
import MetaArrayItem from './MetaArrayItem.vue'
|
||||
|
||||
const { children: schemaChildren, componentName, props } = useProperties().getSchema()
|
||||
const configureMap = useResource().getConfigureMap()
|
||||
const childComponentName =
|
||||
configureMap[componentName]?.nestingRule?.childWhitelist?.[0] || schemaChildren?.[0]?.componentName
|
||||
|
||||
const updateColumns = (columns) => {
|
||||
if (!columns?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const children = columns.map((item) => {
|
||||
return {
|
||||
componentName: childComponentName,
|
||||
props: { ...item }
|
||||
}
|
||||
})
|
||||
|
||||
useProperties().getSchema().children = children
|
||||
nextTick(useCanvas().canvasApi.value.updateRect)
|
||||
}
|
||||
|
||||
updateColumns(props?.columns)
|
||||
</script>
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
<template>
|
||||
<div>
|
||||
<div :class="['toolbar', { _full: fullscreen }]">
|
||||
<div :class="['editor-container', { 'editor-container-full': fullscreen }]">
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-start">
|
||||
<slot name="toolbarStart"></slot>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<slot name="buttons"></slot>
|
||||
<tiny-tooltip v-if="showFormatBtn && options.language === 'json'" content="格式化" placement="top">
|
||||
|
|
@ -8,17 +11,17 @@
|
|||
</tiny-tooltip>
|
||||
<span v-if="showFullScreenBtn">
|
||||
<tiny-tooltip v-if="!fullscreen" content="全屏" placement="top">
|
||||
<public-icon name="full-screen" @click="fullscreen = true"></public-icon>
|
||||
<public-icon name="full-screen" @click="switchFullScreen(true)"></public-icon>
|
||||
</tiny-tooltip>
|
||||
<tiny-tooltip v-else content="退出全屏" placement="top">
|
||||
<public-icon name="cancel-full-screen" @click="fullscreen = false"></public-icon>
|
||||
<public-icon name="cancel-full-screen" @click="switchFullScreen(false)"></public-icon>
|
||||
</tiny-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<monaco-editor
|
||||
ref="editor"
|
||||
:class="fullscreen ? 'fullscreen' : 'iniline'"
|
||||
class="editor"
|
||||
:value="value"
|
||||
:options="editorOptions"
|
||||
language="javascript"
|
||||
|
|
@ -110,12 +113,17 @@ export default {
|
|||
editor.value.getEditor().dispose()
|
||||
})
|
||||
|
||||
const switchFullScreen = (value) => {
|
||||
fullscreen.value = value
|
||||
}
|
||||
|
||||
return {
|
||||
editorOptions,
|
||||
editor,
|
||||
getEditor,
|
||||
getEditorValue,
|
||||
fullscreen,
|
||||
switchFullScreen,
|
||||
getValue,
|
||||
formatCode
|
||||
}
|
||||
|
|
@ -124,41 +132,45 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.editor-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.editor-container-full {
|
||||
position: fixed;
|
||||
top: var(--base-top-panel-height);
|
||||
bottom: 0;
|
||||
left: calc(var(--base-nav-panel-width) + var(--base-left-panel-width));
|
||||
right: var(--base-left-panel-width);
|
||||
z-index: 10;
|
||||
padding: 10px 16px 16px 16px;
|
||||
background-color: var(--ti-lowcode-common-component-bg);
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
justify-content: flex-end;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
z-index: 3000 !important;
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
color: var(--ti-lowcode-component-svg-button-color);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
:hover {
|
||||
color: var(--ti-lowcode-component-svg-button-hover-color);
|
||||
}
|
||||
}
|
||||
&._full {
|
||||
position: fixed;
|
||||
top: 35px;
|
||||
z-index: 1;
|
||||
padding-right: 15px;
|
||||
right: var(--base-left-panel-width);
|
||||
}
|
||||
}
|
||||
.iniline {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.fullscreen {
|
||||
position: fixed;
|
||||
top: 35px;
|
||||
bottom: 0;
|
||||
left: calc(var(--base-nav-panel-width) + 1px);
|
||||
right: var(--base-left-panel-width);
|
||||
z-index: 2500;
|
||||
}
|
||||
.public-icon {
|
||||
font-size: 18px;
|
||||
margin-left: 10px;
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--ti-lowcode-state-management-monaco-editor-border-color);
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
<template>
|
||||
<ul
|
||||
:class="[
|
||||
'block-list',
|
||||
'lowcode-scrollbar',
|
||||
{ 'is-list': blockStyle === 'list' },
|
||||
{ 'is-small-list': blockStyle === 'mini' },
|
||||
{ isShortcutPanel }
|
||||
]"
|
||||
v-if="state.data.length"
|
||||
:class="['block-list', 'lowcode-scrollbar', { 'is-small-list': blockStyle === 'mini' }, { isShortcutPanel }]"
|
||||
@mouseleave="state.hover = false"
|
||||
>
|
||||
<li
|
||||
|
|
@ -17,7 +12,6 @@
|
|||
'block-item',
|
||||
{ 'is-active': state.activeIndex === index },
|
||||
{ 'is-disabled': showBlockDetail },
|
||||
{ 'block-item-list': blockStyle === 'list' },
|
||||
{ 'block-item-small-list': blockStyle === 'mini' }
|
||||
]"
|
||||
:title="getTitle(item)"
|
||||
|
|
@ -129,12 +123,14 @@
|
|||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
<search-empty :isShow="!state.data.length" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, watch, inject, reactive } from 'vue'
|
||||
import { iconSetting, iconPlus } from '@opentiny/vue-icon'
|
||||
import { Tooltip, Progress, Popover } from '@opentiny/vue'
|
||||
import SearchEmpty from './SearchEmpty.vue'
|
||||
import SvgButton from './SvgButton.vue'
|
||||
|
||||
const defaultImg =
|
||||
|
|
@ -147,7 +143,8 @@ export default {
|
|||
IconSetting: iconSetting(),
|
||||
IconPlus: iconPlus(),
|
||||
TinyPopover: Popover,
|
||||
SvgButton
|
||||
SvgButton,
|
||||
SearchEmpty
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
|
|
@ -351,7 +348,7 @@ export default {
|
|||
position: fixed;
|
||||
z-index: 9999;
|
||||
top: 50px;
|
||||
left: calc(var(--base-left-panel-width, 268px) + var(--base-nav-panel-width) + 10px);
|
||||
left: calc(var(--base-left-panel-width) + var(--base-nav-panel-width) + 10px);
|
||||
max-width: 500px;
|
||||
max-height: 136px;
|
||||
padding: 12px;
|
||||
|
|
@ -388,10 +385,7 @@ export default {
|
|||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
color: var(--ti-lowcode-common-secondary-text-color);
|
||||
&.is-list {
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: repeat(auto-fill, 60px);
|
||||
}
|
||||
|
||||
&.is-small-list {
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: repeat(auto-fill, 30px);
|
||||
|
|
@ -427,36 +421,7 @@ export default {
|
|||
border-radius: 4px 0 4px 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
&.block-item-list {
|
||||
flex-direction: row;
|
||||
height: 60px;
|
||||
.item-image {
|
||||
width: 50px;
|
||||
}
|
||||
.item-text {
|
||||
text-align: left;
|
||||
margin-top: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.publish-flag {
|
||||
position: static;
|
||||
}
|
||||
.block-detail,
|
||||
.block-setting {
|
||||
visibility: hidden;
|
||||
position: static;
|
||||
margin-left: 4px;
|
||||
z-index: 9;
|
||||
.block-detail-icon {
|
||||
color: var(--ti-lowcode-component-block-list-setting-btn-color);
|
||||
display: block;
|
||||
&:hover {
|
||||
cursor: not-allowed;
|
||||
color: var(--ti-lowcode-component-block-list-setting-btn-hover-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.block-item-small-list {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
|
@ -485,7 +450,7 @@ export default {
|
|||
color: var(--ti-lowcode-component-block-list-setting-btn-color);
|
||||
display: block;
|
||||
&:hover {
|
||||
cursor: not-allowed;
|
||||
cursor: pointer;
|
||||
color: var(--ti-lowcode-component-block-list-setting-btn-hover-color);
|
||||
}
|
||||
}
|
||||
|
|
@ -592,7 +557,7 @@ export default {
|
|||
.block-detail-icon {
|
||||
color: var(--ti-lowcode-component-block-list-setting-btn-color);
|
||||
&:hover {
|
||||
cursor: not-allowed;
|
||||
cursor: pointer;
|
||||
color: var(--ti-lowcode-component-block-list-setting-btn-hover-color);
|
||||
}
|
||||
}
|
||||
|
|
@ -686,7 +651,6 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
&.is-list,
|
||||
&.is-small-list {
|
||||
display: block;
|
||||
grid-template-columns: initial;
|
||||
|
|
@ -717,22 +681,6 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
&.is-list {
|
||||
.block-item {
|
||||
height: 58px;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
font-size: 2.5em;
|
||||
width: 48px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
width: calc(100% - 56px);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-small-list {
|
||||
.block-item {
|
||||
height: 38px;
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ export default {
|
|||
<style lang="less" scoped>
|
||||
.plugin-setting {
|
||||
position: absolute;
|
||||
left: calc(var(--base-left-panel-width, 268px) - 6px);
|
||||
left: calc(var(--base-left-panel-width) - 6px);
|
||||
top: 0;
|
||||
width: var(--base-collection-panel-width);
|
||||
height: 100%;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-dialog-box :append-to-body="true" :visible="visible" title="新建区块" width="500" @close="cancel">
|
||||
<tiny-dialog-box
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible="visible"
|
||||
title="新建区块"
|
||||
width="500"
|
||||
@close="cancel"
|
||||
>
|
||||
<tiny-form
|
||||
show-message
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-width="120px"
|
||||
:label-align="true"
|
||||
label-position="left"
|
||||
|
|
@ -33,10 +41,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, computed } from 'vue'
|
||||
import { reactive, computed, ref } from 'vue'
|
||||
import { Input, Form, FormItem, Button, DialogBox, Select } from '@opentiny/vue'
|
||||
import { useBlock, useLayout, useCanvas, useModal } from '@opentiny/tiny-engine-controller'
|
||||
import { REGEXP_BLOCK_NAME } from '../js/verification'
|
||||
import { REGEXP_BLOCK_NAME } from '@opentiny/tiny-engine-controller/js/verification'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -64,6 +72,7 @@ export default {
|
|||
const { PLUGIN_NAME, activePlugin } = useLayout()
|
||||
const { isSaved } = useCanvas()
|
||||
const { confirm } = useModal()
|
||||
const formRef = ref(null)
|
||||
|
||||
const categoryList = computed(() =>
|
||||
getCategoryList().map((item) => ({ ...item, value: item.id, label: item.name }))
|
||||
|
|
@ -84,15 +93,21 @@ export default {
|
|||
cancel()
|
||||
}
|
||||
const addBlock = () => {
|
||||
if (isSaved()) {
|
||||
handleAddBlock()
|
||||
return
|
||||
}
|
||||
confirm({
|
||||
message: '当前画布内容尚未保存,新建区块会将画布切换至新区块中,是否要继续切换?',
|
||||
exec: () => {
|
||||
handleAddBlock()
|
||||
formRef.value.validate((valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isSaved()) {
|
||||
handleAddBlock()
|
||||
return
|
||||
}
|
||||
confirm({
|
||||
message: '当前画布内容尚未保存,新建区块会将画布切换至新区块中,是否要继续切换?',
|
||||
exec: () => {
|
||||
handleAddBlock()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -107,6 +122,7 @@ export default {
|
|||
return {
|
||||
formData,
|
||||
categoryList,
|
||||
formRef,
|
||||
rules,
|
||||
addBlock,
|
||||
cancel,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<div v-if="isShow" class="empty-wrap">
|
||||
<svg-icon class="empty-icon" name="empty"></svg-icon>
|
||||
<p class="empty-text">暂无数据</p>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
/**
|
||||
* 控制搜索空数据显示
|
||||
*/
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<script>
|
||||
import * as monacoEditor from 'monaco-editor'
|
||||
import { watch, onMounted, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import { formatString } from '../js/ast.js'
|
||||
import { formatString } from '@opentiny/tiny-engine-controller/js/ast'
|
||||
|
||||
export default {
|
||||
name: 'MonacoEditor',
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import PluginSetting from './component/PluginSetting.vue'
|
||||
import PluginPanel from './component/PluginPanel.vue'
|
||||
import SvgButton from './component/SvgButton.vue'
|
||||
import LinkButton from './component/LinkButton.vue'
|
||||
|
||||
import ConfigCollapse from './component/ConfigCollapse.vue'
|
||||
import ConfigGroup from './component/ConfigGroup.vue'
|
||||
|
|
@ -77,8 +78,10 @@ import MetaRelatedColumns from './component/MetaRelatedColumns.vue'
|
|||
import BlockDeployDialog from './component/BlockDeployDialog.vue'
|
||||
import ProgressBar from './component/ProgressBar.vue'
|
||||
import MetaButtonGroup from './component/MetaButtonGroup.vue'
|
||||
import MetaTableColumns from './component/MetaTableColumns.vue'
|
||||
import SearchEmpty from './component/SearchEmpty.vue'
|
||||
|
||||
import i18n, { i18nKeyMaps } from './js/i18n.js'
|
||||
import i18n, { i18nKeyMaps } from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
|
||||
import enUs from './i18n/en-us.json'
|
||||
import zhCn from './i18n/zh-cn.json'
|
||||
|
|
@ -88,6 +91,20 @@ const { mergeLocaleMessage } = i18n.global
|
|||
mergeLocaleMessage(i18nKeyMaps.enUS, enUs)
|
||||
mergeLocaleMessage(i18nKeyMaps.zhCN, zhCn)
|
||||
|
||||
const globalComponents = {
|
||||
SaveNewBlock,
|
||||
ConfigGroup,
|
||||
ConfigItem
|
||||
}
|
||||
|
||||
export const injectGlobalComponents = {
|
||||
install: (app) => {
|
||||
Object.entries(globalComponents).forEach(([name, component]) => {
|
||||
app.component(name, component)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const MetaComponents = {
|
||||
MetaArrayItem,
|
||||
MetaBindI18n,
|
||||
|
|
@ -128,8 +145,9 @@ export const MetaComponents = {
|
|||
MetaCheckboxGroup,
|
||||
MetaIpSection,
|
||||
MetaRelatedEditor,
|
||||
MetaRelatedColumns
|
||||
|
||||
MetaRelatedColumns,
|
||||
MetaTableColumns,
|
||||
SearchEmpty
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
@ -168,6 +186,7 @@ export {
|
|||
PluginPanel,
|
||||
VideoGuide,
|
||||
SvgButton,
|
||||
LinkButton,
|
||||
BlockHistoryList,
|
||||
BlockHistoryTemplate,
|
||||
BlockLinkField,
|
||||
|
|
@ -188,5 +207,7 @@ export {
|
|||
SaveNewBlock,
|
||||
BindI18n,
|
||||
BlockDeployDialog,
|
||||
ProgressBar
|
||||
ProgressBar,
|
||||
MetaTableColumns,
|
||||
SearchEmpty
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine-common",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.2",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
|
@ -10,37 +10,41 @@
|
|||
"main": "dist/index.js",
|
||||
"module": "dist/index.js",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./js/*": "./js/*.js"
|
||||
".": "./dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"js"
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentiny/tiny-engine",
|
||||
"directory": "packages/common"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/opentiny/tiny-engine/issues"
|
||||
},
|
||||
"author": "OpenTiny Team",
|
||||
"license": "MIT",
|
||||
"homepage": "https://opentiny.design/tiny-engine",
|
||||
"dependencies": {
|
||||
"@babel/generator": "7.18.13",
|
||||
"@babel/parser": "7.18.13",
|
||||
"@babel/traverse": "7.18.13",
|
||||
"@opentiny/tiny-engine-canvas": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-controller": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-http": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-i18n-host": "workspace:^1.0.0",
|
||||
"@opentiny/tiny-engine-utils": "workspace:^1.0.0",
|
||||
"@opentiny/vue": "~3.10.0",
|
||||
"@opentiny/vue-icon": "~3.10.0",
|
||||
"@opentiny/vue-locale": "~3.10.0",
|
||||
"@opentiny/vue-renderless": "~3.10.0",
|
||||
"@opentiny/tiny-engine-canvas": "workspace:*",
|
||||
"@opentiny/tiny-engine-controller": "workspace:*",
|
||||
"@opentiny/tiny-engine-http": "workspace:*",
|
||||
"@opentiny/tiny-engine-utils": "workspace:*",
|
||||
"@vue/shared": "^3.3.4",
|
||||
"css-tree": "^2.3.1",
|
||||
"monaco-editor": "0.33.0",
|
||||
"prettier": "2.7.1",
|
||||
"vue": "3.2.45",
|
||||
"vue-draggable-next": "2.1.0",
|
||||
"vue-i18n": "9.2.2"
|
||||
"vue-draggable-next": "2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^1.3.10",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"vite": "^4.3.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentiny/vue": "^3.14.0",
|
||||
"@opentiny/vue-icon": "^3.14.0",
|
||||
"@opentiny/vue-renderless": "^3.14.0",
|
||||
"vue": "^3.4.15"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue