1
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
module.exports = {
|
||||||
|
types: [
|
||||||
|
{value: 'feat', name: 'feat: 新功能'},
|
||||||
|
{value: 'fix', name: 'fix: 修复'},
|
||||||
|
{value: 'docs', name: 'docs: 文档变更'},
|
||||||
|
{value: 'style', name: 'style: 代码格式(不影响代码运行的变动)'},
|
||||||
|
{value: 'cli', name: 'cli: 脚手架优化(不影响代码运行的变动)'},
|
||||||
|
{value: 'refactor', name: 'refactor: 重构(既不是增加feature,也不是修复bug)'},
|
||||||
|
{value: 'perf', name: 'perf: 性能优化'},
|
||||||
|
{value: 'test', name: 'test: 增加测试'},
|
||||||
|
{value: 'chore', name: 'chore: 构建过程或辅助工具的变动'},
|
||||||
|
{value: 'revert', name: 'revert: 回退'},
|
||||||
|
{value: 'build', name: 'build: 打包'}
|
||||||
|
],
|
||||||
|
// override the messages, defaults are as follows
|
||||||
|
messages: {
|
||||||
|
type: '请选择提交类型:',
|
||||||
|
scope: '请输入文件修改范围(可选):',
|
||||||
|
// used if allowCustomScopes is true
|
||||||
|
customScope: '请输入修改范围(可选):',
|
||||||
|
subject: '请简要描述提交(必填):',
|
||||||
|
body: '请输入详细描述(可选,待优化去除,跳过即可):',
|
||||||
|
// breaking: 'List any BREAKING CHANGES (optional):\n',
|
||||||
|
footer: '请输入要关闭的issue(待优化去除,跳过即可):',
|
||||||
|
confirmCommit: '确认使用以上信息提交?(y/n/e/h)'
|
||||||
|
},
|
||||||
|
allowCustomScopes: true,
|
||||||
|
// allowBreakingChanges: ['feat', 'fix'],
|
||||||
|
skipQuestions: ['body', 'footer'],
|
||||||
|
// limit subject length, commitlint默认是72
|
||||||
|
subjectLimit: 72
|
||||||
|
}
|
||||||
Executable
+68
@@ -0,0 +1,68 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
stats.html
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# custom
|
||||||
|
yarn.lock
|
||||||
|
/index.html
|
||||||
|
dist
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 xaboy
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="http://www.form-create.com">
|
||||||
|
<img width="200" src="http://file.lotkk.com/form-create.png">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# form-create-designer v3
|
||||||
|
|
||||||
|
**这个是 Vue3 版本**
|
||||||
|
|
||||||
|
[](https://github.com/xaboy/form-create-designer)
|
||||||
|
[](https://github.com/xaboy)
|
||||||
|
|
||||||
|
**form-create-designer 是基于 [@form-create/element-ui](https://github.com/xaboy/form-create) vue3版本实现的表单设计器组件。可以通过拖拽的方式快速创建表单,提高开发者对表单的开发效率,节省开发者的时间。**
|
||||||
|
|
||||||
|
**[文档](http://designer.form-create.com/guide/) | [在线演示](http://form-create.com/v3/designer?fr=github) | [form-create 文档](http://form-create.com/v3/guide/)**
|
||||||
|
|
||||||
|
> 如果对您有帮助,您可以点右上角 "Star" 支持一下 谢谢!本项目还在不断开发完善中,如有任何建议或问题[请在这里提出](https://github.com/xaboy/form-create-designer/issues/new)
|
||||||
|
|
||||||
|
> 本项目QQ讨论群[629709230](https://jq.qq.com/?_wv=1027&k=F1FlEFIV)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 引入
|
||||||
|
|
||||||
|
**CDN:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://unpkg.com/element-plus@2.0.1/dist/index.css"></link>
|
||||||
|
<script src="https://unpkg.com/vue@next"></script>
|
||||||
|
<script src="https://unpkg.com/element-plus@2.0.1/dist/index.full.js"></script>
|
||||||
|
<script src="https://unpkg.com/@form-create/element-ui@next/dist/form-create.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/@form-create/designer@next/dist/index.umd.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
**NodeJs:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm install @form-create/designer@next
|
||||||
|
```
|
||||||
|
|
||||||
|
请自行导入`ElementPlus`并挂载
|
||||||
|
|
||||||
|
```js
|
||||||
|
import formCreate from '@form-create/element-ui'
|
||||||
|
import FcDesigner from '@form-create/designer'
|
||||||
|
|
||||||
|
app.use(formCreate)
|
||||||
|
app.use(FcDesigner)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
|
||||||
|
```html
|
||||||
|
<fc-designer ref="designer"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 组件`props`
|
||||||
|
|
||||||
|
- **menu**`MenuList` 重新配置拖拽的组件
|
||||||
|
|
||||||
|
- **height**`int|string` 设计器组件高度, 默认`100%`
|
||||||
|
|
||||||
|
## 组件方法
|
||||||
|
|
||||||
|
- 获取当前生成表单的生成规则
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type getRule = () => Rule[]
|
||||||
|
```
|
||||||
|
**示例: `this.$refs.designer.getRule()`**
|
||||||
|
|
||||||
|
- 获取当前表单的全局配置
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type getOption = () => Object
|
||||||
|
```
|
||||||
|
|
||||||
|
- 设置当前生成表单的规则
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type setRule = (rules: Rule[]) => void;
|
||||||
|
```
|
||||||
|
|
||||||
|
- 设置当前表单的全局配置
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type setOption = (option: Object) => void;
|
||||||
|
```
|
||||||
|
|
||||||
|
- 增加一组拖拽组件
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type addMenu = (menu: Menu) => void;
|
||||||
|
```
|
||||||
|
- 删除一组拖拽组件
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type removeMenu = (name: string) => void;
|
||||||
|
```
|
||||||
|
|
||||||
|
- 批量覆盖插入拖拽组件
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type setMenuItem = (name: string, items: MenuItem[]) => void;
|
||||||
|
```
|
||||||
|
|
||||||
|
- 插入一个拖拽组件到分组
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type appendMenuItem = (name:string, item: MenuItem) => void;
|
||||||
|
```
|
||||||
|
|
||||||
|
- 删除一个拖拽组件
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type removeMenuItem = (item: string | MenuItem) => void;
|
||||||
|
```
|
||||||
|
|
||||||
|
- 新增一个拖拽组件的生成规则
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type addComponent = (item: DragRule) => void;
|
||||||
|
```
|
||||||
|
> **提示! 内置的三个组件分组`name`分别为: `main`,`aide`,`layout`**
|
||||||
|
|
||||||
|
## 捐赠
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 联系
|
||||||
|
|
||||||
|
##### email : xaboy2005@qq.com
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2021-present xaboy
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
'presets': [['@vue/cli-plugin-babel/preset', {'useBuiltIns': false}]],
|
||||||
|
'plugins': ['@vue/babel-plugin-jsx']
|
||||||
|
}
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<div class="_fc-t-header">
|
||||||
|
<img class="_fc-t-logo" src="http://form-create.com/logo.png">
|
||||||
|
<div class="_fc-t-name">form-create-designer</div>
|
||||||
|
<div class="_fc-t-menu">
|
||||||
|
<el-button size="small" @click="setJson"> 导入JSON</el-button>
|
||||||
|
<el-button size="small" @click="setOption"> 导入Options</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="showJson">生成JSON</el-button>
|
||||||
|
<el-button size="small" type="success" @click="showOption">生成Options</el-button>
|
||||||
|
<el-button size="small" type="danger" @click="showTemplate">生成组件</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<fc-designer ref="designer"/>
|
||||||
|
|
||||||
|
<ElFooter class="_fc-copyright" height="30px">
|
||||||
|
<div class="_fc-b-item">
|
||||||
|
<el-popover
|
||||||
|
placement="top"
|
||||||
|
width="400"
|
||||||
|
trigger="hover">
|
||||||
|
<el-image src="http://form-create.com/img/donation.jpg"></el-image>
|
||||||
|
<template #reference>
|
||||||
|
<span>赞助</span>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
<span style="margin: 0 5px;">|</span>
|
||||||
|
<div class="_fc-b-item">
|
||||||
|
<iframe
|
||||||
|
src="https://ghbtns.com/github-btn.html?user=xaboy&repo=form-create-designer&type=star&count=true&size=mini"
|
||||||
|
frameborder="0" scrolling="0" width="90" height="21" title="GitHub"></iframe>
|
||||||
|
</div>
|
||||||
|
<span style="margin: 0 5px;">|</span>
|
||||||
|
<div class="_fc-b-item">
|
||||||
|
<a href='https://gitee.com/xaboy/form-create-designer/stargazers' style="display: inline-flex;"><img
|
||||||
|
src='https://gitee.com/xaboy/form-create-designer/badge/star.svg?theme=dark' alt='gitee'/></a>
|
||||||
|
</div>
|
||||||
|
</ElFooter>
|
||||||
|
|
||||||
|
<el-dialog :title="title[type]" v-model="state" class="_fc-t-dialog">
|
||||||
|
<div ref="editor" v-if="state"></div>
|
||||||
|
<span style="color: red;" v-if="err">输入内容格式有误!</span>
|
||||||
|
<template #footer v-if="type > 2">
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="state = false" size="small">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="onOk" size="small">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import jsonlint from 'jsonlint-mod';
|
||||||
|
import 'codemirror/lib/codemirror.css';
|
||||||
|
import 'codemirror/addon/lint/lint.css';
|
||||||
|
import CodeMirror from 'codemirror/lib/codemirror';
|
||||||
|
import 'codemirror/addon/lint/lint';
|
||||||
|
import 'codemirror/addon/lint/json-lint';
|
||||||
|
import 'codemirror/mode/javascript/javascript';
|
||||||
|
import 'codemirror/mode/vue/vue';
|
||||||
|
import 'codemirror/mode/xml/xml';
|
||||||
|
import 'codemirror/mode/css/css';
|
||||||
|
import 'codemirror/addon/mode/overlay';
|
||||||
|
import 'codemirror/addon/mode/simple';
|
||||||
|
import 'codemirror/addon/selection/selection-pointer';
|
||||||
|
import 'codemirror/mode/handlebars/handlebars';
|
||||||
|
import 'codemirror/mode/htmlmixed/htmlmixed';
|
||||||
|
import 'codemirror/mode/pug/pug';
|
||||||
|
|
||||||
|
import is from '@form-create/utils/lib/type';
|
||||||
|
import formCreate from '@form-create/element-ui';
|
||||||
|
// import image from '../src/components/custom/image.ts';
|
||||||
|
|
||||||
|
|
||||||
|
const TITLE = ['生成规则', '表单规则', '生成组件', '设置生成规则', '设置表单规则'];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'app',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
state: false,
|
||||||
|
value: null,
|
||||||
|
title: TITLE,
|
||||||
|
editor: null,
|
||||||
|
err: false,
|
||||||
|
type: -1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
state(n) {
|
||||||
|
if (!n) {
|
||||||
|
this.value = null;
|
||||||
|
this.err = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value() {
|
||||||
|
this.load();
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
load() {
|
||||||
|
let val;
|
||||||
|
if (this.type === 2) {
|
||||||
|
val = this.value;
|
||||||
|
} else if (this.type === 0) {
|
||||||
|
val = formCreate.toJson(this.value, 2);
|
||||||
|
} else {
|
||||||
|
val = JSON.stringify(this.value, null, 2);
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.editor = CodeMirror(this.$refs.editor, {
|
||||||
|
lineNumbers: true,
|
||||||
|
mode: this.type === 2 ? {name: 'vue'} : 'application/json',
|
||||||
|
gutters: ['CodeMirror-lint-markers'],
|
||||||
|
// lint: true,
|
||||||
|
line: true,
|
||||||
|
tabSize: 2,
|
||||||
|
lineWrapping: true,
|
||||||
|
value: val || ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onValidationError(e) {
|
||||||
|
this.err = e.length !== 0;
|
||||||
|
},
|
||||||
|
showJson() {
|
||||||
|
this.state = true;
|
||||||
|
this.type = 0;
|
||||||
|
this.value = this.$refs.designer.getRule();
|
||||||
|
},
|
||||||
|
showOption() {
|
||||||
|
this.state = true;
|
||||||
|
this.type = 1;
|
||||||
|
this.value = this.$refs.designer.getOption();
|
||||||
|
},
|
||||||
|
showTemplate() {
|
||||||
|
this.state = true;
|
||||||
|
this.type = 2;
|
||||||
|
this.value = this.makeTemplate();
|
||||||
|
},
|
||||||
|
setJson() {
|
||||||
|
this.state = true;
|
||||||
|
this.type = 3;
|
||||||
|
this.value = [];
|
||||||
|
},
|
||||||
|
setOption() {
|
||||||
|
this.state = true;
|
||||||
|
this.type = 4;
|
||||||
|
this.value = {form: {}};
|
||||||
|
},
|
||||||
|
onOk() {
|
||||||
|
if (this.err) return;
|
||||||
|
const json = this.editor.getValue();
|
||||||
|
let val = JSON.parse(json);
|
||||||
|
if (this.type === 3) {
|
||||||
|
if (!Array.isArray(val)) {
|
||||||
|
this.err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$refs.designer.setRule(formCreate.parseJson(json));
|
||||||
|
} else {
|
||||||
|
if (!is.Object(val) || !val.form) {
|
||||||
|
this.err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$refs.designer.setOption(val);
|
||||||
|
}
|
||||||
|
this.state = false;
|
||||||
|
},
|
||||||
|
makeTemplate() {
|
||||||
|
const rule = this.$refs.designer.getRule();
|
||||||
|
const opt = this.$refs.designer.getOption();
|
||||||
|
return `<template>
|
||||||
|
<form-create
|
||||||
|
v-model="fapi"
|
||||||
|
:rule="rule"
|
||||||
|
:option="option"
|
||||||
|
@submit="onSubmit"
|
||||||
|
></form-create>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import formCreate from "@form-create/element-ui";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
fapi: null,
|
||||||
|
rule: formCreate.parseJson('${formCreate.toJson(rule).replaceAll('\\', '\\\\')}'),
|
||||||
|
option: formCreate.parseJson('${JSON.stringify(opt)}')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSubmit (formData) {
|
||||||
|
//todo 提交表单
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<\/script>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeCreate() {
|
||||||
|
window.jsonlint = jsonlint;
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// this.$nextTick(() => {
|
||||||
|
// console.log("插入组件规则",this.$refs.designer);
|
||||||
|
// //插入组件规则
|
||||||
|
// this.$refs.designer.addComponent(image);
|
||||||
|
// //插入拖拽按钮到`main`分类下
|
||||||
|
// this.$refs.designer.appendMenuItem("main", {
|
||||||
|
// icon : image.icon,
|
||||||
|
// name : image.name,
|
||||||
|
// label: image.label
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
._fc-t-header {
|
||||||
|
height: 60px;
|
||||||
|
margin: 0 20px;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-t-logo {
|
||||||
|
height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-t-name {
|
||||||
|
display: inline-block;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-t-menu {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-t-menu i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-copyright {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
border-top: 1px solid #ECECEC;
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-t-dialog .CodeMirror {
|
||||||
|
height: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-t-dialog .CodeMirror-line {
|
||||||
|
line-height: 16px !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-lint-tooltip {
|
||||||
|
z-index: 2021 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-t-dialog .el-dialog__body {
|
||||||
|
padding: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-b-item {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>form-create-designer 示例</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import {createApp} from 'vue';
|
||||||
|
import ELEMENT from 'element-plus';
|
||||||
|
import 'element-plus/dist/index.css';
|
||||||
|
import formCreate from '@form-create/element-ui';
|
||||||
|
import Antd from 'ant-design-vue';
|
||||||
|
import App from './App';
|
||||||
|
import 'ant-design-vue/dist/antd.css';
|
||||||
|
import FcDesigner from '../src/index';
|
||||||
|
|
||||||
|
const app = createApp(App);
|
||||||
|
|
||||||
|
app.use(Antd);
|
||||||
|
app.use(ELEMENT);
|
||||||
|
app.use(formCreate);
|
||||||
|
app.use(FcDesigner);
|
||||||
|
|
||||||
|
|
||||||
|
app.mount('#app')
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
{
|
||||||
|
"name": "@form-create/designer",
|
||||||
|
"version": "3.0.2",
|
||||||
|
"description": "好用的vue可视化表单设计器组件",
|
||||||
|
"unpkg": "./dist/index.umd.js",
|
||||||
|
"jsdelivr": "./dist/index.umd.js",
|
||||||
|
"typings": "./types/index.d.ts",
|
||||||
|
"main": "./dist/index.umd.js",
|
||||||
|
"module": "./dist/index.es.js",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.es.js",
|
||||||
|
"require": "./dist/index.umd.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist/",
|
||||||
|
"dev": "vue-cli-service serve",
|
||||||
|
"rollup": "rollup -c ./rollup.config.ts",
|
||||||
|
"build": "vite build --config ./vite.config.build.js",
|
||||||
|
"build:preview": "vite build --config ./vite.config.preview.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/xaboy/form-create-designer.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"表单设计器",
|
||||||
|
"@form-create",
|
||||||
|
"form-builder",
|
||||||
|
"form-designer",
|
||||||
|
"draggable",
|
||||||
|
"form",
|
||||||
|
"components",
|
||||||
|
"vue3",
|
||||||
|
"element-ui",
|
||||||
|
"json-form",
|
||||||
|
"dynamic-form"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"README.md",
|
||||||
|
"package.json",
|
||||||
|
"LICENSE",
|
||||||
|
"src",
|
||||||
|
"types",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"author": "xaboy",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/xaboy/form-create-designer/issues"
|
||||||
|
},
|
||||||
|
"homepage": "http://designer.form-create.com",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@element-plus/icons-vue": "^0.2.6",
|
||||||
|
"@sixian/css-url": "^1.0.3",
|
||||||
|
"@types/chalk": "^2.2.0",
|
||||||
|
"@types/shelljs": "^0.8.9",
|
||||||
|
"@vitejs/plugin-vue": "^3.1.2",
|
||||||
|
"@vitejs/plugin-vue-jsx": "^2.0.1",
|
||||||
|
"@vue/babel-plugin-jsx": "^1.0.7",
|
||||||
|
"@vue/cli-plugin-babel": "^4.5.13",
|
||||||
|
"@vue/cli-service": "^4.5.3",
|
||||||
|
"@vue/compiler-sfc": "^3.0.11",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"codemirror": "^5.60.0",
|
||||||
|
"commander": "^6.0.0",
|
||||||
|
"commitizen": "^4.1.2",
|
||||||
|
"cross-env": "^7.0.2",
|
||||||
|
"css-loader": "^4.2.1",
|
||||||
|
"cssnano": "^5.1.13",
|
||||||
|
"cssnano-preset-advanced": "^5.3.8",
|
||||||
|
"cz-conventional-changelog": "^3.2.0",
|
||||||
|
"cz-customizable": "^6.3.0",
|
||||||
|
"dayjs": "^1.10.7",
|
||||||
|
"element-plus": "^2.0.1",
|
||||||
|
"eslint": "^7.7.0",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"esno": "^0.9.1",
|
||||||
|
"execa": "^5.1.1",
|
||||||
|
"fast-glob": "^3.2.7",
|
||||||
|
"figlet": "^1.5.0",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"html-webpack-plugin": "^4.3.0",
|
||||||
|
"humps": "^2.0.1",
|
||||||
|
"husky": "^4.2.5",
|
||||||
|
"jsonlint-mod": "^1.7.6",
|
||||||
|
"lint-staged": "^10.2.11",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"ora": "^5.0.0",
|
||||||
|
"postcss": "^8.4.17",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"rollup-plugin-visualizer": "^5.8.2",
|
||||||
|
"shelljs": "^0.8.4",
|
||||||
|
"stringify-author": "^0.1.3",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"typescript": "^4.4.3",
|
||||||
|
"vite": "^3.1.4",
|
||||||
|
"vite-plugin-banner": "^0.5.0",
|
||||||
|
"vite-plugin-css-injected-by-js": "^2.1.0",
|
||||||
|
"vue": "^3.1.5",
|
||||||
|
"vue-loader": "^15.9.3",
|
||||||
|
"vue-style-loader": "^4.1.2",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"commitizen": {
|
||||||
|
"path": "./node_modules/cz-customizable"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": "lint-staged"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{js,jsx,vue}": [
|
||||||
|
"eslint --fix",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@form-create/ant-design-vue": "next",
|
||||||
|
"@form-create/component-wangeditor": "^3.1",
|
||||||
|
"@form-create/designer": "^1.0.8",
|
||||||
|
"@form-create/element-ui": "^3.1.16",
|
||||||
|
"@form-create/utils": "^3.1.15",
|
||||||
|
"ant-design-vue": "^3.2.15",
|
||||||
|
"vuedraggable": "4.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<script>
|
||||||
|
import {h, resolveComponent, defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DragBox',
|
||||||
|
props: ['rule', 'tag', 'formCreateInject'],
|
||||||
|
render(ctx) {
|
||||||
|
const subRule = {...ctx.$props.rule.props, ...ctx.$attrs};
|
||||||
|
let _class = subRule.tag + '-drag drag-box';
|
||||||
|
if (!Object.keys(ctx.$slots).length) {
|
||||||
|
_class += ' ' + subRule.tag + '-holder';
|
||||||
|
}
|
||||||
|
subRule.class = _class;
|
||||||
|
subRule.modelValue = [...this.$props.formCreateInject.children];
|
||||||
|
|
||||||
|
const keys = {};
|
||||||
|
if (ctx.$slots.default) {
|
||||||
|
const children = ctx.$slots.default();
|
||||||
|
children.forEach(v => {
|
||||||
|
if (v.key) {
|
||||||
|
keys[v.key] = v;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return h(resolveComponent('draggable'), subRule, {
|
||||||
|
item: ({element}) => {
|
||||||
|
return h('div', {}, keys[element.__fc__.key + 'fc'])
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<div class="drag-tool" @click.stop="active" :class="{active: state.active === id}">
|
||||||
|
<div class="drag-mask" v-if="mask"></div>
|
||||||
|
<div class="drag-l">
|
||||||
|
<div class="drag-btn _fc-drag-btn" v-if="state.active === id && dragBtn !== false" style="cursor: move;">
|
||||||
|
<i class="fc-icon icon-move"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="drag-r">
|
||||||
|
<div class="drag-btn" @click="$emit('create')">
|
||||||
|
<i class="fc-icon icon-add"></i>
|
||||||
|
</div>
|
||||||
|
<div class="drag-btn" @click="$emit('copy')">
|
||||||
|
<i class="fc-icon icon-copy"></i>
|
||||||
|
</div>
|
||||||
|
<div class="drag-btn" v-if="children" @click="$emit('addChild')">
|
||||||
|
<i class="fc-icon icon-add-child"></i>
|
||||||
|
</div>
|
||||||
|
<div class="drag-btn drag-btn-danger" @click="$emit('delete')">
|
||||||
|
<i class="fc-icon icon-delete"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<slot name="default"></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {computed, inject, toRefs, defineComponent} from 'vue';
|
||||||
|
|
||||||
|
let uni = 1;
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DragTool',
|
||||||
|
props: ['dragBtn', 'children', 'unique', 'mask'],
|
||||||
|
setup(props) {
|
||||||
|
const {unique} = toRefs(props);
|
||||||
|
const id = computed(() => unique.value || uni++);
|
||||||
|
const state = inject('fcx');
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
state
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
active() {
|
||||||
|
if (this.state.active === this.id) return;
|
||||||
|
this.state.active = this.id;
|
||||||
|
this.$emit('active');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.drag-tool {
|
||||||
|
position: relative;
|
||||||
|
min-height: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 2px;
|
||||||
|
outline: 1px dashed #2E73FF;
|
||||||
|
overflow: hidden;
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-tool .drag-tool {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-tool + .drag-tool {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-tool.active {
|
||||||
|
outline: 2px solid #2E73FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-tool.active > div > .drag-btn {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-tool .drag-btn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-r {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
bottom: 2px;
|
||||||
|
z-index: 1904;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-l {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1904
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-btn {
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #2E73FF;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
float: left;
|
||||||
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-btn + .drag-btn {
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-btn-danger {
|
||||||
|
background-color: #FF2E2E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-btn i {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-mask {
|
||||||
|
z-index: 1900;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,861 @@
|
|||||||
|
<style>
|
||||||
|
._fc-designer {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 500px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: default;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-designer > .el-main {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-m .form-create ._fc-l-item {
|
||||||
|
background: #2E73FF;
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all .3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l, ._fc-m, ._fc-r {
|
||||||
|
border-top: 1px solid #ECECEC;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l-group {
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 18px 0px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l-item {
|
||||||
|
display: inline-block;
|
||||||
|
background: #FFF;
|
||||||
|
color: #000;
|
||||||
|
min-width: 70px;
|
||||||
|
width: 33.33%;
|
||||||
|
height: 70px;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
transition: all .2s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l-item i {
|
||||||
|
font-size: 21px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l-item ._fc-l-name {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l-item ._fc-l-icon {
|
||||||
|
padding: 10px 5px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-l-item:hover {
|
||||||
|
background: #2E73FF;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-m-tools {
|
||||||
|
height: 40px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
border: 1px solid #ECECEC;
|
||||||
|
border-top: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-m-tools button.el-button {
|
||||||
|
padding: 5px 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-m-tools .fc-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-r .el-tabs__nav-wrap::after {
|
||||||
|
height: 1px;
|
||||||
|
background-color: #ECECEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-r ._fc-r-tabs {
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
border-bottom: 1px solid #ECECEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-r ._fc-r-tab {
|
||||||
|
height: 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: 40px;
|
||||||
|
display: inline-block;
|
||||||
|
list-style: none;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-r ._fc-r-tab.active {
|
||||||
|
color: #409EFF;
|
||||||
|
border-bottom: 2px solid #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-box {
|
||||||
|
min-height: 60px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-m-drag {
|
||||||
|
overflow: auto;
|
||||||
|
padding: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-m-drag, .draggable-drag {
|
||||||
|
background: #fff;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-m-drag > form, ._fc-m-drag > form > .el-row {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ElContainer class="_fc-designer" :style="'height:'+dragHeight">
|
||||||
|
<ElMain>
|
||||||
|
<ElContainer style="height: 100%;">
|
||||||
|
<el-aside class="_fc-l" width="266px">
|
||||||
|
<template v-for="(item, index) in menuList" :key="index">
|
||||||
|
<div class="_fc-l-group">
|
||||||
|
<h4 class="_fc-l-title">{{ item.title }}</h4>
|
||||||
|
<draggable :group="{name:'default', pull:'clone',put:false}" :sort="false"
|
||||||
|
itemKey="name"
|
||||||
|
:list="item.list">
|
||||||
|
<template #item="{element}">
|
||||||
|
<div class="_fc-l-item">
|
||||||
|
<div class="_fc-l-icon">
|
||||||
|
<i class="fc-icon" :class="element.icon || 'icon-input'"></i>
|
||||||
|
</div>
|
||||||
|
<span class="_fc-l-name">{{ element.label }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-aside>
|
||||||
|
<ElContainer class="_fc-m">
|
||||||
|
<el-header class="_fc-m-tools" height="45">
|
||||||
|
<slot name="handle"></slot>
|
||||||
|
<el-button type="primary" plain round size="small"
|
||||||
|
@click="previewFc"> <i class="fc-icon icon-preview"></i> 预 览
|
||||||
|
</el-button>
|
||||||
|
<el-popconfirm
|
||||||
|
title="清空后将不能恢复,确定要清空吗?"
|
||||||
|
width="200px"
|
||||||
|
confirm-button-text="清空"
|
||||||
|
cancel-button-text="取消"
|
||||||
|
@confirm="clearDragRule">
|
||||||
|
<template #reference>
|
||||||
|
<el-button type="danger" plain round size="small"> <i class="fc-icon icon-delete"></i>清 空
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
|
||||||
|
</el-header>
|
||||||
|
<ElMain style="background: #F5F5F5;padding: 20px;">
|
||||||
|
<div class="_fc-m-drag">
|
||||||
|
<DragForm :rule="dragForm.rule" :option="form.value"
|
||||||
|
v-model:api="dragForm.api"></DragForm>
|
||||||
|
</div>
|
||||||
|
</ElMain>
|
||||||
|
</ElContainer>
|
||||||
|
<ElAside class="_fc-r" width="320px">
|
||||||
|
<ElContainer style="height: 100%;">
|
||||||
|
<el-header height="40px" class="_fc-r-tabs">
|
||||||
|
<div class="_fc-r-tab" :class="{active: activeTab==='props'}" v-if="!!activeRule"
|
||||||
|
@click="activeTab='props'">组件配置
|
||||||
|
</div>
|
||||||
|
<div class="_fc-r-tab" :class="{active: activeTab==='form' && !!activeRule}"
|
||||||
|
@click="activeTab='form'">表单配置
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<ElMain v-show="activeTab==='form'">
|
||||||
|
<DragForm :rule="form.rule" :option="form.option"
|
||||||
|
v-model="form.value.form"></DragForm>
|
||||||
|
</ElMain>
|
||||||
|
<ElMain v-show="activeTab==='props'" style="padding: 0 20px;"
|
||||||
|
:key="activeRule ? activeRule._id: ''">
|
||||||
|
<div>
|
||||||
|
<ElDivider v-if="showBaseRule">基础配置</ElDivider>
|
||||||
|
<DragForm v-show="showBaseRule" v-model:api="baseForm.api"
|
||||||
|
:rule="baseForm.rule"
|
||||||
|
:option="baseForm.options"
|
||||||
|
@change="baseChange"></DragForm>
|
||||||
|
<ElDivider>属性配置</ElDivider>
|
||||||
|
<DragForm v-model:api="propsForm.api" :rule="propsForm.rule"
|
||||||
|
:option="propsForm.options"
|
||||||
|
@change="propChange" @removeField="propRemoveField"></DragForm>
|
||||||
|
<ElDivider v-if="showBaseRule">验证规则</ElDivider>
|
||||||
|
<DragForm v-show="showBaseRule" v-model:api="validateForm.api"
|
||||||
|
:rule="validateForm.rule"
|
||||||
|
:option="validateForm.options"
|
||||||
|
@update:modelValue="validateChange"></DragForm>
|
||||||
|
</div>
|
||||||
|
</ElMain>
|
||||||
|
</ElContainer>
|
||||||
|
</ElAside>
|
||||||
|
<ElDialog v-model="preview.state" width="800px" append-to-body>
|
||||||
|
<ViewForm :rule="preview.rule" :option="preview.option" v-if="preview.state"></ViewForm>
|
||||||
|
</ElDialog>
|
||||||
|
</ElContainer>
|
||||||
|
</ElMain>
|
||||||
|
</ElContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import form from '../config/base/form';
|
||||||
|
import field from '../config/base/field';
|
||||||
|
import validate from '../config/base/validate';
|
||||||
|
import {deepCopy} from '@form-create/utils/lib/deepextend';
|
||||||
|
import is, {hasProperty} from '@form-create/utils/lib/type';
|
||||||
|
import {lower} from '@form-create/utils/lib/tocase';
|
||||||
|
import ruleList from '../config/rule';
|
||||||
|
import draggable from 'vuedraggable/src/vuedraggable';
|
||||||
|
import createMenu from '../config/menu';
|
||||||
|
import {upper} from '../utils/index';
|
||||||
|
import {designerForm} from '../utils/form';
|
||||||
|
import viewForm from '../utils/form';
|
||||||
|
import {computed, reactive, toRefs, ref, getCurrentInstance, provide, nextTick, watch, defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'FcDesigner',
|
||||||
|
components: {
|
||||||
|
draggable,
|
||||||
|
DragForm: designerForm.$form(),
|
||||||
|
ViewForm: viewForm.$form(),
|
||||||
|
},
|
||||||
|
props: ['menu', 'height', 'config', 'mask'],
|
||||||
|
setup(props) {
|
||||||
|
const {menu, height, config, mask} = toRefs(props);
|
||||||
|
const vm = getCurrentInstance();
|
||||||
|
provide('fcx', ref({active: null}));
|
||||||
|
provide('designer', vm.ctx);
|
||||||
|
|
||||||
|
const dragHeight = computed(() => {
|
||||||
|
const h = height.value;
|
||||||
|
if (!h) return '100%';
|
||||||
|
return is.Number(h) ? `${h}px` : h;
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
cacheProps: {},
|
||||||
|
moveRule: null,
|
||||||
|
addRule: null,
|
||||||
|
added: null,
|
||||||
|
activeTab: 'form',
|
||||||
|
activeRule: null,
|
||||||
|
children: ref([]),
|
||||||
|
menuList: menu.value || createMenu(),
|
||||||
|
showBaseRule: false,
|
||||||
|
visible: {
|
||||||
|
preview: false
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
state: false,
|
||||||
|
rule: [],
|
||||||
|
option: {}
|
||||||
|
},
|
||||||
|
dragForm: ref({
|
||||||
|
rule: [],
|
||||||
|
api: {},
|
||||||
|
}),
|
||||||
|
form: {
|
||||||
|
rule: form(),
|
||||||
|
option: {
|
||||||
|
form: {
|
||||||
|
labelPosition: 'top',
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
submitBtn: false
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
form: {
|
||||||
|
inline: false,
|
||||||
|
hideRequiredAsterisk: false,
|
||||||
|
labelPosition: 'right',
|
||||||
|
size: 'small',
|
||||||
|
labelWidth: '125px',
|
||||||
|
formCreateSubmitBtn: true,
|
||||||
|
formCreateResetBtn: false
|
||||||
|
},
|
||||||
|
submitBtn: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
baseForm: {
|
||||||
|
rule: field(),
|
||||||
|
api: {},
|
||||||
|
options: {
|
||||||
|
form: {
|
||||||
|
labelPosition: 'top',
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
submitBtn: false,
|
||||||
|
mounted: (fapi) => {
|
||||||
|
fapi.activeRule = data.activeRule;
|
||||||
|
fapi.setValue(fapi.options.formData || {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validateForm: {
|
||||||
|
rule: validate(),
|
||||||
|
api: {},
|
||||||
|
options: {
|
||||||
|
form: {
|
||||||
|
labelPosition: 'top',
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
submitBtn: false,
|
||||||
|
mounted: (fapi) => {
|
||||||
|
fapi.activeRule = data.activeRule;
|
||||||
|
fapi.setValue(fapi.options.formData || {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
propsForm: {
|
||||||
|
rule: [],
|
||||||
|
api: {},
|
||||||
|
options: {
|
||||||
|
form: {
|
||||||
|
labelPosition: 'top',
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
submitBtn: false,
|
||||||
|
mounted: (fapi) => {
|
||||||
|
fapi.activeRule = data.activeRule;
|
||||||
|
fapi.setValue(fapi.options.formData || {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => data.preview.state, function (n) {
|
||||||
|
if (!n) {
|
||||||
|
nextTick(() => {
|
||||||
|
data.preview.rule = data.preview.option = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const methods = {
|
||||||
|
makeChildren(children) {
|
||||||
|
return reactive({children}).children;
|
||||||
|
},
|
||||||
|
addMenu(config) {
|
||||||
|
if (!config.name || !config.list) return;
|
||||||
|
let flag = true;
|
||||||
|
data.menuList.forEach((v, i) => {
|
||||||
|
if (v.name === config.name) {
|
||||||
|
data.menuList[i] = config
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (flag) {
|
||||||
|
data.menuList.push(config);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeMenu(name) {
|
||||||
|
[...data.menuList].forEach((v, i) => {
|
||||||
|
if (v.name === name) {
|
||||||
|
data.menuList.splice(i, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setMenuItem(name, list) {
|
||||||
|
data.menuList.forEach(v => {
|
||||||
|
if (v.name === name) {
|
||||||
|
v.list = list;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
appendMenuItem(name, item) {
|
||||||
|
data.menuList.forEach(v => {
|
||||||
|
if (v.name === name) {
|
||||||
|
v.list.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeMenuItem(item) {
|
||||||
|
data.menuList.forEach(v => {
|
||||||
|
let idx;
|
||||||
|
if (is.String(item)) {
|
||||||
|
[...v.list].forEach((menu, idx) => {
|
||||||
|
if (menu.name === item) {
|
||||||
|
v.list.splice(idx, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if ((idx = v.list.indexOf(item)) > -1) {
|
||||||
|
v.list.splice(idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addComponent(component) {
|
||||||
|
if (Array.isArray(component)) {
|
||||||
|
component.forEach(v => {
|
||||||
|
ruleList[v.name] = v;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ruleList[component.name] = component;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getParent(rule) {
|
||||||
|
let parent = rule.__fc__.parent.rule;
|
||||||
|
const config = parent.config;
|
||||||
|
if (config && config.config.inside) {
|
||||||
|
rule = parent;
|
||||||
|
parent = parent.__fc__.parent.rule;
|
||||||
|
}
|
||||||
|
return {root: parent, parent: rule};
|
||||||
|
},
|
||||||
|
makeDrag(group, tag, children, on) {
|
||||||
|
return {
|
||||||
|
type: 'DragBox',
|
||||||
|
wrap: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
col: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
inject: true,
|
||||||
|
props: {
|
||||||
|
rule: {
|
||||||
|
props: {
|
||||||
|
tag: 'el-col',
|
||||||
|
group: group === true ? 'default' : group,
|
||||||
|
ghostClass: 'ghost',
|
||||||
|
animation: 150,
|
||||||
|
handle: '._fc-drag-btn',
|
||||||
|
emptyInsertThreshold: 0,
|
||||||
|
direction: 'vertical',
|
||||||
|
itemKey: 'type',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tag,
|
||||||
|
},
|
||||||
|
children,
|
||||||
|
on
|
||||||
|
};
|
||||||
|
},
|
||||||
|
clearDragRule() {
|
||||||
|
methods.setRule([]);
|
||||||
|
},
|
||||||
|
makeDragRule(children) {
|
||||||
|
return methods.makeChildren([methods.makeDrag(true, 'draggable', children, {
|
||||||
|
add: (inject, evt) => methods.dragAdd(children, evt),
|
||||||
|
end: (inject, evt) => methods.dragEnd(children, evt),
|
||||||
|
start: (inject, evt) => methods.dragStart(children, evt),
|
||||||
|
unchoose: (inject, evt) => methods.dragUnchoose(children, evt),
|
||||||
|
})]);
|
||||||
|
},
|
||||||
|
previewFc() {
|
||||||
|
data.preview.state = true;
|
||||||
|
data.preview.rule = methods.getRule();
|
||||||
|
data.preview.option = methods.getOption();
|
||||||
|
},
|
||||||
|
getRule() {
|
||||||
|
return methods.parseRule(deepCopy(data.dragForm.api.rule[0].children));
|
||||||
|
},
|
||||||
|
getJson() {
|
||||||
|
return designerForm.toJson(methods.getRule());
|
||||||
|
},
|
||||||
|
getOption() {
|
||||||
|
const option = deepCopy(data.form.value);
|
||||||
|
option.submitBtn = option.form.formCreateSubmitBtn;
|
||||||
|
option.resetBtn = option.form.formCreateResetBtn;
|
||||||
|
delete option.form.formCreateSubmitBtn;
|
||||||
|
delete option.form.formCreateResetBtn;
|
||||||
|
return option;
|
||||||
|
},
|
||||||
|
setRule(rules) {
|
||||||
|
data.children = methods.makeChildren(methods.loadRule(is.String(rules) ? designerForm.parseJson(rules) : rules));
|
||||||
|
methods.clearActiveRule();
|
||||||
|
data.dragForm.rule = methods.makeDragRule(data.children);
|
||||||
|
},
|
||||||
|
clearActiveRule() {
|
||||||
|
data.activeRule = null;
|
||||||
|
data.activeTab = 'form';
|
||||||
|
},
|
||||||
|
setOption(opt) {
|
||||||
|
let option = {...opt};
|
||||||
|
option.form.formCreateSubmitBtn = !!option.submitBtn;
|
||||||
|
option.form.formCreateResetBtn = !!option.resetBtn;
|
||||||
|
option.submitBtn = false;
|
||||||
|
delete option.resetBtn;
|
||||||
|
data.form.value = option;
|
||||||
|
},
|
||||||
|
loadRule(rules) {
|
||||||
|
const loadRule = [];
|
||||||
|
rules.forEach(rule => {
|
||||||
|
if (is.String(rule)) {
|
||||||
|
return loadRule.push(rule);
|
||||||
|
}
|
||||||
|
const config = ruleList[rule._fc_drag_tag] || ruleList[rule.type];
|
||||||
|
const _children = rule.children;
|
||||||
|
rule.children = [];
|
||||||
|
if (rule.control) {
|
||||||
|
rule._control = rule.control;
|
||||||
|
delete rule.control;
|
||||||
|
}
|
||||||
|
if (config) {
|
||||||
|
rule = methods.makeRule(config, rule);
|
||||||
|
if (_children) {
|
||||||
|
let children = rule.children[0].children;
|
||||||
|
|
||||||
|
if (config.drag) {
|
||||||
|
children = children[0].children;
|
||||||
|
}
|
||||||
|
children.push(...methods.loadRule(_children));
|
||||||
|
}
|
||||||
|
} else if (_children) {
|
||||||
|
rule.children = methods.loadRule(_children);
|
||||||
|
}
|
||||||
|
loadRule.push(rule);
|
||||||
|
});
|
||||||
|
return loadRule;
|
||||||
|
},
|
||||||
|
parseRule(children) {
|
||||||
|
return [...children].reduce((initial, rule) => {
|
||||||
|
if (is.String(rule)) {
|
||||||
|
initial.push(rule);
|
||||||
|
return initial;
|
||||||
|
} else if (rule.type === 'DragBox') {
|
||||||
|
initial.push(...methods.parseRule(rule.children));
|
||||||
|
return initial;
|
||||||
|
} else if (rule.type === 'DragTool') {
|
||||||
|
rule = rule.children[0];
|
||||||
|
if (rule.type === 'DragBox') {
|
||||||
|
initial.push(...methods.parseRule(rule.children));
|
||||||
|
return initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!rule) return initial;
|
||||||
|
rule = {...rule};
|
||||||
|
if (rule.children.length) {
|
||||||
|
rule.children = methods.parseRule(rule.children);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete rule._id;
|
||||||
|
if (rule.config) {
|
||||||
|
delete rule.config.config;
|
||||||
|
}
|
||||||
|
if (rule.effect) {
|
||||||
|
delete rule.effect._fc;
|
||||||
|
delete rule.effect._fc_tool;
|
||||||
|
}
|
||||||
|
if (rule._control) {
|
||||||
|
rule.control = rule._control;
|
||||||
|
delete rule._control;
|
||||||
|
}
|
||||||
|
Object.keys(rule).filter(k => (Array.isArray(rule[k]) && rule[k].length === 0) || (is.Object(rule[k]) && Object.keys(rule[k]).length === 0)).forEach(k => {
|
||||||
|
delete rule[k];
|
||||||
|
});
|
||||||
|
initial.push(rule);
|
||||||
|
return initial;
|
||||||
|
}, []);
|
||||||
|
},
|
||||||
|
baseChange(field, value, _, fapi) {
|
||||||
|
if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
|
||||||
|
data.activeRule[field] = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
propRemoveField(field, _, fapi) {
|
||||||
|
if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
|
||||||
|
data.dragForm.api.sync(data.activeRule);
|
||||||
|
if (field.indexOf('formCreate') === 0) {
|
||||||
|
field = field.replace('formCreate', '');
|
||||||
|
if (!field) return;
|
||||||
|
field = lower(field);
|
||||||
|
if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
|
||||||
|
delete data.activeRule.effect[field.split('>')[1]];
|
||||||
|
} else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
|
||||||
|
delete data.activeRule.props[field.split('>')[1]];
|
||||||
|
} else if (field === 'child') {
|
||||||
|
delete data.activeRule.children[0];
|
||||||
|
} else if (field) {
|
||||||
|
data.activeRule[field] = undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete data.activeRule.props[field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
propChange(field, value, _, fapi) {
|
||||||
|
if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
|
||||||
|
if (field.indexOf('formCreate') === 0) {
|
||||||
|
field = field.replace('formCreate', '');
|
||||||
|
if (!field) return;
|
||||||
|
field = lower(field);
|
||||||
|
if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
|
||||||
|
data.activeRule.effect[field.split('>')[1]] = value;
|
||||||
|
} else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
|
||||||
|
data.activeRule.props[field.split('>')[1]] = value;
|
||||||
|
} else if (field === 'child') {
|
||||||
|
data.activeRule.children[0] = value;
|
||||||
|
} else {
|
||||||
|
data.activeRule[field] = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.activeRule.props[field] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validateChange(formData) {
|
||||||
|
if (!data.activeRule || data.validateForm.api[data.activeRule._id] !== data.activeRule) return;
|
||||||
|
data.activeRule.validate = formData.validate || [];
|
||||||
|
data.dragForm.api.refreshValidate();
|
||||||
|
data.dragForm.api.nextTick(() => {
|
||||||
|
data.dragForm.api.clearValidateState(data.activeRule.field);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toolActive(rule) {
|
||||||
|
if (data.activeRule) {
|
||||||
|
delete data.propsForm.api[data.activeRule._id];
|
||||||
|
delete data.baseForm.api[data.activeRule._id];
|
||||||
|
delete data.validateForm.api[data.activeRule._id];
|
||||||
|
}
|
||||||
|
data.activeRule = rule;
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
data.activeTab = 'props';
|
||||||
|
nextTick(() => {
|
||||||
|
data.propsForm.api[data.activeRule._id] = data.activeRule;
|
||||||
|
data.baseForm.api[data.activeRule._id] = data.activeRule;
|
||||||
|
data.validateForm.api[data.activeRule._id] = data.activeRule;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data.cacheProps[rule._id]) {
|
||||||
|
data.cacheProps[rule._id] = rule.config.config.props(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.propsForm.rule = data.cacheProps[rule._id];
|
||||||
|
|
||||||
|
const formData = {...rule.props, formCreateChild: rule.children[0]};
|
||||||
|
Object.keys(rule).forEach(k => {
|
||||||
|
if (['effect', 'config', 'payload', 'id', 'type'].indexOf(k) < 0)
|
||||||
|
formData['formCreate' + upper(k)] = rule[k];
|
||||||
|
});
|
||||||
|
['props', 'effect'].forEach(name => {
|
||||||
|
rule[name] && Object.keys(rule[name]).forEach(k => {
|
||||||
|
formData['formCreate' + upper(name) + '>' + k] = rule[name][k];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
data.propsForm.options.formData = formData;
|
||||||
|
|
||||||
|
data.showBaseRule = hasProperty(rule, 'field') && rule.input !== false && (!config.value || config.value.showBaseForm !== false);
|
||||||
|
|
||||||
|
if (data.showBaseRule) {
|
||||||
|
data.baseForm.options.formData = {
|
||||||
|
field: rule.field,
|
||||||
|
title: rule.title || '',
|
||||||
|
info: rule.info,
|
||||||
|
_control: rule._control,
|
||||||
|
};
|
||||||
|
|
||||||
|
data.validateForm.options.formData = {validate: rule.validate ? [...rule.validate] : []};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dragStart(children) {
|
||||||
|
console.log('dragStart');
|
||||||
|
data.moveRule = children;
|
||||||
|
data.added = false;
|
||||||
|
},
|
||||||
|
dragUnchoose(children, evt) {
|
||||||
|
console.log('dragUnchoose');
|
||||||
|
data.addRule = {
|
||||||
|
children,
|
||||||
|
oldIndex: evt.oldIndex
|
||||||
|
};
|
||||||
|
},
|
||||||
|
dragAdd(children, evt) {
|
||||||
|
console.log('dragAdd');
|
||||||
|
const newIndex = evt.newIndex;
|
||||||
|
const menu = evt.item._underlying_vm_;
|
||||||
|
if (!menu || menu.__fc__) {
|
||||||
|
if (data.addRule) {
|
||||||
|
const rule = data.addRule.children.splice(data.addRule.oldIndex, 1);
|
||||||
|
children.splice(newIndex, 0, rule[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const rule = methods.makeRule(ruleList[menu.name]);
|
||||||
|
children.splice(newIndex, 0, rule);
|
||||||
|
}
|
||||||
|
data.added = true;
|
||||||
|
// data.dragForm.api.refresh();
|
||||||
|
},
|
||||||
|
dragEnd(children, {newIndex, oldIndex}) {
|
||||||
|
console.log('dragEnd');
|
||||||
|
if (!data.added && !(data.moveRule === children && newIndex === oldIndex)) {
|
||||||
|
const rule = data.moveRule.splice(oldIndex, 1);
|
||||||
|
children.splice(newIndex, 0, rule[0]);
|
||||||
|
}
|
||||||
|
data.moveRule = null;
|
||||||
|
data.addRule = null;
|
||||||
|
data.added = false;
|
||||||
|
// data.dragForm.api.refresh();
|
||||||
|
},
|
||||||
|
makeRule(config, _rule) {
|
||||||
|
const rule = _rule || config.rule();
|
||||||
|
rule.config = {config};
|
||||||
|
if (!rule.effect) rule.effect = {};
|
||||||
|
rule.effect._fc = true;
|
||||||
|
rule._fc_drag_tag = config.name;
|
||||||
|
|
||||||
|
let drag;
|
||||||
|
|
||||||
|
if (config.drag) {
|
||||||
|
rule.children.push(drag = methods.makeDrag(config.drag, rule.type, methods.makeChildren([]), {
|
||||||
|
end: (inject, evt) => methods.dragEnd(inject.self.children, evt),
|
||||||
|
add: (inject, evt) => methods.dragAdd(inject.self.children, evt),
|
||||||
|
start: (inject, evt) => methods.dragStart(inject.self.children, evt),
|
||||||
|
unchoose: (inject, evt) => methods.dragUnchoose(inject.self.children, evt),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.children && !_rule) {
|
||||||
|
const child = methods.makeRule(ruleList[config.children]);
|
||||||
|
(drag || rule).children.push(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dragMask = mask.value !== undefined ? mask.value !== false : config.mask !== false;
|
||||||
|
|
||||||
|
if (config.inside) {
|
||||||
|
rule.children = methods.makeChildren([{
|
||||||
|
type: 'DragTool',
|
||||||
|
props: {
|
||||||
|
dragBtn: config.dragBtn !== false,
|
||||||
|
children: config.children,
|
||||||
|
mask: dragMask,
|
||||||
|
},
|
||||||
|
effect: {
|
||||||
|
_fc_tool: true
|
||||||
|
},
|
||||||
|
inject: true,
|
||||||
|
on: {
|
||||||
|
delete: ({self}) => {
|
||||||
|
const parent = methods.getParent(self).parent;
|
||||||
|
parent.__fc__.rm();
|
||||||
|
vm.emit('delete', parent);
|
||||||
|
methods.clearActiveRule();
|
||||||
|
},
|
||||||
|
create: ({self}) => {
|
||||||
|
const top = methods.getParent(self);
|
||||||
|
vm.emit('create', top.parent);
|
||||||
|
top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, methods.makeRule(top.parent.config.config));
|
||||||
|
},
|
||||||
|
addChild: ({self}) => {
|
||||||
|
const top = methods.getParent(self);
|
||||||
|
const config = top.parent.config.config;
|
||||||
|
const item = ruleList[config.children];
|
||||||
|
if (!item) return;
|
||||||
|
(!config.drag ? top.parent : top.parent.children[0]).children[0].children.push(methods.makeRule(item));
|
||||||
|
},
|
||||||
|
copy: ({self}) => {
|
||||||
|
const top = methods.getParent(self);
|
||||||
|
vm.emit('copy', top.parent);
|
||||||
|
top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, designerForm.copyRule(top.parent));
|
||||||
|
},
|
||||||
|
active: ({self}) => {
|
||||||
|
const top = methods.getParent(self);
|
||||||
|
vm.emit('active', top.parent);
|
||||||
|
methods.toolActive(top.parent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: rule.children
|
||||||
|
}]);
|
||||||
|
return rule;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
type: 'DragTool',
|
||||||
|
props: {
|
||||||
|
dragBtn: config.dragBtn !== false,
|
||||||
|
children: config.children,
|
||||||
|
mask: dragMask,
|
||||||
|
},
|
||||||
|
effect: {
|
||||||
|
_fc_tool: true
|
||||||
|
},
|
||||||
|
inject: true,
|
||||||
|
on: {
|
||||||
|
delete: ({self}) => {
|
||||||
|
vm.emit('delete', self.children[0]);
|
||||||
|
self.__fc__.rm();
|
||||||
|
methods.clearActiveRule();
|
||||||
|
},
|
||||||
|
create: ({self}) => {
|
||||||
|
vm.emit('create', self.children[0]);
|
||||||
|
const top = methods.getParent(self);
|
||||||
|
top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, methods.makeRule(self.children[0].config.config));
|
||||||
|
},
|
||||||
|
addChild: ({self}) => {
|
||||||
|
const config = self.children[0].config.config;
|
||||||
|
const item = ruleList[config.children];
|
||||||
|
if (!item) return;
|
||||||
|
(!config.drag ? self : self.children[0]).children[0].children.push(methods.makeRule(item));
|
||||||
|
},
|
||||||
|
copy: ({self}) => {
|
||||||
|
vm.emit('copy', self.children[0]);
|
||||||
|
const top = methods.getParent(self);
|
||||||
|
top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, designerForm.copyRule(top.parent));
|
||||||
|
},
|
||||||
|
active: ({self}) => {
|
||||||
|
vm.emit('active', self.children[0]);
|
||||||
|
methods.toolActive(self.children[0]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: methods.makeChildren([rule])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data.dragForm.rule = methods.makeDragRule(methods.makeChildren(data.children));
|
||||||
|
return {
|
||||||
|
...toRefs(data), ...methods, dragHeight
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
document.body.ondrop = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
<template>
|
||||||
|
<div class="_fc_fetch">
|
||||||
|
<DragForm v-model:api="api" :modelValue="formValue" :rule="rule" :option="option" @change="input"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import debounce from '@form-create/utils/lib/debounce';
|
||||||
|
import is from '@form-create/utils/lib/type';
|
||||||
|
import {designerForm} from '../utils/form';
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Fetch',
|
||||||
|
props: {
|
||||||
|
modelValue: [Object, String],
|
||||||
|
to: String,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
DragForm: designerForm.$form(),
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
formValue() {
|
||||||
|
const val = this.modelValue;
|
||||||
|
if (!val) return {};
|
||||||
|
if (is.String(val)) {
|
||||||
|
return {
|
||||||
|
action: val
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!val._parse && val.parse) {
|
||||||
|
return {...val, _parse: '' + val.parse};
|
||||||
|
} else if (is.Function(val._parse)) {
|
||||||
|
return {...val, _parse: '' + val._parse};
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
api: {},
|
||||||
|
fetch: {},
|
||||||
|
option: {
|
||||||
|
form: {
|
||||||
|
labelPosition: 'right',
|
||||||
|
size: 'small',
|
||||||
|
labelWidth: '90px'
|
||||||
|
},
|
||||||
|
submitBtn: false,
|
||||||
|
},
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
field: 'action',
|
||||||
|
title: '接口: ',
|
||||||
|
validate: [{required: true, message: '请数据接口'}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
field: 'method',
|
||||||
|
title: '请求方式: ',
|
||||||
|
value: 'GET',
|
||||||
|
options: [
|
||||||
|
{label: 'GET', value: 'GET'},
|
||||||
|
{label: 'POST', value: 'POST'},
|
||||||
|
],
|
||||||
|
control: [
|
||||||
|
{
|
||||||
|
value: 'POST',
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
field: 'dataType',
|
||||||
|
title: '提交方式: ',
|
||||||
|
value: 'FormData',
|
||||||
|
options: [
|
||||||
|
{label: 'FormData', value: 'FormData'},
|
||||||
|
{label: 'JSON', value: 'JSON'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'data',
|
||||||
|
title: '附带数据: ',
|
||||||
|
value: {},
|
||||||
|
props: {
|
||||||
|
defaultValue: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'headers',
|
||||||
|
title: 'header信息: ',
|
||||||
|
value: {},
|
||||||
|
props: {
|
||||||
|
defaultValue: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
field: '_parse',
|
||||||
|
title: '解析函数',
|
||||||
|
info: '解析接口数据,返回组件所需的数据结构',
|
||||||
|
value: 'function (res){\n return res.data;\n}',
|
||||||
|
props: {
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 8,
|
||||||
|
},
|
||||||
|
validate: [{
|
||||||
|
validator: (_, v, cb) => {
|
||||||
|
if (!v) return cb();
|
||||||
|
try {
|
||||||
|
this.parseFn(v);
|
||||||
|
} catch (e) {
|
||||||
|
return cb(false);
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
}, message: '请输入正确的解析函数'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
parseFn(v) {
|
||||||
|
return eval(`(function () {
|
||||||
|
return ${v}
|
||||||
|
})()`);
|
||||||
|
},
|
||||||
|
_input() {
|
||||||
|
this.api.submit((formData) => {
|
||||||
|
formData.to = this.to || 'options';
|
||||||
|
if (formData._parse) formData.parse = this.parseFn(formData._parse);
|
||||||
|
this.$emit('update:modelValue', formData);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
input: debounce(function () {
|
||||||
|
this._input();
|
||||||
|
}, 1000),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this._input();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
._fc_fetch .el-form-item__label {
|
||||||
|
float: left;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc_fetch {
|
||||||
|
background-color: #bfdaf7;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-029747aa="">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M771.776 794.88A384 384 0 0 1 128 512h64a320 320 0 0 0 555.712 216.448H654.72a32 32 0 1 1 0-64h149.056a32 32 0 0 1 32 32v148.928a32 32 0 1 1-64 0v-50.56zM276.288 295.616h92.992a32 32 0 0 1 0 64H220.16a32 32 0 0 1-32-32V178.56a32 32 0 0 1 64 0v50.56A384 384 0 0 1 896.128 512h-64a320 320 0 0 0-555.776-216.384z"></path>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'IconRefresh'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="_fc-required">
|
||||||
|
<ElSwitch v-model="required"></ElSwitch>
|
||||||
|
<ElInput v-model="requiredMsg" v-if="required" placeholder="请输入提示语"></ElInput>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import is from '@form-create/utils/lib/type';
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Required',
|
||||||
|
props: {
|
||||||
|
modelValue: {}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
required() {
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
requiredMsg() {
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
modelValue(n) {
|
||||||
|
const flag = is.String(n);
|
||||||
|
this.required = n === undefined ? false : (flag ? true : !!n);
|
||||||
|
this.requiredMsg = flag ? n : '';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
const flag = is.String(this.modelValue);
|
||||||
|
return {
|
||||||
|
required: this.modelValue === undefined ? false : (flag ? true : !!this.modelValue),
|
||||||
|
requiredMsg: flag ? this.modelValue : ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
update() {
|
||||||
|
let val;
|
||||||
|
if (this.required === false) {
|
||||||
|
val = false;
|
||||||
|
} else {
|
||||||
|
val = this.requiredMsg;
|
||||||
|
}
|
||||||
|
this.$emit('update:modelValue', val);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
._fc-required {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-required .el-input {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-required .el-switch {
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<div class="_fc_struct">
|
||||||
|
<ElButton @click="visible=true" style="width: 100%;">{{ title }}</ElButton>
|
||||||
|
<ElDialog :title="title" v-model="visible" :close-on-click-modal="false" append-to-body>
|
||||||
|
<div ref="editor" v-if="visible"></div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<span class="_fc_err" v-if="err">
|
||||||
|
输入内容格式有误{{ err !== true ? err : '' }}</span>
|
||||||
|
<ElButton @click="visible = false" size="small">取 消</ElButton>
|
||||||
|
<ElButton type="primary" @click="onOk" size="small">确 定</ElButton>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import 'codemirror/lib/codemirror.css';
|
||||||
|
import CodeMirror from 'codemirror/lib/codemirror';
|
||||||
|
import 'codemirror/mode/javascript/javascript';
|
||||||
|
import {deepParseFn, toJSON} from '../utils/index';
|
||||||
|
import {deepCopy} from '@form-create/utils/lib/deepextend';
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Struct',
|
||||||
|
props: {
|
||||||
|
modelValue: [Object, Array],
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '编辑数据'
|
||||||
|
},
|
||||||
|
defaultValue: {
|
||||||
|
require: false
|
||||||
|
},
|
||||||
|
validate: Function,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
visible: false,
|
||||||
|
err: false,
|
||||||
|
oldVal: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue() {
|
||||||
|
this.load();
|
||||||
|
},
|
||||||
|
visible(n) {
|
||||||
|
if (n) {
|
||||||
|
this.load();
|
||||||
|
} else {
|
||||||
|
this.err = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
load() {
|
||||||
|
const val = toJSON(this.modelValue ? deepParseFn(deepCopy(this.modelValue)) : this.defaultValue);
|
||||||
|
this.oldVal = val;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.editor = CodeMirror(this.$refs.editor, {
|
||||||
|
lineNumbers: true,
|
||||||
|
mode: 'javascript',
|
||||||
|
gutters: ['CodeMirror-lint-markers'],
|
||||||
|
lint: true,
|
||||||
|
line: true,
|
||||||
|
tabSize: 2,
|
||||||
|
lineWrapping: true,
|
||||||
|
value: val || ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onOk() {
|
||||||
|
if (this.err) return;
|
||||||
|
const str = this.editor.getValue();
|
||||||
|
let val;
|
||||||
|
try {
|
||||||
|
val = eval('(function (){return ' + str + '}())');
|
||||||
|
} catch (e) {
|
||||||
|
this.err = ` (${e})`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.validate && false === this.validate(val)) {
|
||||||
|
this.err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.visible = false;
|
||||||
|
if (toJSON(val, null, 2) !== this.oldVal) {
|
||||||
|
this.$emit('update:modelValue', val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
._fc_struct{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc_struct .CodeMirror {
|
||||||
|
height: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc_struct .CodeMirror-line {
|
||||||
|
line-height: 16px !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-lint-tooltip {
|
||||||
|
z-index: 2021 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc_struct .el-dialog__body {
|
||||||
|
padding: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc_err {
|
||||||
|
color: red;
|
||||||
|
float: left;
|
||||||
|
text-align: left;
|
||||||
|
width: 65%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="_fc_table_opt">
|
||||||
|
<el-table
|
||||||
|
:data="modelValue"
|
||||||
|
border
|
||||||
|
size="small"
|
||||||
|
style="width: 100%">
|
||||||
|
<template v-for="(col,idx) in column" :key="col.label + idx">
|
||||||
|
<el-table-column :label="col.label">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input size="small" :modelValue="scope.row[col.key] || ''"
|
||||||
|
@Update:modelValue="(n)=>(scope.row[col.key] = n, onInput(scope.row))"></el-input>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<el-table-column min-width="35" align="center" fixed="right" label="操作">
|
||||||
|
|
||||||
|
<template #default="scope">
|
||||||
|
<i class="fc-icon icon-delete" @click="del(scope.$index)"></i>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-button link type="primary" @click="add">
|
||||||
|
<i class="fc-icon icon-add"></i> 添加
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'TableOptions',
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: {
|
||||||
|
modelValue: [Object, Array, String]
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
column: [{label: 'label', key: 'label'}, {label: 'value', key: 'value'}]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (!Array.isArray(this.modelValue)) {
|
||||||
|
this.$emit('input', []);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onInput(item) {
|
||||||
|
if (item.label && item.value) {
|
||||||
|
this.input();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
input() {
|
||||||
|
this.$emit('update:modelValue', this.modelValue);
|
||||||
|
},
|
||||||
|
add() {
|
||||||
|
this.modelValue.push(this.column.reduce((initial, v) => {
|
||||||
|
initial[v.key] = '';
|
||||||
|
return initial;
|
||||||
|
}, {}));
|
||||||
|
},
|
||||||
|
del(idx) {
|
||||||
|
this.modelValue.splice(idx, 1);
|
||||||
|
this.input(this.modelValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._fc_table_opt {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
<template>
|
||||||
|
<DragForm class="_fc-validate" :rule="rule" :option="option" :modelValue="formValue"
|
||||||
|
@update:modelValue="onInput"></DragForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {designerForm} from '../utils/form';
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Validate',
|
||||||
|
inject: ['designer'],
|
||||||
|
props: {
|
||||||
|
modelValue: Array
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
DragForm: designerForm.$form(),
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(n) {
|
||||||
|
this.formValue = this.parseValue(n);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formValue: {},
|
||||||
|
option: {
|
||||||
|
form: {
|
||||||
|
labelPosition: 'top',
|
||||||
|
size: 'small',
|
||||||
|
labelWidth: '90px'
|
||||||
|
},
|
||||||
|
submitBtn: false,
|
||||||
|
formData: this.parseValue(this.modelValue)
|
||||||
|
},
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
field: 'type',
|
||||||
|
value: '',
|
||||||
|
title: '字段类型',
|
||||||
|
options: [
|
||||||
|
{value: '', label: '请选择'},
|
||||||
|
{value: 'string', label: 'String'},
|
||||||
|
{value: 'array', label: 'Array'},
|
||||||
|
{value: 'number', label: 'Number'},
|
||||||
|
{value: 'integer', label: 'Integer'},
|
||||||
|
{value: 'float', label: 'Float'},
|
||||||
|
{value: 'object', label: 'Object'},
|
||||||
|
{value: 'date', label: 'Date'},
|
||||||
|
{value: 'url', label: 'url'},
|
||||||
|
{value: 'hex', label: 'hex'},
|
||||||
|
{value: 'email', label: 'email'},
|
||||||
|
],
|
||||||
|
control: [
|
||||||
|
{
|
||||||
|
handle: v => {
|
||||||
|
return !!v;
|
||||||
|
},
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
field: 'validate',
|
||||||
|
props: {
|
||||||
|
expand: 1,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
title: '触发方式',
|
||||||
|
field: 'trigger',
|
||||||
|
value: 'change',
|
||||||
|
options: [
|
||||||
|
{label: 'change', value: 'change'},
|
||||||
|
{label: 'submit', value: 'submit'},
|
||||||
|
{label: 'blur', value: 'blur'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
title: '验证方式',
|
||||||
|
field: 'mode',
|
||||||
|
options: [
|
||||||
|
{value: 'required', label: '必填'},
|
||||||
|
{value: 'pattern', label: '正则表达式'},
|
||||||
|
{value: 'min', label: '最小值'},
|
||||||
|
{value: 'max', label: '最大值'},
|
||||||
|
{value: 'len', label: '长度'},
|
||||||
|
],
|
||||||
|
value: 'required',
|
||||||
|
control: [
|
||||||
|
{
|
||||||
|
value: 'required',
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'hidden',
|
||||||
|
field: 'required',
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'pattern',
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
field: 'pattern',
|
||||||
|
title: '正则表达式'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'min',
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'min',
|
||||||
|
title: '最小值'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'max',
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'max',
|
||||||
|
title: '最大值'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'len',
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'len',
|
||||||
|
title: '长度'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
title: '错误信息',
|
||||||
|
field: 'message',
|
||||||
|
value: '',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'span',
|
||||||
|
slot: 'append',
|
||||||
|
inject: true,
|
||||||
|
class: 'append-msg',
|
||||||
|
on: {
|
||||||
|
click: (inject) => {
|
||||||
|
if (this.designer.activeRule) {
|
||||||
|
let msg = '请输入';
|
||||||
|
if (inject.api.form.mode !== 'required') {
|
||||||
|
msg += '正确的';
|
||||||
|
}
|
||||||
|
msg += this.designer.activeRule.title;
|
||||||
|
inject.api.setValue('message', msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: ['自动获取']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
value: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onInput: function (formData) {
|
||||||
|
let val = [];
|
||||||
|
const {validate, type} = formData;
|
||||||
|
if (type && (!validate || !validate.length)) {
|
||||||
|
return;
|
||||||
|
} else if (type) {
|
||||||
|
validate.forEach(v => {
|
||||||
|
v.type = type;
|
||||||
|
});
|
||||||
|
val = [...validate];
|
||||||
|
}
|
||||||
|
this.$emit('update:modelValue', val);
|
||||||
|
},
|
||||||
|
parseValue(n) {
|
||||||
|
let val = {
|
||||||
|
validate: n ? [...n] : [],
|
||||||
|
type: n.length ? n[0].type : undefined
|
||||||
|
};
|
||||||
|
val.validate.forEach(v => {
|
||||||
|
if (!v.mode) {
|
||||||
|
Object.keys(v).forEach(k => {
|
||||||
|
if (['message', 'type', 'trigger', 'mode'].indexOf(k) < 0) {
|
||||||
|
v.mode = k;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
._fc-validate .form-create .el-form-item {
|
||||||
|
margin-bottom: 22px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-validate .append-msg {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
._fc-validate .el-input-group__append {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import IconRefresh from '../../components/IconRefresh.vue';
|
||||||
|
import {markRaw} from 'vue';
|
||||||
|
|
||||||
|
export default function field() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
field: 'field',
|
||||||
|
value: '',
|
||||||
|
title: '字段 ID',
|
||||||
|
}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'title',
|
||||||
|
value: '',
|
||||||
|
title: '字段名称',
|
||||||
|
}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'info',
|
||||||
|
value: '',
|
||||||
|
title: '提示信息',
|
||||||
|
}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: '_control',
|
||||||
|
value: [],
|
||||||
|
title: '联动数据',
|
||||||
|
props: {
|
||||||
|
defaultValue: [],
|
||||||
|
validate(val) {
|
||||||
|
if (!Array.isArray(val)) return false;
|
||||||
|
if (!val.length) return true;
|
||||||
|
return !val.some(({rule}) => {
|
||||||
|
return !Array.isArray(rule);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
type: 'col',
|
||||||
|
props: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'el-button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
size: 'small',
|
||||||
|
},
|
||||||
|
inject: true,
|
||||||
|
on: {
|
||||||
|
click({$f}) {
|
||||||
|
const rule = $f.activeRule;
|
||||||
|
if (rule) {
|
||||||
|
rule.__fc__.updateKey();
|
||||||
|
rule.value = undefined;
|
||||||
|
rule.__fc__.$api.sync(rule);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
native: true,
|
||||||
|
children: [{type: 'i', class: 'fc-icon icon-delete'}, '清空值']
|
||||||
|
}, {
|
||||||
|
type: 'el-button',
|
||||||
|
props: {
|
||||||
|
type: 'success',
|
||||||
|
size: 'small',
|
||||||
|
icon: markRaw(IconRefresh),
|
||||||
|
},
|
||||||
|
inject: true,
|
||||||
|
on: {
|
||||||
|
click({$f}) {
|
||||||
|
const rule = $f.activeRule;
|
||||||
|
if (rule) {
|
||||||
|
rule.__fc__.updateKey(true);
|
||||||
|
rule.__fc__.$api.sync(rule);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
native: true,
|
||||||
|
children: ['刷新']
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
export default function form() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'radio',
|
||||||
|
field: 'labelPosition',
|
||||||
|
value: 'left',
|
||||||
|
title: '标签位置',
|
||||||
|
options: [
|
||||||
|
{value: 'right', label: 'right'},
|
||||||
|
{value: 'left', label: 'left'},
|
||||||
|
{value: 'top', label: 'top'},
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
type: 'radio',
|
||||||
|
field: 'size',
|
||||||
|
value: 'small',
|
||||||
|
title: '表单尺寸',
|
||||||
|
options: [
|
||||||
|
{value: 'large', label: 'large'},
|
||||||
|
{value: 'default', label: 'default'},
|
||||||
|
{value: 'small', label: 'small'},
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'labelWidth',
|
||||||
|
value: '125px',
|
||||||
|
title: '标签宽度',
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'hideRequiredAsterisk',
|
||||||
|
value: false,
|
||||||
|
title: '隐藏必填字段的标签旁边的红色星号',
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'showMessage',
|
||||||
|
value: true,
|
||||||
|
title: '显示校验错误信息',
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'inlineMessage',
|
||||||
|
value: false,
|
||||||
|
title: '以行内形式展示校验信息',
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'formCreateSubmitBtn',
|
||||||
|
value: true,
|
||||||
|
title: '是否显示表单提交按钮',
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'formCreateResetBtn',
|
||||||
|
value: false,
|
||||||
|
title: '是否显示表单重置按钮',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export default function validate() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'validate',
|
||||||
|
field: 'validate',
|
||||||
|
value: []
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import radio from './rule/radio';
|
||||||
|
import checkbox from './rule/checkbox';
|
||||||
|
import input from './rule/input';
|
||||||
|
import number from './rule/number';
|
||||||
|
import select from './rule/select';
|
||||||
|
import _switch from './rule/switch';
|
||||||
|
import slider from './rule/slider';
|
||||||
|
import time from './rule/time';
|
||||||
|
import date from './rule/date';
|
||||||
|
import rate from './rule/rate';
|
||||||
|
import color from './rule/color';
|
||||||
|
import row from './rule/row';
|
||||||
|
import divider from './rule/divider';
|
||||||
|
import cascader from './rule/cascader';
|
||||||
|
import upload from './rule/upload';
|
||||||
|
import transfer from './rule/transfer';
|
||||||
|
import tree from './rule/tree';
|
||||||
|
import alert from './rule/alert';
|
||||||
|
import span from './rule/span';
|
||||||
|
import space from './rule/space';
|
||||||
|
import button from './rule/button';
|
||||||
|
import editor from './rule/editor';
|
||||||
|
import tab from './rule/tab';
|
||||||
|
import drawer from './rule/drawer';
|
||||||
|
import image from './rule/image.ts';
|
||||||
|
// 还需要在./rule/index.js文件里注册
|
||||||
|
export default function createMenu() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'main',
|
||||||
|
title: '表单组件',
|
||||||
|
list: [
|
||||||
|
input, number, radio, checkbox, select, _switch, time, date, slider, rate, color, cascader, upload, transfer, tree, editor
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'aide',
|
||||||
|
title: '辅助组件',
|
||||||
|
list: [
|
||||||
|
alert, button, span, divider,image
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'layout',
|
||||||
|
title: '布局组件',
|
||||||
|
list: [
|
||||||
|
row, tab, space,drawer
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
const label = '提示';
|
||||||
|
const name = 'el-alert';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-alert',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
props: {
|
||||||
|
title: '提示',
|
||||||
|
description: 'form-create',
|
||||||
|
type: 'success',
|
||||||
|
effect: 'dark',
|
||||||
|
},
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [{type: 'input', field: 'title', title: '标题'}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'type',
|
||||||
|
title: '主题',
|
||||||
|
options: [{label: 'success', value: 'success'}, {label: 'warning', value: 'warning'}, {
|
||||||
|
label: 'info',
|
||||||
|
value: 'info'
|
||||||
|
}, {label: 'error', value: 'error'}]
|
||||||
|
}, {type: 'input', field: 'description', title: '辅助性文字'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'closable',
|
||||||
|
title: '是否可关闭',
|
||||||
|
value: true
|
||||||
|
}, {type: 'switch', field: 'center', title: '文字是否居中', value: true}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'closeText',
|
||||||
|
title: '关闭按钮自定义文本'
|
||||||
|
}, {type: 'switch', field: 'showIcon', title: '是否显示图标'}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'effect',
|
||||||
|
title: '选择提供的主题',
|
||||||
|
options: [{label: 'light', value: 'light'}, {label: 'dark', value: 'dark'}]
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
const label = '按钮';
|
||||||
|
const name = 'el-button';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-button',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
mask: false,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
props: {},
|
||||||
|
children: ['按钮'],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [{
|
||||||
|
type: 'input',
|
||||||
|
field: 'formCreateChild',
|
||||||
|
title: '内容',
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'size',
|
||||||
|
title: '尺寸',
|
||||||
|
options: [{label: 'large', value: 'large'}, {label: 'default', value: 'default'}, {
|
||||||
|
label: 'small',
|
||||||
|
value: 'small'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'type',
|
||||||
|
title: '类型',
|
||||||
|
options: [{label: 'primary', value: 'primary'}, {
|
||||||
|
label: 'success',
|
||||||
|
value: 'success'
|
||||||
|
}, {label: 'warning', value: 'warning'}, {label: 'danger', value: 'danger'}, {
|
||||||
|
label: 'info',
|
||||||
|
value: 'info'
|
||||||
|
}]
|
||||||
|
}, {type: 'switch', field: 'plain', title: '是否朴素按钮'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'round',
|
||||||
|
title: '是否圆角按钮'
|
||||||
|
}, {type: 'switch', field: 'circle', title: '是否圆形按钮'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'loading',
|
||||||
|
title: '是否加载中状态'
|
||||||
|
}, {type: 'switch', field: 'disabled', title: '是否禁用状态'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'icon',
|
||||||
|
title: '图标类名'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeOptionsRule, makeRequiredRule} from '../../utils/index';
|
||||||
|
|
||||||
|
const label = '级联选择器';
|
||||||
|
const name = 'cascader';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-cascader',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
effect: {
|
||||||
|
fetch: ''
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
options: [{
|
||||||
|
value: 'zhinan',
|
||||||
|
label: '指南',
|
||||||
|
children: [{
|
||||||
|
value: 'shejiyuanze',
|
||||||
|
label: '设计原则',
|
||||||
|
children: [{
|
||||||
|
value: 'yizhi',
|
||||||
|
label: '一致'
|
||||||
|
}, {
|
||||||
|
value: 'fankui',
|
||||||
|
label: '反馈'
|
||||||
|
}, {
|
||||||
|
value: 'xiaolv',
|
||||||
|
label: '效率'
|
||||||
|
}, {
|
||||||
|
value: 'kekong',
|
||||||
|
label: '可控'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
value: 'daohang',
|
||||||
|
label: '导航',
|
||||||
|
children: [{
|
||||||
|
value: 'cexiangdaohang',
|
||||||
|
label: '侧向导航'
|
||||||
|
}, {
|
||||||
|
value: 'dingbudaohang',
|
||||||
|
label: '顶部导航'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
value: 'zujian',
|
||||||
|
label: '组件',
|
||||||
|
children: [{
|
||||||
|
value: 'basic',
|
||||||
|
label: 'Basic',
|
||||||
|
children: [{
|
||||||
|
value: 'layout',
|
||||||
|
label: 'Layout 布局'
|
||||||
|
}, {
|
||||||
|
value: 'color',
|
||||||
|
label: 'Color 色彩'
|
||||||
|
}, {
|
||||||
|
value: 'typography',
|
||||||
|
label: 'Typography 字体'
|
||||||
|
}, {
|
||||||
|
value: 'icon',
|
||||||
|
label: 'Icon 图标'
|
||||||
|
}, {
|
||||||
|
value: 'button',
|
||||||
|
label: 'Button 按钮'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
value: 'form',
|
||||||
|
label: 'Form',
|
||||||
|
children: [{
|
||||||
|
value: 'radio',
|
||||||
|
label: 'Radio 单选框'
|
||||||
|
}, {
|
||||||
|
value: 'checkbox',
|
||||||
|
label: 'Checkbox 多选框'
|
||||||
|
}, {
|
||||||
|
value: 'input',
|
||||||
|
label: 'Input 输入框'
|
||||||
|
}, {
|
||||||
|
value: 'input-number',
|
||||||
|
label: 'InputNumber 计数器'
|
||||||
|
}, {
|
||||||
|
value: 'select',
|
||||||
|
label: 'Select 选择器'
|
||||||
|
}, {
|
||||||
|
value: 'cascader',
|
||||||
|
label: 'Cascader 级联选择器'
|
||||||
|
}, {
|
||||||
|
value: 'switch',
|
||||||
|
label: 'Switch 开关'
|
||||||
|
}, {
|
||||||
|
value: 'slider',
|
||||||
|
label: 'Slider 滑块'
|
||||||
|
}, {
|
||||||
|
value: 'time-picker',
|
||||||
|
label: 'TimePicker 时间选择器'
|
||||||
|
}, {
|
||||||
|
value: 'date-picker',
|
||||||
|
label: 'DatePicker 日期选择器'
|
||||||
|
}, {
|
||||||
|
value: 'datetime-picker',
|
||||||
|
label: 'DateTimePicker 日期时间选择器'
|
||||||
|
}, {
|
||||||
|
value: 'upload',
|
||||||
|
label: 'Upload 上传'
|
||||||
|
}, {
|
||||||
|
value: 'rate',
|
||||||
|
label: 'Rate 评分'
|
||||||
|
}, {
|
||||||
|
value: 'form',
|
||||||
|
label: 'Form 表单'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
makeRequiredRule(),
|
||||||
|
makeOptionsRule('props.options', false),
|
||||||
|
{
|
||||||
|
type: 'Object',
|
||||||
|
field: 'props',
|
||||||
|
title: '配置选项',
|
||||||
|
props: {
|
||||||
|
rule: [{
|
||||||
|
type: 'select',
|
||||||
|
field: 'expandTrigger',
|
||||||
|
title: '次级菜单的展开方式',
|
||||||
|
options: [{label: 'click', value: 'click'}, {label: 'hover', value: 'hover'}]
|
||||||
|
}, {type: 'switch', field: 'multiple', title: '是否多选'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'checkStrictly',
|
||||||
|
title: '是否严格的遵守父子节点不互相关联'
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'emitPath',
|
||||||
|
title: '在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false,则只返回该节点的值',
|
||||||
|
value: true
|
||||||
|
}, {type: 'input', field: 'value', title: '指定选项的值为选项对象的某个属性值'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'label',
|
||||||
|
title: '指定选项标签为选项对象的某个属性值'
|
||||||
|
}, {type: 'input', field: 'children', title: '指定选项的子选项为选项对象的某个属性值'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '指定选项的禁用为选项对象的某个属性值'
|
||||||
|
}, {type: 'input', field: 'leaf', title: '指定选项的叶子节点的标志位为选项对象的某个属性值'}]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'size',
|
||||||
|
title: '尺寸',
|
||||||
|
options: [{label: 'large', value: 'large'}, {label: 'default', value: 'default'}, {
|
||||||
|
label: 'small',
|
||||||
|
value: 'small'
|
||||||
|
}]
|
||||||
|
}, {type: 'input', field: 'placeholder', title: '输入框占位文本'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '是否禁用'
|
||||||
|
}, {type: 'switch', field: 'clearable', title: '是否支持清空选项'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'showAllLevels',
|
||||||
|
title: '输入框中是否显示选中值的完整路径',
|
||||||
|
value: true
|
||||||
|
}, {type: 'switch', field: 'collapseTags', title: '多选模式下是否折叠Tag'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'separator',
|
||||||
|
title: '选项分隔符'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeOptionsRule, makeRequiredRule} from '../../utils/index';
|
||||||
|
|
||||||
|
const label = '多选框';
|
||||||
|
const name = 'checkbox';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-checkbox',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
effect: {
|
||||||
|
fetch: ''
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
options: [
|
||||||
|
{value: '1', label: '选项1'},
|
||||||
|
{value: '2', label: '选项2'},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
makeRequiredRule(), makeOptionsRule('options'),
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
field: 'type',
|
||||||
|
title: '按钮类型',
|
||||||
|
props: {activeValue: 'button', inactiveValue: 'default'}
|
||||||
|
}, {type: 'switch', field: 'disabled', title: '是否禁用'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'min',
|
||||||
|
title: '可被勾选的 checkbox 的最小数量'
|
||||||
|
}, {type: 'inputNumber', field: 'max', title: '可被勾选的 checkbox 的最大数量'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'textColor',
|
||||||
|
title: '按钮形式的 Checkbox 激活时的文本颜色'
|
||||||
|
}, {type: 'input', field: 'fill', title: '按钮形式的 Checkbox 激活时的填充色和边框色'}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
const name = 'col';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name,
|
||||||
|
drag: true,
|
||||||
|
dragBtn: false,
|
||||||
|
inside: true,
|
||||||
|
mask: false,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
props: {span: 12},
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
{type: 'slider', field: 'span', title: '栅格占据的列数', value: 12, props: {min: 0, max: 24}},
|
||||||
|
{type: 'slider', field: 'offset', title: '栅格左侧的间隔格数', props: {min: 0, max: 24}},
|
||||||
|
{type: 'slider', field: 'push', title: '栅格向右移动格数', props: {min: 0, max: 24}},
|
||||||
|
{type: 'slider', field: 'pull', title: '栅格向左移动格数', props: {min: 0, max: 24}}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '颜色选择器';
|
||||||
|
const name = 'colorPicker';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-color',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
makeRequiredRule(), {type: 'switch', field: 'disabled', title: '是否禁用'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'showAlpha',
|
||||||
|
title: '是否支持透明度选择'
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'colorFormat',
|
||||||
|
title: '颜色的格式',
|
||||||
|
options: [{label: 'hsl', value: 'hsl'}, {label: 'hsv', value: 'hsv'}, {
|
||||||
|
label: 'hex',
|
||||||
|
value: 'hex'
|
||||||
|
}, {label: 'rgb', value: 'rgb'}]
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '日期选择器';
|
||||||
|
const name = 'datePicker';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-date',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'pickerOptions',
|
||||||
|
title: '当前时间日期选择器特有的选项',
|
||||||
|
props: {defaultValue: {}}
|
||||||
|
}, {type: 'switch', field: 'readonly', title: '完全只读'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '禁用'
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'type',
|
||||||
|
title: '显示类型',
|
||||||
|
options: [{label: 'year', value: 'year'}, {label: 'month', value: 'month'}, {
|
||||||
|
label: 'date',
|
||||||
|
value: 'date'
|
||||||
|
}, {label: 'dates', value: 'dates'}, {label: 'week', value: 'week'}, {
|
||||||
|
label: 'datetime',
|
||||||
|
value: 'datetime'
|
||||||
|
}, {label: 'datetimerange', value: 'datetimerange'}, {
|
||||||
|
label: 'daterange',
|
||||||
|
value: 'daterange'
|
||||||
|
}, {label: 'monthrange', value: 'monthrange'}]
|
||||||
|
}, {type: 'switch', field: 'editable', title: '文本框可输入', value: true}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'clearable',
|
||||||
|
title: '是否显示清除按钮',
|
||||||
|
value: true
|
||||||
|
}, {type: 'input', field: 'placeholder', title: '非范围选择时的占位内容'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'startPlaceholder',
|
||||||
|
title: '范围选择时开始日期的占位内容'
|
||||||
|
}, {type: 'input', field: 'endPlaceholder', title: '范围选择时结束日期的占位内容'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'format',
|
||||||
|
title: '显示在输入框中的格式'
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'align',
|
||||||
|
title: '对齐方式',
|
||||||
|
options: [{label: 'left', value: 'left'}, {label: 'center', value: 'center'}, {
|
||||||
|
label: 'right',
|
||||||
|
value: 'right'
|
||||||
|
}, {label: 'left', value: 'left'}]
|
||||||
|
}, {type: 'input', field: 'rangeSeparator', title: '选择范围时的分隔符'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'unlinkPanels',
|
||||||
|
title: '在范围选择器里取消两个日期面板之间的联动'
|
||||||
|
}, {type: 'input', field: 'prefixIcon', title: '自定义头部图标的类名'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'clearIcon',
|
||||||
|
title: '自定义清空图标的类名'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
const label = '分割线';
|
||||||
|
const name = 'el-divider';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-divider',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
props: {},
|
||||||
|
wrap: {show: false},
|
||||||
|
native: false,
|
||||||
|
children: [''],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [{
|
||||||
|
type: 'select',
|
||||||
|
field: 'direction',
|
||||||
|
title: '设置分割线方向',
|
||||||
|
options: [{label: 'horizontal', value: 'horizontal'}, {label: 'vertical', value: 'vertical'}]
|
||||||
|
}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'formCreateChild',
|
||||||
|
title: '设置分割线文案',
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'contentPosition',
|
||||||
|
title: '设置分割线文案的位置',
|
||||||
|
options: [{label: 'left', value: 'left'}, {label: 'right', value: 'right'}, {
|
||||||
|
label: 'center',
|
||||||
|
value: 'center'
|
||||||
|
}]
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
const label = "浮层面板";
|
||||||
|
const name = "a-drawer";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: "icon-row",
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
drag: true,
|
||||||
|
dragBtn: false,
|
||||||
|
mask: false,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type : name,
|
||||||
|
props : {
|
||||||
|
title:"Create a new account",
|
||||||
|
width:"720",
|
||||||
|
visible:false,
|
||||||
|
},
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
{ type: "input", field: "width", title: "宽度" },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '富文本框';
|
||||||
|
const name = 'fc-editor';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-editor',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {type: 'switch', field: 'disabled', title: '是否禁用'}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
// import FcDesigner from "@form-create/ant-design-vue";
|
||||||
|
import {makeRequiredRule,makeOptionsRule} from '../../utils';
|
||||||
|
const label = "图片";
|
||||||
|
const name = "a-image";
|
||||||
|
const icon = "icon-xingzhuang-tupian";
|
||||||
|
let i = 1;
|
||||||
|
const uniqueId = () => `uni${i++}`;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
//拖拽组件的图标
|
||||||
|
icon,
|
||||||
|
//拖拽组件的名称
|
||||||
|
label,
|
||||||
|
//拖拽组件的 key
|
||||||
|
name,
|
||||||
|
//拖拽组件的生成规则
|
||||||
|
rule() {
|
||||||
|
//如果在 props 方法中需要修改 rule 的属性,需要提前在 rule 上定义对应的属性
|
||||||
|
return {
|
||||||
|
//生成组件的名称
|
||||||
|
type: name,
|
||||||
|
//field 自定不能重复,所以这里每次都会生成一个新的
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: "",
|
||||||
|
effect: {
|
||||||
|
fetch: ""
|
||||||
|
},
|
||||||
|
//这里设置组件的默认props配置项, 在下面的 props 方法里面设置无效
|
||||||
|
props: {
|
||||||
|
src: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png",
|
||||||
|
width: 200,
|
||||||
|
placeholder: true,
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
//拖拽组件配置项(props)的生成规则
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
//生成`checkbox`组件的`options`配置规则
|
||||||
|
// makeRequiredRule(),
|
||||||
|
// makeOptionsRule("props"),
|
||||||
|
{ type: "input", field: "src", title: "图片地址(支持http/base64)" },
|
||||||
|
{ type: "input", field: "fallback", title: "加载失败容错地址" },
|
||||||
|
{ type: "input", field: "width", title: "图像宽度" },
|
||||||
|
{ type: "input", field: "height", title: "图像高度" },
|
||||||
|
{ type: "switch", field: "preview", title: "预览参数,为 false 时禁用" },
|
||||||
|
{ type: "switch", field: "placeholder", title: "加载占位, 为 true 时使用默认占位"},
|
||||||
|
{ type: "input", field: "alt", title: "图像描述"},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import radio from './radio';
|
||||||
|
import checkbox from './checkbox';
|
||||||
|
import input from './input';
|
||||||
|
import number from './number';
|
||||||
|
import select from './select';
|
||||||
|
import _switch from './switch';
|
||||||
|
import slider from './slider';
|
||||||
|
import time from './time';
|
||||||
|
import date from './date';
|
||||||
|
import rate from './rate';
|
||||||
|
import color from './color';
|
||||||
|
import row from './row';
|
||||||
|
import col from './col';
|
||||||
|
import tabPane from './tabPane';
|
||||||
|
import divider from './divider';
|
||||||
|
import cascader from './cascader';
|
||||||
|
import upload from './upload';
|
||||||
|
import transfer from './transfer';
|
||||||
|
import tree from './tree';
|
||||||
|
import alert from './alert';
|
||||||
|
import span from './span';
|
||||||
|
import space from './space';
|
||||||
|
import tab from './tab';
|
||||||
|
import button from './button';
|
||||||
|
import editor from './editor';
|
||||||
|
import drawer from './drawer';
|
||||||
|
import image from './image.ts';
|
||||||
|
|
||||||
|
// 还需要在../menu.js文件里注册
|
||||||
|
|
||||||
|
const ruleList = {
|
||||||
|
[drawer.name]: drawer,
|
||||||
|
[radio.name]: radio,
|
||||||
|
[checkbox.name]: checkbox,
|
||||||
|
[input.name]: input,
|
||||||
|
[number.name]: number,
|
||||||
|
[select.name]: select,
|
||||||
|
[_switch.name]: _switch,
|
||||||
|
[slider.name]: slider,
|
||||||
|
[time.name]: time,
|
||||||
|
[date.name]: date,
|
||||||
|
[rate.name]: rate,
|
||||||
|
[color.name]: color,
|
||||||
|
[row.name]: row,
|
||||||
|
[col.name]: col,
|
||||||
|
[tab.name]: tab,
|
||||||
|
[tabPane.name]: tabPane,
|
||||||
|
[divider.name]: divider,
|
||||||
|
[cascader.name]: cascader,
|
||||||
|
[upload.name]: upload,
|
||||||
|
[transfer.name]: transfer,
|
||||||
|
[tree.name]: tree,
|
||||||
|
[alert.name]: alert,
|
||||||
|
[span.name]: span,
|
||||||
|
[space.name]: space,
|
||||||
|
[button.name]: button,
|
||||||
|
[editor.name]: editor,
|
||||||
|
[image.name]: image,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ruleList;
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '输入框';
|
||||||
|
const name = 'input';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-input',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {
|
||||||
|
type: 'select',
|
||||||
|
field: 'type',
|
||||||
|
title: '类型',
|
||||||
|
options: [{label: 'text', value: 'text'}, {
|
||||||
|
label: 'textarea',
|
||||||
|
value: 'textarea'
|
||||||
|
}, {label: 'number', value: 'number'}, {label: 'password', value: 'password'}]
|
||||||
|
}, {type: 'inputNumber', field: 'maxlength', title: '最大输入长度'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'minlength',
|
||||||
|
title: '最小输入长度'
|
||||||
|
}, {type: 'switch', field: 'showWordLimit', title: '是否显示输入字数统计'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'placeholder',
|
||||||
|
title: '输入框占位文本'
|
||||||
|
}, {type: 'switch', field: 'clearable', title: '是否可清空'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'showPassword',
|
||||||
|
title: '是否显示切换密码图标'
|
||||||
|
}, {type: 'switch', field: 'disabled', title: '禁用'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'prefixIcon',
|
||||||
|
title: '输入框头部图标'
|
||||||
|
}, {type: 'input', field: 'suffixIcon', title: '输入框尾部图标'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'rows',
|
||||||
|
info: '只对 type="textarea" 有效',
|
||||||
|
title: '输入框行数'
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'autocomplete',
|
||||||
|
title: '自动补全',
|
||||||
|
options: [{label: 'on', value: 'on'}, {label: 'off', value: 'off'}]
|
||||||
|
}, {type: 'switch', field: 'readonly', title: '是否只读'}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'resize',
|
||||||
|
title: '控制是否能被用户缩放',
|
||||||
|
options: [{label: 'none', value: 'none'}, {label: 'both', value: 'both'}, {
|
||||||
|
label: 'horizontal',
|
||||||
|
value: 'horizontal'
|
||||||
|
}, {label: 'vertical', value: 'vertical'}]
|
||||||
|
}, {type: 'switch', field: 'autofocus', title: '自动获取焦点'}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '计数器';
|
||||||
|
const name = 'inputNumber';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-number',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {type: 'inputNumber', field: 'min', title: '设置计数器允许的最小值'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'max',
|
||||||
|
title: '设置计数器允许的最大值'
|
||||||
|
}, {type: 'inputNumber', field: 'step', title: '计数器步长'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'stepStrictly',
|
||||||
|
title: '是否只能输入 step 的倍数'
|
||||||
|
}, {type: 'switch', field: 'disabled', title: '是否禁用计数器'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'controls',
|
||||||
|
title: '是否使用控制按钮',
|
||||||
|
value: true
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'controlsPosition',
|
||||||
|
title: '控制按钮位置',
|
||||||
|
options: [{label: 'default', value: ''}, {label: 'right', value: 'right'}]
|
||||||
|
}, {type: 'input', field: 'placeholder', title: '输入框默认 placeholder'}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeOptionsRule, makeRequiredRule} from '../../utils/index';
|
||||||
|
|
||||||
|
const label = '单选框';
|
||||||
|
const name = 'radio';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-radio',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
effect: {
|
||||||
|
fetch: ''
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
options: [
|
||||||
|
{value: '1', label: '选项1'},
|
||||||
|
{value: '2', label: '选项2'},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
makeRequiredRule(),
|
||||||
|
makeOptionsRule('options'),
|
||||||
|
{type: 'switch', field: 'disabled', title: '是否禁用'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'type',
|
||||||
|
title: '按钮形式',
|
||||||
|
props: {activeValue: 'button', inactiveValue: 'default'}
|
||||||
|
}, {type: 'input', field: 'textColor', title: '按钮形式的 Radio 激活时的文本颜色'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'fill',
|
||||||
|
title: '按钮形式的 Radio 激活时的填充色和边框色'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '评分';
|
||||||
|
const name = 'rate';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-rate',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
makeRequiredRule(), {type: 'inputNumber', field: 'max', title: '最大分值'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '是否为只读'
|
||||||
|
}, {type: 'switch', field: 'allowHalf', title: '是否允许半选'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'voidColor',
|
||||||
|
title: '未选中 icon 的颜色'
|
||||||
|
}, {type: 'input', field: 'disabledVoidColor', title: '只读时未选中 icon 的颜色'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'voidIconClass',
|
||||||
|
title: '未选中 icon 的类名'
|
||||||
|
}, {type: 'input', field: 'disabledVoidIconClass', title: '只读时未选中 icon 的类名'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'showScore',
|
||||||
|
title: '是否显示当前分数,show-score 和 show-text 不能同时为真'
|
||||||
|
}, {type: 'input', field: 'textColor', title: '辅助文字的颜色'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'scoreTemplate',
|
||||||
|
title: '分数显示模板'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
const label = '栅格布局';
|
||||||
|
const name = 'row';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-row',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
mask: false,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: 'FcRow',
|
||||||
|
props: {},
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
children: 'col',
|
||||||
|
props() {
|
||||||
|
return [{type: 'inputNumber', field: 'gutter', title: '栅格间隔'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'type',
|
||||||
|
title: 'flex布局模式',
|
||||||
|
props: {activeValue: 'flex', inactiveValue: 'default'}
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'justify',
|
||||||
|
title: 'flex 布局下的水平排列方式',
|
||||||
|
options: [{label: 'start', value: 'start'}, {label: 'end', value: 'end'}, {
|
||||||
|
label: 'center',
|
||||||
|
value: 'center'
|
||||||
|
}, {label: 'space-around', value: 'space-around'}, {label: 'space-between', value: 'space-between'}]
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'align',
|
||||||
|
title: 'flex 布局下的垂直排列方式',
|
||||||
|
options: [{label: 'top', value: 'top'}, {label: 'middle', value: 'middle'}, {
|
||||||
|
label: 'bottom',
|
||||||
|
value: 'bottom'
|
||||||
|
}]
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeOptionsRule, makeRequiredRule} from '../../utils/index';
|
||||||
|
|
||||||
|
const label = '选择器';
|
||||||
|
const name = 'select';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-select',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
effect: {
|
||||||
|
fetch: ''
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
options: [
|
||||||
|
{value: '1', label: '选项1'},
|
||||||
|
{value: '2', label: '选项2'},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
makeRequiredRule(),
|
||||||
|
makeOptionsRule('options'),
|
||||||
|
{type: 'switch', field: 'multiple', title: '是否多选'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '是否禁用'
|
||||||
|
}, {type: 'switch', field: 'clearable', title: '是否可以清空选项'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'collapseTags',
|
||||||
|
title: '多选时是否将选中值按文字的形式展示'
|
||||||
|
}, {type: 'inputNumber', field: 'multipleLimit', title: '多选时用户最多可以选择的项目数,为 0 则不限制'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'autocomplete',
|
||||||
|
title: 'autocomplete 属性'
|
||||||
|
}, {type: 'input', field: 'placeholder', title: '占位符'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'filterable',
|
||||||
|
title: '是否可搜索'
|
||||||
|
}, {type: 'switch', field: 'allowCreate', title: '是否允许用户创建新条目'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'noMatchText',
|
||||||
|
title: '搜索条件无匹配时显示的文字'
|
||||||
|
}, {type: 'input', field: 'noDataText', title: '选项为空时显示的文字'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'reserveKeyword',
|
||||||
|
title: '多选且可搜索时,是否在选中一个选项后保留当前的搜索关键词'
|
||||||
|
}, {type: 'switch', field: 'defaultFirstOption', title: '在输入框按下回车,选择第一个匹配项'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'popperAppendToBody',
|
||||||
|
title: '是否将弹出框插入至 body 元素',
|
||||||
|
value: true
|
||||||
|
}, {type: 'switch', field: 'automaticDropdown', title: '对于不可搜索的 Select,是否在输入框获得焦点后自动弹出选项菜单'}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '滑块';
|
||||||
|
const name = 'slider';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-slider',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {type: 'inputNumber', field: 'min', title: '最小值'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'max',
|
||||||
|
title: '最大值'
|
||||||
|
}, {type: 'switch', field: 'disabled', title: '是否禁用'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'step',
|
||||||
|
title: '步长'
|
||||||
|
}, {type: 'switch', field: 'showInput', title: '是否显示输入框,仅在非范围选择时有效'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'showInputControls',
|
||||||
|
title: '在显示输入框的情况下,是否显示输入框的控制按钮',
|
||||||
|
value: true
|
||||||
|
}, {type: 'switch', field: 'showStops', title: '是否显示间断点'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'range',
|
||||||
|
title: '是否为范围选择'
|
||||||
|
}, {type: 'switch', field: 'vertical', title: '是否竖向模式'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'height',
|
||||||
|
title: 'Slider 高度,竖向模式时必填'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
const label = '间距';
|
||||||
|
const name = 'div';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-space',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
wrap: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
native: false,
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
height: '20px',
|
||||||
|
},
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
field: 'formCreateStyle',
|
||||||
|
native: true,
|
||||||
|
props: {
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
field: 'height',
|
||||||
|
title: 'height',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
const label = '文字';
|
||||||
|
const name = 'span';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-span',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
title: '文字',
|
||||||
|
native: false,
|
||||||
|
children: ['这是一段文字'],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
field: 'formCreateTitle',
|
||||||
|
title: 'title',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
field: 'formCreateChild',
|
||||||
|
title: '内容',
|
||||||
|
props: {
|
||||||
|
type: 'textarea'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '开关';
|
||||||
|
const name = 'switch';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-switch',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {type: 'switch', field: 'disabled', title: '是否禁用'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'width',
|
||||||
|
title: '宽度(px)'
|
||||||
|
}, {type: 'input', field: 'activeText', title: 'switch 打开时的文字描述'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'inactiveText',
|
||||||
|
title: 'switch 关闭时的文字描述'
|
||||||
|
}, {type: 'input', field: 'activeValue', title: 'switch 打开时的值'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'inactiveValue',
|
||||||
|
title: 'switch 关闭时的值'
|
||||||
|
}, {type: 'input', field: 'activeColor', title: 'switch 打开时的背景色'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'inactiveColor',
|
||||||
|
title: 'switch 关闭时的背景色'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
const label = '标签页';
|
||||||
|
const name = 'tab';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-tab',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
children: 'tab-pane',
|
||||||
|
mask: false,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: 'el-tabs',
|
||||||
|
style:'width:100%;',
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [{
|
||||||
|
type: 'select',
|
||||||
|
field: 'type',
|
||||||
|
title: '风格类型',
|
||||||
|
options: [{
|
||||||
|
label: 'card',
|
||||||
|
value: 'card'
|
||||||
|
}, {label: 'border-card', value: 'border-card'}]
|
||||||
|
}, {type: 'switch', field: 'closable', title: '标签是否可关闭'}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'tabPosition',
|
||||||
|
title: '选项卡所在位置',
|
||||||
|
options: [{label: 'top', value: 'top'}, {label: 'right', value: 'right'}, {
|
||||||
|
label: 'left',
|
||||||
|
value: 'left'
|
||||||
|
}]
|
||||||
|
}, {type: 'switch', field: 'stretch', title: '标签的宽度是否自撑开'}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
const label = '标签页';
|
||||||
|
const name = 'tab-pane';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
inside: true,
|
||||||
|
drag: true,
|
||||||
|
dragBtn: false,
|
||||||
|
mask: false,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: 'el-tab-pane',
|
||||||
|
props: {label: '新标签页'},
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [{type: 'input', field: 'label', title: '选项卡标题'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '是否禁用'
|
||||||
|
}, {type: 'input', field: 'name', title: '与选项卡绑定值 value 对应的标识符,表示选项卡别名'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'lazy',
|
||||||
|
title: '标签是否延迟渲染'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '时间选择器';
|
||||||
|
const name = 'timePicker';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-time',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'pickerOptions',
|
||||||
|
title: '当前时间日期选择器特有的选项',
|
||||||
|
props: {defaultValue: {}}
|
||||||
|
}, {type: 'switch', field: 'readonly', title: '完全只读'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '禁用'
|
||||||
|
}, {type: 'switch', field: 'editable', title: '文本框可输入', value: true}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'clearable',
|
||||||
|
title: '是否显示清除按钮',
|
||||||
|
value: true
|
||||||
|
}, {type: 'input', field: 'placeholder', title: '非范围选择时的占位内容'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'startPlaceholder',
|
||||||
|
title: '范围选择时开始日期的占位内容'
|
||||||
|
}, {type: 'input', field: 'endPlaceholder', title: '范围选择时开始日期的占位内容'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'isRange',
|
||||||
|
title: '是否为时间范围选择'
|
||||||
|
}, {type: 'switch', field: 'arrowControl', title: '是否使用箭头进行时间选择'}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'align',
|
||||||
|
title: '对齐方式',
|
||||||
|
options: [{label: 'left', value: 'left'}, {label: 'center', value: 'center'}, {
|
||||||
|
label: 'right',
|
||||||
|
value: 'right'
|
||||||
|
}]
|
||||||
|
}, {type: 'input', field: 'prefixIcon', title: '自定义头部图标的类名'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'clearIcon',
|
||||||
|
title: '自定义清空图标的类名'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
|
||||||
|
const label = '穿梭框';
|
||||||
|
const name = 'el-transfer';
|
||||||
|
|
||||||
|
const generateData = _ => {
|
||||||
|
const data = [];
|
||||||
|
for (let i = 1; i <= 15; i++) {
|
||||||
|
data.push({
|
||||||
|
key: i,
|
||||||
|
label: `备选项 ${i}`,
|
||||||
|
disabled: i % 4 === 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-transfer',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {
|
||||||
|
data: generateData()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [{
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'data',
|
||||||
|
title: 'Transfer 的数据源',
|
||||||
|
props: {defaultValue: []}
|
||||||
|
}, {type: 'switch', field: 'filterable', title: '是否可搜索'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'filterPlaceholder',
|
||||||
|
title: '搜索框占位符'
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
field: 'targetOrder',
|
||||||
|
title: '右侧列表元素的排序策略',
|
||||||
|
info: '若为 original,则保持与数据源相同的顺序;若为 push,则新加入的元素排在最后;若为 unshift,则新加入的元素排在最前',
|
||||||
|
options: [{label: 'original', value: 'original'}, {
|
||||||
|
label: 'push',
|
||||||
|
value: 'push'
|
||||||
|
}, {label: 'unshift', value: 'unshift'}]
|
||||||
|
}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'titles',
|
||||||
|
title: '自定义列表标题',
|
||||||
|
props: {defaultValue: []}
|
||||||
|
}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'buttonTexts',
|
||||||
|
title: '自定义按钮文案',
|
||||||
|
props: {defaultValue: []}
|
||||||
|
}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'format',
|
||||||
|
title: '列表顶部勾选状态文案',
|
||||||
|
props: {defaultValue: {}}
|
||||||
|
}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'props',
|
||||||
|
title: '数据源的字段别名',
|
||||||
|
props: {defaultValue: {}}
|
||||||
|
}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'leftDefaultChecked',
|
||||||
|
title: '初始状态下左侧列表的已勾选项的 key 数组',
|
||||||
|
props: {defaultValue: []}
|
||||||
|
}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'rightDefaultChecked',
|
||||||
|
title: '初始状态下右侧列表的已勾选项的 key 数组',
|
||||||
|
props: {defaultValue: []}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeOptionsRule, makeRequiredRule} from '../../utils/index';
|
||||||
|
|
||||||
|
const label = '树形控件';
|
||||||
|
const name = 'tree';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-tree',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
effect: {
|
||||||
|
fetch: ''
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
props: {
|
||||||
|
label: 'label',
|
||||||
|
},
|
||||||
|
showCheckbox: true,
|
||||||
|
nodeKey: 'id',
|
||||||
|
data: [{
|
||||||
|
id: 1,
|
||||||
|
label: '一级 1',
|
||||||
|
children: [{
|
||||||
|
id: 4,
|
||||||
|
label: '二级 1-1',
|
||||||
|
children: [{
|
||||||
|
id: 9,
|
||||||
|
label: '三级 1-1-1'
|
||||||
|
}, {
|
||||||
|
id: 10,
|
||||||
|
label: '三级 1-1-2'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
id: 2,
|
||||||
|
label: '一级 2',
|
||||||
|
children: [{
|
||||||
|
id: 5,
|
||||||
|
label: '二级 2-1'
|
||||||
|
}, {
|
||||||
|
id: 6,
|
||||||
|
label: '二级 2-2'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
id: 3,
|
||||||
|
label: '一级 3',
|
||||||
|
children: [{
|
||||||
|
id: 7,
|
||||||
|
label: '二级 3-1'
|
||||||
|
}, {
|
||||||
|
id: 8,
|
||||||
|
label: '二级 3-2'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [
|
||||||
|
makeRequiredRule(),
|
||||||
|
makeOptionsRule('props.data', false),
|
||||||
|
{type: 'input', field: 'emptyText', title: '内容为空的时候展示的文本'}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'props',
|
||||||
|
title: '配置选项,具体看下表',
|
||||||
|
props: {defaultValue: {}}
|
||||||
|
}, {type: 'switch', field: 'renderAfterExpand', title: '是否在第一次展开某个树节点后才渲染其子节点', value: true}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'defaultExpandAll',
|
||||||
|
title: '是否默认展开所有节点',
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'expandOnClickNode',
|
||||||
|
title: '是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。',
|
||||||
|
value: true
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'checkOnClickNode',
|
||||||
|
title: '是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点。'
|
||||||
|
}, {type: 'switch', field: 'autoExpandParent', title: '展开子节点的时候是否自动展开父节点', value: true}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'checkStrictly',
|
||||||
|
title: '在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false'
|
||||||
|
}, {type: 'switch', field: 'accordion', title: '是否每次只打开一个同级树节点展开'}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'indent',
|
||||||
|
title: '相邻级节点间的水平缩进,单位为像素'
|
||||||
|
}, {type: 'input', field: 'iconClass', title: '自定义树节点的图标'}, {
|
||||||
|
type: 'input',
|
||||||
|
field: 'nodeKey',
|
||||||
|
title: '每个树节点用来作为唯一标识的属性,整棵树应该是唯一的'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import uniqueId from '@form-create/utils/lib/unique';
|
||||||
|
import {makeRequiredRule} from '../../utils';
|
||||||
|
|
||||||
|
const label = '上传';
|
||||||
|
const name = 'upload';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
icon: 'icon-upload',
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
rule() {
|
||||||
|
return {
|
||||||
|
type: name,
|
||||||
|
field: uniqueId(),
|
||||||
|
title: label,
|
||||||
|
info: '',
|
||||||
|
props: {
|
||||||
|
action: '',
|
||||||
|
onSuccess(res, file) {
|
||||||
|
file.url = res.data.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props() {
|
||||||
|
return [makeRequiredRule(), {
|
||||||
|
type: 'select',
|
||||||
|
field: 'uploadType',
|
||||||
|
title: '上传类型',
|
||||||
|
value: 'image',
|
||||||
|
options: [{label: '图片', value: 'image'}, {
|
||||||
|
label: '文件',
|
||||||
|
value: 'file'
|
||||||
|
}]
|
||||||
|
}, {type: 'input', field: 'action', title: '上传的地址(必填)'}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'headers',
|
||||||
|
title: '设置上传的请求头部',
|
||||||
|
props: {defaultValue: {}}
|
||||||
|
}, {type: 'switch', field: 'multiple', title: '是否支持多选文件'}, {
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'data',
|
||||||
|
title: '上传时附带的额外参数',
|
||||||
|
props: {defaultValue: {}}
|
||||||
|
}, {type: 'input', field: 'name', title: '上传的文件字段名'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'withCredentials',
|
||||||
|
title: '支持发送 cookie 凭证信息'
|
||||||
|
}, {type: 'input', field: 'accept', title: '接受上传的文件类型(thumbnail-mode 模式下此参数无效)'}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'autoUpload',
|
||||||
|
title: '是否在选取文件后立即进行上传',
|
||||||
|
value: true
|
||||||
|
}, {
|
||||||
|
type: 'switch',
|
||||||
|
field: 'disabled',
|
||||||
|
title: '是否禁用'
|
||||||
|
}, {
|
||||||
|
type: 'inputNumber',
|
||||||
|
field: 'limit',
|
||||||
|
title: '最大允许上传个数'
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import FcDesigner from './components/FcDesigner.vue';
|
||||||
|
import DragTool from './components/DragTool.vue';
|
||||||
|
import Struct from './components/Struct.vue';
|
||||||
|
import Fetch from './components/Fetch.vue';
|
||||||
|
import Validate from './components/Validate.vue';
|
||||||
|
import DragBox from './components/DragBox.vue';
|
||||||
|
import Required from './components/Required.vue';
|
||||||
|
import TableOptions from './components/TableOptions.vue';
|
||||||
|
import {designerForm} from './utils/form';
|
||||||
|
import FcEditor from '@form-create/component-wangeditor';
|
||||||
|
import './style/index.css';
|
||||||
|
import draggable from 'vuedraggable/src/vuedraggable';
|
||||||
|
import unique from '@form-create/utils/lib/unique';
|
||||||
|
import {makeOptionsRule} from './utils/index';
|
||||||
|
import formCreate from './utils/form';
|
||||||
|
|
||||||
|
designerForm.component('draggable', draggable);
|
||||||
|
designerForm.component('DragTool', DragTool);
|
||||||
|
designerForm.component('DragBox', DragBox);
|
||||||
|
designerForm.component('Validate', Validate);
|
||||||
|
designerForm.component('Struct', Struct);
|
||||||
|
designerForm.component('Fetch', Fetch);
|
||||||
|
designerForm.component('Required', Required);
|
||||||
|
designerForm.component('TableOptions', TableOptions);
|
||||||
|
designerForm.component('FcEditor', FcEditor);
|
||||||
|
formCreate.component('FcEditor', FcEditor);
|
||||||
|
|
||||||
|
designerForm.register('_fc', {
|
||||||
|
init(fc, rule) {
|
||||||
|
rule._id = unique();
|
||||||
|
if (fc.repeat)
|
||||||
|
rule.field = unique();
|
||||||
|
if (fc.value) {
|
||||||
|
rule.effect._fc = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
designerForm.register('_fc_tool', {
|
||||||
|
init(_, rule) {
|
||||||
|
rule.props.unique = unique();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const install = function (Vue) {
|
||||||
|
Vue.component('FcDesigner', FcDesigner);
|
||||||
|
};
|
||||||
|
|
||||||
|
FcDesigner.install = install;
|
||||||
|
FcDesigner.makeOptionsRule = makeOptionsRule;
|
||||||
|
FcDesigner.formCreate = formCreate;
|
||||||
|
FcDesigner.designerForm = designerForm;
|
||||||
|
|
||||||
|
export default FcDesigner;
|
||||||
|
|
||||||
|
export {formCreate, designerForm, install};
|
||||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "iconfont"; /* Project id */
|
||||||
|
src: url('iconfont.ttf?t=1669574713695') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-family: "iconfont" !important;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xingzhuang-tupian:before {
|
||||||
|
content: "\eb98";
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,138 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "fc-icon";
|
||||||
|
src: url(fonts/fc-icons.woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "fc-icon"; /* Project id */
|
||||||
|
src: url('fonts/iconfont.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
.fc-icon {
|
||||||
|
font-family: "fc-icon" !important;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
.icon-xingzhuang-tupian:before {
|
||||||
|
content: "\eb98";
|
||||||
|
}
|
||||||
|
.icon-add-child:before {
|
||||||
|
content: "\e789";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-switch:before {
|
||||||
|
content: "\e77c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-tab:before {
|
||||||
|
content: "\e77b";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button:before {
|
||||||
|
content: "\e77e";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-input:before {
|
||||||
|
content: "\e77f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-checkbox:before {
|
||||||
|
content: "\e780";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-radio:before {
|
||||||
|
content: "\e781";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-rate:before {
|
||||||
|
content: "\e782";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-number:before {
|
||||||
|
content: "\e783";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-upload:before {
|
||||||
|
content: "\e784";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-cascader:before {
|
||||||
|
content: "\e785";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-space:before {
|
||||||
|
content: "\e786";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-color:before {
|
||||||
|
content: "\e787";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-span:before {
|
||||||
|
content: "\e788";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-alert:before {
|
||||||
|
content: "\e78a";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-row:before {
|
||||||
|
content: "\e78b";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-divider:before {
|
||||||
|
content: "\e78d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-select:before {
|
||||||
|
content: "\e78e";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-transfer:before {
|
||||||
|
content: "\e78f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-editor:before {
|
||||||
|
content: "\e790";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-slider:before {
|
||||||
|
content: "\e791";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-tree:before {
|
||||||
|
content: "\e792";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-date:before {
|
||||||
|
content: "\e793";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-time:before {
|
||||||
|
content: "\e794";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-delete:before {
|
||||||
|
content: "\e770";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-copy:before {
|
||||||
|
content: "\e771";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-import:before {
|
||||||
|
content: "\e773";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add:before {
|
||||||
|
content: "\e774";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-preview:before {
|
||||||
|
content: "\e776";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-move:before {
|
||||||
|
content: "\e777";
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import formCreate from '@form-create/element-ui';
|
||||||
|
|
||||||
|
const viewForm = formCreate;
|
||||||
|
|
||||||
|
const designerForm = formCreate.factory();
|
||||||
|
|
||||||
|
export default viewForm;
|
||||||
|
|
||||||
|
export {designerForm};
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import is, {hasProperty} from '@form-create/utils/lib/type';
|
||||||
|
import {parseFn} from '@form-create/utils/lib/json';
|
||||||
|
|
||||||
|
export function makeRequiredRule() {
|
||||||
|
return {
|
||||||
|
type: 'Required', field: 'formCreate$required', title: '是否必填'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeOptionsRule(to, flag) {
|
||||||
|
const options = [
|
||||||
|
{'label': 'JSON数据', 'value': 0},
|
||||||
|
{'label': '接口数据', 'value': 1},
|
||||||
|
];
|
||||||
|
|
||||||
|
const control = [
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'Struct',
|
||||||
|
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||||
|
props: {defaultValue: []}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'Fetch',
|
||||||
|
field: 'formCreateEffect>fetch',
|
||||||
|
props: {
|
||||||
|
to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if (flag !== false) {
|
||||||
|
options.splice(0, 0, {'label': '静态数据', 'value': 2});
|
||||||
|
control.push({
|
||||||
|
value: 2,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
type: 'TableOptions',
|
||||||
|
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||||
|
props: {defaultValue: []}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'radio',
|
||||||
|
title: '选项数据',
|
||||||
|
field: '_optionType',
|
||||||
|
value: flag !== false ? 2 : 0,
|
||||||
|
options,
|
||||||
|
props: {
|
||||||
|
type: 'button'
|
||||||
|
},
|
||||||
|
control
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function upper(str) {
|
||||||
|
return str.replace(str[0], str[0].toLocaleUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const toJSON = function (val) {
|
||||||
|
const type = /object ([a-zA-Z]*)/.exec(Object.prototype.toString.call(val));
|
||||||
|
if (type && _toJSON[type[1].toLowerCase()]) {
|
||||||
|
return _toJSON[type[1].toLowerCase()](val);
|
||||||
|
} else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const _toJSON = {
|
||||||
|
object: function (val) {
|
||||||
|
var json = [];
|
||||||
|
for (var i in val) {
|
||||||
|
if (!hasProperty(val, i)) continue;
|
||||||
|
json.push(
|
||||||
|
toJSON(i) + ': ' +
|
||||||
|
((val[i] != null) ? toJSON(val[i]) : 'null')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '{\n ' + json.join(',\n ') + '\n}';
|
||||||
|
},
|
||||||
|
array: function (val) {
|
||||||
|
for (var i = 0, json = []; i < val.length; i++)
|
||||||
|
json[i] = (val[i] != null) ? toJSON(val[i]) : 'null';
|
||||||
|
return '[' + json.join(', ') + ']';
|
||||||
|
},
|
||||||
|
string: function (val) {
|
||||||
|
var tmp = val.split('');
|
||||||
|
for (var i = 0; i < tmp.length; i++) {
|
||||||
|
var c = tmp[i];
|
||||||
|
(c >= ' ') ?
|
||||||
|
(c === '\\') ? (tmp[i] = '\\\\') :
|
||||||
|
(c === '"') ? (tmp[i] = '\\"') : 0 :
|
||||||
|
(tmp[i] =
|
||||||
|
(c === '\n') ? '\\n' :
|
||||||
|
(c === '\r') ? '\\r' :
|
||||||
|
(c === '\t') ? '\\t' :
|
||||||
|
(c === '\b') ? '\\b' :
|
||||||
|
(c === '\f') ? '\\f' :
|
||||||
|
(c = c.charCodeAt(), ('\\u00' + ((c > 15) ? 1 : 0) + (c % 16)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '"' + tmp.join('') + '"';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deepParseFn = function (target) {
|
||||||
|
for (let key in target) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
||||||
|
let data = target[key];
|
||||||
|
if (Array.isArray(data) || is.Object(data)) {
|
||||||
|
deepParseFn(data);
|
||||||
|
}
|
||||||
|
if (is.String(data)) {
|
||||||
|
target[key] = parseFn(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
};
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* @Author : djkloop
|
||||||
|
* @Date : 2021-09-15 15:13:17
|
||||||
|
* @LastEditors : djkloop
|
||||||
|
* @LastEditTime : 2021-09-19 16:10:22
|
||||||
|
* @Description : 头部注释
|
||||||
|
* @FilePath : /form-create2/tools/cli/run.ts
|
||||||
|
*/
|
||||||
|
import {program} from 'commander';
|
||||||
|
import path from 'path';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import build from '../lib/build';
|
||||||
|
// pkgUrl
|
||||||
|
const log = console.log
|
||||||
|
const commandExecUrl = process.cwd()
|
||||||
|
log()
|
||||||
|
log(' ' + chalk.green('command run path with: ', commandExecUrl))
|
||||||
|
log()
|
||||||
|
const pkgUrl = path.join(commandExecUrl, '/lerna.json');
|
||||||
|
|
||||||
|
program.on('--help', () => {
|
||||||
|
log();
|
||||||
|
log(chalk.blue.bold(' Usage:'), chalk.cyan.bold('tools build tools with Node 👍 ~'));
|
||||||
|
log();
|
||||||
|
})
|
||||||
|
|
||||||
|
/// tools 版本
|
||||||
|
program
|
||||||
|
.version(`@form-create/tools v${require(pkgUrl).version}`, '-v, --version', 'tools versions')
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('build [flag]')
|
||||||
|
.description('build components && packages || build components || build packages')
|
||||||
|
.option('-a,--all', 'Build @form-create/[all]packages') /// 默认打包components和packages
|
||||||
|
.option('-c, --components <ui-compnents...>', 'Build @form-create/component-<ui-package> package or packages array') // 打单独的组件
|
||||||
|
.option('-p, --packages <ui-package...>', 'Build @form-create/<ui-package> package or packages array') // 打单独的包
|
||||||
|
.action((_: any, cmd: any) => build(_, cleanArgs(cmd)));
|
||||||
|
|
||||||
|
program.parse(process.argv);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// code with vue-cli: https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli/bin/vue.js#L275
|
||||||
|
function camelize(str: string) {
|
||||||
|
return str.replace(/-(\w)/g, (_, c) => c ? c.toUpperCase() : '')
|
||||||
|
}
|
||||||
|
|
||||||
|
// commander passes the Command object itself as options,
|
||||||
|
// extract only actual options into a fresh object.
|
||||||
|
function cleanArgs(cmd: any) {
|
||||||
|
const args: any = {}
|
||||||
|
cmd.options.forEach((o: any) => {
|
||||||
|
const key = camelize(o.long.replace(/^--/, ''))
|
||||||
|
// if an option is not present and Command has a method with the same name
|
||||||
|
// it should not be copied
|
||||||
|
if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') {
|
||||||
|
args[key] = cmd[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return args
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* @Author : djkloop
|
||||||
|
* @Date : 2020-08-15 17:21:22
|
||||||
|
* @LastEditors : djkloop
|
||||||
|
* @LastEditTime : 2021-10-04 19:33:38
|
||||||
|
* @Description : 头部注释
|
||||||
|
* @FilePath : /form-create2/tools/lib/build.ts
|
||||||
|
*/
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import ora from 'ora';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { exit } from 'process';
|
||||||
|
import shell from 'shelljs';
|
||||||
|
import createBuildComponents from './components';
|
||||||
|
import createBuildPackages from './packages';
|
||||||
|
import { blue, getFolderNames, getSingleComponentPaths, getSinglePackagePaths, red, targets as getAllTargetsPath, yellow } from './utils'
|
||||||
|
|
||||||
|
|
||||||
|
let spinner
|
||||||
|
const log = console.log
|
||||||
|
const context = process.cwd()
|
||||||
|
|
||||||
|
|
||||||
|
async function buildAllComponents(paths: string[] = []) {
|
||||||
|
let componentsPathsObject = Object.create(null)
|
||||||
|
paths.forEach((comPath: string) => {
|
||||||
|
const [name, cname] = comPath.split('/')
|
||||||
|
const componentsPaths = getSingleComponentPaths('components', name, cname)
|
||||||
|
|
||||||
|
if (!componentsPathsObject[name]) {
|
||||||
|
componentsPathsObject[name] = componentsPaths[name]
|
||||||
|
} else {
|
||||||
|
componentsPathsObject[name] = [...componentsPathsObject[name], ...componentsPaths[name]]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await createBuildComponents(componentsPathsObject)
|
||||||
|
await exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function createBuildTask(args: any) {
|
||||||
|
const isAll = args.all || Object.keys(args).length === 0
|
||||||
|
const isComponentsAll = args?.components?.includes('all')
|
||||||
|
const isPackagesAll = args?.packages?.includes('all')
|
||||||
|
let tips = '';
|
||||||
|
if (isAll) {
|
||||||
|
tips = 'build all components and all packages'
|
||||||
|
} else if (isComponentsAll) {
|
||||||
|
tips = 'build all components'
|
||||||
|
} else if (isPackagesAll) {
|
||||||
|
tips = 'build all packages'
|
||||||
|
} else {
|
||||||
|
tips = ' build task time' + ' ' + dayjs().format('YYYY-MM-DD HH:mm:ss') + '\n'
|
||||||
|
}
|
||||||
|
yellow(tips, true)
|
||||||
|
blue(' ---------------------- start ----------------------\n', true)
|
||||||
|
/// not all components
|
||||||
|
if (!isComponentsAll && args?.components?.length) {
|
||||||
|
const libs = args?.components
|
||||||
|
if (libs.length === 1) {
|
||||||
|
/// 先切包名
|
||||||
|
const lib = libs[0];
|
||||||
|
/// 单包下存在多个包
|
||||||
|
if (lib.includes('*') || !lib.includes('/')) {
|
||||||
|
/// xxx/*
|
||||||
|
const [name] = !lib.includes('/') ? [lib] : lib.split('/')
|
||||||
|
const _p = getFolderNames('components', name)
|
||||||
|
buildAllComponents(_p)
|
||||||
|
} else {
|
||||||
|
const [name, cname] = lib.split('/')
|
||||||
|
const componentsPaths = getSingleComponentPaths('components', name, cname)
|
||||||
|
await createBuildComponents(componentsPaths)
|
||||||
|
await exit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const compsPaths = args?.components;
|
||||||
|
const allPaths = compsPaths.filter(cp => cp.includes('*') || !cp.includes('/'));
|
||||||
|
const fixPaths = compsPaths.filter(cp => !cp.includes('*') && cp.includes('/'));
|
||||||
|
let _all_ = [...fixPaths]
|
||||||
|
if (allPaths.length) {
|
||||||
|
allPaths.forEach(allp => {
|
||||||
|
const [name] = !allp.includes('/') ? [allp] : allp.split('/')
|
||||||
|
const _p = getFolderNames('components', name)
|
||||||
|
_all_ = [..._all_, ..._p]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
buildAllComponents(_all_)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPackagesAll && args?.packages?.length) {
|
||||||
|
const libs = args?.packages
|
||||||
|
if (libs.length === 1) {
|
||||||
|
/// 先切包名
|
||||||
|
const lib = libs[0];
|
||||||
|
const [name] = lib.split('/')
|
||||||
|
const packagesAllPaths = getSinglePackagePaths('packages', name)
|
||||||
|
await createBuildPackages(packagesAllPaths)
|
||||||
|
await exit();
|
||||||
|
} else {
|
||||||
|
let componentsPathsObject = Object.create(null)
|
||||||
|
libs.forEach(async lib => {
|
||||||
|
const componentsPaths = getSinglePackagePaths('packages', lib)
|
||||||
|
componentsPathsObject[lib] = componentsPaths[lib]
|
||||||
|
});
|
||||||
|
await createBuildPackages(componentsPathsObject)
|
||||||
|
await exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 如果是打包全部
|
||||||
|
if (isAll) {
|
||||||
|
/// 先打对应的依赖components
|
||||||
|
const componentsAllPaths = getAllTargetsPath('components')
|
||||||
|
const packagesAllPaths = getAllTargetsPath('packages')
|
||||||
|
if (!Object.keys(componentsAllPaths).length && !Object.keys(packagesAllPaths).length) {
|
||||||
|
yellow('\n no build components and packages task! please check buildFormCreateOptions or private with components/*/*/package.json \n')
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!Object.keys(componentsAllPaths).length) {
|
||||||
|
yellow('\n no build components task! please check buildFormCreateOptions or private with components/*/*/package.json \n')
|
||||||
|
}
|
||||||
|
if (!Object.keys(packagesAllPaths).length) {
|
||||||
|
yellow('\n no build packages task! please check buildFormCreateOptions or private with packages/*/package.json \n')
|
||||||
|
}
|
||||||
|
/// 打印对应的组件
|
||||||
|
await createBuildComponents(componentsAllPaths)
|
||||||
|
/// 再打对应的包
|
||||||
|
await createBuildPackages(packagesAllPaths)
|
||||||
|
/// 退出
|
||||||
|
await exit();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/// 单独打所有的component组件
|
||||||
|
if(isComponentsAll) {
|
||||||
|
const componentsAllPaths = getAllTargetsPath('components')
|
||||||
|
if (!Object.keys(componentsAllPaths).length) {
|
||||||
|
yellow('\n no build components task! please check buildFormCreateOptions or private with components/*/*/package.json \n')
|
||||||
|
await exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
await createBuildComponents(componentsAllPaths)
|
||||||
|
await exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 单独打所有的package包
|
||||||
|
if (isPackagesAll) {
|
||||||
|
const packagesAllPaths = getAllTargetsPath('packages')
|
||||||
|
if (!Object.keys(packagesAllPaths).length) {
|
||||||
|
yellow('\n no build packages task! please check buildFormCreateOptions or private with packages/*/package.json \n')
|
||||||
|
await exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
await createBuildPackages(packagesAllPaths)
|
||||||
|
await exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (_: any, args: any) => {
|
||||||
|
return createBuildTask(args)
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* 打包components文件
|
||||||
|
*/
|
||||||
|
import type { Ora } from 'ora';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import ora from 'ora';
|
||||||
|
import os from 'os';
|
||||||
|
import execa from 'execa';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let spinner: Ora;
|
||||||
|
const build = async (target: string, comp: string, targetName: string) => {
|
||||||
|
dayjs().startOf('millisecond');
|
||||||
|
/// env 先写死
|
||||||
|
const env = 'production'
|
||||||
|
await execa(
|
||||||
|
'rollup',
|
||||||
|
[
|
||||||
|
`-c`,
|
||||||
|
'--environment',
|
||||||
|
[
|
||||||
|
`NODE_ENV:${env}`,
|
||||||
|
`BUILD_TARGET:${targetName}`,
|
||||||
|
`BUILD_TARGET_COMP:${comp}`,
|
||||||
|
`BUILD_TYPE:component`,
|
||||||
|
`BUILD_TARGET_PATH:${target}`
|
||||||
|
].filter(Boolean).join(',')
|
||||||
|
],
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
console.log('build task time' + ' ' + dayjs().format('YYYY-MM-DD HH:mm:ss'))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const runParallel = async (maxConcurrency: number, source: string[], buildName: string, iteratorFn: Function) => {
|
||||||
|
const ret = []
|
||||||
|
const executing = []
|
||||||
|
for (const item of source) {
|
||||||
|
const comp = item.split('/').pop()
|
||||||
|
const p = Promise.resolve().then(() => iteratorFn(item, comp, buildName))
|
||||||
|
ret.push(p)
|
||||||
|
|
||||||
|
if (maxConcurrency <= source.length) {
|
||||||
|
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
|
||||||
|
executing.push(e)
|
||||||
|
if (executing.length >= maxConcurrency) {
|
||||||
|
await Promise.race(executing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.all(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildAll = async (comAllTargets) => {
|
||||||
|
await runParallel(os.cpus().length, comAllTargets[1], comAllTargets[0], build)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createBuildComponents = async (cpaths: { [k: string]: any }) => {
|
||||||
|
/// 根据每个不同的ui库去生成每个ui库下面的不同的组件打包
|
||||||
|
const cps = Object.entries(cpaths)
|
||||||
|
for (const cpath of cps) {
|
||||||
|
await buildAll(cpath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createBuildComponents
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* 打包packages文件
|
||||||
|
*/
|
||||||
|
import type {Ora} from 'ora';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import ora from 'ora';
|
||||||
|
import os from 'os';
|
||||||
|
import execa from 'execa';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
let spinner: Ora;
|
||||||
|
const build = async (target: string, comp: string, targetName: string) => {
|
||||||
|
dayjs().startOf('millisecond');
|
||||||
|
spinner.text = chalk.bold.yellow(`start build ${targetName} ui \n`);
|
||||||
|
/// env 先写死
|
||||||
|
const env = 'production'
|
||||||
|
await execa(
|
||||||
|
'rollup',
|
||||||
|
[
|
||||||
|
'-c',
|
||||||
|
'--environment',
|
||||||
|
[
|
||||||
|
`NODE_ENV:${env}`,
|
||||||
|
`BUILD_TARGET:${targetName}`,
|
||||||
|
`BUILD_TARGET_COMP:${comp}`,
|
||||||
|
'BUILD_TYPE:packages',
|
||||||
|
`BUILD_TARGET_PATH:${target}`
|
||||||
|
].filter(Boolean).join(',')
|
||||||
|
],
|
||||||
|
{stdio: 'inherit'}
|
||||||
|
);
|
||||||
|
spinner.text = chalk.bold.green(`finished build ${targetName} ui time: ${dayjs().startOf('millisecond').format('SSS')}ms. \n `);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const runParallel = async (maxConcurrency: number, source: string[], buildName: string, iteratorFn: Function) => {
|
||||||
|
const ret = []
|
||||||
|
const executing = []
|
||||||
|
for (const item of source) {
|
||||||
|
const comp = item.split('/').pop()
|
||||||
|
const p = Promise.resolve().then(() => iteratorFn(item, comp, buildName))
|
||||||
|
ret.push(p)
|
||||||
|
|
||||||
|
if (maxConcurrency <= source.length) {
|
||||||
|
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
|
||||||
|
executing.push(e)
|
||||||
|
if (executing.length >= maxConcurrency) {
|
||||||
|
await Promise.race(executing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.all(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildAll = async (comAllTargets) => {
|
||||||
|
await runParallel(os.cpus().length, comAllTargets[1], comAllTargets[0], build)
|
||||||
|
}
|
||||||
|
|
||||||
|
const _filter_current_url_ = (urls: Array<any>) => {
|
||||||
|
const arr = []
|
||||||
|
urls.map((url) => {
|
||||||
|
const itemUrlLibName = url[0];
|
||||||
|
let itemUrlLibsUrl = '';
|
||||||
|
url[1].forEach((item, idx) => {
|
||||||
|
const suffix = item.split('/').pop()
|
||||||
|
if (suffix === itemUrlLibName) {
|
||||||
|
itemUrlLibsUrl = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const item = [itemUrlLibName, [itemUrlLibsUrl]]
|
||||||
|
arr.push(item)
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
const createBuildPackages = async (cpaths: { [k: string]: any }) => {
|
||||||
|
const tips = chalk.redBright.bold('\n start build all packages \n')
|
||||||
|
spinner = ora(tips).start()
|
||||||
|
/// 根据每个不同的ui库去生成每个ui库下面的不同的组件打包
|
||||||
|
const cps = Object.entries(cpaths)
|
||||||
|
/// 处理下当前的url
|
||||||
|
const fCps = _filter_current_url_(cps)
|
||||||
|
for (const cpath of fCps) {
|
||||||
|
await buildAll(cpath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createBuildPackages
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
/// 项目目录
|
||||||
|
export const projRoot = path.resolve(__dirname, '../../');
|
||||||
|
/// 单独component目录
|
||||||
|
export const compRoot = path.resolve(projRoot, './components');
|
||||||
|
/// packages目录
|
||||||
|
export const pkgRoot = path.resolve(projRoot, './packages');
|
||||||
|
/// file - packages.json \\\
|
||||||
|
export const pkgFileRoot = path.resolve(projRoot, './package.json');
|
||||||
|
/// file - lerna.json \\\
|
||||||
|
export const lernaFileRoot = path.resolve(projRoot, './lerna.json');
|
||||||
|
/// file - rollup.config.js \\\
|
||||||
|
export const rollupFileRoot = path.resolve(projRoot, './rollup.config.ts');
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import chalk from "chalk";
|
||||||
|
import fs from "fs";
|
||||||
|
import { projRoot } from "./paths";
|
||||||
|
|
||||||
|
|
||||||
|
export function yellow(str: string, isBold: boolean = false) {
|
||||||
|
isBold ? console.log(chalk.bold.yellow(str)) : console.log(chalk.yellow(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function green(str: string, isBold: boolean = false) {
|
||||||
|
isBold ? console.log(chalk.bold.green(str)) : console.log(chalk.green(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function blue(str: string, isBold: boolean = false) {
|
||||||
|
isBold ? console.log(chalk.bold.blue(str)) : console.log(chalk.blue(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function red(str: string, isBold: boolean = false) {
|
||||||
|
isBold ? console.log(chalk.bold.red(str)) : console.log(chalk.red(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function errorAndExit(e) {
|
||||||
|
red(e.message)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const targets = (dir: 'packages' | 'components' = 'packages') => {
|
||||||
|
const componentsAllPaths = Object.create(null);
|
||||||
|
const uiFoldersPath = fs.readdirSync(dir).filter(uiFolderPath => {
|
||||||
|
if (fs.statSync(`${projRoot}/${dir}/${uiFolderPath}`).isDirectory()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// uiFoldersPath.forEach(uiPath => {
|
||||||
|
// const pkg = require(`${projRoot}/${dir}/${uiPath}/package.json`)
|
||||||
|
// if (pkg.private || !pkg.buildFormCreateOptions) {
|
||||||
|
// blue(`\n info: ${projRoot}/${dir}/${uiPath}/package.json private is true or buildFormCreateOptions is not exists!`)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
if (dir === 'packages') {
|
||||||
|
const packagesFolderPath = []
|
||||||
|
for (let index = 0; index < uiFoldersPath.length; index++) {
|
||||||
|
const uiPath = uiFoldersPath[index];
|
||||||
|
if (!fs.statSync(`${projRoot}/${dir}/${uiPath}`).isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const pkg = require(`${projRoot}/${dir}/${uiPath}/package.json`)
|
||||||
|
fs.rmdirSync(`${projRoot}/${dir}/${uiPath}/dist`, { recursive: true });
|
||||||
|
if (pkg.private || !pkg.buildFormCreateOptions) {
|
||||||
|
red(`\n info: ${projRoot}/${dir}/${uiPath}/package.json private is true or buildFormCreateOptions is not exists!`)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
packagesFolderPath.push(`${projRoot}/${dir}/${uiPath}`)
|
||||||
|
if (packagesFolderPath.length) {
|
||||||
|
componentsAllPaths[uiPath] = packagesFolderPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir === 'components') {
|
||||||
|
uiFoldersPath.forEach(uiPath => {
|
||||||
|
const componentFolderPath = []
|
||||||
|
const alen = fs.readdirSync(`${projRoot}/${dir}/${uiPath}`).length
|
||||||
|
for (let index = 0; index < alen; index++) {
|
||||||
|
const comPath = fs.readdirSync(`${projRoot}/${dir}/${uiPath}`)[index];
|
||||||
|
if (!fs.statSync(`${projRoot}/${dir}/${uiPath}/${comPath}`).isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const pkg = require(`${projRoot}/${dir}/${uiPath}/${comPath}/package.json`)
|
||||||
|
fs.rmdirSync(`${projRoot}/${dir}/${uiPath}/${comPath}/dist`, { recursive: true });
|
||||||
|
if (pkg.private || !pkg.buildFormCreateOptions) {
|
||||||
|
red(`\n info: ${projRoot}/${dir}/${uiPath}/${comPath}/package.json private is true or buildFormCreateOptions is not exists!`)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
componentFolderPath.push(`${projRoot}/${dir}/${uiPath}/${comPath}`)
|
||||||
|
}
|
||||||
|
if (componentFolderPath.length) {
|
||||||
|
componentsAllPaths[uiPath] = componentFolderPath
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return componentsAllPaths
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const getSingleComponentPaths = (dir: string = 'components', libname: string = '', comname: string = '') => {
|
||||||
|
const fpath = Object.create(null)
|
||||||
|
const _rootPath = dir
|
||||||
|
const _libPath = libname
|
||||||
|
const _compPath = comname
|
||||||
|
|
||||||
|
if (!fs.statSync(`${projRoot}/${_rootPath}/${_libPath}/${_compPath}`).isDirectory()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const pkg = require(`${projRoot}/${_rootPath}/${_libPath}/${_compPath}/package.json`)
|
||||||
|
fs.rmdirSync(`${projRoot}/${_rootPath}/${_libPath}/${_compPath}/dist`, { recursive: true });
|
||||||
|
if (pkg.private || !pkg.buildFormCreateOptions) {
|
||||||
|
red(`\n info: ${projRoot}/${_rootPath}/${_libPath}/${_compPath}/package.json private is true or buildFormCreateOptions is not exists!`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fpath[_libPath] = [`${projRoot}/${_rootPath}/${_libPath}/${_compPath}`]
|
||||||
|
|
||||||
|
return fpath
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSinglePackagePaths = (dir: string = 'packages', libname: string = '') => {
|
||||||
|
const fpath = Object.create(null)
|
||||||
|
const _rootPath = dir
|
||||||
|
const _libPath = libname
|
||||||
|
|
||||||
|
if (!fs.statSync(`${projRoot}/${_rootPath}/${_libPath}`).isDirectory()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const pkg = require(`${projRoot}/${_rootPath}/${_libPath}/package.json`)
|
||||||
|
fs.rmdirSync(`${projRoot}/${_rootPath}/${_libPath}/dist`, { recursive: true });
|
||||||
|
if (pkg.private || !pkg.buildFormCreateOptions) {
|
||||||
|
red(`\n info: ${projRoot}/${_rootPath}/${_libPath}/package.json private is true or buildFormCreateOptions is not exists!`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fpath[_libPath] = [`${projRoot}/${_rootPath}/${_libPath}`]
|
||||||
|
|
||||||
|
return fpath
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all the folder names under the current folder
|
||||||
|
export const getFolderNames = (folder: string, uiFolder: string) => {
|
||||||
|
return fs.readdirSync(`${folder}/${uiFolder}`).map(uiFolderPath => {
|
||||||
|
if (fs.statSync(`${projRoot}/${folder}/${uiFolder}`).isDirectory()) {
|
||||||
|
fs.rmdirSync(`${projRoot}/${folder}/${uiFolder}/dist`, { recursive: true });
|
||||||
|
return `${uiFolder}/${uiFolderPath}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* @Author : djkloop
|
||||||
|
* @Date : 2021-09-19 13:53:31
|
||||||
|
* @LastEditors : djkloop
|
||||||
|
* @LastEditTime : 2021-09-19 14:11:52
|
||||||
|
* @Description : 头部注释
|
||||||
|
* @FilePath : /form-create2/tools/rollup/plugin/index.ts
|
||||||
|
*/
|
||||||
|
import vue from 'rollup-plugin-vue';
|
||||||
|
import postcss from 'rollup-plugin-postcss';
|
||||||
|
import { cssUrl } from '@sixian/css-url';
|
||||||
|
import externals from 'rollup-plugin-node-externals';
|
||||||
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import babel from '@rollup/plugin-babel';
|
||||||
|
|
||||||
|
export const createRollupPlugins = () => {
|
||||||
|
|
||||||
|
const rollupPlugins = [
|
||||||
|
vue({
|
||||||
|
preprocessStyles: true,
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
/// css settings
|
||||||
|
rollupPlugins.push(postcss({
|
||||||
|
minimize: true,
|
||||||
|
extract: false,
|
||||||
|
plugins: [
|
||||||
|
cssUrl({
|
||||||
|
imgExtensions: /\.(png|jpg|jpeg|gif|svg)$/,
|
||||||
|
fontExtensions: /\.(ttf|woff|woff2|eot)$/,
|
||||||
|
limit: 8192,
|
||||||
|
hash: false,
|
||||||
|
slash: false
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
/// devDependencies
|
||||||
|
rollupPlugins.push(externals({
|
||||||
|
devDeps: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
/// j
|
||||||
|
rollupPlugins.push(nodeResolve({
|
||||||
|
extensions: ['.js', '.json', '.jsx', '.ts', '.tsx'],
|
||||||
|
preferBuiltins: true,
|
||||||
|
browser: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
/// commonjs
|
||||||
|
rollupPlugins.push(commonjs());
|
||||||
|
|
||||||
|
rollupPlugins.push(babel({
|
||||||
|
babelHelpers: 'bundled',
|
||||||
|
exclude: 'node_modules/**',
|
||||||
|
extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
// if (visualizer) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
return rollupPlugins
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"sourceMap": true,
|
||||||
|
"allowUnreachableCode": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"importHelpers": true,
|
||||||
|
"jsx": "preserve"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"*.vue",
|
||||||
|
"*",
|
||||||
|
"types/typing.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
import {Rule} from "@form-create/element-ui";
|
||||||
|
|
||||||
|
export interface MenuItem {
|
||||||
|
label: string,
|
||||||
|
name: string,
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Menu {
|
||||||
|
title: string;
|
||||||
|
name: string;
|
||||||
|
list: MenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuList extends Array<Menu> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DragRule {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
rule(): Rule;
|
||||||
|
|
||||||
|
props(): Rule[];
|
||||||
|
|
||||||
|
children?: string;
|
||||||
|
inside?: true;
|
||||||
|
drag?: true | String;
|
||||||
|
dragBtn?: false;
|
||||||
|
mask?: false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import {defineConfig} from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import vueJSX from '@vitejs/plugin-vue-jsx'
|
||||||
|
import banner from 'vite-plugin-banner'
|
||||||
|
import cssnano from 'cssnano'
|
||||||
|
import visualizer from 'rollup-plugin-visualizer';
|
||||||
|
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
|
||||||
|
import {author, license, name, version} from './package.json'
|
||||||
|
|
||||||
|
const extnedsPlugins = [];
|
||||||
|
|
||||||
|
function getBanner(banner, pkg) {
|
||||||
|
if (!banner || typeof banner === 'string') {
|
||||||
|
return banner || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
banner = {...pkg, ...(banner === true ? {} : banner)};
|
||||||
|
|
||||||
|
const author =banner.author
|
||||||
|
|
||||||
|
const license = banner.license || '';
|
||||||
|
return (
|
||||||
|
'/*!\n' +
|
||||||
|
' * form-create 可视化表单设计器\n' +
|
||||||
|
` * ${banner.name} v${banner.version}\n` +
|
||||||
|
` * (c) ${author || ''}\n` +
|
||||||
|
(license && ` * Released under the ${license} License.\n`) +
|
||||||
|
' */'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const __banner__ = {
|
||||||
|
author: `2021-${new Date().getFullYear()} ${author}\n * Github https://github.com/xaboy/form-create-designer`,
|
||||||
|
license,
|
||||||
|
name,
|
||||||
|
version
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打包生产环境才引入的插件
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
// 打包依赖展示
|
||||||
|
extnedsPlugins.push(
|
||||||
|
visualizer({
|
||||||
|
open: true,
|
||||||
|
gzipSize: true,
|
||||||
|
brotliSize: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: 'src/index.js',
|
||||||
|
name: 'FcDesigner',
|
||||||
|
fileName: format => `index.${format}.js`,
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
exports: 'named',
|
||||||
|
globals: {
|
||||||
|
vue: 'Vue'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
external: [
|
||||||
|
'vue',
|
||||||
|
'element-plus',
|
||||||
|
'@form-create/element-ui'
|
||||||
|
],
|
||||||
|
|
||||||
|
},
|
||||||
|
brotliSize: true
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: [
|
||||||
|
cssnano({
|
||||||
|
preset: 'advanced'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [vue(), vueJSX(), banner(getBanner(__banner__)),cssInjectedByJsPlugin(), ...extnedsPlugins]
|
||||||
|
})
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {defineConfig} from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import vueJSX from '@vitejs/plugin-vue-jsx'
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
cssCodeSplit: true,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks: {
|
||||||
|
vue: ['vue'],
|
||||||
|
'element-plus': ['element-plus'],
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
vue: 'Vue',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
chunkSizeWarningLimit: 2000,
|
||||||
|
},
|
||||||
|
plugins: [vue(), vueJSX()]
|
||||||
|
})
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* @Author : djkloop
|
||||||
|
* @Date : 2020-08-15 21:16:03
|
||||||
|
* @LastEditors : djkloop
|
||||||
|
* @LastEditTime : 2021-09-21 17:18:46
|
||||||
|
* @Description : 头部注释
|
||||||
|
* @FilePath : /form-create2/packages/element-ui/vue.config.js
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
pages: {
|
||||||
|
app: {
|
||||||
|
entry: 'examples/main.js',
|
||||||
|
template: 'examples/index.html',
|
||||||
|
filename: 'index.html'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
configureWebpack: {
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.mjs$/,
|
||||||
|
include: /node_modules/,
|
||||||
|
type: 'javascript/auto'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user