commit e7a012f0eb7e9c055bdc7c5f87ee4209c7af8651 Author: 李志强 <2997723368@qq.com> Date: Mon Mar 20 14:43:23 2023 +0800 可视化表单 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8dcab82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +.DS_Store +node_modules +/dist +/dist0/ +/dist2 +.VSCodeCounter + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +/package-lock.json +/VariantForm.iml +yarn.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..0aaf98f --- /dev/null +++ b/README.md @@ -0,0 +1,195 @@ +# Variant Form +#### 一款高效的Vue低代码表单,可视化设计,一键生成源码,享受更多摸鱼时间。 + +![image](https://ks3-cn-beijing.ksyuncs.com/vform-static/img/vform_demo.gif) + +
+ +### 立即体验 +[在线Demo](http://120.92.142.115/) + +### 立即体验VForm Pro高级版(提供商业支持) +[Pro Demo](https://vform666.com/pages/pro/) + +### 视频教程集合: +[B站观看](https://space.bilibili.com/626932375) + +### Vue 3正式版已发布 +[立即进入](https://gitee.com/vdpadmin/variant-form3-vite) + +### 🎉🎉基于Vant组件库的Mobile版本已发布🎉🎉 +[立即进入](https://vform666.com/vform-mobile.html) + + +### 友情链接 +[Fantastic-admin](https://hooray.gitee.io/fantastic-admin/) —— 一款开箱即用的 Vue 中后台管理系统框架(支持Vue2/Vue3) + +[REBUILD](https://getrebuild.com/) —— 高度可定制化的企业管理系统 + +
+ +### 功能一览 +``` +> 拖拽式可视化表单设计; +> 支持PC、Pad、H5三种布局; +> 支持运行时动态加载表单; +> 支持表单复杂交互控制; +> 支持自定义CSS样式; +> 支持自定义校验逻辑; +> 支持国际化多语言; +> 兼容IE 11浏览器; +> 可导出Vue组件、HTML源码; +> 可导出Vue的SFC单文件组件; +> 支持开发自定义组件; +> 支持响应式自适应布局; +> 支持VS Code插件; +> 更多功能等你探究...; +``` + +### 安装依赖 +``` +npm install --registry=https://registry.npm.taobao.org +``` + +### 开发调试 +``` +npm run serve +``` + +### 生产打包 +``` +npm run build +``` + +### 表单设计器 + 表单渲染器打包 +``` +npm run lib +``` + +### 表单渲染器打包 +``` +npm run lib-render +``` + +### 浏览器兼容性 +```Chrome(及同内核的浏览器如QQ浏览器、360浏览器等等),Edge, Firefox,Safari,IE 11``` + +
+ +### 跟Vue项目集成 + +
+ +#### 1. 安装包 + ```bash + npm i vform-builds + ``` +或 + ```bash + yarn add vform-builds + ``` + +
+ +#### 2. 引入并全局注册VForm组件 +```javascript +import Vue from 'vue' +import App from './App.vue' + +import ElementUI from 'element-ui' //引入element-ui库 +import VForm from 'vform-builds' //引入VForm库 + +import 'element-ui/lib/theme-chalk/index.css' //引入element-ui样式 +import 'vform-builds/dist/VFormDesigner.css' //引入VForm样式 + +Vue.config.productionTip = false + +Vue.use(ElementUI) //全局注册element-ui +Vue.use(VForm) //全局注册VForm(同时注册了v-form-designer和v-form-render组件) + +new Vue({ + render: h => h(App), +}).$mount('#app') +``` + +
+ +#### 3. 在Vue模板中使用表单设计器组件 +```html + + + + + +``` + +
+ +#### 4. 在Vue模板中使用表单渲染器组件 +```html + + +``` + +
+ +### 资源链接 +
+ +文档官网:https://www.vform666.com/ + +在线演示:http://120.92.142.115/ + +Gitee仓库:https://gitee.com/vdpadmin/variant-form + +Github仓库:https://github.com/vform666/variant-form + +VS Code插件:https://www.vform666.com/pages/plugin/ + +更新日志:https://www.vform666.com/changelog.html + +订阅Pro版:https://www.vform666.com/pages/pro/ + +技术交流群:扫如下二维码加群 + +![image](https://vform2022.ks3-cn-beijing.ksyuncs.com/vchat_qrcode.png) diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..e955840 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +} diff --git a/index_template/index_dev.html b/index_template/index_dev.html new file mode 100644 index 0000000..d6f067b --- /dev/null +++ b/index_template/index_dev.html @@ -0,0 +1,19 @@ + + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + +
+ + + diff --git a/index_template/index_prod.html b/index_template/index_prod.html new file mode 100644 index 0000000..2e95736 --- /dev/null +++ b/index_template/index_prod.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + +
+ + + + + + diff --git a/install-render.js b/install-render.js new file mode 100644 index 0000000..da60086 --- /dev/null +++ b/install-render.js @@ -0,0 +1,29 @@ +import VFormRender from '@/components/form-render/index.vue' +import {loadExtension} from "@/extension/extension-loader" +import axios from "axios" + +loadExtension() + +VFormRender.install = function (Vue) { + Vue.component(VFormRender.name, VFormRender) +} + +const components = [ + VFormRender +] + +const install = (Vue) => { + window.axios = axios + components.forEach(component => { + Vue.component(component.name, component) + }) +} + +if (typeof window !== 'undefined' && window.Vue) { /* script方式引入时主动调用install方法!! */ + install(window.Vue); +} + +export default { + install, + VFormRender +} diff --git a/install.js b/install.js new file mode 100644 index 0000000..71df886 --- /dev/null +++ b/install.js @@ -0,0 +1,41 @@ +import axios from 'axios' + +import VFormDesigner from '@/components/form-designer/index.vue' +import VFormRender from '@/components/form-render/index.vue' +import {loadExtension} from "@/extension/extension-loader" + +import '@/utils/directive' +import '@/icons' +import '@/iconfont/iconfont.css' + +loadExtension() + +VFormDesigner.install = function (Vue) { + Vue.component(VFormDesigner.name, VFormDesigner) +} + +VFormRender.install = function (Vue) { + Vue.component(VFormRender.name, VFormRender) +} + +const components = [ + VFormDesigner, + VFormRender +] + +const install = (Vue) => { + window.axios = axios + components.forEach(component => { + Vue.component(component.name, component) + }) +} + +if (typeof window !== 'undefined' && window.Vue) { /* script方式引入时主动调用install方法!! */ + install(window.Vue); +} + +export default { + install, + VFormDesigner, + VFormRender +} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..7d63aa6 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,10 @@ +{ + "######": "本文件用于解决IDEA无法识别Vue项目@符号的问题", + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + } + }, + "exclude": ["node_modules", "dist"] +} diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..01f25e7 --- /dev/null +++ b/license.txt @@ -0,0 +1,8 @@ +# Variant Form 许可条款 1.0 + +1. 免责声明:任何情况下根据任何法律,本作者不对用户因使用VariantForm产生的侵权、数据损坏丢失、软硬件故障和违法犯罪等问题承担任何责任; +2. 禁止任何用户对VariantForm进行简单包装后,即声称为自己的产品、销售源码获利; +3. VariantForm为开源项目,获取到源代码的用户可自由修改源码供自身开发使用,可分发build构建后的库代码,也可分发VariantForm源代码(需保留文件头部的作者声明),本作者保留VariantForm的原始著作权; +4. 个人或公司用户均可将VariantForm项目应用于商业项目开发,为支持本项目持续开发,请尽量购买VariantForm Pro版源码订阅更新服务; +5. 如果你不同意本许可条款,请勿使用VariantForm;任何情况下,一旦实际使用VariantForm,则代表你已确定完全同意本许可条款; +6. 条款内容结束。 diff --git a/package.json b/package.json new file mode 100644 index 0000000..6742540 --- /dev/null +++ b/package.json @@ -0,0 +1,56 @@ +{ + "name": "variant-form", + "version": "2.2.9", + "private": false, + "scripts": { + "serve": "vue-cli-service serve --open src/main.js", + "build": "vue-cli-service build --report --dest dist/build", + "lib": "vue-cli-service build --report --target lib --dest dist/lib --name VFormDesigner install.js", + "lib-render": "vue-cli-service build --report --target lib --dest dist/lib-render --name VFormRender install-render.js", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "axios": "^0.21.1", + "clipboard": "^2.0.8", + "core-js": "^3.6.5", + "element-ui": "^2.15.1", + "file-saver": "^2.0.5", + "vue": "^2.6.11", + "vue2-editor": "^2.10.2", + "vuedraggable": "^2.24.3" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~4.5.0", + "@vue/cli-plugin-eslint": "~4.5.0", + "@vue/cli-service": "~4.5.0", + "ace-builds": "^1.4.12", + "babel-eslint": "^10.1.0", + "babel-polyfill": "^6.26.0", + "eslint": "^6.7.2", + "eslint-plugin-vue": "^6.2.2", + "mvdir": "^1.0.21", + "sass": "^1.45.1", + "sass-loader": "^8.0.2", + "svg-sprite-loader": "^5.2.1", + "vue-template-compiler": "^2.6.11" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/essential", + "eslint:recommended" + ], + "parserOptions": { + "parser": "babel-eslint" + }, + "rules": {} + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead" + ] +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..84ed3f9 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..d6f067b --- /dev/null +++ b/public/index.html @@ -0,0 +1,19 @@ + + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + +
+ + + diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..6fb0056 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/assets/ft-images/t1.png b/src/assets/ft-images/t1.png new file mode 100644 index 0000000..620f536 Binary files /dev/null and b/src/assets/ft-images/t1.png differ diff --git a/src/assets/ft-images/t2.png b/src/assets/ft-images/t2.png new file mode 100644 index 0000000..a968ef7 Binary files /dev/null and b/src/assets/ft-images/t2.png differ diff --git a/src/assets/ft-images/t3.png b/src/assets/ft-images/t3.png new file mode 100644 index 0000000..0239058 Binary files /dev/null and b/src/assets/ft-images/t3.png differ diff --git a/src/assets/ft-images/t4.png b/src/assets/ft-images/t4.png new file mode 100644 index 0000000..7996852 Binary files /dev/null and b/src/assets/ft-images/t4.png differ diff --git a/src/assets/ft-images/t5.png b/src/assets/ft-images/t5.png new file mode 100644 index 0000000..35e03d2 Binary files /dev/null and b/src/assets/ft-images/t5.png differ diff --git a/src/assets/ft-images/t6.png b/src/assets/ft-images/t6.png new file mode 100644 index 0000000..22aeb50 Binary files /dev/null and b/src/assets/ft-images/t6.png differ diff --git a/src/assets/ft-images/t7.png b/src/assets/ft-images/t7.png new file mode 100644 index 0000000..7128e37 Binary files /dev/null and b/src/assets/ft-images/t7.png differ diff --git a/src/assets/ft-images/t8.png b/src/assets/ft-images/t8.png new file mode 100644 index 0000000..37baf96 Binary files /dev/null and b/src/assets/ft-images/t8.png differ diff --git a/src/assets/vform-logo.png b/src/assets/vform-logo.png new file mode 100644 index 0000000..f8cc5df Binary files /dev/null and b/src/assets/vform-logo.png differ diff --git a/src/components/code-editor/index.vue b/src/components/code-editor/index.vue new file mode 100644 index 0000000..11e47a5 --- /dev/null +++ b/src/components/code-editor/index.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/src/components/form-designer/designer.js b/src/components/form-designer/designer.js new file mode 100644 index 0000000..c9e29c6 --- /dev/null +++ b/src/components/form-designer/designer.js @@ -0,0 +1,962 @@ +/** + * author: vformAdmin + * email: vdpadmin@163.com + * website: https://www.vform666.com + * date: 2021.08.18 + * remark: 如果要分发VForm源码,需在本文件顶部保留此文件头信息!! + */ + +import {deepClone, generateId, getDefaultFormConfig, overwriteObj} from "@/utils/util" +import {containers, advancedFields, basicFields, customFields} from "@/components/form-designer/widget-panel/widgetsConfig.js" +import {VARIANT_FORM_VERSION} from "@/utils/config" + +export function createDesigner(vueInstance) { + let defaultFormConfig = deepClone( getDefaultFormConfig() ) + + return { + widgetList: [], + formConfig: {cssCode: ''}, + + selectedId: null, + selectedWidget: null, + selectedWidgetName: null, //选中组件名称(唯一) + vueInstance: vueInstance, + + formWidget: null, //表单设计容器 + + cssClassList: [], //自定义样式列表 + + historyData: { + index: -1, //index: 0, + maxStep: 20, + steps: [], + }, + + initDesigner(resetFormJson) { + this.widgetList = [] + this.formConfig = deepClone(defaultFormConfig) + + //输出版本信息和语雀链接 + console.info(`%cVariantForm %cVer${VARIANT_FORM_VERSION} %chttps://www.yuque.com/visualdev/vform`, + "color:#409EFF;font-size: 22px;font-weight:bolder", + "color:#999;font-size: 12px", + "color:#333" + ) + + if (!resetFormJson) { + this.initHistoryData() + } + }, + + clearDesigner(skipHistoryChange) { + let emptyWidgetListFlag = (this.widgetList.length === 0) + this.widgetList = [] + this.selectedId = null + this.selectedWidgetName = null + this.selectedWidget = {} //this.selectedWidget = null + overwriteObj(this.formConfig, defaultFormConfig) // + + if (!!skipHistoryChange) { + //什么也不做!! + } else if (!emptyWidgetListFlag) { + this.emitHistoryChange() + } else { + this.saveCurrentHistoryStep() + } + }, + + loadPresetCssCode(preCssCode) { + if ((this.formConfig.cssCode === '') && !!preCssCode) { + this.formConfig.cssCode = preCssCode + } + }, + + getLayoutType() { + return this.formConfig.layoutType || 'PC' + }, + + changeLayoutType(newType) { + this.formConfig.layoutType = newType + }, + + getImportTemplate() { + return { + widgetList: [], + // formConfig: deepClone(this.formConfig) + formConfig: deepClone(defaultFormConfig) + } + }, + + loadFormJson(formJson) { + let modifiedFlag = false + + if (!!formJson && !!formJson.widgetList) { + this.formWidget.clearWidgetRefList() + this.widgetList = formJson.widgetList + modifiedFlag = true + } + if (!!formJson && !!formJson.formConfig) { + //this.formConfig = importObj.formConfig + overwriteObj(this.formConfig, formJson.formConfig) /* 用=赋值,会导致inject依赖注入的formConfig属性变成非响应式 */ + modifiedFlag = true + } + + if (modifiedFlag) { + this.emitEvent('form-json-imported', []) // 通知其他组件 + } + + return modifiedFlag + }, + + setSelected(selected) { + if (!selected) { + this.clearSelected() + return + } + + this.selectedWidget = selected + if (!!selected.id) { + this.selectedId = selected.id + this.selectedWidgetName = selected.options.name + } + }, + + updateSelectedWidgetNameAndLabel(selectedWidget, newName, newLabel) { + this.selectedWidgetName = newName + //selectedWidget.options.name = newName //此行多余 + if (!!newLabel && (Object.keys(selectedWidget.options).indexOf('label') > -1)) { + selectedWidget.options.label = newLabel + } + }, + + clearSelected() { + this.selectedId = null + this.selectedWidgetName = null + this.selectedWidget = {} //this.selectedWidget = null + }, + + checkWidgetMove(evt) { /* Only field widget can be dragged into sub-form */ + if (!!evt.draggedContext && !!evt.draggedContext.element) { + let wgCategory = evt.draggedContext.element.category + let wgType = evt.draggedContext.element.type + if (!!evt.to) { + if ((evt.to.className === 'sub-form-table') && (wgCategory === 'container')) { + //this.$message.info(this.vueInstance.i18nt('designer.hint.onlyFieldWidgetAcceptable')) + return false + } + } + } + + return true + }, + + checkFieldMove(evt) { + if (!!evt.draggedContext && !!evt.draggedContext.element) { + let wgCategory = evt.draggedContext.element.category + let wgType = evt.draggedContext.element.type + '' + //console.log('wgType======', wgType) + if (!!evt.to) { + if ((evt.to.className === 'sub-form-table') && (wgType === 'slot')) { + //this.$message.info(this.vueInstance.i18nt('designer.hint.onlyFieldWidgetAcceptable')) + return false + } + } + } + + return true + }, + + /** + * 追加表格新行 + * @param widget + */ + appendTableRow(widget) { + let rowIdx = widget.rows.length//确定插入行位置 + let newRow = deepClone(widget.rows[widget.rows.length - 1]) + newRow.id = 'table-row-' + generateId() + newRow.merged = false + newRow.cols.forEach(col => { + col.id = 'table-cell-' + generateId() + col.options.name = col.id + col.merged = false + col.options.colspan = 1 + col.options.rowspan = 1 + col.widgetList.length = 0 + }) + widget.rows.splice(rowIdx, 0, newRow) + + this.emitHistoryChange() + }, + + /** + * 追加表格新列 + * @param widget + */ + appendTableCol(widget) { + let colIdx = widget.rows[0].cols.length //确定插入列位置 + widget.rows.forEach(row => { + let newCol = deepClone(this.getContainerByType('table-cell')) + newCol.id = 'table-cell-' + generateId() + newCol.options.name = newCol.id + newCol.merged = false + newCol.options.colspan = 1 + newCol.options.rowspan = 1 + newCol.widgetList.length = 0 + row.cols.splice(colIdx, 0, newCol) + }) + + this.emitHistoryChange() + }, + + insertTableRow(widget, insertPos, cloneRowIdx, curCol, aboveFlag) { + let newRowIdx = !!aboveFlag ? insertPos : (insertPos + 1) //初步确定插入行位置 + if (!aboveFlag) { //继续向下寻找同列第一个未被合并的单元格 + let tmpRowIdx = newRowIdx + let rowFoundFlag = false + while (tmpRowIdx < widget.rows.length) { + if (!widget.rows[tmpRowIdx].cols[curCol].merged) { + newRowIdx = tmpRowIdx + rowFoundFlag = true + break + } else { + tmpRowIdx++ + } + } + + if (!rowFoundFlag) { + newRowIdx = widget.rows.length + } + } + + let newRow = deepClone( widget.rows[cloneRowIdx] ) + newRow.id = 'table-row-' + generateId() + newRow.merged = false + newRow.cols.forEach(col => { + col.id = 'table-cell-' + generateId() + col.options.name = col.id + col.merged = false + col.options.colspan = 1 + col.options.rowspan = 1 + col.widgetList.length = 0 + }) + widget.rows.splice(newRowIdx, 0, newRow) + + let colNo = 0 + while ((newRowIdx < widget.rows.length - 1) && (colNo < widget.rows[0].cols.length)) { //越界判断 + const cellOfNextRow = widget.rows[newRowIdx + 1].cols[colNo] + const rowMerged = cellOfNextRow.merged //确定插入位置下一行的单元格是否为合并单元格 + if (!!rowMerged) { + let rowArray = widget.rows + let unMergedCell = {} + let startRowIndex = null + for (let i = newRowIdx; i >= 0; i--) { //查找该行已合并的主单元格 + if (!rowArray[i].cols[colNo].merged && (rowArray[i].cols[colNo].options.rowspan > 1)) { + startRowIndex = i + unMergedCell = rowArray[i].cols[colNo] + break + } + } + + if (!!unMergedCell.options) { //如果有符合条件的unMergedCell + let newRowspan = unMergedCell.options.rowspan + 1 + this.setPropsOfMergedRows(widget.rows, startRowIndex, colNo, unMergedCell.options.colspan, newRowspan) + colNo += unMergedCell.options.colspan + } else { + colNo += 1 + } + } else { + //colNo += 1 + colNo += cellOfNextRow.options.colspan || 1 + } + } + + this.emitHistoryChange() + }, + + insertTableCol(widget, insertPos, curRow, leftFlag) { + let newColIdx = !!leftFlag ? insertPos : (insertPos + 1) //初步确定插入列位置 + if (!leftFlag) { //继续向右寻找同行第一个未被合并的单元格 + let tmpColIdx = newColIdx + let colFoundFlag = false + while (tmpColIdx < widget.rows[curRow].cols.length) { + if (!widget.rows[curRow].cols[tmpColIdx].merged) { + newColIdx = tmpColIdx + colFoundFlag = true + break + } else { + tmpColIdx++ + } + + if (!colFoundFlag) { + newColIdx = widget.rows[curRow].cols.length + } + } + } + + widget.rows.forEach(row => { + let newCol = deepClone(this.getContainerByType('table-cell')) + newCol.id = 'table-cell-' + generateId() + newCol.options.name = newCol.id + newCol.merged = false + newCol.options.colspan = 1 + newCol.options.rowspan = 1 + newCol.widgetList.length = 0 + row.cols.splice(newColIdx, 0, newCol) + }) + + let rowNo = 0 + while((newColIdx < widget.rows[0].cols.length - 1) && (rowNo < widget.rows.length)) { //越界判断 + const cellOfNextCol = widget.rows[rowNo].cols[newColIdx + 1] + const colMerged = cellOfNextCol.merged //确定插入位置右侧列的单元格是否为合并单元格 + if (!!colMerged) { + let colArray = widget.rows[rowNo].cols + let unMergedCell = {} + let startColIndex = null + for (let i = newColIdx; i >= 0; i--) { //查找该行已合并的主单元格 + if (!colArray[i].merged && (colArray[i].options.colspan > 1)) { + startColIndex = i + unMergedCell = colArray[i] + break + } + } + + if (!!unMergedCell.options) { //如果有符合条件的unMergedCell + let newColspan = unMergedCell.options.colspan + 1 + this.setPropsOfMergedCols(widget.rows, rowNo, startColIndex, newColspan, unMergedCell.options.rowspan) + rowNo += unMergedCell.options.rowspan + } else { + rowNo += 1 + } + } else { + //rowNo += 1 + rowNo += cellOfNextCol.options.rowspan || 1 + } + } + + this.emitHistoryChange() + }, + + setPropsOfMergedCols(rowArray, startRowIndex, startColIndex, newColspan, rowspan) { + for (let i = startRowIndex; i < startRowIndex + rowspan; i++) { + for (let j = startColIndex; j < startColIndex + newColspan; j++) { + if ((i === startRowIndex) && (j === startColIndex)) { + rowArray[i].cols[j].options.colspan = newColspan //合并后的主单元格 + continue + } + + rowArray[i].cols[j].merged = true + rowArray[i].cols[j].options.colspan = newColspan + rowArray[i].cols[j].widgetList = [] + } + } + }, + + setPropsOfMergedRows(rowArray, startRowIndex, startColIndex, colspan, newRowspan) { + for (let i = startRowIndex; i < startRowIndex + newRowspan; i++) { + for (let j = startColIndex; j < startColIndex + colspan; j++) { + if ((i === startRowIndex) && (j === startColIndex)) { + rowArray[i].cols[j].options.rowspan = newRowspan + continue + } + + rowArray[i].cols[j].merged = true + rowArray[i].cols[j].options.rowspan = newRowspan + rowArray[i].cols[j].widgetList = [] + } + } + }, + + setPropsOfSplitCol(rowArray, startRowIndex, startColIndex, colspan, rowspan) { + for (let i = startRowIndex; i < startRowIndex + rowspan; i++) { + for (let j = startColIndex; j < startColIndex + colspan; j++) { + rowArray[i].cols[j].merged = false; + rowArray[i].cols[j].options.rowspan = 1 + rowArray[i].cols[j].options.colspan = 1 + } + } + }, + + setPropsOfSplitRow(rowArray, startRowIndex, startColIndex, colspan, rowspan) { + for (let i = startRowIndex; i < startRowIndex + rowspan; i++) { + for (let j = startColIndex; j < startColIndex + colspan; j++) { + rowArray[i].cols[j].merged = false; + rowArray[i].cols[j].options.rowspan = 1 + rowArray[i].cols[j].options.colspan = 1 + } + } + }, + + mergeTableCol(rowArray, colArray, curRow, curCol, leftFlag, cellWidget) { + let mergedColIdx = !!leftFlag ? curCol : curCol + colArray[curCol].options.colspan + + // let remainedColIdx = !!leftFlag ? curCol - colArray[curCol - 1].options.colspan : curCol + let remainedColIdx = !!leftFlag ? curCol - 1 : curCol + if (!!leftFlag) { //继续向左寻找同行未被合并的第一个单元格 + let tmpColIdx = remainedColIdx + while (tmpColIdx >= 0) { + if (!rowArray[curRow].cols[tmpColIdx].merged) { + remainedColIdx = tmpColIdx + break; + } else { + tmpColIdx-- + } + } + } + + if (!!colArray[mergedColIdx].widgetList && (colArray[mergedColIdx].widgetList.length > 0)) { //保留widgetList + if (!colArray[remainedColIdx].widgetList || (colArray[remainedColIdx].widgetList.length === 0)) { + colArray[remainedColIdx].widgetList = deepClone(colArray[mergedColIdx].widgetList) + } + } + + let newColspan = colArray[mergedColIdx].options.colspan * 1 + colArray[remainedColIdx].options.colspan * 1 + this.setPropsOfMergedCols(rowArray, curRow, remainedColIdx, newColspan, cellWidget.options.rowspan) + + this.emitHistoryChange() + }, + + mergeTableWholeRow(rowArray, colArray, rowIndex, colIndex) { //需要考虑操作的行存在已合并的单元格!! + //整行所有单元格行高不一致不可合并!! + let startRowspan = rowArray[rowIndex].cols[0].options.rowspan + let unmatchedFlag = false + for (let i = 1; i < rowArray[rowIndex].cols.length; i++) { + if (rowArray[rowIndex].cols[i].options.rowspan !== startRowspan) { + unmatchedFlag = true + break; + } + } + if (unmatchedFlag) { + this.vueInstance.$message.info(this.vueInstance.i18nt('designer.hint.rowspanNotConsistentForMergeEntireRow')) + return + } + + let widgetListCols = colArray.filter((colItem) => { + return !colItem.merged && !!colItem.widgetList && (colItem.widgetList.length > 0) + }) + if (!!widgetListCols && (widgetListCols.length > 0)) { //保留widgetList + if ((widgetListCols[0].id !== colArray[0].id) && (!colArray[0].widgetList || + colArray[0].widgetList.length <= 0)) { + colArray[0].widgetList = deepClone( widgetListCols[0].widgetList ) + } + } + + this.setPropsOfMergedCols(rowArray, rowIndex, 0, colArray.length, colArray[colIndex].options.rowspan) + + this.emitHistoryChange() + }, + + mergeTableRow(rowArray, curRow, curCol, aboveFlag, cellWidget) { + let mergedRowIdx = !!aboveFlag ? curRow : curRow + cellWidget.options.rowspan + + //let remainedRowIdx = !!aboveFlag ? curRow - cellWidget.options.rowspan : curRow + let remainedRowIdx = !!aboveFlag ? curRow - 1 : curRow + if (!!aboveFlag) { //继续向上寻找同列未被合并的第一个单元格 + let tmpRowIdx = remainedRowIdx + while (tmpRowIdx >= 0) { + if (!rowArray[tmpRowIdx].cols[curCol].merged) { + remainedRowIdx = tmpRowIdx + break; + } else { + tmpRowIdx-- + } + } + } + + if (!!rowArray[mergedRowIdx].cols[curCol].widgetList && (rowArray[mergedRowIdx].cols[curCol].widgetList.length > 0)) { //保留widgetList + if (!rowArray[remainedRowIdx].cols[curCol].widgetList || (rowArray[remainedRowIdx].cols[curCol].widgetList.length === 0)) { + rowArray[remainedRowIdx].cols[curCol].widgetList = deepClone(rowArray[mergedRowIdx].cols[curCol].widgetList) + } + } + + let newRowspan = rowArray[mergedRowIdx].cols[curCol].options.rowspan * 1 + rowArray[remainedRowIdx].cols[curCol].options.rowspan * 1 + this.setPropsOfMergedRows(rowArray, remainedRowIdx, curCol, cellWidget.options.colspan, newRowspan) + + this.emitHistoryChange() + }, + + mergeTableWholeCol(rowArray, colArray, rowIndex, colIndex) { //需要考虑操作的列存在已合并的单元格!! + //整列所有单元格列宽不一致不可合并!! + let startColspan = rowArray[0].cols[colIndex].options.colspan + let unmatchedFlag = false + for (let i = 1; i < rowArray.length; i++) { + if (rowArray[i].cols[colIndex].options.colspan !== startColspan) { + unmatchedFlag = true + break; + } + } + if (unmatchedFlag) { + this.vueInstance.$message.info(this.vueInstance.i18nt('designer.hint.colspanNotConsistentForMergeEntireColumn')) + return + } + + let widgetListCols = [] + rowArray.forEach(rowItem => { + let tempCell = rowItem.cols[colIndex] + if (!tempCell.merged && !!tempCell.widgetList && (tempCell.widgetList.length > 0)) { + widgetListCols.push(tempCell) + } + }) + + let firstCellOfCol = rowArray[0].cols[colIndex] + if (!!widgetListCols && (widgetListCols.length > 0)) { //保留widgetList + if ((widgetListCols[0].id !== firstCellOfCol.id) && (!firstCellOfCol.widgetList || + firstCellOfCol.widgetList.length <= 0)) { + firstCellOfCol.widgetList = deepClone( widgetListCols[0].widgetList ) + } + } + + this.setPropsOfMergedRows(rowArray, 0, colIndex, firstCellOfCol.options.colspan, rowArray.length) + + this.emitHistoryChange() + }, + + undoMergeTableCol(rowArray, rowIndex, colIndex, colspan, rowspan) { + this.setPropsOfSplitCol(rowArray, rowIndex, colIndex, colspan, rowspan) + + this.emitHistoryChange() + }, + + undoMergeTableRow(rowArray, rowIndex, colIndex, colspan, rowspan) { + this.setPropsOfSplitRow(rowArray, rowIndex, colIndex, colspan, rowspan) + + this.emitHistoryChange() + }, + + deleteTableWholeCol(rowArray, colIndex) { //需考虑删除的是合并列!! + let onlyOneColFlag = true + rowArray.forEach(ri => { + if (ri.cols[0].options.colspan !== rowArray[0].cols.length) { + onlyOneColFlag = false + } + }) + //仅剩一列则不可删除!! + if (onlyOneColFlag) { + this.vueInstance.$message.info(this.vueInstance.i18nt('designer.hint.lastColCannotBeDeleted')) + return + } + + //整列所有单元格列宽不一致不可删除!! + let startColspan = rowArray[0].cols[colIndex].options.colspan + let unmatchedFlag = false + for (let i = 1; i < rowArray.length; i++) { + if (rowArray[i].cols[colIndex].options.colspan !== startColspan) { + unmatchedFlag = true + break; + } + } + if (unmatchedFlag) { + this.vueInstance.$message.info(this.vueInstance.i18nt('designer.hint.colspanNotConsistentForDeleteEntireColumn')) + return + } + + rowArray.forEach((rItem) => { + rItem.cols.splice(colIndex, startColspan) + }) + + this.emitHistoryChange() + }, + + deleteTableWholeRow(rowArray, rowIndex) { //需考虑删除的是合并行!! + let onlyOneRowFlag = true + rowArray[0].cols.forEach(ci => { + if (ci.options.rowspan !== rowArray.length) { + onlyOneRowFlag = false + } + }) + //仅剩一行则不可删除!! + if (onlyOneRowFlag) { + this.vueInstance.$message.info(this.vueInstance.i18nt('designer.hint.lastRowCannotBeDeleted')) + return + } + + //整行所有单元格行高不一致不可删除!! + let startRowspan = rowArray[rowIndex].cols[0].options.rowspan + let unmatchedFlag = false + for (let i = 1; i < rowArray[rowIndex].cols.length; i++) { + if (rowArray[rowIndex].cols[i].options.rowspan !== startRowspan) { + unmatchedFlag = true + break; + } + } + if (unmatchedFlag) { + this.vueInstance.$message.info(this.vueInstance.i18nt('designer.hint.rowspanNotConsistentForDeleteEntireRow')) + return + } + + rowArray.splice(rowIndex, startRowspan) + + this.emitHistoryChange() + }, + + getContainerByType(typeName) { + let allWidgets = [...containers, ...basicFields, ...advancedFields, ...customFields] + let foundCon = null + allWidgets.forEach(con => { + if (!!con.category && !!con.type && (con.type === typeName)) { + foundCon = con + } + }) + + return foundCon + }, + + getFieldWidgetByType(typeName) { + let allWidgets = [...containers, ...basicFields, ...advancedFields, ...customFields] + let foundWidget = null + allWidgets.forEach(widget => { + if (!!!widget.category && !!widget.type && (widget.type === typeName)) { + foundWidget = widget + } + }) + + return foundWidget + }, + + hasConfig(widget, configName) { + let originalWidget = null + if (!!widget.category) { + originalWidget = this.getContainerByType(widget.type) + } else { + originalWidget = this.getFieldWidgetByType(widget.type) + } + + if (!originalWidget || !originalWidget.options) { + return false + } + + return Object.keys(originalWidget.options).indexOf(configName) > -1 + }, + + upgradeWidgetConfig(oldWidget) { + let newWidget = null + if (!!oldWidget.category) { + newWidget = this.getContainerByType(oldWidget.type) + } else { + newWidget = this.getFieldWidgetByType(oldWidget.type) + } + + if (!newWidget || !newWidget.options) { + return + } + + Object.keys(newWidget.options).forEach(ck => { + if (!oldWidget.hasOwnProperty(ck)) { + oldWidget.options[ck] = deepClone(newWidget.options[ck]) + } + }) + }, + + upgradeFormConfig(oldFormConfig) { + Object.keys(this.formConfig).forEach(fc => { + if (!oldFormConfig.hasOwnProperty(fc)) { + oldFormConfig[fc] = deepClone(this.formConfig[fc]) + } + }) + }, + + cloneGridCol(widget, parentWidget) { + let newGridCol = deepClone(this.getContainerByType('grid-col')) + newGridCol.options.span = widget.options.span + let tmpId = generateId() + newGridCol.id = 'grid-col-' + tmpId + newGridCol.options.name = 'gridCol' + tmpId + + parentWidget.cols.push(newGridCol) + }, + + cloneContainer(containWidget) { + if (containWidget.type === 'grid') { + let newGrid = deepClone(this.getContainerByType('grid')) + newGrid.id = newGrid.type + generateId() + newGrid.options.name = newGrid.id + containWidget.cols.forEach(gridCol => { + let newGridCol = deepClone(this.getContainerByType('grid-col')) + let tmpId = generateId() + newGridCol.id = 'grid-col-' + tmpId + newGridCol.options.name = 'gridCol' + tmpId + newGridCol.options.span = gridCol.options.span + newGrid.cols.push(newGridCol) + }) + + return newGrid + } else if (containWidget.type === 'table') { + let newTable = deepClone(this.getContainerByType('table')) + newTable.id = newTable.type + generateId() + newTable.options.name = newTable.id + containWidget.rows.forEach(tRow => { + let newRow = deepClone(tRow) + newRow.id = 'table-row-' + generateId() + newRow.cols.forEach(col => { + col.id = 'table-cell-' + generateId() + col.options.name = col.id + col.widgetList = [] //清空组件列表 + }) + newTable.rows.push(newRow) + }) + + return newTable + } else { //其他容器组件不支持clone操作 + return null + } + }, + + moveUpWidget(parentList, indexOfParentList) { + if (!!parentList) { + if (indexOfParentList === 0) { + this.vueInstance.$message(this.vueInstance.i18nt('designer.hint.moveUpFirstChildHint')) + return + } + + let tempWidget = parentList[indexOfParentList] + parentList.splice(indexOfParentList, 1) + parentList.splice(indexOfParentList - 1, 0, tempWidget) + } + }, + + moveDownWidget(parentList, indexOfParentList) { + if (!!parentList) { + if (indexOfParentList === parentList.length - 1) { + this.vueInstance.$message(this.vueInstance.i18nt('designer.hint.moveDownLastChildHint')) + return + } + + let tempWidget = parentList[indexOfParentList] + parentList.splice(indexOfParentList, 1) + parentList.splice(indexOfParentList + 1, 0, tempWidget) + } + }, + + copyNewFieldWidget(origin) { + let newWidget = deepClone(origin) + let tempId = generateId() + newWidget.id = newWidget.type.replace(/-/g, '') + tempId + newWidget.options.name = newWidget.id + newWidget.options.label = newWidget.options.label || newWidget.type.toLowerCase() + + delete newWidget.displayName + return newWidget + }, + + copyNewContainerWidget(origin) { + let newCon = deepClone(origin) + newCon.id = newCon.type.replace(/-/g, '') + generateId() + newCon.options.name = newCon.id + if (newCon.type === 'grid') { + let newCol = deepClone( this.getContainerByType('grid-col') ) + let tmpId = generateId() + newCol.id = 'grid-col-' + tmpId + newCol.options.name = 'gridCol' + tmpId + newCon.cols.push(newCol) + // + newCol = deepClone(newCol) + tmpId = generateId() + newCol.id = 'grid-col-' + tmpId + newCol.options.name = 'gridCol' + tmpId + newCon.cols.push(newCol) + } else if (newCon.type === 'table') { + let newRow = {cols: []} + newRow.id = 'table-row-' + generateId() + newRow.merged = false + let newCell = deepClone( this.getContainerByType('table-cell') ) + newCell.id = 'table-cell-' + generateId() + newCell.options.name = newCell.id + newCell.merged = false + newCell.options.colspan = 1 + newCell.options.rowspan = 1 + newRow.cols.push(newCell) + newCon.rows.push(newRow) + } else if (newCon.type === 'tab') { + let newTabPane = deepClone( this.getContainerByType('tab-pane') ) + newTabPane.id = 'tab-pane-' + generateId() + newTabPane.options.name = 'tab1' + newTabPane.options.label = 'tab 1' + newCon.tabs.push(newTabPane) + } + //newCon.options.customClass = [] + + delete newCon.displayName + return newCon + }, + + addContainerByDbClick(container) { + let newCon = this.copyNewContainerWidget(container) + this.widgetList.push(newCon) + this.setSelected(newCon) + }, + + addFieldByDbClick(widget) { + let newWidget = this.copyNewFieldWidget(widget) + if (!!this.selectedWidget && this.selectedWidget.type === 'tab') { + //获取当前激活的tabPane + let activeTab = this.selectedWidget.tabs[0] + this.selectedWidget.tabs.forEach(tabPane => { + if (!!tabPane.options.active) { + activeTab = tabPane + } + }) + + !!activeTab && activeTab.widgetList.push(newWidget) + } else if (!!this.selectedWidget && !!this.selectedWidget.widgetList) { + this.selectedWidget.widgetList.push(newWidget) + } else { + this.widgetList.push(newWidget) + } + + this.setSelected(newWidget) + this.emitHistoryChange() + }, + + deleteColOfGrid(gridWidget, colIdx) { + if (!!gridWidget && !!gridWidget.cols) { + gridWidget.cols.splice(colIdx, 1) + } + }, + + addNewColOfGrid(gridWidget) { + const cols = gridWidget.cols + let newGridCol = deepClone(this.getContainerByType('grid-col')) + let tmpId = generateId() + newGridCol.id = 'grid-col-' + tmpId + newGridCol.options.name = 'gridCol' + tmpId + if ((!!cols) && (cols.length > 0)) { + let spanSum = 0 + cols.forEach((col) => { + spanSum += col.options.span + }) + + if (spanSum >= 24) { + //this.$message.info('列栅格之和超出24') + console.log('列栅格之和超出24') + gridWidget.cols.push(newGridCol) + } else { + newGridCol.options.span = (24 - spanSum) > 12 ? 12 : (24 - spanSum) + gridWidget.cols.push(newGridCol) + } + } else { + gridWidget.cols = [newGridCol] + } + }, + + addTabPaneOfTabs(tabsWidget) { + const tabPanes = tabsWidget.tabs + let newTabPane = deepClone( this.getContainerByType('tab-pane') ) + newTabPane.id = 'tab-pane-' + generateId() + newTabPane.options.name = newTabPane.id + newTabPane.options.label = 'tab ' + (tabPanes.length + 1) + tabPanes.push(newTabPane) + }, + + deleteTabPaneOfTabs(tabsWidget, tpIdx) { + tabsWidget.tabs.splice(tpIdx, 1) + }, + + emitEvent(evtName, evtData) { //用于兄弟组件发射事件 + this.vueInstance.$emit(evtName, evtData) + }, + + handleEvent(evtName, callback) { //用于兄弟组件接收事件 + this.vueInstance.$on(evtName, (data) => callback(data)) + }, + + setCssClassList(cssClassList) { + this.cssClassList = cssClassList + }, + + getCssClassList() { + return this.cssClassList + }, + + registerFormWidget(formWidget) { + this.formWidget = formWidget + }, + + initHistoryData() { + this.loadFormContentFromStorage() + this.historyData.index++ + this.historyData.steps[this.historyData.index] = ({ + widgetList: deepClone(this.widgetList), + formConfig: deepClone(this.formConfig) + }) + }, + + emitHistoryChange() { + //console.log('------------', 'Form history changed!') + + if (this.historyData.index === this.historyData.maxStep - 1) { + this.historyData.steps.shift() + } else { + this.historyData.index++ + } + + this.historyData.steps[this.historyData.index] = ({ + widgetList: deepClone(this.widgetList), + formConfig: deepClone(this.formConfig) + }) + + this.saveFormContentToStorage() + + if (this.historyData.index < this.historyData.steps.length - 1) { + this.historyData.steps = this.historyData.steps.slice(0, this.historyData.index + 1) + } + + //console.log('history', this.historyData.index) + }, + + saveCurrentHistoryStep() { + this.historyData.steps[this.historyData.index] = deepClone({ + widgetList: this.widgetList, + formConfig: this.formConfig + }) + + this.saveFormContentToStorage() + }, + + undoHistoryStep() { + if (this.historyData.index !== 0) { + this.historyData.index-- + } + //console.log('undo', this.historyData.index) + + this.widgetList = deepClone(this.historyData.steps[this.historyData.index].widgetList) + this.formConfig = deepClone(this.historyData.steps[this.historyData.index].formConfig) + }, + + redoHistoryStep() { + if (this.historyData.index !== (this.historyData.steps.length - 1)) { + this.historyData.index++ + } + //console.log('redo', this.historyData.index) + + this.widgetList = deepClone(this.historyData.steps[this.historyData.index].widgetList) + this.formConfig = deepClone(this.historyData.steps[this.historyData.index].formConfig) + }, + + undoEnabled() { + return (this.historyData.index > 0) && (this.historyData.steps.length > 0) + }, + + redoEnabled() { + return this.historyData.index < (this.historyData.steps.length - 1) + }, + + saveFormContentToStorage() { + window.localStorage.setItem('widget__list__backup', JSON.stringify(this.widgetList)) + window.localStorage.setItem('form__config__backup', JSON.stringify(this.formConfig)) + }, + + loadFormContentFromStorage() { + let widgetListBackup = window.localStorage.getItem('widget__list__backup') + if (!!widgetListBackup) { + this.widgetList = JSON.parse(widgetListBackup) + } + + let formConfigBackup = window.localStorage.getItem('form__config__backup') + if (!!formConfigBackup) { + //this.formConfig = JSON.parse(formConfigBackup) + overwriteObj(this.formConfig, JSON.parse(formConfigBackup)) /* 用=赋值,会导致inject依赖注入的formConfig属性变成非响应式 */ + } + }, + + + } +} diff --git a/src/components/form-designer/form-widget/container-widget/container-wrapper.vue b/src/components/form-designer/form-widget/container-widget/container-wrapper.vue new file mode 100644 index 0000000..813f8bf --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/container-wrapper.vue @@ -0,0 +1,107 @@ + + + + + + + diff --git a/src/components/form-designer/form-widget/container-widget/containerMixin.js b/src/components/form-designer/form-widget/container-widget/containerMixin.js new file mode 100644 index 0000000..2426325 --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/containerMixin.js @@ -0,0 +1,93 @@ +export default { + inject: ['getGlobalDsv'], + methods: { + appendTableRow(widget) { + this.designer.appendTableRow(widget) + }, + + appendTableCol(widget) { + this.designer.appendTableCol(widget) + }, + + onContainerDragAdd(evt, subList) { + const newIndex = evt.newIndex + if (!!subList[newIndex]) { + this.designer.setSelected( subList[newIndex] ) + } + + this.designer.emitHistoryChange() + this.designer.emitEvent('field-selected', this.widget) + }, + + onContainerDragUpdate() { + this.designer.emitHistoryChange() + }, + + checkContainerMove(evt) { + return this.designer.checkWidgetMove(evt) + }, + + selectWidget(widget) { + this.designer.setSelected(widget) + }, + + selectParentWidget() { + if (this.parentWidget) { + this.designer.setSelected(this.parentWidget) + } else { + this.designer.clearSelected() + } + }, + + moveUpWidget() { + this.designer.moveUpWidget(this.parentList, this.indexOfParentList) + this.designer.emitHistoryChange() + }, + + moveDownWidget() { + this.designer.moveDownWidget(this.parentList, this.indexOfParentList) + this.designer.emitHistoryChange() + }, + + cloneContainer(widget) { + if (!!this.parentList) { + let newCon = this.designer.cloneContainer(widget) + this.parentList.splice(this.indexOfParentList + 1, 0, newCon) + this.designer.setSelected(newCon) + + this.designer.emitHistoryChange() + } + }, + + removeWidget() { + if (!!this.parentList) { + const widgetRefName = this.designer.selectedWidgetName + let nextSelected = null + if (this.parentList.length === 1) { + if (!!this.parentWidget) { + nextSelected = this.parentWidget + } + } else if (this.parentList.length === (1 + this.indexOfParentList)) { + nextSelected = this.parentList[this.indexOfParentList - 1] + } else { + nextSelected = this.parentList[this.indexOfParentList + 1] + } + + this.$nextTick(() => { + this.parentList.splice(this.indexOfParentList, 1) + this.designer.setSelected(nextSelected) + + this.designer.formWidget.deleteWidgetRef(widgetRefName) //删除组件ref!!! + this.designer.emitHistoryChange() + }) + } + }, + + setWidgetOption(optionName, optionValue) { //通用组件选项修改API + if (this.widget.options.hasOwnProperty(optionName)) { + this.widget.options[optionName] = optionValue + } + }, + + } +} diff --git a/src/components/form-designer/form-widget/container-widget/grid-col-widget.vue b/src/components/form-designer/form-widget/container-widget/grid-col-widget.vue new file mode 100644 index 0000000..37d7fad --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/grid-col-widget.vue @@ -0,0 +1,314 @@ + + + + + diff --git a/src/components/form-designer/form-widget/container-widget/grid-widget.vue b/src/components/form-designer/form-widget/container-widget/grid-widget.vue new file mode 100644 index 0000000..f75f91e --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/grid-widget.vue @@ -0,0 +1,93 @@ + + + + + + + diff --git a/src/components/form-designer/form-widget/container-widget/index.js b/src/components/form-designer/form-widget/container-widget/index.js new file mode 100644 index 0000000..79f6d00 --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/index.js @@ -0,0 +1,24 @@ +import Vue from 'vue' + +const requireComponent = require.context('./', false, /\w+\.vue$/) + +/** + * 容器组件时递归组件,且内部可以嵌套其他容器,局部注册会找不到组件,必须注册为全局组件,原因不明?! + * begin + * +let comps = {} + +requireComponent.keys().map(fileName => { + let comp = requireComponent(fileName).default; + comps[comp.name] = comp +}) + +export default comps; + +end */ + +/* 全局注册!! */ +requireComponent.keys().map(fileName => { + let comp = requireComponent(fileName).default; + Vue.component(comp.name, comp) +}) diff --git a/src/components/form-designer/form-widget/container-widget/tab-widget.vue b/src/components/form-designer/form-widget/container-widget/tab-widget.vue new file mode 100644 index 0000000..e966aff --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/tab-widget.vue @@ -0,0 +1,124 @@ + + + + + + + diff --git a/src/components/form-designer/form-widget/container-widget/table-cell-widget.vue b/src/components/form-designer/form-widget/container-widget/table-cell-widget.vue new file mode 100644 index 0000000..8dccee5 --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/table-cell-widget.vue @@ -0,0 +1,347 @@ + + + + + diff --git a/src/components/form-designer/form-widget/container-widget/table-widget.vue b/src/components/form-designer/form-widget/container-widget/table-widget.vue new file mode 100644 index 0000000..4119c03 --- /dev/null +++ b/src/components/form-designer/form-widget/container-widget/table-widget.vue @@ -0,0 +1,116 @@ + + + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/button-widget.vue b/src/components/form-designer/form-widget/field-widget/button-widget.vue new file mode 100644 index 0000000..758117f --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/button-widget.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/cascader-widget.vue b/src/components/form-designer/form-widget/field-widget/cascader-widget.vue new file mode 100644 index 0000000..5fa2a0b --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/cascader-widget.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/checkbox-widget.vue b/src/components/form-designer/form-widget/field-widget/checkbox-widget.vue new file mode 100644 index 0000000..b7e21b5 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/checkbox-widget.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/color-widget.vue b/src/components/form-designer/form-widget/field-widget/color-widget.vue new file mode 100644 index 0000000..b02789c --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/color-widget.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/date-range-widget.vue b/src/components/form-designer/form-widget/field-widget/date-range-widget.vue new file mode 100644 index 0000000..9c26ec1 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/date-range-widget.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/date-widget.vue b/src/components/form-designer/form-widget/field-widget/date-widget.vue new file mode 100644 index 0000000..5fd071b --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/date-widget.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/divider-widget.vue b/src/components/form-designer/form-widget/field-widget/divider-widget.vue new file mode 100644 index 0000000..a09117a --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/divider-widget.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/fieldMixin.js b/src/components/form-designer/form-widget/field-widget/fieldMixin.js new file mode 100644 index 0000000..6e400ff --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/fieldMixin.js @@ -0,0 +1,613 @@ +import {deepClone} from "@/utils/util" +import FormValidators from '@/utils/validators' + +export default { + inject: ['refList', 'formConfig', 'getGlobalDsv', 'globalOptionData', 'globalModel', 'getOptionData'], + + computed: { + subFormName() { + return !!this.parentWidget ? this.parentWidget.options.name : '' + }, + + subFormItemFlag() { + return !!this.parentWidget ? this.parentWidget.type === 'sub-form' : false + }, + + formModel: { + cache: false, + get() { + return this.globalModel.formModel + } + }, + + }, + + methods: { + + //--------------------- 组件内部方法 begin ------------------// + getPropName() { + if (this.subFormItemFlag && !this.designState) { + return this.subFormName + "." + this.subFormRowIndex + "." + this.field.options.name + "" + } else { + return this.field.options.name + } + }, + + initFieldModel() { + if (!this.field.formItemFlag) { + return + } + + if (!!this.subFormItemFlag && !this.designState) { //SubForm子表单组件需要特殊处理!! + let subFormData = this.formModel[this.subFormName] + if (((subFormData === undefined) || (subFormData[this.subFormRowIndex] === undefined) || + (subFormData[this.subFormRowIndex][this.field.options.name] === undefined)) && + (this.field.options.defaultValue !== undefined)) { + this.fieldModel = this.field.options.defaultValue + subFormData[this.subFormRowIndex][this.field.options.name] = this.field.options.defaultValue + } else if (subFormData[this.subFormRowIndex][this.field.options.name] === undefined) { + this.fieldModel = null + subFormData[this.subFormRowIndex][this.field.options.name] = null + } else { + this.fieldModel = subFormData[this.subFormRowIndex][this.field.options.name] + } + + /* 主动触发子表单内field-widget的onChange事件!! */ + setTimeout(() => { //延时触发onChange事件, 便于更新计算字段!! + this.handleOnChangeForSubForm(this.fieldModel, this.oldFieldValue, subFormData, this.subFormRowId) + }, 800) + this.oldFieldValue = deepClone(this.fieldModel) + + this.initFileList() //处理图片上传、文件上传字段 + + return + } + + if ((this.formModel[this.field.options.name] === undefined) && + (this.field.options.defaultValue !== undefined)) { + this.fieldModel = this.field.options.defaultValue + } else if (this.formModel[this.field.options.name] === undefined) { //如果formModel为空对象,则初始化字段值为null!! + this.formModel[this.field.options.name] = null + } else { + this.fieldModel = this.formModel[this.field.options.name] + } + this.oldFieldValue = deepClone(this.fieldModel) + this.initFileList() //处理图片上传、文件上传字段 + }, + + initFileList() { //初始化上传组件的已上传文件列表 + if ( ((this.field.type !== 'picture-upload') && (this.field.type !== 'file-upload')) || (this.designState === true) ) { + return + } + + if (!!this.fieldModel) { + if (Array.isArray(this.fieldModel)) { + this.fileList = deepClone(this.fieldModel) + } else { + this.fileList.splice(0, 0, deepClone(this.fieldModel)) + } + } + }, + + initEventHandler() { + this.$on('setFormData', (newFormData) => { + //console.log('formModel of globalModel----------', this.globalModel.formModel) + if (!this.subFormItemFlag) { + this.setValue(newFormData[this.field.options.name]) + } + }) + + this.$on('field-value-changed', (values) => { + if (!!this.subFormItemFlag) { + let subFormData = this.formModel[this.subFormName] + this.handleOnChangeForSubForm(values[0], values[1], subFormData, this.subFormRowId) + } else { + this.handleOnChange(values[0], values[1]) + } + }) + + /* 监听重新加载选项事件 */ + this.$on('reloadOptionItems', (widgetNames) => { + if ((widgetNames.length === 0) || (widgetNames.indexOf(this.field.options.name) > -1)) { + this.initOptionItems(true) + } + }) + }, + + handleOnCreated() { + if (!!this.field.options.onCreated) { + let customFunc = new Function(this.field.options.onCreated) + customFunc.call(this) + } + }, + + handleOnMounted() { + if (!!this.field.options.onMounted) { + let mountFunc = new Function(this.field.options.onMounted) + mountFunc.call(this) + } + }, + + registerToRefList(oldRefName) { + if ((this.refList !== null) && !!this.field.options.name) { + if (this.subFormItemFlag && !this.designState) { //处理子表单元素(且非设计状态) + if (!!oldRefName) { + delete this.refList[oldRefName + '@row' + this.subFormRowId] + } + this.refList[this.field.options.name + '@row' + this.subFormRowId] = this + } else { + if (!!oldRefName) { + delete this.refList[oldRefName] + } + this.refList[this.field.options.name] = this + } + } + }, + + unregisterFromRefList() { //销毁组件时注销组件ref + if ((this.refList !== null) && !!this.field.options.name) { + let oldRefName = this.field.options.name + if (this.subFormItemFlag && !this.designState) { //处理子表单元素(且非设计状态) + delete this.refList[oldRefName + '@row' + this.subFormRowId] + } else { + delete this.refList[oldRefName] + } + } + }, + + initOptionItems(keepSelected) { + if (this.designState) { + return + } + + if ((this.field.type === 'radio') || (this.field.type === 'checkbox') + || (this.field.type === 'select') || (this.field.type === 'cascader')) { + /* 异步更新option-data之后globalOptionData不能获取到最新值,改用provide的getOptionData()方法 */ + const newOptionItems = this.getOptionData() + if (!!newOptionItems && newOptionItems.hasOwnProperty(this.field.options.name)) { + if (!!keepSelected) { + this.reloadOptions(newOptionItems[this.field.options.name]) + } else { + this.loadOptions(newOptionItems[this.field.options.name]) + } + } + } + }, + + refreshDefaultValue() { + if ((this.designState === true) && (this.field.options.defaultValue !== undefined)) { + this.fieldModel = this.field.options.defaultValue + } + }, + + clearFieldRules() { + if (!this.field.formItemFlag) { + return + } + + this.rules.splice(0, this.rules.length) //清空已有 + }, + + buildFieldRules() { + if (!this.field.formItemFlag && this.field.options.hidden) { + return + } + + this.rules.splice(0, this.rules.length) //清空已有 + if (!!this.field.options.required) { + this.rules.push({ + required: true, + //trigger: ['blur', 'change'], + trigger: ['blur'], /* 去掉change事件触发校验,change事件触发时formModel数据尚未更新,导致radio/checkbox必填校验出错!! */ + message: this.field.options.requiredHint || this.i18nt('render.hint.fieldRequired'), + }) + } + + if (!!this.field.options.validation) { + let vldName = this.field.options.validation + if (!!FormValidators[vldName]) { + this.rules.push({ + validator: FormValidators[vldName], + trigger: ['blur', 'change'], + label: this.field.options.label, + errorMsg: this.field.options.validationHint + }) + } else { + this.rules.push({ + validator: FormValidators['regExp'], + trigger: ['blur', 'change'], + regExp: vldName, + label: this.field.options.label, + errorMsg: this.field.options.validationHint + }) + } + } + + if (!!this.field.options.onValidate) { + let customFn = (rule, value, callback) => { + let tmpFunc = new Function('rule', 'value', 'callback', this.field.options.onValidate) + return tmpFunc.call(this, rule, value, callback) + } + this.rules.push({ + validator: customFn, + trigger: ['blur', 'change'], + label: this.field.options.label + }) + } + }, + + /** + * 禁用字段值变动触发表单校验 + */ + disableChangeValidate() { + if (!this.rules) { + return + } + + this.rules.forEach(rule => { + if (!!rule.trigger) { + rule.trigger.splice(0, rule.trigger.length) + } + }) + }, + + /** + * 启用字段值变动触发表单校验 + */ + enableChangeValidate() { + if (!this.rules) { + return + } + + this.rules.forEach(rule => { + if (!!rule.trigger) { + rule.trigger.push('blur') + rule.trigger.push('change') + } + }) + }, + + disableOptionOfList(optionList, optionValue) { + if (!!optionList && (optionList.length > 0)) { + optionList.forEach(opt => { + if (opt.value === optionValue) { + opt.disabled = true + } + }) + } + }, + + enableOptionOfList(optionList, optionValue) { + if (!!optionList && (optionList.length > 0)) { + optionList.forEach(opt => { + if (opt.value === optionValue) { + opt.disabled = false + } + }) + } + }, + + //--------------------- 组件内部方法 end ------------------// + + //--------------------- 事件处理 begin ------------------// + + emitFieldDataChange(newValue, oldValue) { + this.$emit('field-value-changed', [newValue, oldValue]) + + /* 必须用dispatch向指定父组件派发消息!! */ + this.dispatch('VFormRender', 'fieldChange', + [this.field.options.name, newValue, oldValue, this.subFormName, this.subFormRowIndex]) + }, + + syncUpdateFormModel(value) { + if (!!this.designState) { + return + } + + if (!!this.subFormItemFlag) { + let subFormData = this.formModel[this.subFormName] || [{}] + let subFormDataRow = subFormData[this.subFormRowIndex] + subFormDataRow[this.field.options.name] = value + } else { + this.formModel[this.field.options.name] = value + } + }, + + handleChangeEvent(value) { /* input的清除输入小按钮会同时触发handleChangeEvent、handleInputCustomEvent!! */ + this.syncUpdateFormModel(value) + this.emitFieldDataChange(value, this.oldFieldValue) + + //number组件一般不会触发focus事件,故此处需要手工赋值oldFieldValue!! + this.oldFieldValue = deepClone(value) /* oldFieldValue需要在initFieldModel()方法中赋初值!! */ + + /* 主动触发表单的单个字段校验,用于清除字段可能存在的校验错误提示 */ + this.dispatch('VFormRender', 'fieldValidation', [this.getPropName()]) + }, + + handleFocusCustomEvent(event) { + this.oldFieldValue = deepClone(this.fieldModel) //保存修改change之前的值 + + if (!!this.field.options.onFocus) { + let customFn = new Function('event', this.field.options.onFocus) + customFn.call(this, event) + } + }, + + handleBlurCustomEvent(event) { + if (!!this.field.options.onBlur) { + let customFn = new Function('event', this.field.options.onBlur) + customFn.call(this, event) + } + }, + + handleInputCustomEvent(value) { + this.syncUpdateFormModel(value) + + /* 主动触发表单的单个字段校验,用于清除字段可能存在的校验错误提示 */ + this.dispatch('VFormRender', 'fieldValidation', [this.getPropName()]) + + if (!!this.field.options.onInput) { + let customFn = new Function('value', this.field.options.onInput) + customFn.call(this, value) + } + }, + + emitAppendButtonClick() { + if (!!this.designState) { //设计状态不触发点击事件 + return + } + + if (!!this.field.options.onAppendButtonClick) { + let customFn = new Function(this.field.options.onAppendButtonClick) + customFn.call(this) + } else { + /* 必须调用mixins中的dispatch方法逐级向父组件发送消息!! */ + this.dispatch('VFormRender', 'appendButtonClick', [this]) + } + }, + + handleOnChange(val, oldVal) { //自定义onChange事件 + if (!!this.field.options.onChange) { + let changeFn = new Function('value', 'oldValue', this.field.options.onChange) + changeFn.call(this, val, oldVal) + } + }, + + handleOnChangeForSubForm(val, oldVal, subFormData, rowId) { //子表单自定义onChange事件 + if (!!this.field.options.onChange) { + let changeFn = new Function('value', 'oldValue', 'subFormData', 'rowId', this.field.options.onChange) + changeFn.call(this, val, oldVal, subFormData, rowId) + } + }, + + handleButtonWidgetClick() { + if (!!this.designState) { //设计状态不触发点击事件 + return + } + + if (!!this.field.options.onClick) { + let changeFn = new Function(this.field.options.onClick) + changeFn.call(this) + } else { + this.dispatch('VFormRender', 'buttonClick', [this]); + } + }, + + remoteQuery(keyword) { + if (!!this.field.options.onRemoteQuery) { + let remoteFn = new Function('keyword', this.field.options.onRemoteQuery) + remoteFn.call(this, keyword) + } + }, + + //--------------------- 事件处理 end ------------------// + + //--------------------- 以下为组件支持外部调用的API方法 begin ------------------// + /* 提示:用户可自行扩充这些方法!!! */ + + getFormRef() { /* 获取VFrom引用,必须在VForm组件created之后方可调用 */ + return this.refList['v_form_ref'] + }, + + getWidgetRef(widgetName, showError) { + let foundRef = this.refList[widgetName] + if (!foundRef && !!showError) { + this.$message.error(this.i18nt('render.hint.refNotFound') + widgetName) + } + return foundRef + }, + + getFieldEditor() { //获取内置的el表单组件 + return this.$refs['fieldEditor'] + }, + + /* + 注意:VFormRender的setFormData方法不会触发子表单内field-widget的setValue方法, + 因为setFormData方法调用后,子表单内所有field-widget组件已被清空,接收不到setFormData事件!! + * */ + setValue(newValue) { + /* if ((this.field.type === 'picture-upload') || (this.field.type === 'file-upload')) { + this.fileList = newValue + } else */ if (!!this.field.formItemFlag) { + let oldValue = deepClone(this.fieldModel) + this.fieldModel = newValue + this.initFileList() + + this.syncUpdateFormModel(newValue) + this.emitFieldDataChange(newValue, oldValue) + } + }, + + getValue() { + /* if ((this.field.type === 'picture-upload') || (this.field.type === 'file-upload')) { + return this.fileList + } else */ { + return this.fieldModel + } + }, + + resetField() { + if (!!this.subFormItemFlag) { //跳过子表单组件 + return + } + + let defaultValue = this.field.options.defaultValue + this.setValue(defaultValue) + + //清空上传组件文件列表 + if ((this.field.type === 'picture-upload') || (this.field.type === 'file-upload')) { + this.$refs['fieldEditor'].clearFiles() + this.fileList.splice(0, this.fileList.length) + } + }, + + setWidgetOption(optionName, optionValue) { //通用组件选项修改API + if (this.field.options.hasOwnProperty(optionName)) { + this.field.options[optionName] = optionValue + //TODO: 是否重新构建组件??有些属性修改后必须重新构建组件才能生效,比如字段校验规则。 + } + }, + + setReadonly(flag) { + this.field.options.readonly = flag + }, + + setDisabled(flag) { + this.field.options.disabled = flag + }, + + setAppendButtonVisible(flag) { + this.field.options.appendButton = flag + }, + + setAppendButtonDisabled(flag) { + this.field.options.appendButtonDisabled = flag + }, + + setHidden(flag) { + this.field.options.hidden = flag + + if (!!flag) { //清除组件校验规则 + this.clearFieldRules() + } else { //重建组件校验规则 + this.buildFieldRules() + } + }, + + setRequired(flag) { + this.field.options.required = flag + this.buildFieldRules() + }, + + setLabel(newLabel) { + this.field.options.label = newLabel + }, + + focus() { + if (!!this.getFieldEditor() && !!this.getFieldEditor().focus) { + this.getFieldEditor().focus() + } + }, + + clearSelectedOptions() { //清空已选选项 + if ((this.field.type !== 'checkbox') && (this.field.type !== 'radio') && (this.field.type !== 'select')) { + return + } + + if ((this.field.type === 'checkbox') || + ((this.field.type === 'select') && this.field.options.multiple)) { + this.fieldModel = [] + } else { + this.fieldModel = '' + } + }, + + /** + * 加载选项,并清空字段值 + * @param options + */ + loadOptions(options) { + this.field.options.optionItems = deepClone(options) + //this.clearSelectedOptions() //清空已选选项 + }, + + /** + * 重新加载选项,不清空字段值 + * @param options + */ + reloadOptions(options) { + this.field.options.optionItems = deepClone(options) + }, + + /** + * 返回radio/checkbox/select/cascader的选项数据 + * @returns 选择项数组 + */ + getOptions() { + return this.field.options.optionItems + }, + + disableOption(optionValue) { + this.disableOptionOfList(this.field.options.optionItems, optionValue) + }, + + enableOption(optionValue) { + this.enableOptionOfList(this.field.options.optionItems, optionValue) + }, + + setUploadHeader(name, value) { + this.$set(this.uploadHeaders, name, value) + }, + + setUploadData(name, value) { + this.$set(this.uploadData, name, value) + }, + + setToolbar(customToolbar) { + this.customToolbar = customToolbar + }, + + /** + * 是否子表单内嵌的组件 + * @returns {boolean} + */ + isSubFormItem() { + return !!this.parentWidget ? this.parentWidget.type === 'sub-form' : false + }, + + /** + * 动态增加自定义css样式 + * @param className + */ + addCssClass(className) { + if (!this.field.options.customClass) { + this.field.options.customClass = [className] + } else { + this.field.options.customClass.push(className) + } + }, + + /** + * 动态移除自定义css样式 + * @param className + */ + removeCssClass(className) { + if (!this.field.options.customClass) { + return + } + + let foundIdx = -1 + this.field.options.customClass.map((cc, idx) => { + if (cc === className) { + foundIdx = idx + } + }) + if (foundIdx > -1) { + this.field.options.customClass.splice(foundIdx, 1) + } + }, + + //--------------------- 以上为组件支持外部调用的API方法 end ------------------// + + } +} diff --git a/src/components/form-designer/form-widget/field-widget/file-upload-widget.vue b/src/components/form-designer/form-widget/field-widget/file-upload-widget.vue new file mode 100644 index 0000000..332923e --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/file-upload-widget.vue @@ -0,0 +1,303 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/form-item-wrapper.vue b/src/components/form-designer/form-widget/field-widget/form-item-wrapper.vue new file mode 100644 index 0000000..9b4ec8d --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/form-item-wrapper.vue @@ -0,0 +1,331 @@ + + + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/html-text-widget.vue b/src/components/form-designer/form-widget/field-widget/html-text-widget.vue new file mode 100644 index 0000000..6046b65 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/html-text-widget.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/index.js b/src/components/form-designer/form-widget/field-widget/index.js new file mode 100644 index 0000000..9e0f6ae --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/index.js @@ -0,0 +1,10 @@ +const requireComponent = require.context('./', false, /\w+\.vue$/) + +let comps = {} + +requireComponent.keys().map(fileName => { + let comp = requireComponent(fileName).default; + comps[comp.name] = comp +}) + +export default comps; diff --git a/src/components/form-designer/form-widget/field-widget/input-widget.vue b/src/components/form-designer/form-widget/field-widget/input-widget.vue new file mode 100644 index 0000000..dac4785 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/input-widget.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/number-widget.vue b/src/components/form-designer/form-widget/field-widget/number-widget.vue new file mode 100644 index 0000000..a685192 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/number-widget.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/picture-upload-widget.vue b/src/components/form-designer/form-widget/field-widget/picture-upload-widget.vue new file mode 100644 index 0000000..9705220 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/picture-upload-widget.vue @@ -0,0 +1,270 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/radio-widget.vue b/src/components/form-designer/form-widget/field-widget/radio-widget.vue new file mode 100644 index 0000000..8dc04f7 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/radio-widget.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/rate-widget.vue b/src/components/form-designer/form-widget/field-widget/rate-widget.vue new file mode 100644 index 0000000..aab9897 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/rate-widget.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/rich-editor-widget.vue b/src/components/form-designer/form-widget/field-widget/rich-editor-widget.vue new file mode 100644 index 0000000..c6d70bd --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/rich-editor-widget.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/select-widget.vue b/src/components/form-designer/form-widget/field-widget/select-widget.vue new file mode 100644 index 0000000..150faf0 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/select-widget.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/slider-widget.vue b/src/components/form-designer/form-widget/field-widget/slider-widget.vue new file mode 100644 index 0000000..ecbe13c --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/slider-widget.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/slot-widget.vue b/src/components/form-designer/form-widget/field-widget/slot-widget.vue new file mode 100644 index 0000000..7fd1545 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/slot-widget.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/static-content-wrapper.vue b/src/components/form-designer/form-widget/field-widget/static-content-wrapper.vue new file mode 100644 index 0000000..9aaf3da --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/static-content-wrapper.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/static-text-widget.vue b/src/components/form-designer/form-widget/field-widget/static-text-widget.vue new file mode 100644 index 0000000..8cddc7f --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/static-text-widget.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/switch-widget.vue b/src/components/form-designer/form-widget/field-widget/switch-widget.vue new file mode 100644 index 0000000..5b433d5 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/switch-widget.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/textarea-widget.vue b/src/components/form-designer/form-widget/field-widget/textarea-widget.vue new file mode 100644 index 0000000..4e1f6dd --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/textarea-widget.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/time-range-widget.vue b/src/components/form-designer/form-widget/field-widget/time-range-widget.vue new file mode 100644 index 0000000..8a83704 --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/time-range-widget.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/components/form-designer/form-widget/field-widget/time-widget.vue b/src/components/form-designer/form-widget/field-widget/time-widget.vue new file mode 100644 index 0000000..b4f15aa --- /dev/null +++ b/src/components/form-designer/form-widget/field-widget/time-widget.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/components/form-designer/form-widget/index.vue b/src/components/form-designer/form-widget/index.vue new file mode 100644 index 0000000..90ecafb --- /dev/null +++ b/src/components/form-designer/form-widget/index.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/src/components/form-designer/index.vue b/src/components/form-designer/index.vue new file mode 100644 index 0000000..8ee68d3 --- /dev/null +++ b/src/components/form-designer/index.vue @@ -0,0 +1,500 @@ + + + + + + + diff --git a/src/components/form-designer/refMixinDesign.js b/src/components/form-designer/refMixinDesign.js new file mode 100644 index 0000000..0b027f1 --- /dev/null +++ b/src/components/form-designer/refMixinDesign.js @@ -0,0 +1,28 @@ +export default { + methods: { + initRefList() { + if ((this.refList !== null) && !!this.widget.options.name) { + this.refList[this.widget.options.name] = this + } + }, + + getWidgetRef(widgetName, showError = false) { + let foundRef = this.refList[widgetName] + if (!foundRef && !!showError) { + this.$message.error(this.i18nt('render.hint.refNotFound') + widgetName) + } + return foundRef + }, + + /* 该方法用于组件重名检查!! */ + registerToRefList(oldRefName) { + if ((this.refList !== null) && !!this.widget.options.name) { + if (!!oldRefName) { + delete this.refList[oldRefName] + } + this.refList[this.widget.options.name] = this + } + }, + + } +} diff --git a/src/components/form-designer/setting-panel/form-setting.vue b/src/components/form-designer/setting-panel/form-setting.vue new file mode 100644 index 0000000..0bc6d93 --- /dev/null +++ b/src/components/form-designer/setting-panel/form-setting.vue @@ -0,0 +1,354 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/index.vue b/src/components/form-designer/setting-panel/index.vue new file mode 100644 index 0000000..d065f3b --- /dev/null +++ b/src/components/form-designer/setting-panel/index.vue @@ -0,0 +1,367 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/option-items-setting.vue b/src/components/form-designer/setting-panel/option-items-setting.vue new file mode 100644 index 0000000..9076356 --- /dev/null +++ b/src/components/form-designer/setting-panel/option-items-setting.vue @@ -0,0 +1,234 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor-factory.js b/src/components/form-designer/setting-panel/property-editor-factory.js new file mode 100644 index 0000000..8838555 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor-factory.js @@ -0,0 +1,173 @@ +import {translate} from "@/utils/i18n" +import emitter from '@/utils/emitter' + +export const createInputTextEditor = function (propName, propLabelKey) { + return { + props: { + optionModel: Object, + }, + render(h) { + return ( + + + + ) + } + } +} + +export const createInputNumberEditor = function (propName, propLabelKey) { + return { + props: { + optionModel: Object, + }, + methods: { + updateValue(newValue) { + if ((newValue === undefined) || (newValue === null) || isNaN(newValue)) { + this.optionModel[propName] = null + } else { + this.optionModel[propName] = Number(newValue) + } + }, + }, + render(h) { + return ( + + + + ) + } + } +} + +export const createBooleanEditor = function (propName, propLabelKey) { + return { + props: { + optionModel: Object, + }, + render(h) { + return ( + + + + ) + } + } +} + +export const createCheckboxGroupEditor = function (propName, propLabelKey, configs) { + return { + props: { + optionModel: Object, + }, + render(h) { + return ( + + + { + configs.optionItems.map(item => { + return {item.label} + }) + } + + + ) + } + } +} + + +export const createRadioGroupEditor = function (propName, propLabelKey, configs) { + return { + props: { + optionModel: Object, + }, + render(h) { + return ( + + + { + configs.optionItems.map(item => { + return {item.label} + }) + } + + + ) + } + } +} + +export const createRadioButtonGroupEditor = function (propName, propLabelKey, configs) { + return { + props: { + optionModel: Object, + }, + render(h) { + return ( + + + { + configs.optionItems.map(item => { + return {item.label} + }) + } + + + ) + } + } +} + +export const createSelectEditor = function (propName, propLabelKey, configs) { + return { + props: { + optionModel: Object, + }, + render(h) { + return ( + + + { + configs.optionItems.map(item => { + return + }) + } + + + ) + } + } +} + +export const createEventHandlerEditor = function (eventPropName, eventParams) { + return { + props: { + optionModel: Object, + }, + mixins: [emitter], + methods: { + editEventHandler() { + this.dispatch('SettingPanel', 'editEventHandler', [eventPropName, [...eventParams]]) + }, + }, + render(h) { + return ( + + + {translate('designer.setting.addEventHandler')} + + ) + } + } +} + +export const createEmptyEditor = function () { + return { + render() { + return
+ } + } +} + diff --git a/src/components/form-designer/setting-panel/property-editor/allowCreate-editor.vue b/src/components/form-designer/setting-panel/property-editor/allowCreate-editor.vue new file mode 100644 index 0000000..299fcb2 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/allowCreate-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/appendButton-editor.vue b/src/components/form-designer/setting-panel/property-editor/appendButton-editor.vue new file mode 100644 index 0000000..aa9d15e --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/appendButton-editor.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/appendButtonDisabled-editor.vue b/src/components/form-designer/setting-panel/property-editor/appendButtonDisabled-editor.vue new file mode 100644 index 0000000..dd5c4f0 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/appendButtonDisabled-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/automaticDropdown-editor.vue b/src/components/form-designer/setting-panel/property-editor/automaticDropdown-editor.vue new file mode 100644 index 0000000..b5d5b40 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/automaticDropdown-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/border-editor.vue b/src/components/form-designer/setting-panel/property-editor/border-editor.vue new file mode 100644 index 0000000..8f76f15 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/border-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/buttonIcon-editor.vue b/src/components/form-designer/setting-panel/property-editor/buttonIcon-editor.vue new file mode 100644 index 0000000..93848a4 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/buttonIcon-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/buttonStyle-editor.vue b/src/components/form-designer/setting-panel/property-editor/buttonStyle-editor.vue new file mode 100644 index 0000000..060c0df --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/buttonStyle-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/clearable-editor.vue b/src/components/form-designer/setting-panel/property-editor/clearable-editor.vue new file mode 100644 index 0000000..bae7dc0 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/clearable-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/columnWidth-editor.vue b/src/components/form-designer/setting-panel/property-editor/columnWidth-editor.vue new file mode 100644 index 0000000..64552be --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/columnWidth-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-offset-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-offset-editor.vue new file mode 100644 index 0000000..046818c --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-offset-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-pull-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-pull-editor.vue new file mode 100644 index 0000000..3cfb0c4 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-pull-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-push-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-push-editor.vue new file mode 100644 index 0000000..23d0815 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-push-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-responsive-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-responsive-editor.vue new file mode 100644 index 0000000..820802c --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-responsive-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-span-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-span-editor.vue new file mode 100644 index 0000000..a7f0eef --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-grid-col/grid-col-span-editor.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-grid/colHeight-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-grid/colHeight-editor.vue new file mode 100644 index 0000000..c2648a2 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-grid/colHeight-editor.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue new file mode 100644 index 0000000..0be4106 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-sub-form/showBlankRow-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-sub-form/showBlankRow-editor.vue new file mode 100644 index 0000000..629cdae --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-sub-form/showBlankRow-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-sub-form/showRowNumber-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-sub-form/showRowNumber-editor.vue new file mode 100644 index 0000000..3395796 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-sub-form/showRowNumber-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-sub-form/sub-form-labelAlign-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-sub-form/sub-form-labelAlign-editor.vue new file mode 100644 index 0000000..aea845b --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-sub-form/sub-form-labelAlign-editor.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-tab/tab-customClass-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-tab/tab-customClass-editor.vue new file mode 100644 index 0000000..89fc1dc --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-tab/tab-customClass-editor.vue @@ -0,0 +1,119 @@ + + + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-table-cell/cellHeight-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-table-cell/cellHeight-editor.vue new file mode 100644 index 0000000..0fab2bf --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-table-cell/cellHeight-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-table-cell/cellWidth-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-table-cell/cellWidth-editor.vue new file mode 100644 index 0000000..f2fad36 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-table-cell/cellWidth-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/container-table-cell/wordBreak-editor.vue b/src/components/form-designer/setting-panel/property-editor/container-table-cell/wordBreak-editor.vue new file mode 100644 index 0000000..0417fee --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/container-table-cell/wordBreak-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/customClass-editor.vue b/src/components/form-designer/setting-panel/property-editor/customClass-editor.vue new file mode 100644 index 0000000..d0042a7 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/customClass-editor.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/defaultValue-editor.vue new file mode 100644 index 0000000..3122cf0 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/defaultValue-editor.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/disabled-editor.vue b/src/components/form-designer/setting-panel/property-editor/disabled-editor.vue new file mode 100644 index 0000000..baba3a0 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/disabled-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/displayStyle-editor.vue b/src/components/form-designer/setting-panel/property-editor/displayStyle-editor.vue new file mode 100644 index 0000000..fef5866 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/displayStyle-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/editable-editor.vue b/src/components/form-designer/setting-panel/property-editor/editable-editor.vue new file mode 100644 index 0000000..105aa51 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/editable-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/endPlaceholder-editor.vue b/src/components/form-designer/setting-panel/property-editor/endPlaceholder-editor.vue new file mode 100644 index 0000000..bfb6a50 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/endPlaceholder-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/eventMixin.js b/src/components/form-designer/setting-panel/property-editor/event-handler/eventMixin.js new file mode 100644 index 0000000..8792dd1 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/eventMixin.js @@ -0,0 +1,12 @@ +import emitter from '@/utils/emitter' + +export default { + mixins: [emitter], + created() {}, + methods: { + editEventHandler(eventName, eventParams) { + this.dispatch('SettingPanel', 'editEventHandler', [eventName, [...eventParams]]) + }, + + } +} diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onAppendButtonClick-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onAppendButtonClick-editor.vue new file mode 100644 index 0000000..99c7cf9 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onAppendButtonClick-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onBeforeUpload-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onBeforeUpload-editor.vue new file mode 100644 index 0000000..e4355dd --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onBeforeUpload-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onBlur-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onBlur-editor.vue new file mode 100644 index 0000000..393f7e6 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onBlur-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onChange-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onChange-editor.vue new file mode 100644 index 0000000..8010610 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onChange-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onClick-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onClick-editor.vue new file mode 100644 index 0000000..c154bcf --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onClick-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onCreated-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onCreated-editor.vue new file mode 100644 index 0000000..afc1e8c --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onCreated-editor.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onFileRemove.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onFileRemove.vue new file mode 100644 index 0000000..08946b3 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onFileRemove.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onFocus-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onFocus-editor.vue new file mode 100644 index 0000000..1c24dad --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onFocus-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onInput-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onInput-editor.vue new file mode 100644 index 0000000..35d4982 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onInput-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onMounted-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onMounted-editor.vue new file mode 100644 index 0000000..bbb8bc6 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onMounted-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onRemoteQuery-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onRemoteQuery-editor.vue new file mode 100644 index 0000000..5275c61 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onRemoteQuery-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowAdd-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowAdd-editor.vue new file mode 100644 index 0000000..26abcfe --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowAdd-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowChange-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowChange-editor.vue new file mode 100644 index 0000000..254638a --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowChange-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowDelete-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowDelete-editor.vue new file mode 100644 index 0000000..8666b9e --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowDelete-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowInsert-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowInsert-editor.vue new file mode 100644 index 0000000..ed71c3d --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onSubFormRowInsert-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onUploadError-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onUploadError-editor.vue new file mode 100644 index 0000000..7562f96 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onUploadError-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onUploadSuccess-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onUploadSuccess-editor.vue new file mode 100644 index 0000000..925f791 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onUploadSuccess-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/event-handler/onValidate-editor.vue b/src/components/form-designer/setting-panel/property-editor/event-handler/onValidate-editor.vue new file mode 100644 index 0000000..44cc2a1 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/event-handler/onValidate-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-button/button-type-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-button/button-type-editor.vue new file mode 100644 index 0000000..4bb13de --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-button/button-type-editor.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-button/circle-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-button/circle-editor.vue new file mode 100644 index 0000000..a5c0f6a --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-button/circle-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-button/icon-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-button/icon-editor.vue new file mode 100644 index 0000000..177ce68 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-button/icon-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-button/plain-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-button/plain-editor.vue new file mode 100644 index 0000000..f825841 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-button/plain-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-button/round-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-button/round-editor.vue new file mode 100644 index 0000000..33c5612 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-button/round-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-cascader/cascader-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-cascader/cascader-defaultValue-editor.vue new file mode 100644 index 0000000..8ccc44e --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-cascader/cascader-defaultValue-editor.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-cascader/cascader-multiple-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-cascader/cascader-multiple-editor.vue new file mode 100644 index 0000000..7446820 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-cascader/cascader-multiple-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-cascader/checkStrictly-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-cascader/checkStrictly-editor.vue new file mode 100644 index 0000000..3216dad --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-cascader/checkStrictly-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-cascader/showAllLevels-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-cascader/showAllLevels-editor.vue new file mode 100644 index 0000000..68c91fc --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-cascader/showAllLevels-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-checkbox/checkbox-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-checkbox/checkbox-defaultValue-editor.vue new file mode 100644 index 0000000..9660985 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-checkbox/checkbox-defaultValue-editor.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-color/color-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-color/color-defaultValue-editor.vue new file mode 100644 index 0000000..21523ee --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-color/color-defaultValue-editor.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue new file mode 100644 index 0000000..d0df950 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-format-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-format-editor.vue new file mode 100644 index 0000000..35a0353 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-format-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-type-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-type-editor.vue new file mode 100644 index 0000000..e31e968 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-type-editor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-valueFormat-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-valueFormat-editor.vue new file mode 100644 index 0000000..bdca28c --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date-range/date-range-valueFormat-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue new file mode 100644 index 0000000..0b292e5 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date/date-format-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date/date-format-editor.vue new file mode 100644 index 0000000..0a28e69 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date/date-format-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date/date-type-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date/date-type-editor.vue new file mode 100644 index 0000000..2dcb301 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date/date-type-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-date/date-valueFormat-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-date/date-valueFormat-editor.vue new file mode 100644 index 0000000..ae5c6f6 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-date/date-valueFormat-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-divider/contentPosition-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-divider/contentPosition-editor.vue new file mode 100644 index 0000000..ca21786 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-divider/contentPosition-editor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-file-upload/file-upload-fileTypes-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-file-upload/file-upload-fileTypes-editor.vue new file mode 100644 index 0000000..a18c22a --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-file-upload/file-upload-fileTypes-editor.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-html-text/htmlContent-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-html-text/htmlContent-editor.vue new file mode 100644 index 0000000..7de014f --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-html-text/htmlContent-editor.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-number/controlsPosition-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-number/controlsPosition-editor.vue new file mode 100644 index 0000000..6cc39e5 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-number/controlsPosition-editor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-picture-upload/picture-upload-fileTypes-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-picture-upload/picture-upload-fileTypes-editor.vue new file mode 100644 index 0000000..697d3df --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-picture-upload/picture-upload-fileTypes-editor.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-radio/radio-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-radio/radio-defaultValue-editor.vue new file mode 100644 index 0000000..0f846a9 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-radio/radio-defaultValue-editor.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-rate/allowHalf-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-rate/allowHalf-editor.vue new file mode 100644 index 0000000..929a36c --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-rate/allowHalf-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-rate/highThreshold-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-rate/highThreshold-editor.vue new file mode 100644 index 0000000..c5fe412 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-rate/highThreshold-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-rate/lowThreshold-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-rate/lowThreshold-editor.vue new file mode 100644 index 0000000..00464b2 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-rate/lowThreshold-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-rate/rate-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-rate/rate-defaultValue-editor.vue new file mode 100644 index 0000000..d4dd66b --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-rate/rate-defaultValue-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-rate/rate-max-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-rate/rate-max-editor.vue new file mode 100644 index 0000000..a43c192 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-rate/rate-max-editor.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-rate/showScore-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-rate/showScore-editor.vue new file mode 100644 index 0000000..f929132 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-rate/showScore-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-rate/showText-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-rate/showText-editor.vue new file mode 100644 index 0000000..85625d5 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-rate/showText-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-select/select-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-select/select-defaultValue-editor.vue new file mode 100644 index 0000000..56612ee --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-select/select-defaultValue-editor.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-slider/range-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-slider/range-editor.vue new file mode 100644 index 0000000..7b1ef04 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-slider/range-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-slider/showStops-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-slider/showStops-editor.vue new file mode 100644 index 0000000..ae79fe8 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-slider/showStops-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-slider/vertical-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-slider/vertical-editor.vue new file mode 100644 index 0000000..42cb5e3 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-slider/vertical-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-static-text/fontSize-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-static-text/fontSize-editor.vue new file mode 100644 index 0000000..b2c1758 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-static-text/fontSize-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-static-text/preWrap-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-static-text/preWrap-editor.vue new file mode 100644 index 0000000..61ee8a3 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-static-text/preWrap-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-static-text/textContent-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-static-text/textContent-editor.vue new file mode 100644 index 0000000..5c6e145 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-static-text/textContent-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-switch/activeColor-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-switch/activeColor-editor.vue new file mode 100644 index 0000000..641bc94 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-switch/activeColor-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-switch/activeText-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-switch/activeText-editor.vue new file mode 100644 index 0000000..5c77879 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-switch/activeText-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-switch/inactiveColor-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-switch/inactiveColor-editor.vue new file mode 100644 index 0000000..dd4cb5c --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-switch/inactiveColor-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-switch/inactiveText-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-switch/inactiveText-editor.vue new file mode 100644 index 0000000..c37698a --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-switch/inactiveText-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-switch/switch-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-switch/switch-defaultValue-editor.vue new file mode 100644 index 0000000..08012b6 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-switch/switch-defaultValue-editor.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-switch/switchWidth-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-switch/switchWidth-editor.vue new file mode 100644 index 0000000..969f1c9 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-switch/switchWidth-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue new file mode 100644 index 0000000..36a0dd3 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-time-range/time-range-format-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-time-range/time-range-format-editor.vue new file mode 100644 index 0000000..d461dcc --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-time-range/time-range-format-editor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue new file mode 100644 index 0000000..d9d1e43 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/field-time/time-format-editor.vue b/src/components/form-designer/setting-panel/property-editor/field-time/time-format-editor.vue new file mode 100644 index 0000000..6ffe0bc --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/field-time/time-format-editor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/fileMaxSize-editor.vue b/src/components/form-designer/setting-panel/property-editor/fileMaxSize-editor.vue new file mode 100644 index 0000000..52df908 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/fileMaxSize-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/filterable-editor.vue b/src/components/form-designer/setting-panel/property-editor/filterable-editor.vue new file mode 100644 index 0000000..3c72077 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/filterable-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/hidden-editor.vue b/src/components/form-designer/setting-panel/property-editor/hidden-editor.vue new file mode 100644 index 0000000..a954304 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/hidden-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/index.js b/src/components/form-designer/setting-panel/property-editor/index.js new file mode 100644 index 0000000..918fbdf --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/index.js @@ -0,0 +1,10 @@ +const requireComponent = require.context('./', true, /\w+\.vue$/) //遍历当前目录和子目录 + +let comps = {} + +requireComponent.keys().map(fileName => { + let comp = requireComponent(fileName).default; + comps[comp.name] = comp +}) + +export default comps; diff --git a/src/components/form-designer/setting-panel/property-editor/label-editor.vue b/src/components/form-designer/setting-panel/property-editor/label-editor.vue new file mode 100644 index 0000000..cfa112e --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/label-editor.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/labelAlign-editor.vue b/src/components/form-designer/setting-panel/property-editor/labelAlign-editor.vue new file mode 100644 index 0000000..a704ab8 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/labelAlign-editor.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/labelHidden-editor.vue b/src/components/form-designer/setting-panel/property-editor/labelHidden-editor.vue new file mode 100644 index 0000000..e512ab4 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/labelHidden-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/labelIconClass-editor.vue b/src/components/form-designer/setting-panel/property-editor/labelIconClass-editor.vue new file mode 100644 index 0000000..5e32f65 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/labelIconClass-editor.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/labelIconPosition-editor.vue b/src/components/form-designer/setting-panel/property-editor/labelIconPosition-editor.vue new file mode 100644 index 0000000..805c793 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/labelIconPosition-editor.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/labelTooltip-editor.vue b/src/components/form-designer/setting-panel/property-editor/labelTooltip-editor.vue new file mode 100644 index 0000000..3ee1308 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/labelTooltip-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/labelWidth-editor.vue b/src/components/form-designer/setting-panel/property-editor/labelWidth-editor.vue new file mode 100644 index 0000000..96cedad --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/labelWidth-editor.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/limit-editor.vue b/src/components/form-designer/setting-panel/property-editor/limit-editor.vue new file mode 100644 index 0000000..b9a64f2 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/limit-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/max-editor.vue b/src/components/form-designer/setting-panel/property-editor/max-editor.vue new file mode 100644 index 0000000..ab5f320 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/max-editor.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/maxLength-editor.vue b/src/components/form-designer/setting-panel/property-editor/maxLength-editor.vue new file mode 100644 index 0000000..9545cf4 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/maxLength-editor.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/min-editor.vue b/src/components/form-designer/setting-panel/property-editor/min-editor.vue new file mode 100644 index 0000000..513fd24 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/min-editor.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/minLength-editor.vue b/src/components/form-designer/setting-panel/property-editor/minLength-editor.vue new file mode 100644 index 0000000..1b0e2e4 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/minLength-editor.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/multiple-editor.vue b/src/components/form-designer/setting-panel/property-editor/multiple-editor.vue new file mode 100644 index 0000000..487e4ad --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/multiple-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/multipleLimit-editor.vue b/src/components/form-designer/setting-panel/property-editor/multipleLimit-editor.vue new file mode 100644 index 0000000..3fae0c7 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/multipleLimit-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/multipleSelect-editor.vue b/src/components/form-designer/setting-panel/property-editor/multipleSelect-editor.vue new file mode 100644 index 0000000..8303980 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/multipleSelect-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/name-editor.vue b/src/components/form-designer/setting-panel/property-editor/name-editor.vue new file mode 100644 index 0000000..4ffb2f5 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/name-editor.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/optionItems-editor.vue b/src/components/form-designer/setting-panel/property-editor/optionItems-editor.vue new file mode 100644 index 0000000..d911453 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/optionItems-editor.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/placeholder-editor.vue b/src/components/form-designer/setting-panel/property-editor/placeholder-editor.vue new file mode 100644 index 0000000..e44ff8e --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/placeholder-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/precision-editor.vue b/src/components/form-designer/setting-panel/property-editor/precision-editor.vue new file mode 100644 index 0000000..4e64878 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/precision-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/prefixIcon-editor.vue b/src/components/form-designer/setting-panel/property-editor/prefixIcon-editor.vue new file mode 100644 index 0000000..361ff3a --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/prefixIcon-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/propertyMixin.js b/src/components/form-designer/setting-panel/property-editor/propertyMixin.js new file mode 100644 index 0000000..550e119 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/propertyMixin.js @@ -0,0 +1,55 @@ +export default { + methods: { + hasConfig(configName) { + if (!this.designer || !this.designer.selectedWidget) { + return false + } + + return this.designer.hasConfig(this.selectedWidget, configName) + }, + + emitDefaultValueChange() { + if (!!this.designer) { + if (!!this.designer.formWidget) { + let fieldWidget = this.designer.formWidget.getWidgetRef(this.designer.selectedWidget.options.name) + if (!!fieldWidget && !!fieldWidget.refreshDefaultValue) { + fieldWidget.refreshDefaultValue() + } + } + } + }, + + inputNumberHandler({target}) { + target.value = target.value.replace(/[^0-9]/gi, '') + }, + + onRemoteChange(val) { + if (!!val) { + this.optionModel.filterable = true + this.optionModel.allowCreate = false + } + }, + + onMultipleSelected(val) { + if (val) { + //debugger + + // 清空已选项,否则console会报错!! + let foundRef = this.designer.formWidget.getWidgetRef(this.optionModel.name) + if (!!foundRef && !!foundRef.clearSelectedOptions) { + foundRef.clearSelectedOptions() + } + + this.optionModel.defaultValue = [] //清空原默认值!! + } else { + if (!!this.optionModel.defaultValue && (this.optionModel.defaultValue.length > 0)) { + this.optionModel.defaultValue = this.optionModel.defaultValue[0] + } else { + this.optionModel.defaultValue = '' + } + } + }, + + + } +} diff --git a/src/components/form-designer/setting-panel/property-editor/readonly-editor.vue b/src/components/form-designer/setting-panel/property-editor/readonly-editor.vue new file mode 100644 index 0000000..b13462e --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/readonly-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/remote-editor.vue b/src/components/form-designer/setting-panel/property-editor/remote-editor.vue new file mode 100644 index 0000000..def1ff2 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/remote-editor.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/required-editor.vue b/src/components/form-designer/setting-panel/property-editor/required-editor.vue new file mode 100644 index 0000000..6925b12 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/required-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/requiredHint-editor.vue b/src/components/form-designer/setting-panel/property-editor/requiredHint-editor.vue new file mode 100644 index 0000000..d44c442 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/requiredHint-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/rows-editor.vue b/src/components/form-designer/setting-panel/property-editor/rows-editor.vue new file mode 100644 index 0000000..dafd688 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/rows-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/showFileList-editor.vue b/src/components/form-designer/setting-panel/property-editor/showFileList-editor.vue new file mode 100644 index 0000000..04e2def --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/showFileList-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/showPassword-editor.vue b/src/components/form-designer/setting-panel/property-editor/showPassword-editor.vue new file mode 100644 index 0000000..902818d --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/showPassword-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/showWordLimit-editor.vue b/src/components/form-designer/setting-panel/property-editor/showWordLimit-editor.vue new file mode 100644 index 0000000..07fab83 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/showWordLimit-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/size-editor.vue b/src/components/form-designer/setting-panel/property-editor/size-editor.vue new file mode 100644 index 0000000..671ceb5 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/size-editor.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/startPlaceholder-editor.vue b/src/components/form-designer/setting-panel/property-editor/startPlaceholder-editor.vue new file mode 100644 index 0000000..c1832a8 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/startPlaceholder-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/step-editor.vue b/src/components/form-designer/setting-panel/property-editor/step-editor.vue new file mode 100644 index 0000000..ac64aff --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/step-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/suffixIcon-editor.vue b/src/components/form-designer/setting-panel/property-editor/suffixIcon-editor.vue new file mode 100644 index 0000000..6f45b71 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/suffixIcon-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/textAlign-editor.vue b/src/components/form-designer/setting-panel/property-editor/textAlign-editor.vue new file mode 100644 index 0000000..0d49890 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/textAlign-editor.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/type-editor.vue b/src/components/form-designer/setting-panel/property-editor/type-editor.vue new file mode 100644 index 0000000..7f4ee50 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/type-editor.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/uploadTip-editor.vue b/src/components/form-designer/setting-panel/property-editor/uploadTip-editor.vue new file mode 100644 index 0000000..f58b6fd --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/uploadTip-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/uploadURL-editor.vue b/src/components/form-designer/setting-panel/property-editor/uploadURL-editor.vue new file mode 100644 index 0000000..6b651ae --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/uploadURL-editor.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/validation-editor.vue b/src/components/form-designer/setting-panel/property-editor/validation-editor.vue new file mode 100644 index 0000000..8a5c425 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/validation-editor.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/validationHint-editor.vue b/src/components/form-designer/setting-panel/property-editor/validationHint-editor.vue new file mode 100644 index 0000000..006696e --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/validationHint-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/property-editor/withCredentials-editor.vue b/src/components/form-designer/setting-panel/property-editor/withCredentials-editor.vue new file mode 100644 index 0000000..b965627 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/withCredentials-editor.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/propertyRegister.js b/src/components/form-designer/setting-panel/propertyRegister.js new file mode 100644 index 0000000..3e9536c --- /dev/null +++ b/src/components/form-designer/setting-panel/propertyRegister.js @@ -0,0 +1,215 @@ +import Vue from 'vue' + +/** + * 格式说明:属性名称==对应属性编辑器的组件名称 + */ +const COMMON_PROPERTIES = { + //字段 + 'name' : 'name-editor', + 'label' : 'label-editor', + 'labelAlign' : 'labelAlign-editor', + 'type' : 'type-editor', + 'defaultValue' : 'defaultValue-editor', + 'placeholder' : 'placeholder-editor', + 'startPlaceholder' : 'startPlaceholder-editor', + 'endPlaceholder' : 'endPlaceholder-editor', + 'columnWidth' : 'columnWidth-editor', + 'size' : 'size-editor', + 'showStops' : 'showStops-editor', + 'displayStyle' : 'displayStyle-editor', + 'buttonStyle' : 'buttonStyle-editor', + 'border' : 'border-editor', + 'labelWidth' : 'labelWidth-editor', + 'labelHidden' : 'labelHidden-editor', + 'rows' : 'rows-editor', + 'required' : 'required-editor', + 'requiredHint' : 'requiredHint-editor', + 'validation' : 'validation-editor', + 'validationHint' : 'validationHint-editor', + 'readonly' : 'readonly-editor', + 'disabled' : 'disabled-editor', + 'hidden' : 'hidden-editor', + 'clearable' : 'clearable-editor', + 'editable' : 'editable-editor', + 'showPassword' : 'showPassword-editor', + 'textContent' : 'textContent-editor', + 'textAlign' : 'textAlign-editor', + 'fontSize' : 'fontSize-editor', + 'preWrap' : 'preWrap-editor', + 'htmlContent' : 'htmlContent-editor', + 'format' : 'format-editor', + 'valueFormat' : 'valueFormat-editor', + 'filterable' : 'filterable-editor', + 'allowCreate' : 'allowCreate-editor', + 'remote' : 'remote-editor', + 'automaticDropdown' : 'automaticDropdown-editor', + 'checkStrictly' : 'checkStrictly-editor', + 'showAllLevels' : 'showAllLevels-editor', + 'multiple' : 'multiple-editor', + 'multipleLimit' : 'multipleLimit-editor', + 'contentPosition' : 'contentPosition-editor', + 'optionItems' : 'optionItems-editor', + 'uploadURL' : 'uploadURL-editor', + 'uploadTip' : 'uploadTip-editor', + 'withCredentials' : 'withCredentials-editor', + 'multipleSelect' : 'multipleSelect-editor', + 'limit' : 'limit-editor', + 'fileMaxSize' : 'fileMaxSize-editor', + 'fileTypes' : 'fileTypes-editor', + 'customClass' : 'customClass-editor', + + //容器 + 'showBlankRow' : 'showBlankRow-editor', + 'showRowNumber' : 'showRowNumber-editor', + 'cellWidth' : 'cellWidth-editor', + 'cellHeight' : 'cellHeight-editor', + 'colHeight' : 'colHeight-editor', + 'wordBreak' : 'wordBreak-editor', + 'gutter' : 'gutter-editor', + 'responsive' : 'responsive-editor', + 'span' : 'span-editor', + 'offset' : 'offset-editor', + 'push' : 'push-editor', + 'pull' : 'pull-editor', + +} + +const ADVANCED_PROPERTIES = { + 'min' : 'min-editor', + 'max' : 'max-editor', + 'precision' : 'precision-editor', + 'step' : 'step-editor', + 'controlsPosition' : 'controlsPosition-editor', + 'minLength' : 'minLength-editor', + 'maxLength' : 'maxLength-editor', + 'showWordLimit' : 'showWordLimit-editor', + 'prefixIcon' : 'prefixIcon-editor', + 'suffixIcon' : 'suffixIcon-editor', + 'switchWidth' : 'switchWidth-editor', + 'activeText' : 'activeText-editor', + 'inactiveText' : 'inactiveText-editor', + 'activeColor' : 'activeColor-editor', + 'inactiveColor' : 'inactiveColor-editor', + 'lowThreshold' : 'lowThreshold-editor', + 'highThreshold' : 'highThreshold-editor', + 'allowHalf' : 'allowHalf-editor', + 'showText' : 'showText-editor', + 'showScore' : 'showScore-editor', + 'range' : 'range-editor', + 'vertical' : 'vertical-editor', + 'plain' : 'plain-editor', + 'round' : 'round-editor', + 'circle' : 'circle-editor', + 'icon' : 'icon-editor', + 'labelIconClass' : 'labelIconClass-editor', + 'labelIconPosition' : 'labelIconPosition-editor', + 'labelTooltip' : 'labelTooltip-editor', + 'appendButton' : 'appendButton-editor', + 'appendButtonDisabled': 'appendButtonDisabled-editor', + 'buttonIcon' : 'buttonIcon-editor', + +} + +const EVENT_PROPERTIES = { + //字段 + 'onCreated' : 'onCreated-editor', + 'onMounted' : 'onMounted-editor', + 'onClick' : 'onClick-editor', + 'onInput' : 'onInput-editor', + 'onChange' : 'onChange-editor', + 'onFocus' : 'onFocus-editor', + 'onBlur' : 'onBlur-editor', + 'onRemoteQuery' : 'onRemoteQuery-editor', + 'onBeforeUpload' : 'onBeforeUpload-editor', + 'onUploadSuccess' : 'onUploadSuccess-editor', + 'onUploadError' : 'onUploadError-editor', + 'onFileRemove' : 'onFileRemove-editor', + 'onValidate' : 'onValidate-editor', + 'onAppendButtonClick': 'onAppendButtonClick-editor', + + //容器 + 'onSubFormRowAdd' : 'onSubFormRowAdd-editor', + 'onSubFormRowInsert': 'onSubFormRowInsert-editor', + 'onSubFormRowDelete': 'onSubFormRowDelete-editor', + 'onSubFormRowChange': 'onSubFormRowChange-editor', + +} + +/** + * 注册组件常见属性 + * 如属性编辑器的组件名称propEditorName设置为null,则不显示该属性编辑器!! + * @param uniquePropName 属性名称(保证名称唯一,不跟其他组件属性冲突) + * @param propEditorName 对应属性编辑器的组件名称 + */ +export function registerCommonProperty(uniquePropName, propEditorName) { + COMMON_PROPERTIES[uniquePropName] = propEditorName +} + +/** + * 注册组件高级属性 + * 如属性编辑器的组件名称propEditorName设置为null,则不显示该属性编辑器!! + * @param uniquePropName 属性名称(保证名称唯一,不跟其他组件属性冲突) + * @param propEditorName 对应属性编辑器的组件名称 + */ +export function registerAdvancedProperty(uniquePropName, propEditorName) { + ADVANCED_PROPERTIES[uniquePropName] = propEditorName +} + +/** + * 注册组件事件属性 + * 如属性编辑器的组件名称propEditorName设置为null,则不显示该属性编辑器!! + * @param uniquePropName 属性名称(保证名称唯一,不跟其他组件属性冲突) + * @param propEditorName 对应属性编辑器的组件名称 + */ +export function registerEventProperty(uniquePropName, propEditorName) { + EVENT_PROPERTIES[uniquePropName] = propEditorName +} + +/** + * 判断属性是否已注册 + * @param uniquePropName 属性名称(保证名称唯一,不跟其他组件属性冲突) + */ +export function propertyRegistered(uniquePropName) { + return !!COMMON_PROPERTIES[uniquePropName] || !!ADVANCED_PROPERTIES[uniquePropName] || !!EVENT_PROPERTIES[uniquePropName] +} + +/** + * 注册常见属性对应的属性编辑器 + * @param uniquePropName + * @param propEditorName + * @param editorComponent + */ +export function registerCPEditor(uniquePropName, propEditorName, editorComponent) { + Vue.component(propEditorName, editorComponent) + registerCommonProperty(uniquePropName, propEditorName) +} + +/** + * 注册高级属性对应的属性编辑器 + * @param uniquePropName + * @param propEditorName + * @param editorComponent + */ +export function registerAPEditor(uniquePropName, propEditorName, editorComponent) { + Vue.component(propEditorName, editorComponent) + registerAdvancedProperty(uniquePropName, propEditorName) +} + +/** + * 注册事件属性对应的属性编辑器 + * @param uniquePropName + * @param propEditorName + * @param editorComponent + */ +export function registerEPEditor(uniquePropName, propEditorName, editorComponent) { + Vue.component(propEditorName, editorComponent) + registerEventProperty(uniquePropName, propEditorName) +} + +export default { + COMMON_PROPERTIES, + ADVANCED_PROPERTIES, + EVENT_PROPERTIES +} + + diff --git a/src/components/form-designer/toolbar-panel/index.vue b/src/components/form-designer/toolbar-panel/index.vue new file mode 100644 index 0000000..42b93a2 --- /dev/null +++ b/src/components/form-designer/toolbar-panel/index.vue @@ -0,0 +1,886 @@ + + + + + diff --git a/src/components/form-designer/widget-panel/index.vue b/src/components/form-designer/widget-panel/index.vue new file mode 100644 index 0000000..7b6dc89 --- /dev/null +++ b/src/components/form-designer/widget-panel/index.vue @@ -0,0 +1,386 @@ + + + + + diff --git a/src/components/form-designer/widget-panel/templatesConfig.js b/src/components/form-designer/widget-panel/templatesConfig.js new file mode 100644 index 0000000..bf67a61 --- /dev/null +++ b/src/components/form-designer/widget-panel/templatesConfig.js @@ -0,0 +1,58 @@ +export const formTemplates = [ + { + title: '单列表单', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t1.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json1.txt', + description: '表单模板详细说明...' + }, + + { + title: '多列表单', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t2.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json2.txt', + description: '表单模板详细说明...' + }, + + { + title: '分组表单', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t3.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json3.txt', + description: '表单模板详细说明...' + }, + + { + title: '标签页表单', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t4.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json4.txt', + description: '表单模板详细说明...' + }, + + { + title: '主从表单', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t5.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json5.txt', + description: '表单模板详细说明...' + }, + + { + title: '响应式表单', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t6.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json6.txt', + description: '表单模板详细说明...' + }, + + { + title: '问卷调查表', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t7.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json7.txt', + description: '表单模板详细说明...' + }, + + { + title: '固定表格表单', + imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t8.png', + jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json8.txt', + description: '表单模板详细说明...' + }, + +] diff --git a/src/components/form-designer/widget-panel/widgetsConfig.js b/src/components/form-designer/widget-panel/widgetsConfig.js new file mode 100644 index 0000000..5c986e6 --- /dev/null +++ b/src/components/form-designer/widget-panel/widgetsConfig.js @@ -0,0 +1,934 @@ + +export const containers = [ + { + type: 'grid', + category: 'container', + icon: 'grid', + cols: [], + options: { + name: '', + hidden: false, + gutter: 12, + colHeight: null, //栅格列统一高度属性,用于解决栅格列设置响应式布局浮动后被挂住的问题!! + customClass: '', //自定义css类名 + } + }, + + { + type: 'table', + category: 'container', + icon: 'table', + rows: [], + options: { + name: '', + hidden: false, + customClass: '', //自定义css类名 + } + }, + + { + type: 'tab', + category: 'container', + icon: 'tab', + displayType: 'border-card', + tabs: [], + options: { + name: '', + hidden: false, + customClass: '', //自定义css类名 + } + }, + + { + type: 'grid-col', + category: 'container', + icon: 'grid-col', + internal: true, + widgetList: [], + options: { + name: '', + hidden: false, + span: 12, + offset: 0, + push: 0, + pull: 0, + responsive: false, //是否开启响应式布局 + md: 12, + sm: 12, + xs: 12, + customClass: '', //自定义css类名 + } + }, + + { + type: 'table-cell', + category: 'container', + icon: 'table-cell', + internal: true, + widgetList: [], + merged: false, + options: { + name: '', + cellWidth: '', + cellHeight: '', + colspan: 1, + rowspan: 1, + wordBreak: false, //是否自动换行 + customClass: '', //自定义css类名 + } + }, + + { + type: 'tab-pane', + category: 'container', + icon: 'tab-pane', + internal: true, + widgetList: [], + options: { + name: '', + label: '', + hidden: false, + active: false, + disabled: false, + customClass: '', //自定义css类名 + } + }, + + +] + +export const basicFields = [ + { + type: 'input', + icon: 'text-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + type: 'text', + defaultValue: '', + placeholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + readonly: false, + disabled: false, + hidden: false, + clearable: true, + showPassword: false, + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + minLength: null, + maxLength: null, + showWordLimit: false, + prefixIcon: '', + suffixIcon: '', + appendButton: false, + appendButtonDisabled: false, + buttonIcon: 'el-icon-search', + //------------------- + onCreated: '', + onMounted: '', + onInput: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + onAppendButtonClick: '', + }, + }, + + { + type: 'textarea', + icon: 'textarea-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + rows: 3, + defaultValue: '', + placeholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + readonly: false, + disabled: false, + hidden: false, + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + minLength: null, + maxLength: null, + showWordLimit: false, + //------------------- + onCreated: '', + onMounted: '', + onInput: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + + { + type: 'number', + icon: 'number-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: 0, + placeholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + min: -100000000000, + max: 100000000000, + precision: 0, + step: 1, + controlsPosition: 'right', + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + + { + type: 'radio', + icon: 'radio-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: null, + columnWidth: '200px', + size: '', + displayStyle: 'inline', + buttonStyle: false, + border: false, + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + optionItems: [ + {label: 'radio 1', value: 1}, + {label: 'radio 2', value: 2}, + {label: 'radio 3', value: 3}, + ], + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onValidate: '', + }, + }, + + { + type: 'checkbox', + icon: 'checkbox-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: [], + columnWidth: '200px', + size: '', + displayStyle: 'inline', + buttonStyle: false, + border: false, + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + optionItems: [ + {label: 'check 1', value: 1}, + {label: 'check 2', value: 2}, + {label: 'check 3', value: 3}, + ], + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onValidate: '', + }, + }, + + { + type: 'select', + icon: 'select-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: '', + placeholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + clearable: true, + filterable: false, + allowCreate: false, + remote: false, + automaticDropdown: false, //自动下拉 + multiple: false, + multipleLimit: 0, + optionItems: [ + {label: 'select 1', value: 1}, + {label: 'select 2', value: 2}, + {label: 'select 3', value: 3}, + ], + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onRemoteQuery: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + + { + type: 'time', + icon: 'time-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: null, + placeholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + readonly: false, + disabled: false, + hidden: false, + clearable: true, + editable: false, + format: 'HH:mm:ss', //时间格式 + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + + { + type: 'time-range', + icon: 'time-range-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: null, + startPlaceholder: '', + endPlaceholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + readonly: false, + disabled: false, + hidden: false, + clearable: true, + editable: false, + format: 'HH:mm:ss', //时间格式 + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + + { + type: 'date', + icon: 'date-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + type: 'date', + defaultValue: null, + placeholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + readonly: false, + disabled: false, + hidden: false, + clearable: true, + editable: false, + format: 'yyyy-MM-dd', //日期显示格式 + valueFormat: 'yyyy-MM-dd', //日期对象格式 + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + + { + type: 'date-range', + icon: 'date-range-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + type: 'daterange', + defaultValue: null, + startPlaceholder: '', + endPlaceholder: '', + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + readonly: false, + disabled: false, + hidden: false, + clearable: true, + editable: false, + format: 'yyyy-MM-dd', //日期显示格式 + valueFormat: 'yyyy-MM-dd', //日期对象格式 + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + + { + type: 'switch', + icon: 'switch-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: null, + columnWidth: '200px', + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + switchWidth: 40, + activeText: '', + inactiveText: '', + activeColor: null, + inactiveColor: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onValidate: '', + }, + }, + + { + type: 'rate', + icon: 'rate-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: null, + columnWidth: '200px', + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + max: 5, + lowThreshold: 2, + highThreshold: 4, + allowHalf: false, + showText: false, + showScore: false, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onValidate: '', + }, + }, + + { + type: 'color', + icon: 'color-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: null, + columnWidth: '200px', + size: '', + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onValidate: '', + }, + }, + + { + type: 'slider', + icon: 'slider-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + columnWidth: '200px', + showStops: true, + size: '', + labelWidth: null, + labelHidden: false, + disabled: false, + hidden: false, + required: false, + requiredHint: '', + validation: '', + validationHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + min: 0, + max: 100, + step: 10, + range: false, + //vertical: false, + height: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onValidate: '', + }, + }, + + { + type: 'static-text', + icon: 'static-text', + formItemFlag: false, + options: { + name: '', + columnWidth: '200px', + hidden: false, + textContent: 'static text', + textAlign: 'left', + fontSize: '13px', + preWrap: false, //是否自动换行 + //------------------- + customClass: '', //自定义css类名 + //------------------- + onCreated: '', + onMounted: '', + }, + }, + + { + type: 'html-text', + icon: 'html-text', + formItemFlag: false, + options: { + name: '', + columnWidth: '200px', + hidden: false, + htmlContent: 'html text', + //------------------- + customClass: '', //自定义css类名 + //------------------- + onCreated: '', + onMounted: '', + }, + }, + + { + type: 'button', + icon: 'button', + formItemFlag: false, + options: { + name: '', + label: '', + columnWidth: '200px', + size: '', + displayStyle: 'block', + disabled: false, + hidden: false, + type: '', + plain: false, + round: false, + circle: false, + icon: null, + //------------------- + customClass: '', //自定义css类名 + //------------------- + onCreated: '', + onMounted: '', + onClick: '', + }, + }, + + { + type: 'divider', + icon: 'divider', + formItemFlag: false, + options: { + name: '', + label: '', + columnWidth: '200px', + direction: 'horizontal', + contentPosition: 'center', + hidden: false, + //------------------- + customClass: '', //自定义css类名 + //------------------- + onCreated: '', + onMounted: '', + }, + }, + + // + +] + +export const advancedFields = [ + { + type: 'picture-upload', + icon: 'picture-upload-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + labelWidth: null, + labelHidden: false, + columnWidth: '200px', + disabled: false, + hidden: false, + required: false, + requiredHint: '', + customRule: '', + customRuleHint: '', + //------------------- + uploadURL: '', + uploadTip: '', + withCredentials: false, + multipleSelect: false, + showFileList: true, + limit: 3, + fileMaxSize: 5, //MB + fileTypes: ['jpg', 'jpeg', 'png'], + //headers: [], + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onBeforeUpload: '', + onUploadSuccess: '', + onUploadError: '', + onFileRemove: '', + onValidate: '', + //onFileChange: '', + }, + + }, + + { + type: 'file-upload', + icon: 'file-upload-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + labelWidth: null, + labelHidden: false, + columnWidth: '200px', + disabled: false, + hidden: false, + required: false, + requiredHint: '', + customRule: '', + customRuleHint: '', + //------------------- + uploadURL: '', + uploadTip: '', + withCredentials: false, + multipleSelect: false, + showFileList: true, + limit: 3, + fileMaxSize: 5, //MB + fileTypes: ['doc', 'docx', 'xls', 'xlsx'], + //headers: [], + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onBeforeUpload: '', + onUploadSuccess: '', + onUploadError: '', + onFileRemove: '', + onValidate: '', + //onFileChange: '', + }, + }, + + { + type: 'rich-editor', + icon: 'rich-editor-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + placeholder: '', + labelWidth: null, + labelHidden: false, + columnWidth: '200px', + disabled: false, + hidden: false, + required: false, + requiredHint: '', + customRule: '', + customRuleHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + minLength: null, + maxLength: null, + showWordLimit: false, + //------------------- + onCreated: '', + onMounted: '', + onValidate: '', + }, + }, + + { + type: 'cascader', + icon: 'cascader-field', + formItemFlag: true, + options: { + name: '', + label: '', + labelAlign: '', + defaultValue: '', + placeholder: '', + size: '', + labelWidth: null, + labelHidden: false, + columnWidth: '200px', + disabled: false, + hidden: false, + clearable: true, + filterable: false, + multiple: false, + checkStrictly: false, //可选择任意一级选项,默认不开启 + showAllLevels: true, //显示完整路径 + optionItems: [ + {label: 'select 1', value: 1, children: [{label: 'child 1', value: 11}]}, + {label: 'select 2', value: 2}, + {label: 'select 3', value: 3}, + ], + required: false, + requiredHint: '', + customRule: '', + customRuleHint: '', + //------------------- + customClass: '', //自定义css类名 + labelIconClass: null, + labelIconPosition: 'rear', + labelTooltip: null, + //------------------- + onCreated: '', + onMounted: '', + onChange: '', + onFocus: '', + onBlur: '', + onValidate: '', + }, + }, + +] + +export const customFields = [ + +] + +export function addContainerWidgetSchema(containerSchema) { + containers.push(containerSchema) +} + +export function addBasicFieldSchema(fieldSchema) { + basicFields.push(fieldSchema) +} + +export function addAdvancedFieldSchema(fieldSchema) { + advancedFields.push(fieldSchema) +} + +export function addCustomWidgetSchema(widgetSchema) { + customFields.push(widgetSchema) +} diff --git a/src/components/form-render/container-item/container-item-wrapper.vue b/src/components/form-render/container-item/container-item-wrapper.vue new file mode 100644 index 0000000..288f792 --- /dev/null +++ b/src/components/form-render/container-item/container-item-wrapper.vue @@ -0,0 +1,37 @@ + + + + + + + diff --git a/src/components/form-render/container-item/containerItemMixin.js b/src/components/form-render/container-item/containerItemMixin.js new file mode 100644 index 0000000..c73e45d --- /dev/null +++ b/src/components/form-render/container-item/containerItemMixin.js @@ -0,0 +1,221 @@ +import { traverseFieldWidgetsOfContainer } from "@/utils/util"; + +export default { + inject: ['getGlobalDsv'], + computed: { + customClass() { + return this.widget.options.customClass || '' + }, + + formModel: { + cache: false, + get() { + return this.globalModel.formModel + } + }, + + }, + + mounted() { + this.callSetHidden() + }, + + methods: { + unregisterFromRefList() { //销毁容器组件时注销组件ref + if ((this.refList !== null) && !!this.widget.options.name) { + let oldRefName = this.widget.options.name + delete this.refList[oldRefName] + } + }, + + /* 主动触发setHidden()方法,以清空被隐藏容器内字段组件的校验规则!! */ + callSetHidden() { + if (this.widget.options.hidden === true) { + this.setHidden(true) + } + }, + + //--------------------- 以下为组件支持外部调用的API方法 begin ------------------// + /* 提示:用户可自行扩充这些方法!!! */ + + setHidden(flag) { + this.widget.options.hidden = flag + + /* 容器被隐藏后,需要同步清除容器内部字段组件的校验规则 */ + let clearRulesFn = (fieldWidget) => { + let fwName = fieldWidget.options.name + let fwRef = this.getWidgetRef(fwName) + if (flag && !!fwRef && !!fwRef.clearFieldRules) { + fwRef.clearFieldRules() + } + + if (!flag && !!fwRef && !!fwRef.buildFieldRules) { + fwRef.buildFieldRules() + } + } + + traverseFieldWidgetsOfContainer(this.widget, clearRulesFn) + }, + + activeTab(tabIndex) { //tabIndex从0计数 + if ((tabIndex >= 0) && (tabIndex < this.widget.tabs.length)) { + this.widget.tabs.forEach((tp, idx) => { + tp.options.active = idx === tabIndex + if (idx === tabIndex) { + this.activeTabName = tp.options.name + } + }) + } + }, + + disableTab(tabIndex) { + if ((tabIndex >= 0) && (tabIndex < this.widget.tabs.length)) { + this.widget.tabs[tabIndex].options.disabled = true + } + }, + + enableTab(tabIndex) { + if ((tabIndex >= 0) && (tabIndex < this.widget.tabs.length)) { + this.widget.tabs[tabIndex].options.disabled = false + } + }, + + hideTab(tabIndex) { + if ((tabIndex >= 0) && (tabIndex < this.widget.tabs.length)) { + this.widget.tabs[tabIndex].options.hidden = true + } + }, + + showTab(tabIndex) { + if ((tabIndex >= 0) && (tabIndex < this.widget.tabs.length)) { + this.widget.tabs[tabIndex].options.hidden = false + } + }, + + setWidgetOption(optionName, optionValue) { //通用组件选项修改API + if (this.widget.options.hasOwnProperty(optionName)) { + this.widget.options[optionName] = optionValue + } + }, + + /** + * 获取子表单的行数 + */ + getSubFormRowCount() { + return !this.rowIdData ? 0 : this.rowIdData.length + }, + + disableSubFormRow(rowIndex) { + this.widget.widgetList.forEach(subWidget => { + let swRefName = subWidget.options.name + '@row' + this.rowIdData[rowIndex] + let foundSW = this.getWidgetRef(swRefName) + if (!!foundSW) { + foundSW.setDisabled(true) + } + }) + }, + + enableSubFormRow(rowIndex) { + this.widget.widgetList.forEach(subWidget => { + let swRefName = subWidget.options.name + '@row' + this.rowIdData[rowIndex] + let foundSW = this.getWidgetRef(swRefName) + if (!!foundSW) { + foundSW.setDisabled(false) + } + }) + }, + + disableSubForm() { + if (this.rowIdData.length > 0) { + this.rowIdData.forEach((dataRow, rIdx) => { + this.disableSubFormRow(rIdx) + }) + } + + //禁用3个操作按钮 + this.actionDisabled = true + }, + + enableSubForm() { + if (this.rowIdData.length > 0) { + this.rowIdData.forEach((dataRow, rIdx) => { + this.enableSubFormRow(rIdx) + }) + } + + //启用3个操作按钮 + this.actionDisabled = false + }, + + resetSubForm() { //重置subForm数据为空 + if (this.widget.type === 'sub-form') { + let subFormModel = this.formModel[this.widget.options.name] + if (!!subFormModel) { + subFormModel.splice(0, subFormModel.length) + this.rowIdData.splice(0, this.rowIdData.length) + } + + if (this.widget.options.showBlankRow) { + this.addSubFormRow() + } + } + }, + + getSubFormValues(needValidation = true) { + if (this.widget.type === 'sub-form') { + //TODO: 逐行校验子表单!暂未实现!! + return this.formModel[this.widget.options.name] + } else { + this.$message.error(this.i18nt('render.hint.nonSubFormType')) + } + }, + + setSubFormValues(subFormValues) { + //TODO: 待实现!! + }, + + // validateField(fieldName) { //逐行校验子表单字段 + // //TODO: + // }, + // + // validateSubForm() { //逐行校验子表单全部字段 + // //TODO: + // }, + + /** + * 动态增加自定义css样式 + * @param className + */ + addCssClass(className) { + if (!this.widget.options.customClass) { + this.widget.options.customClass = [className] + } else { + this.widget.options.customClass.push(className) + } + }, + + /** + * 动态移除自定义css样式 + * @param className + */ + removeCssClass(className) { + if (!this.widget.options.customClass) { + return + } + + let foundIdx = -1 + this.widget.options.customClass.map((cc, idx) => { + if (cc === className) { + foundIdx = idx + } + }) + if (foundIdx > -1) { + this.widget.options.customClass.splice(foundIdx, 1) + } + }, + + //--------------------- 以上为组件支持外部调用的API方法 end ------------------// + + }, + +} diff --git a/src/components/form-render/container-item/grid-col-item.vue b/src/components/form-render/container-item/grid-col-item.vue new file mode 100644 index 0000000..280138e --- /dev/null +++ b/src/components/form-render/container-item/grid-col-item.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/src/components/form-render/container-item/grid-item.vue b/src/components/form-render/container-item/grid-item.vue new file mode 100644 index 0000000..5488fb9 --- /dev/null +++ b/src/components/form-render/container-item/grid-item.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/src/components/form-render/container-item/index.js b/src/components/form-render/container-item/index.js new file mode 100644 index 0000000..ac67666 --- /dev/null +++ b/src/components/form-render/container-item/index.js @@ -0,0 +1,24 @@ +import Vue from "vue" + +const requireComponent = require.context('./', false, /\w+\.vue$/) + +/** + * 容器组件时递归组件,且内部可以嵌套其他容器,局部注册会找不到组件,必须注册为全局组件,原因不明?! + * begin + * +let comps = {} + +requireComponent.keys().map(fileName => { + let comp = requireComponent(fileName).default; + comps[comp.name] = comp +}) + +export default comps; + +end */ + +/* 全局注册!! */ +requireComponent.keys().map(fileName => { + let comp = requireComponent(fileName).default; + Vue.component(comp.name, comp) +}) diff --git a/src/components/form-render/container-item/sub-form-item.vue b/src/components/form-render/container-item/sub-form-item.vue new file mode 100644 index 0000000..12193de --- /dev/null +++ b/src/components/form-render/container-item/sub-form-item.vue @@ -0,0 +1,417 @@ + + + + + diff --git a/src/components/form-render/container-item/tab-item.vue b/src/components/form-render/container-item/tab-item.vue new file mode 100644 index 0000000..2a5267b --- /dev/null +++ b/src/components/form-render/container-item/tab-item.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/components/form-render/container-item/table-cell-item.vue b/src/components/form-render/container-item/table-cell-item.vue new file mode 100644 index 0000000..300b344 --- /dev/null +++ b/src/components/form-render/container-item/table-cell-item.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/src/components/form-render/container-item/table-item.vue b/src/components/form-render/container-item/table-item.vue new file mode 100644 index 0000000..a694839 --- /dev/null +++ b/src/components/form-render/container-item/table-item.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/components/form-render/index.vue b/src/components/form-render/index.vue new file mode 100644 index 0000000..d43b790 --- /dev/null +++ b/src/components/form-render/index.vue @@ -0,0 +1,721 @@ + + + + + + + diff --git a/src/components/form-render/refMixin.js b/src/components/form-render/refMixin.js new file mode 100644 index 0000000..e129ea1 --- /dev/null +++ b/src/components/form-render/refMixin.js @@ -0,0 +1,30 @@ +export default { + methods: { + initRefList() { + if ((this.refList !== null) && !!this.widget.options.name) { + this.refList[this.widget.options.name] = this + } + }, + + getWidgetRef(widgetName, showError = false) { + let foundRef = this.refList[widgetName] + if (!foundRef && !!showError) { + this.$message.error(this.i18nt('render.hint.refNotFound') + widgetName) + } + return foundRef + }, + + getFormRef() { /* 获取VFrom引用,必须在VForm组件created之后方可调用 */ + return this.refList['v_form_ref'] + }, + + getComponentByContainer(con) { + if (con.type === 'grid') { //grid-item跟VueGridLayout全局注册组件重名,故特殊处理!! + return 'vf-grid-item' + } + + return con.type + '-item' + }, + + } +} diff --git a/src/components/svg-icon/index.vue b/src/components/svg-icon/index.vue new file mode 100644 index 0000000..8fc1294 --- /dev/null +++ b/src/components/svg-icon/index.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/src/components/v-table/index.vue b/src/components/v-table/index.vue new file mode 100644 index 0000000..371330d --- /dev/null +++ b/src/components/v-table/index.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/extension/extension-helper.js b/src/extension/extension-helper.js new file mode 100644 index 0000000..6f6c1f4 --- /dev/null +++ b/src/extension/extension-helper.js @@ -0,0 +1,23 @@ +import { + addContainerWidgetSchema, + addBasicFieldSchema, + addAdvancedFieldSchema, + addCustomWidgetSchema +} from '@/components/form-designer/widget-panel/widgetsConfig' +import { + registerCommonProperty, + registerAdvancedProperty, + registerEventProperty +} from '@/components/form-designer/setting-panel/propertyRegister' + + +export default { + addContainerWidgetSchema, + addBasicFieldSchema, + addAdvancedFieldSchema, + addCustomWidgetSchema, + + registerCommonProperty, + registerAdvancedProperty, + registerEventProperty, +} diff --git a/src/extension/extension-loader.js b/src/extension/extension-loader.js new file mode 100644 index 0000000..7b67c8c --- /dev/null +++ b/src/extension/extension-loader.js @@ -0,0 +1,116 @@ +import Vue from 'vue' + +import { + addContainerWidgetSchema, + addCustomWidgetSchema +} from '@/components/form-designer/widget-panel/widgetsConfig' +import * as PERegister from '@/components/form-designer/setting-panel/propertyRegister' +import * as PEFactory from '@/components/form-designer/setting-panel/property-editor-factory' + +import {cardSchema} from "@/extension/samples/extension-schema" +import CardWidget from '@/extension/samples/card/card-widget' +import CardItem from '@/extension/samples/card/card-item' +import {registerCWGenerator} from '@/utils/sfc-generator' +import {cardTemplateGenerator} from '@/extension/samples/extension-sfc-generator' + +import {alertSchema} from "@/extension/samples/extension-schema" +import AlertWidget from '@/extension/samples/alert/alert-widget' +import {registerFWGenerator} from '@/utils/sfc-generator' +import {alertTemplateGenerator} from '@/extension/samples/extension-sfc-generator' + +export const loadExtension = function () { + + /** + * 加载容器组件步骤: + * 1. 加载组件Json Schema; + * 2. 全局注册容器组件,容器组件有两种状态——设计期和运行期,故需要注册两个组件; + * 3. 全局注册属性编辑器组件(基本属性、高级属性、事件属性); + * 4. 注册容器组件的代码生成器; + * 5. 加载完毕。 + */ + addContainerWidgetSchema(cardSchema) //加载组件Json Schema + /* -------------------------------------------------- */ + Vue.component(CardWidget.name, CardWidget) //注册设计期的容器组件 + Vue.component(CardItem.name, CardItem) //注册运行期的容器组件 + /* -------------------------------------------------- */ + PERegister.registerCPEditor('card-folded', 'card-folded-editor', + PEFactory.createBooleanEditor('folded', 'extension.setting.cardFolded')) + + PERegister.registerCPEditor('card-showFold', 'card-showFold-editor', + PEFactory.createBooleanEditor('showFold', 'extension.setting.cardShowFold')) + + PERegister.registerCPEditor('card-cardWidth', 'card-cardWidth-editor', + PEFactory.createInputTextEditor('cardWidth', 'extension.setting.cardWidth')) + + let shadowOptions = [ + {label: 'never', value: 'never'}, + {label: 'hover', value: 'hover'}, + {label: 'always', value: 'always'}, + ] + PERegister.registerCPEditor('card-shadow', 'card-shadow-editor', + PEFactory.createSelectEditor('shadow', 'extension.setting.cardShadow', + {optionItems: shadowOptions})) + /* -------------------------------------------------- */ + registerCWGenerator('card', cardTemplateGenerator) //注册容器组件的代码生成器 + /* -------------------------------------------------- */ + /* 容器组件加载完毕 end */ + + /** + * 加载字段组件步骤: + * 1. 加载组件Json Schema; + * 2. 全局注册字段组件,字段组件设计期和运行期共用,故需要仅需注册一个组件; + * 3. 全局注册属性编辑器组件(基本属性、高级属性、事件属性); + * 4. 注册字段组件的代码生成器; + * 5. 加载完毕。 + */ + addCustomWidgetSchema(alertSchema) //加载组件Json Schema + /* -------------------------------------------------- */ + Vue.component(AlertWidget.name, AlertWidget) //注册组件 + /* -------------------------------------------------- */ + PERegister.registerCPEditor('alert-title', 'alert-title-editor', + PEFactory.createInputTextEditor('title', 'extension.setting.alertTitle')) + + let typeOptions = [ + {label: 'success', value: 'success'}, + {label: 'warning', value: 'warning'}, + {label: 'info', value: 'info'}, + {label: 'error', value: 'error'}, + ] + // PERegister.registerCPEditor('alert-type', 'alert-type-editor', + // PEFactory.createSelectEditor('type', 'extension.setting.alertType', + // {optionItems: typeOptions})) + /* type属性映射已存在,无须再注册,故只需注册属性编辑器即可!! */ + Vue.component('alert-type-editor', + PEFactory.createSelectEditor('type', 'extension.setting.alertType', + {optionItems: typeOptions})) + + PERegister.registerCPEditor('alert-description', 'alert-description-editor', + PEFactory.createInputTextEditor('description', 'extension.setting.description')) + + PERegister.registerCPEditor('alert-closable', 'alert-closable-editor', + PEFactory.createBooleanEditor('closable', 'extension.setting.closable')) + + PERegister.registerCPEditor('alert-closeText', 'alert-closeText-editor', + PEFactory.createInputTextEditor('closeText', 'extension.setting.closeText')) + + PERegister.registerCPEditor('alert-center', 'alert-center-editor', + PEFactory.createBooleanEditor('center', 'extension.setting.center')) + + PERegister.registerCPEditor('alert-showIcon', 'alert-showIcon-editor', + PEFactory.createBooleanEditor('showIcon', 'extension.setting.showIcon')) + + let effectOptions = [ + {label: 'light', value: 'light'}, + {label: 'dark', value: 'dark'}, + ] + PERegister.registerCPEditor('alert-effect', 'alert-effect-editor', + PEFactory.createRadioButtonGroupEditor('effect', 'extension.setting.effect', + {optionItems: effectOptions})) + + PERegister.registerEPEditor('alert-onClose', 'alert-onClose-editor', + PEFactory.createEventHandlerEditor('onClose', [])) + /* -------------------------------------------------- */ + registerFWGenerator('alert', alertTemplateGenerator) //注册字段组件的代码生成器 + /* -------------------------------------------------- */ + /* 字段组件加载完毕 end */ +} diff --git a/src/extension/samples/alert/alert-widget.vue b/src/extension/samples/alert/alert-widget.vue new file mode 100644 index 0000000..f13eb6e --- /dev/null +++ b/src/extension/samples/alert/alert-widget.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/src/extension/samples/card/card-item.vue b/src/extension/samples/card/card-item.vue new file mode 100644 index 0000000..e80dbf8 --- /dev/null +++ b/src/extension/samples/card/card-item.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/src/extension/samples/card/card-widget.vue b/src/extension/samples/card/card-widget.vue new file mode 100644 index 0000000..f090af5 --- /dev/null +++ b/src/extension/samples/card/card-widget.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/extension/samples/extension-schema.js b/src/extension/samples/extension-schema.js new file mode 100644 index 0000000..abdae48 --- /dev/null +++ b/src/extension/samples/extension-schema.js @@ -0,0 +1,36 @@ +export const cardSchema = { + type: 'card', + category: 'container', + icon: 'card', + widgetList: [], + options: { + name: '', + label: 'card', + hidden: false, + folded: false, + showFold: true, + cardWidth: '100%', + shadow: 'never', + customClass: '', + } +} + +export const alertSchema = { + type: 'alert', + icon: 'alert', + formItemFlag: false, + options: { + name: '', + title: 'Good things are coming...', + type: 'info', + description: '', + closable: true, + closeText: '', + center: true, + showIcon: false, + effect: 'light', + hidden: false, + onClose: '', + customClass: '', + } +} diff --git a/src/extension/samples/extension-sfc-generator.js b/src/extension/samples/extension-sfc-generator.js new file mode 100644 index 0000000..4625c03 --- /dev/null +++ b/src/extension/samples/extension-sfc-generator.js @@ -0,0 +1,50 @@ +import {buildClassAttr, buildContainerWidget, buildFieldWidget} from '@/utils/sfc-generator' + +export const cardTemplateGenerator = function (cw, formConfig) { + const wop = cw.options + //const headerAttr = `header="${wop.label}"` + const classAttr = buildClassAttr(cw) + const styleAttr = !!wop.cardWidth ? `style="{width: ${wop.cardWidth} !important}"` : '' + const shadowAttr = `shadow="${wop.shadow}"` + const vShowAttr = !!wop.hidden ? `v-show="false"` : '' + + const cardTemplate = +`
+ +
+ ${wop.label} + ${!!wop.showFold ? `` : ''} +
+ ${ + cw.widgetList.map(wItem => { + if (wItem.category === 'container') { + return buildContainerWidget(wItem, formConfig) + } else { + return buildFieldWidget(wItem, formConfig) + } + }).join('') + } +
+
` + + return cardTemplate +} + +export const alertTemplateGenerator = function(fw, formConfig) { + const wop = fw.options + const titleAttr = `title="${wop.title}"` + const typeAttr = `type=${wop.type}` + const descriptionAttr = !!wop.description ? `description="${wop.description}"` : '' + const closableAttr = `:closable="${wop.closable}"` + const closeTextAttr = !!wop.closeText ? `close-text="${wop.closeText}"` : '' + const centerAttr = `:center="${wop.center}"` + const showIconAttr = `:show-icon="${wop.showIcon}"` + const effectAttr = `effect="${wop.effect}"` + + const alertTemplate = +` +` + + return alertTemplate +} diff --git a/src/iconfont/iconfont.css b/src/iconfont/iconfont.css new file mode 100644 index 0000000..32f87eb --- /dev/null +++ b/src/iconfont/iconfont.css @@ -0,0 +1,29 @@ +@font-face { + font-family: "iconfont"; /* Project id */ + src: url('iconfont.ttf?t=1620643511304') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-insertcolumn:before { + content: "\e753"; +} + +.icon-insertrow:before { + content: "\e754"; +} + +.icon-hide:before { + content: "\e76b"; +} + +.icon-drag:before { + content: "\e61d"; +} + diff --git a/src/iconfont/iconfont.eot b/src/iconfont/iconfont.eot new file mode 100644 index 0000000..fc442ca Binary files /dev/null and b/src/iconfont/iconfont.eot differ diff --git a/src/iconfont/iconfont.js b/src/iconfont/iconfont.js new file mode 100644 index 0000000..577219f --- /dev/null +++ b/src/iconfont/iconfont.js @@ -0,0 +1 @@ +!function(e){var t,n,o,l,c,i,a='',d=(d=document.getElementsByTagName("script"))[d.length-1].getAttribute("data-injectcss");if(d&&!e.__iconfont__svg__cssinject__){e.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(e){console&&console.log(e)}}function s(){c||(c=!0,o())}t=function(){var e,t,n,o;(o=document.createElement("div")).innerHTML=a,a=null,(n=o.getElementsByTagName("svg")[0])&&(n.setAttribute("aria-hidden","true"),n.style.position="absolute",n.style.width=0,n.style.height=0,n.style.overflow="hidden",e=n,(t=document.body).firstChild?(o=e,(n=t.firstChild).parentNode.insertBefore(o,n)):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(n=function(){document.removeEventListener("DOMContentLoaded",n,!1),t()},document.addEventListener("DOMContentLoaded",n,!1)):document.attachEvent&&(o=t,l=e.document,c=!1,(i=function(){try{l.documentElement.doScroll("left")}catch(e){return void setTimeout(i,50)}s()})(),l.onreadystatechange=function(){"complete"==l.readyState&&(l.onreadystatechange=null,s())})}(window); \ No newline at end of file diff --git a/src/iconfont/iconfont.json b/src/iconfont/iconfont.json new file mode 100644 index 0000000..92af6b1 --- /dev/null +++ b/src/iconfont/iconfont.json @@ -0,0 +1,37 @@ +{ + "id": "", + "name": "", + "font_family": "iconfont", + "css_prefix_text": "icon-", + "description": "", + "glyphs": [ + { + "icon_id": "586931", + "name": "insert-column", + "font_class": "insertcolumn", + "unicode": "e753", + "unicode_decimal": 59219 + }, + { + "icon_id": "586932", + "name": "insert-row", + "font_class": "insertrow", + "unicode": "e754", + "unicode_decimal": 59220 + }, + { + "icon_id": "1030072", + "name": "hide", + "font_class": "hide", + "unicode": "e76b", + "unicode_decimal": 59243 + }, + { + "icon_id": "14772710", + "name": "drag", + "font_class": "drag", + "unicode": "e61d", + "unicode_decimal": 58909 + } + ] +} diff --git a/src/iconfont/iconfont.svg b/src/iconfont/iconfont.svg new file mode 100644 index 0000000..207c0c9 --- /dev/null +++ b/src/iconfont/iconfont.svg @@ -0,0 +1,35 @@ + + + + + +Created by iconfont + + + + + + + + + + + + + + + + + + + + diff --git a/src/iconfont/iconfont.ttf b/src/iconfont/iconfont.ttf new file mode 100644 index 0000000..d7a08f5 Binary files /dev/null and b/src/iconfont/iconfont.ttf differ diff --git a/src/iconfont/iconfont.woff b/src/iconfont/iconfont.woff new file mode 100644 index 0000000..330d984 Binary files /dev/null and b/src/iconfont/iconfont.woff differ diff --git a/src/iconfont/iconfont.woff2 b/src/iconfont/iconfont.woff2 new file mode 100644 index 0000000..aea096e Binary files /dev/null and b/src/iconfont/iconfont.woff2 differ diff --git a/src/icons/index.js b/src/icons/index.js new file mode 100644 index 0000000..4c4c36e --- /dev/null +++ b/src/icons/index.js @@ -0,0 +1,3 @@ +const requireAll = requireContext => requireContext.keys().map(requireContext) +const req = require.context('./svg', false, /\.svg$/) +requireAll(req) diff --git a/src/icons/svg/alert.svg b/src/icons/svg/alert.svg new file mode 100644 index 0000000..f1182f0 --- /dev/null +++ b/src/icons/svg/alert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/button.svg b/src/icons/svg/button.svg new file mode 100644 index 0000000..174a34a --- /dev/null +++ b/src/icons/svg/button.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/card.svg b/src/icons/svg/card.svg new file mode 100644 index 0000000..0e5404b --- /dev/null +++ b/src/icons/svg/card.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/cascader-field.svg b/src/icons/svg/cascader-field.svg new file mode 100644 index 0000000..ac4ef8e --- /dev/null +++ b/src/icons/svg/cascader-field.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/checkbox-field.svg b/src/icons/svg/checkbox-field.svg new file mode 100644 index 0000000..0f14ae4 --- /dev/null +++ b/src/icons/svg/checkbox-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/color-field.svg b/src/icons/svg/color-field.svg new file mode 100644 index 0000000..8dca8c5 --- /dev/null +++ b/src/icons/svg/color-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/custom-component.svg b/src/icons/svg/custom-component.svg new file mode 100644 index 0000000..2633507 --- /dev/null +++ b/src/icons/svg/custom-component.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/data-table.svg b/src/icons/svg/data-table.svg new file mode 100644 index 0000000..d4e7caf --- /dev/null +++ b/src/icons/svg/data-table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/date-field.svg b/src/icons/svg/date-field.svg new file mode 100644 index 0000000..54c51f1 --- /dev/null +++ b/src/icons/svg/date-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/date-range-field.svg b/src/icons/svg/date-range-field.svg new file mode 100644 index 0000000..66526ba --- /dev/null +++ b/src/icons/svg/date-range-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/divider.svg b/src/icons/svg/divider.svg new file mode 100644 index 0000000..286c16b --- /dev/null +++ b/src/icons/svg/divider.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/document.svg b/src/icons/svg/document.svg new file mode 100644 index 0000000..93668d5 --- /dev/null +++ b/src/icons/svg/document.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/drag.svg b/src/icons/svg/drag.svg new file mode 100644 index 0000000..990dce4 --- /dev/null +++ b/src/icons/svg/drag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/file-upload-field.svg b/src/icons/svg/file-upload-field.svg new file mode 100644 index 0000000..614405e --- /dev/null +++ b/src/icons/svg/file-upload-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/github.svg b/src/icons/svg/github.svg new file mode 100644 index 0000000..42f596d --- /dev/null +++ b/src/icons/svg/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/grid.svg b/src/icons/svg/grid.svg new file mode 100644 index 0000000..f1b9f1d --- /dev/null +++ b/src/icons/svg/grid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/html-text.svg b/src/icons/svg/html-text.svg new file mode 100644 index 0000000..44b9963 --- /dev/null +++ b/src/icons/svg/html-text.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/node-tree.svg b/src/icons/svg/node-tree.svg new file mode 100644 index 0000000..37f45fc --- /dev/null +++ b/src/icons/svg/node-tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/number-field.svg b/src/icons/svg/number-field.svg new file mode 100644 index 0000000..19a53a6 --- /dev/null +++ b/src/icons/svg/number-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/picture-upload-field.svg b/src/icons/svg/picture-upload-field.svg new file mode 100644 index 0000000..dde3bb4 --- /dev/null +++ b/src/icons/svg/picture-upload-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/radio-field.svg b/src/icons/svg/radio-field.svg new file mode 100644 index 0000000..274cb17 --- /dev/null +++ b/src/icons/svg/radio-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/rate-field.svg b/src/icons/svg/rate-field.svg new file mode 100644 index 0000000..5852671 --- /dev/null +++ b/src/icons/svg/rate-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/redo.svg b/src/icons/svg/redo.svg new file mode 100644 index 0000000..e5ea4a7 --- /dev/null +++ b/src/icons/svg/redo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/rich-editor-field.svg b/src/icons/svg/rich-editor-field.svg new file mode 100644 index 0000000..bb540f7 --- /dev/null +++ b/src/icons/svg/rich-editor-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/section.svg b/src/icons/svg/section.svg new file mode 100644 index 0000000..9249c99 --- /dev/null +++ b/src/icons/svg/section.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/select-field.svg b/src/icons/svg/select-field.svg new file mode 100644 index 0000000..59f83f1 --- /dev/null +++ b/src/icons/svg/select-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/slider-field.svg b/src/icons/svg/slider-field.svg new file mode 100644 index 0000000..f8f47dc --- /dev/null +++ b/src/icons/svg/slider-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/slot-component.svg b/src/icons/svg/slot-component.svg new file mode 100644 index 0000000..6adea10 --- /dev/null +++ b/src/icons/svg/slot-component.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/slot-field.svg b/src/icons/svg/slot-field.svg new file mode 100644 index 0000000..16e953a --- /dev/null +++ b/src/icons/svg/slot-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/static-text.svg b/src/icons/svg/static-text.svg new file mode 100644 index 0000000..fccdc45 --- /dev/null +++ b/src/icons/svg/static-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/sub-form.svg b/src/icons/svg/sub-form.svg new file mode 100644 index 0000000..13475d0 --- /dev/null +++ b/src/icons/svg/sub-form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/switch-field.svg b/src/icons/svg/switch-field.svg new file mode 100644 index 0000000..a5ccb46 --- /dev/null +++ b/src/icons/svg/switch-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/tab.svg b/src/icons/svg/tab.svg new file mode 100644 index 0000000..b171999 --- /dev/null +++ b/src/icons/svg/tab.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/table.svg b/src/icons/svg/table.svg new file mode 100644 index 0000000..8876696 --- /dev/null +++ b/src/icons/svg/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/text-field.svg b/src/icons/svg/text-field.svg new file mode 100644 index 0000000..7a411c0 --- /dev/null +++ b/src/icons/svg/text-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/textarea-field.svg b/src/icons/svg/textarea-field.svg new file mode 100644 index 0000000..967a753 --- /dev/null +++ b/src/icons/svg/textarea-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/time-field.svg b/src/icons/svg/time-field.svg new file mode 100644 index 0000000..9ad81e9 --- /dev/null +++ b/src/icons/svg/time-field.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/time-range-field.svg b/src/icons/svg/time-range-field.svg new file mode 100644 index 0000000..c5d9413 --- /dev/null +++ b/src/icons/svg/time-range-field.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/undo.svg b/src/icons/svg/undo.svg new file mode 100644 index 0000000..032c7ee --- /dev/null +++ b/src/icons/svg/undo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/vue-sfc.svg b/src/icons/svg/vue-sfc.svg new file mode 100644 index 0000000..4bd20bb --- /dev/null +++ b/src/icons/svg/vue-sfc.svg @@ -0,0 +1 @@ + diff --git a/src/lang/en-US.js b/src/lang/en-US.js new file mode 100644 index 0000000..d7f2969 --- /dev/null +++ b/src/lang/en-US.js @@ -0,0 +1,354 @@ +export default { + application: { + 'zh-CN': '简体中文', + 'en-US': 'English', + productTitle: 'Online Form Designer', + github: 'GitHub', + document: 'Docs', + qqGroup: 'WeChat Group', + deployment: 'Deployment', + subscription: 'Subscription', + }, + + designer: { + componentLib: 'Components', + formLib: 'Templates', + containerTitle: 'Container', + dragHandlerHint: 'drag container or field to layout center', + dragAction: 'drag', + basicFieldTitle: 'Basic Field', + advancedFieldTitle: 'Advanced Field', + customFieldTitle: 'Customized Field', + + noWidgetHint: 'Please select a widget from the left list, drag and drop to this container.', + + widgetLabel: { + grid: 'Grid', + table: 'Table', + tab: 'Tab', + section: 'Section', + 'sub-form': 'SubForm', + 'grid-col': 'GridCol', + 'table-cell': 'TableCell', + 'tab-pane': 'TabPane', + 'data-table': 'DataTable', + + input: 'Input', + textarea: 'Textarea', + number: 'InputNumber', + radio: 'Radio', + checkbox: 'Checkbox', + select: 'Select', + time: 'Time', + 'time-range': 'Time range', + date: 'Date', + 'date-range': 'Date range', + switch: 'Switch', + rate: 'Rate', + color: 'ColorPicker', + slider: 'Slider', + 'static-text': 'Text', + 'html-text': 'HTML', + button: 'Button', + divider: 'Divider', + + 'picture-upload': 'Picture', + 'file-upload': 'File', + 'rich-editor': 'Rich Editor', + cascader: 'Cascader', + slot: 'Slot', + + custom: 'Custom Component', + }, + + hint: { + selectParentWidget: 'Select parent of this widget', + moveUpWidget: 'Move up this widget', + moveDownWidget: 'Move down this widget', + cloneWidget: 'Clone this widget', + insertRow: 'Insert new row', + insertColumn: 'Insert new column', + remove: 'Remove this widget', + cellSetting: 'Cell setting', + dragHandler: 'Drag handler', + copyField: 'Copy field widget', + onlyFieldWidgetAcceptable: 'Only field widget can be dragged into sub-form', + moveUpFirstChildHint: 'First child can not be move up', + moveDownLastChildHint: 'Last child can not be move down', + + closePreview: 'Close', + copyJson: 'Copy', + saveFormJson: 'Save As File', + copyVueCode: 'Copy Vue Code', + copyHtmlCode: 'Copy HTML Code', + copyJsonSuccess: 'Copy succeed', + importJsonSuccess: 'Import succeed', + copyJsonFail: 'Copy failed', + copyVueCodeSuccess: 'Copy succeed', + copyVueCodeFail: 'Copy failed', + copyHtmlCodeSuccess: 'Copy succeed', + copyHtmlCodeFail: 'Copy failed', + saveVueCode: 'Save Vue File', + saveHtmlCode: 'Save Html File', + getFormData: 'Get Data', + resetForm: 'Reset', + disableForm: 'Disable', + enableForm: 'Enable', + exportFormData: 'Form Data', + copyFormData: 'Copy', + saveFormData: 'Save As File', + copyVue2SFC: 'Copy Vue2', + copyVue3SFC: 'Copy Vue3', + copySFCFail: 'Copy failed', + copySFCSuccess: 'Copy succeed', + saveVue2SFC: 'Save As Vue2', + saveVue3SFC: 'Save As Vue3', + fileNameForSave: 'File name:', + saveFileTitle: 'Save as File', + fileNameInputPlaceholder: 'Enter the file name', + sampleLoadedSuccess: 'Example loaded successfully', + sampleLoadedFail: 'Sample load failed', + loadFormTemplate: 'Load This', + loadFormTemplateHint: 'Are you sure to load this template?', + loadFormTemplateSuccess: 'Load form template success!', + loadFormTemplateFailed: 'Load form template failed.', + currentNodeCannotBeSelected: 'The current node cannot be selected.', + + widgetSetting: 'Widget Config', + formSetting: 'Form Config', + + prompt: 'Prompt', + confirm: 'OK', + cancel: 'Cancel', + import: 'Import', + importJsonHint: 'The code to be imported should have the following JSON format.', + invalidOptionsData: 'Invalid data of options:', + lastPaneCannotBeDeleted: 'The last pane cannot be deleted.', + duplicateName: 'Duplicate name: ', + nameRequired: 'Name required.', + + numberValidator: 'Number', + letterValidator: 'Letter', + letterAndNumberValidator: 'LetterAndNumber', + mobilePhoneValidator: 'MobilePhone', + emailValidator: 'Email', + urlValidator: 'URL', + noChineseValidator: 'Non-Chinese', + chineseValidator: 'Chinese', + + rowspanNotConsistentForMergeEntireRow: 'Cells in this row don\'t have the same rowspan, operation failed.', + colspanNotConsistentForMergeEntireColumn: 'Cells in this column don\'t have the same colspan, operation failed.', + rowspanNotConsistentForDeleteEntireRow: 'Cells in this row don\'t have the same rowspan, operation failed.', + colspanNotConsistentForDeleteEntireColumn: 'Cells in this column don\'t have the same colspan, operation failed.', + lastColCannotBeDeleted: 'The last col cannot be deleted.', + lastRowCannotBeDeleted: 'The last row cannot be deleted.', + }, + + toolbar: { + undoHint: 'Undo', + redoHint: 'Redo', + pcLayout: 'PC', + padLayout: 'Pad', + mobileLayout: 'H5', + nodeTreeHint: 'Tree View Of Component Hierarchy', + nodeTreeTitle: 'Tree View Of Component Hierarchy', + clear: 'Clear', + preview: 'Preview', + importJson: 'Import', + exportJson: 'Export', + exportCode: 'Codes', + generateCode: 'Generate Code', + generateSFC: 'Generate SFC', + }, + + setting: { + basicSetting: 'Basic Setting', + attributeSetting: 'Attribute Setting', + commonSetting: 'Common Setting', + advancedSetting: 'Advanced Setting', + eventSetting: 'Event Setting', + uniqueName: 'Unique Name', + editNameHelp: 'Press enter to confirm the modification', + label: 'Label', + displayType: 'Type', + defaultValue: 'Default Value', + placeholder: 'Placeholder', + startPlaceholder: 'Start Placeholder', + endPlaceholder: 'End Placeholder', + widgetColumnWidth: 'Width', + widgetSize: 'Size', + fontSize: 'Font Size', + textAlign: 'Text Align', + showStops: 'Show Stops', + displayStyle: 'Display Style', + inlineLayout: 'inline', + blockLayout: 'block', + buttonStyle: 'Show As Button', + border: 'Show Border', + labelWidth: 'Width Of Label', + rows: 'Rows', + labelHidden: 'Hide Label', + required: 'Required', + requiredHint: 'Failure Hint', + validation: 'Validation', + validationHelp: 'Regular expressions supported', + validationHint: 'Validation Hint', + readonly: 'Readonly', + disabled: 'Disabled', + hidden: 'Hidden', + textContent: 'Text', + preWrap: 'Line Wrap', + htmlContent: 'HTML', + clearable: 'Clearable', + editable: 'Editable', + format: 'Format', + valueFormat: 'Value Format', + showPassword: 'Show Reveal', + filterable: 'Filterable', + allowCreate: 'Allow Create', + remote: 'Remote Query', + automaticDropdown: 'Automatic Dropdown', + multiple: 'Multiple', + multipleLimit: 'Multiple Limit', + checkStrictly: 'Any Level Selectable', + showAllLevels: 'Show All Levels', + contentPosition: 'Content Position', + plain: 'Plain', + round: 'Round', + circle: 'Circle', + icon: 'Icon', + optionsSetting: 'Options Setting', + addOption: 'Add Option', + importOptions: 'Import Options', + resetDefault: 'Reset Default', + uploadSetting: 'Upload Setting', + uploadURL: 'Upload URL', + uploadTip: 'Tip Content', + withCredentials: 'Send Cookie', + multipleSelect: 'File Multi-select', + showFileList: 'Show File List', + limit: 'Max Upload Number', + fileMaxSize: 'Max Size(MB)', + fileTypes: 'Upload File Types', + fileTypesHelp: 'Allows to add more file types', + headers: 'Request Headers', + + cellWidth: 'Width', + cellHeight: 'Height', + wordBreak: 'Line Wrap', + gridColHeight: 'Height Of Col(px)', + gutter: 'Gutter(px)', + columnSetting: 'Cols Setting', + colsOfGrid: 'Cols Of Grid:', + colSpanTitle: 'Spans Of Col', + colOffsetTitle: 'Offset Of Col', + colPushTitle: 'Push Of Col', + colPullTitle: 'Pull Of Col', + addColumn: 'Add Column', + responsive: 'Responsive', + + tabPaneSetting: 'Tab Panes', + addTabPane: 'Add Tab Pane', + paneActive: 'Active', + + customLabelIcon: 'Custom Label', + labelIconClass: 'Label Icon Class', + labelIconPosition: 'Label Icon Position', + labelTooltip: 'Label Tooltip', + minValue: 'Min Value', + maxValue: 'Max Value', + precision: 'Precision', + step: 'Step', + controlsPosition: 'Controls Position', + minLength: 'Min Length', + maxLength: 'Max Length', + showWordLimit: 'Show Word Limit', + prefixIcon: 'Prefix Icon', + suffixIcon: 'Suffix Icon', + inputButton: 'Input Button Setting', + appendButton: 'Append Button', + appendButtonDisabled: 'Button Disabled', + appendButtonIcon: 'Append Button Icon', + buttonIcon: 'Button Icon', + switchWidth: 'Width of Switch(px)', + activeText: 'Active Text', + inactiveText: 'Inactive Text', + activeColor: 'Active Color', + inactiveColor: 'Inactive Color', + maxStars: 'Stars Max Number', + lowThreshold: 'Low Threshold', + highThreshold: 'High Threshold', + allowHalf: 'Allow Half', + showText: 'Show Text', + showScore: 'Show Score', + range: 'Range', + vertical: 'Vertical', + showBlankRow: 'Show Blank Row', + showRowNumber: 'Show Row Number', + + insertColumnToLeft: 'insert column to left', + insertColumnToRight: 'insert column to right', + insertRowAbove: 'insert row above', + insertRowBelow: 'insert row below', + mergeLeftColumn: 'merge left cell', + mergeRightColumn: 'merge right cell', + mergeEntireRow: 'merge entire row', + mergeRowAbove: 'merge cell above', + mergeRowBelow: 'merge cell below', + mergeEntireColumn: 'merge entire column', + undoMergeCol: 'undo merge column', + undoMergeRow: 'undo merge row', + deleteEntireCol: 'delete entire column', + deleteEntireRow: 'delete entire row', + + widgetName: 'Unique Name', + formSize: 'Size', + labelPosition: 'Position Of Label', + topPosition: 'Top', + leftPosition: 'Left', + labelAlign: 'Label Align', + leftAlign: 'Left', + centerAlign: 'Center', + rightAlign: 'Right', + formCss: 'Form CSS', + addCss: 'Edit', + customClass: 'Custom Class', + globalFunctions: 'Global Functions', + addEventHandler: 'Edit', + editWidgetEventHandler: 'Edit Widget Event Handler', + editFormEventHandler: 'Edit Form Event Handler', + formSFCSetting: 'SFC Setting', + formModelName: 'Model Name', + formRefName: 'Ref Name', + formRulesName: 'Rules Name', + syntaxCheckWarning: 'Syntax error in the javascript codes, please check again!', + + //data-table + tableWidth: 'Width(px/%)', + tableHeight: 'Height(px/%)', + showCheckBox: 'Show CheckBox', + showIndex: 'Show Row Number', + showPagination: 'Show Pagination', + smallPagination: 'Small Pagination', + tableColEdit: 'Edit Cols', + tableDataEdit: 'Edit Data', + stripe: 'Stripe', + showSummary: 'Show Summary', + rowSpacing: 'Row Spacing(px)', + editAction: 'Edit...', + columnName: 'Name', + columnLabel: 'Label', + columnWidth: 'Width(px/%)', + visibleColumn: 'Visible', + sortableColumn: 'Sortable', + fixedColumn: 'Fixed', + alignTypeOfColumn: 'Align', + formatOfColumn: 'Format', + actionColumn: 'Action', + addTableColumn: 'Add New Column', + deleteTableColumn: 'Delete This Column', + OnlyOneColumnCannotBeDeleted: 'The last column cannot be deleted.', + } + + } +} diff --git a/src/lang/en-US_extension.js b/src/lang/en-US_extension.js new file mode 100644 index 0000000..2149320 --- /dev/null +++ b/src/lang/en-US_extension.js @@ -0,0 +1,26 @@ +export default { + extension: { + widgetLabel: { + card: 'Card', + alert: 'Alert', + }, + + setting: { + cardFolded: 'Folded', + cardShowFold: 'Show Fold', + cardWidth: 'Width Of Card', + cardShadow: 'Shadow', + + alertTitle: 'Title', + alertType: 'Type', + description: 'Description', + closable: 'Closable', + closeText: 'Text On Close Btn', + center: 'Center', + showIcon: 'Show Icon', + effect: 'Effect', + + }, + + } +} diff --git a/src/lang/en-US_render.js b/src/lang/en-US_render.js new file mode 100644 index 0000000..8582386 --- /dev/null +++ b/src/lang/en-US_render.js @@ -0,0 +1,38 @@ +export default { + render: { + + hint: { + prompt: 'Prompt', + confirm: 'OK', + cancel: 'Cancel', + + selectPlaceholder: 'Pick some item', + timePlaceholder: 'Select time', + startTimePlaceholder: 'Start time', + endTimePlaceholder: 'End time', + datePlaceholder: 'Select date', + startDatePlaceholder: 'Start date', + endDatePlaceholder: 'End date', + blankCellContent: '--', + + uploadError: 'Upload error: ', + uploadExceed: 'The maximum number(${uploadLimit}) of file uploads has been exceeded.', + unsupportedFileType: 'Unsupported format: ', + fileSizeExceed: 'File size out of limit: ', + refNotFound: 'Ref not found: ', + fieldRequired: 'Input value should be not null.', + invalidNumber: 'Invalid number format', + selectFile: ' File...', + downloadFile: 'Download', + removeFile: 'Remove', + validationFailed: 'Form validation failed', + + subFormAction: 'Action', + subFormAddAction: 'Add', + subFormAddActionHint: 'add new row', + insertSubFormRow: 'insert new row', + deleteSubFormRow: 'delete this row', + nonSubFormType: 'The type of widget don\'t match sub-form', + } + } +} diff --git a/src/lang/zh-CN.js b/src/lang/zh-CN.js new file mode 100644 index 0000000..cdaeb98 --- /dev/null +++ b/src/lang/zh-CN.js @@ -0,0 +1,354 @@ +export default { + application: { + 'zh-CN': '简体中文', + 'en-US': 'English', + productTitle: '表单设计器', + github: 'GitHub', + document: '文档', + qqGroup: '技术WX群', + deployment: '私有部署', + subscription: '订阅Pro', + }, + + designer: { + componentLib: '组件库', + formLib: '表单模板', + containerTitle: '容器', + dragHandlerHint: '鼠标拖拽容器组件或字段组件并放置于表单中', + dragAction: '拖动', + basicFieldTitle: '基础字段', + advancedFieldTitle: '高级字段', + customFieldTitle: '自定义扩展字段', + + noWidgetHint: '请从左侧列表中选择一个组件, 然后用鼠标拖动组件放置于此处.', + + widgetLabel: { + grid: '栅格', + table: '表格', + tab: '标签页', + section: '区块', + 'sub-form': '子表单', + 'grid-col': '栅格列', + 'table-cell': '单元格', + 'tab-pane': '选项卡页', + 'data-table': '数据表格', + + input: '单行输入', + textarea: '多行输入', + number: '计数器', + radio: '单选项', + checkbox: '多选项', + select: '下拉选项', + time: '时间', + 'time-range': '时间范围', + date: '日期', + 'date-range': '日期范围', + switch: '开关', + rate: '评分', + color: '颜色选择器', + slider: '滑块', + 'static-text': '静态文字', + 'html-text': 'HTML', + button: '按钮', + divider: '分隔线', + + 'picture-upload': '图片', + 'file-upload': '文件', + 'rich-editor': '富文本', + cascader: '级联选择', + slot: '插槽', + + custom: 'Custom Component', + }, + + hint: { + selectParentWidget: '选中父组件', + moveUpWidget: '上移组件', + moveDownWidget: '下移组件', + cloneWidget: '复制组件', + insertRow: '插入新行', + insertColumn: '插入新列', + remove: '移除组件', + cellSetting: '单元格操作', + dragHandler: '拖拽手柄', + copyField: '复制字段组件', + onlyFieldWidgetAcceptable: '子表单只能接收字段组件', + moveUpFirstChildHint: '已经移动到最上面', + moveDownLastChildHint: '已经移动到最下面', + + closePreview: '关闭', + copyJson: '复制JSON', + saveFormJson: '保存为文件', + copyVueCode: '复制Vue代码', + copyHtmlCode: '复制HTML代码', + copyJsonSuccess: '复制JSON成功', + importJsonSuccess: '导入JSON成功', + copyJsonFail: '复制JSON失败', + copyVueCodeSuccess: '复制Vue代码成功', + copyVueCodeFail: '复制Vue代码失败', + copyHtmlCodeSuccess: '复制HTML代码成功', + copyHtmlCodeFail: '复制HTML代码失败', + saveVueCode: '保存Vue文件', + saveHtmlCode: '保存Html文件', + getFormData: '获取数据', + resetForm: '重置表单', + disableForm: '禁用编辑', + enableForm: '恢复编辑', + exportFormData: '表单数据', + copyFormData: '复制JSON', + saveFormData: '保存为文件', + copyVue2SFC: '复制Vue2代码', + copyVue3SFC: '复制Vue3代码', + copySFCFail: '复制SFC代码失败', + copySFCSuccess: '复制SFC代码成功', + saveVue2SFC: '保存为Vue2组件', + saveVue3SFC: '保存为Vue3组件', + fileNameForSave: '文件名:', + saveFileTitle: '保存为文件', + fileNameInputPlaceholder: '请输入文件名', + sampleLoadedSuccess: '表单示例加载成功', + sampleLoadedFail: '表单示例加载失败', + loadFormTemplate: '加载此模板', + loadFormTemplateHint: '是否加载这个模板?加载后会覆盖设计器当前表单,你可以使用“撤销”功能恢复。', + loadFormTemplateSuccess: '表单模板加载成功', + loadFormTemplateFailed: '表单模板加载失败', + currentNodeCannotBeSelected: '当前组件节点不可选择', + + widgetSetting: '组件设置', + formSetting: '表单设置', + + prompt: '提示', + confirm: '确定', + cancel: '取消', + import: '导入', + importJsonHint: '导入的JSON内容须符合下述格式,以保证顺利导入.', + invalidOptionsData: '无效的选项数据:', + lastPaneCannotBeDeleted: '仅剩一个选项卡页不可删除.', + duplicateName: '组件名称已存在: ', + nameRequired: '组件名称不可为空', + + numberValidator: '数字', + letterValidator: '字母', + letterAndNumberValidator: '数字字母', + mobilePhoneValidator: '手机号码', + emailValidator: '邮箱', + urlValidator: '网址', + noChineseValidator: '非中文字符', + chineseValidator: '仅中文字符', + + rowspanNotConsistentForMergeEntireRow: '存在行高不一致的单元格, 无法合并整行.', + colspanNotConsistentForMergeEntireColumn: '存在列宽不一致的单元格, 无法合并整列.', + rowspanNotConsistentForDeleteEntireRow: '存在行高不一致的单元格, 不可删除整行.', + colspanNotConsistentForDeleteEntireColumn: '存在列宽不一致的单元格, 不可删除整列.', + lastColCannotBeDeleted: '最后一列不可删除.', + lastRowCannotBeDeleted: '最后一行不可删除.', + }, + + toolbar: { + undoHint: '撤销', + redoHint: '重做', + pcLayout: 'PC', + padLayout: 'Pad', + mobileLayout: 'H5', + nodeTreeHint: '组件层次结构树', + nodeTreeTitle: '组件层次结构树', + clear: '清空', + preview: '预览', + importJson: '导入JSON', + exportJson: '导出JSON', + exportCode: '导出代码', + generateCode: '生成代码', + generateSFC: '生成SFC', + }, + + setting: { + basicSetting: '基本属性', + attributeSetting: '属性设置', + commonSetting: '常见属性', + advancedSetting: '高级属性', + eventSetting: '事件属性', + uniqueName: '唯一名称', + editNameHelp: '修改名称后需按回车确认', + label: '标签', + displayType: '显示类型', + defaultValue: '默认值', + placeholder: '占位内容', + startPlaceholder: '起始占位内容', + endPlaceholder: '截止占位内容', + widgetColumnWidth: '组件列宽', + widgetSize: '组件大小', + fontSize: '字体大小', + textAlign: '文字对齐', + showStops: '显示间断点', + displayStyle: '显示样式', + inlineLayout: '行内', + blockLayout: '块', + buttonStyle: '显示为按钮', + border: '带有边框', + labelWidth: '标签宽度', + rows: '行数', + labelHidden: '隐藏字段标签', + required: '必填字段', + validation: '字段校验', + requiredHint: '必填校验提示', + validationHelp: '支持输入正则表达式', + validationHint: '校验失败提示', + readonly: '只读', + disabled: '禁用', + hidden: '隐藏', + textContent: '静态文字', + preWrap: '自动换行', + htmlContent: 'HTML', + clearable: '可清除', + editable: '可输入', + format: '显示格式', + valueFormat: '绑定值格式', + showPassword: '可显示密码', + filterable: '可搜索选项', + allowCreate: '允许创建选项', + remote: '可远程搜索', + automaticDropdown: '自动弹出选项', + multiple: '选项可多选', + multipleLimit: '多选数量限制', + checkStrictly: '任意级节点可选', + showAllLevels: '显示完整路径', + contentPosition: '文字位置', + plain: '朴素按钮', + round: '圆角按钮', + circle: '圆形按钮', + icon: '图标', + optionsSetting: '选项设置', + addOption: '增加选项', + importOptions: '导入选项', + resetDefault: '重设选中项', + uploadSetting: '上传参数设置', + uploadURL: '上传地址', + uploadTip: '上传提示内容', + withCredentials: '发送cookie凭证', + multipleSelect: '文件可多选', + showFileList: '显示文件列表', + limit: '最大上传数量', + fileMaxSize: '文件大小限制(MB)', + fileTypes: '上传文件类型', + fileTypesHelp: '支持添加其他文件类型', + headers: '上传请求头', + + cellWidth: '宽度', + cellHeight: '高度', + wordBreak: '文字自动换行', + gridColHeight: '栅格列统一高度(px)', + gutter: '栅格间隔(px)', + columnSetting: '栅格属性设置', + colsOfGrid: '当前栅格列:', + colSpanTitle: '栅格宽度', + colOffsetTitle: '左侧间隔格数', + colPushTitle: '右移栅格数', + colPullTitle: '左移栅格数', + addColumn: '增加栅格', + responsive: '响应式布局', + + tabPaneSetting: '选项卡设置', + addTabPane: '增加选项卡页', + paneActive: '激活', + + customLabelIcon: '定制字段标签', + labelIconClass: '标签Icon样式', + labelIconPosition: '标签Icon位置', + labelTooltip: '标签文字提示', + minValue: '最小值', + maxValue: '最大值', + precision: '精度', + step: '增减步长', + controlsPosition: '控制按钮位置', + minLength: '最小长度', + maxLength: '最大长度', + showWordLimit: '显示字数统计', + prefixIcon: '头部Icon', + suffixIcon: '尾部Icon', + inputButton: '输入框按钮设置', + appendButton: '添加后置按钮', + appendButtonDisabled: '后置按钮禁用', + appendButtonIcon: '后置按钮Icon', + buttonIcon: '按钮Icon', + switchWidth: '开关宽度(像素)', + activeText: '开启时文字描述', + inactiveText: '关闭时文字描述', + activeColor: '开启时背景色', + inactiveColor: '关闭时背景色', + maxStars: '最大评分值', + lowThreshold: '低分界限值', + highThreshold: '高分界限值', + allowHalf: '允许半选', + showText: '显示辅助文字', + showScore: '显示当前分数', + range: '是否为范围选择', + vertical: '是否竖向显示', + showBlankRow: '默认显示新行', + showRowNumber: '显示行号', + + insertColumnToLeft: '插入左侧列', + insertColumnToRight: '插入右侧列', + insertRowAbove: '插入上方行', + insertRowBelow: '插入下方行', + mergeLeftColumn: '合并左侧单元格', + mergeRightColumn: '合并右侧单元格', + mergeEntireRow: '合并整行', + mergeRowAbove: '合并上方单元格', + mergeRowBelow: '合并下方单元格', + mergeEntireColumn: '合并整列', + undoMergeCol: '撤销列合并', + undoMergeRow: '撤销行合并', + deleteEntireCol: '删除整列', + deleteEntireRow: '删除整行', + + widgetName: '组件唯一名称', + formSize: '全局组件大小', + labelPosition: '字段标签位置', + topPosition: '顶部', + leftPosition: '左边', + labelAlign: '标签对齐', + leftAlign: '居左', + centerAlign: '居中', + rightAlign: '居右', + formCss: '表单全局CSS', + addCss: '编写CSS', + customClass: '自定义CSS样式', + globalFunctions: '表单全局函数', + addEventHandler: '编写代码', + editWidgetEventHandler: '组件事件处理', + editFormEventHandler: '表单事件处理', + formSFCSetting: '生成SFC设置', + formModelName: '数据对象名称', + formRefName: '引用名称', + formRulesName: '验证规则名称', + syntaxCheckWarning: 'JS代码存在语法错误,请仔细检查!', + + //data-table + tableWidth: '宽度(px/%)', + tableHeight: '高度(px/%)', + showCheckBox: '是否显示复选框列', + showIndex: '是否显示行号', + showPagination: '是否显示分页', + smallPagination: '小型分页', + tableColEdit: '表格列编辑', + tableDataEdit: '表格数据编辑', + showSummary: '是否合计', + stripe: '是否斑马线', + rowSpacing: '行距(px)', + editAction: '编辑...', + columnName: '字段名称', + columnLabel: '显示名称', + columnWidth: '列宽(px/%)', + visibleColumn: '是否显示', + sortableColumn: '是否排序', + fixedColumn: '是否固定', + alignTypeOfColumn: '对齐方式', + formatOfColumn: '格式化', + actionColumn: '操作', + addTableColumn: '增加列', + deleteTableColumn: '删除列', + OnlyOneColumnCannotBeDeleted: '表格只有一列时不可删除.', + } + + } +} diff --git a/src/lang/zh-CN_extension.js b/src/lang/zh-CN_extension.js new file mode 100644 index 0000000..907e38e --- /dev/null +++ b/src/lang/zh-CN_extension.js @@ -0,0 +1,26 @@ +export default { + extension: { + widgetLabel: { + card: '卡片', + alert: '提示', + }, + + setting: { + cardFolded: '是否收起', + cardShowFold: '显示折叠按钮', + cardWidth: '卡片宽度', + cardShadow: '显示阴影', + + alertTitle: '标题', + alertType: '类型', + description: '辅助性文字', + closable: '是否可关闭', + closeText: '关闭按钮文字', + center: '文字居中', + showIcon: '显示图标', + effect: '显示效果', + + }, + + } +} diff --git a/src/lang/zh-CN_render.js b/src/lang/zh-CN_render.js new file mode 100644 index 0000000..1dd74c4 --- /dev/null +++ b/src/lang/zh-CN_render.js @@ -0,0 +1,38 @@ +export default { + render: { + + hint: { + prompt: '提示', + confirm: '确定', + cancel: '取消', + + selectPlaceholder: '请选择', + timePlaceholder: '选择时间', + startTimePlaceholder: '起始时间', + endTimePlaceholder: '截止时间', + datePlaceholder: '选择日期', + startDatePlaceholder: '起始日期', + endDatePlaceholder: '截止日期', + blankCellContent: '--', + + uploadError: '上传错误: ', + uploadExceed: '最大上传数量(${uploadLimit})已超出.', + unsupportedFileType: '不支持格式: ', + fileSizeExceed: '文件大小已超出: ', + refNotFound: '组件未找到: ', + fieldRequired: '字段值不可为空', + invalidNumber: '数据格式错误', + selectFile: ' 选择文件', + downloadFile: '下载', + removeFile: '移除', + validationFailed: '表单数据校验失败', + + subFormAction: '操作', + subFormAddAction: '新增', + subFormAddActionHint: '新增行', + insertSubFormRow: '插入行', + deleteSubFormRow: '删除行', + nonSubFormType: '组件类型不是子表单', + } + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..6b28b0b --- /dev/null +++ b/src/main.js @@ -0,0 +1,29 @@ +import 'babel-polyfill' +import './utils/debug-console' +import Vue from 'vue' +import axios from "axios"; +import App from './App.vue' +import ElementUI from 'element-ui' +import './utils/directive' +import './icons' + +import 'element-ui/lib/theme-chalk/index.css' +import '@/styles/index.scss' +import '@/iconfont/iconfont.css' + +import {loadExtension} from '@/extension/extension-loader' + +loadExtension() + +Vue.use(ElementUI, { size: 'small' }) + +if (typeof window !== 'undefined') { + window.axios = axios +} + +Vue.config.productionTip = false + +new Vue({ + el: "#app", + render: h => h(App), +}) diff --git a/src/styles/global.scss b/src/styles/global.scss new file mode 100644 index 0000000..76f2814 --- /dev/null +++ b/src/styles/global.scss @@ -0,0 +1,108 @@ +/* 全局css变量 */ +$--color-primary: #409EFF; + +.primary-color { + color: $--color-primary; +} + +.background-opacity { + background: rgba(64, 158, 255, 0.6); +} + +.form-widget-list { + + .ghost{ + content: ''; + font-size: 0; + height: 3px; + box-sizing: border-box; + background: $--color-primary; + border: 2px solid $--color-primary; + outline-width: 0; + padding: 0; + overflow: hidden; + } +} + +.el-form-item--medium { + .el-radio { + line-height: 36px !important; + } + + .el-rate{ + margin-top: 8px; + } +} + +.el-form-item--small { + .el-radio { + line-height: 32px !important; + } + + .el-rate{ + margin-top: 6px; + } +} + +.el-form-item--mini { + .el-radio { + line-height: 28px !important; + } + + .el-rate{ + margin-top: 4px; + } +} + +.el-card { + margin-top: 3px; + margin-bottom: 3px; +} + +input[type="password"]::-ms-reveal { /* 隐藏IE/Edge原生的密码查看按钮 */ + display: none; +} + +/* 滚动条样式 begin */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + width: 8px; + background: rgba(#101F1C, 0.1); + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em; +} + +::-webkit-scrollbar-thumb { + background-color: rgba(#101F1C, 0.35); + background-clip: padding-box; + min-height: 28px; + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em; +} + +::-webkit-scrollbar-thumb:hover { + background-color: rgba(#101F1C, 0.85); +} + +* {//Firefox浏览器滚动条样式 + scrollbar-color: #e5e5e5 #f7f7f9; //滚动条轨道颜色、滚动条滑块的颜色 + scrollbar-width: thin; //thin模式下滚动条两端的三角按钮会消失 +} + + +/* +body {//IE浏览器滚动条样式 + scrollbar-shadow-color: #e5e5e5; + scrollbar-face-color: #e5e5e5; + scrollbar-base-color: #ffffff; + scrollbar-arrow-color: #444040; +} +*/ + +/* 滚动条样式 end */ diff --git a/src/styles/index.scss b/src/styles/index.scss new file mode 100644 index 0000000..ebb3bc7 --- /dev/null +++ b/src/styles/index.scss @@ -0,0 +1,15 @@ + +html { + height: 100%; + box-sizing: border-box; +} + +body { + height: 100%; + margin: 0; /* */ + background-color: #ffffff; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; +} diff --git a/src/utils/beautifierLoader.js b/src/utils/beautifierLoader.js new file mode 100644 index 0000000..3736b8f --- /dev/null +++ b/src/utils/beautifierLoader.js @@ -0,0 +1,77 @@ +import {loadRemoteScript} from "@/utils/util"; +import {BEAUTIFIER_PATH} from "@/utils/config"; + +let beautifierObj + +export const beautifierOpts = { + html: { + indent_size: '2', + indent_char: ' ', + max_preserve_newlines: '-1', + preserve_newlines: false, + keep_array_indentation: false, + break_chained_methods: false, + indent_scripts: 'separate', + brace_style: 'end-expand', + space_before_conditional: true, + unescape_strings: false, + jslint_happy: false, + end_with_newline: true, + wrap_line_length: '110', + indent_inner_html: true, + comma_first: false, + e4x: true, + indent_empty_lines: true + }, + js: { + indent_size: '2', + indent_char: ' ', + max_preserve_newlines: '-1', + preserve_newlines: false, + keep_array_indentation: false, + break_chained_methods: false, + indent_scripts: 'normal', + brace_style: 'end-expand', + space_before_conditional: true, + unescape_strings: false, + jslint_happy: true, + end_with_newline: true, + wrap_line_length: '110', + indent_inner_html: true, + comma_first: false, + e4x: true, + indent_empty_lines: true + }, + css: { + indent_size: '2', + indent_char: ' ', + max_preserve_newlines: '-1', + preserve_newlines: false, + keep_array_indentation: false, + break_chained_methods: false, + indent_scripts: 'normal', + brace_style: 'end-expand', + space_before_conditional: true, + unescape_strings: false, + jslint_happy: true, + end_with_newline: true, + wrap_line_length: '110', + indent_inner_html: true, + comma_first: false, + e4x: true, + indent_empty_lines: true + } +} + +export default function loadBeautifier(callback) { + if (beautifierObj) { + callback(beautifierObj) + return + } + + loadRemoteScript(BEAUTIFIER_PATH, () => { + // eslint-disable-next-line no-undef + beautifierObj = beautifier //beautifier为全局对象 + callback(beautifierObj) + }) +} diff --git a/src/utils/code-generator.js b/src/utils/code-generator.js new file mode 100644 index 0000000..221743a --- /dev/null +++ b/src/utils/code-generator.js @@ -0,0 +1,91 @@ +export const generateCode = function(formJson, codeType= 'vue') { + let formJsonStr = JSON.stringify(formJson) + + if (codeType === 'html') { + return ` + + + + + VForm Demo + + + + + + +
+ + + Submit +
+ + + + + + + +` + + } else { + return ` +` + + } +} diff --git a/src/utils/config.js b/src/utils/config.js new file mode 100644 index 0000000..373f3f0 --- /dev/null +++ b/src/utils/config.js @@ -0,0 +1,9 @@ +export const VARIANT_FORM_VERSION = '2.2.9' + +//export const MOCK_CASE_URL = 'https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/' +export const MOCK_CASE_URL = 'https://ks3-cn-beijing.ksyuncs.com/vform-static/vcase/' + +//export const ACE_BASE_PATH = 'public/lib/ace/src-min-noconflict' +export const ACE_BASE_PATH = 'https://ks3-cn-beijing.ksyun.com/vform2021/ace-mini' + +export const BEAUTIFIER_PATH= 'https://ks3-cn-beijing.ksyun.com/vform2021/js-beautify/1.14.0/beautifier.min.js' diff --git a/src/utils/debug-console.js b/src/utils/debug-console.js new file mode 100644 index 0000000..f4e6063 --- /dev/null +++ b/src/utils/debug-console.js @@ -0,0 +1,7 @@ +console.log = (function(logFunc) { + return function () { + if (process.env.NODE_ENV === 'development') { + logFunc.call(console, ...arguments); + } + } +})(console.log) diff --git a/src/utils/directive.js b/src/utils/directive.js new file mode 100644 index 0000000..4f3a671 --- /dev/null +++ b/src/utils/directive.js @@ -0,0 +1,74 @@ +import Vue from 'vue' + +// v-dialogDrag: 弹窗拖拽 +Vue.directive('dialogDrag', { + bind(el, binding, vnode, oldVnode) { + const dialogHeaderEl = el.querySelector('.el-dialog__header') + const dragDom = el.querySelector('.el-dialog') + dialogHeaderEl.style.cursor = 'move' + + // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); + const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null) + + dialogHeaderEl.onmousedown = (e) => { + // 鼠标按下,计算当前元素距离可视区的距离 + const disX = e.clientX - dialogHeaderEl.offsetLeft + const disY = e.clientY - dialogHeaderEl.offsetTop + + // 获取到的值带px 正则匹配替换 + let styL, styT + + // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px + if (sty.left.includes('%')) { + styL = +document.body.clientWidth * (+sty.left.replace(/%/g, '') / 100) + styT = +document.body.clientHeight * (+sty.top.replace(/%/g, '') / 100) + } else { + styL = +sty.left.replace(/px/g, '') + styT = +sty.top.replace(/px/g, '') + } + + document.onmousemove = function(e) { + // 通过事件委托,计算移动的距离 + const l = e.clientX - disX + const t = e.clientY - disY + + // 移动当前元素 + dragDom.style.left = `${l + styL}px` + dragDom.style.top = `${t + styT}px` + + // 将此时的位置传出去 + // binding.value({x:e.pageX,y:e.pageY}) + } + + document.onmouseup = function(e) { + document.onmousemove = null + document.onmouseup = null + } + } + } +}) + +// v-dialogDragWidth: 弹窗宽度拖大 拖小 +Vue.directive('dialogDragWidth', { + bind(el, binding, vnode, oldVnode) { + const dragDom = binding.value.$el.querySelector('.el-dialog') + + el.onmousedown = (e) => { + // 鼠标按下,计算当前元素距离可视区的距离 + const disX = e.clientX - el.offsetLeft + + document.onmousemove = function(e) { + e.preventDefault() // 移动时禁用默认事件 + + // 通过事件委托,计算移动的距离 + const l = e.clientX - disX + dragDom.style.width = `${l}px` + } + + document.onmouseup = function(e) { + document.onmousemove = null + document.onmouseup = null + } + } + } +}) diff --git a/src/utils/emitter.js b/src/utils/emitter.js new file mode 100644 index 0000000..5547e80 --- /dev/null +++ b/src/utils/emitter.js @@ -0,0 +1,34 @@ +function broadcast(componentName, eventName, params) { + this.$children.forEach(child => { + var name = child.$options.componentName; + + if (name === componentName) { + child.$emit.apply(child, [eventName].concat(params)); + broadcast.apply(child, [componentName, eventName].concat([params])); //继续遍历子节点!! + } else { + broadcast.apply(child, [componentName, eventName].concat([params])); + } + }); +} +export default { + methods: { + dispatch(componentName, eventName, params) { + var parent = this.$parent || this.$root; + var name = parent.$options.componentName; + + while (parent && (!name || name !== componentName)) { + parent = parent.$parent; + + if (parent) { + name = parent.$options.componentName; + } + } + if (parent) { + parent.$emit.apply(parent, [eventName].concat(params)); + } + }, + broadcast(componentName, eventName, params) { + broadcast.call(this, componentName, eventName, params); + } + } +}; diff --git a/src/utils/format.js b/src/utils/format.js new file mode 100644 index 0000000..9698368 --- /dev/null +++ b/src/utils/format.js @@ -0,0 +1,214 @@ + +export function formatDate1(date) { + if (new Date(Date.parse(date.replace(/-/g, "/"))) === "Invalid Date") { + return date; + } + date = new Date(Date.parse(date.replace(/-/g, "/"))); //转换成Date + let y = date.getFullYear(); + let m = date.getMonth() + 1; + m = m < 10 ? '0' + m : m; + let d = date.getDate(); + d = d < 10 ? ('0' + d) : d; + return y + '-' + m + '-' + d; +} + +export function formatDate2(date) { + if (new Date(Date.parse(date.replace(/-/g, "/"))) === "Invalid Date") { + return date; + } + date = new Date(Date.parse(date.replace(/-/g, "/"))); //转换成Date + let y = date.getFullYear(); + let m = date.getMonth() + 1; + m = m < 10 ? '0' + m : m; + let d = date.getDate(); + d = d < 10 ? ('0' + d) : d; + return y + '/' + m + '/' + d; +} + +export function formatDate3(date) { + if (new Date(Date.parse(date.replace(/-/g, "/"))) === "Invalid Date") { + return date; + } + date = new Date(Date.parse(date.replace(/-/g, "/"))); //转换成Date + let y = date.getFullYear(); + let m = date.getMonth() + 1; + m = m < 10 ? '0' + m : m; + let d = date.getDate(); + d = d < 10 ? ('0' + d) : d; + return y + '年' + m + '月' + d +'日'; +} + +export function formatDate4(date) { + if (new Date(Date.parse(date.replace(/-/g, "/"))) === "Invalid Date"){ + return date; + } + date = new Date(Date.parse(date.replace(/-/g, "/"))); //转换成Date + return date.toLocaleString() +} + +export function formatDate5(date) { + if (new Date(Date.parse(date.replace(/-/g, "/"))) === "Invalid Date") { + return date; + } + date = new Date(Date.parse(date.replace(/-/g, "/"))); //转换成Data(); + return date.toLocaleString('chinese', { hour12: false }) +} + +// ###,###,###,##0.###### +export function formatNumber1(v) { + if (typeof(v) != "number") { + return v; + } + + let length = v.toString().split(".")[1].length; + switch(length){ + case 0: + v = v.toFixed(0) + break; + case 1: + v = v.toFixed(1) + break; + case 2: + v = v.toFixed(2) + break; + case 3: + v = v.toFixed(3) + break; + case 4: + v = v.toFixed(4) + break; + case 5: + v = v.toFixed(5) + break; + default: + v = v.toFixed(6) + } + let res = v.toString().replace(/\d+/, function(n){ // 先提取整数部分 + return n.replace(/(\d)(?=(\d{3})+$)/g,function($1){ + return $1+","; + }); + }) + return res; +} + +//###,###,###,##0.00#### +export function formatNumber2(v) { + if (typeof(v) != "number") { + return v; + } + + let length = v.toString().split(".")[1].length; + switch(length){ + case 0: + case 1: + case 2: + v = v.toFixed(2) + break; + case 3: + v = v.toFixed(3) + break; + case 4: + v = v.toFixed(4) + break; + case 5: + v = v.toFixed(5) + break; + default: + v = v.toFixed(6) + } + + let res = v.toString().replace(/\d+/, function(n){ // 先提取整数部分 + return n.replace(/(\d)(?=(\d{3})+$)/g,function($1){ + return $1+","; + }); + }) + return res; +} + +// ###,###,###,##0.000000 +export function formatNumber3(v) { + if (typeof(v) != "number") { + return v; + } + + v = v.toFixed(6) + let res = v.toString().replace(/\d+/, function(n){ // 先提取整数部分 + return n.replace(/(\d)(?=(\d{3})+$)/g,function($1){ + return $1+","; + }); + }) + return res; +} +// ###,###,###,##0.000 +export function formatNumber4(v) { + if (typeof(v) != "number") { + return v; + } + + v = v.toFixed(3) + let res = v.toString().replace(/\d+/, function(n){ // 先提取整数部分 + return n.replace(/(\d)(?=(\d{3})+$)/g,function($1){ + return $1+","; + }); + }) + return res; +} + +// ###,###,###,##0.00 +export function formatNumber5(v) { + if (typeof(v) != "number") { + return v; + } + + v = v.toFixed(2) + let res = v.toString().replace(/\d+/, function(n){ // 先提取整数部分 + return n.replace(/(\d)(?=(\d{3})+$)/g,function($1){ + return $1+","; + }); + }) + return res; +} + +// ###,###,###,##0 +export function formatNumber6(v) { + if (typeof(v) != "number") { + return v; + } + + v = v.toFixed(0) + let res = v.toString().replace(/\d+/, function(n){ // 先提取整数部分 + return n.replace(/(\d)(?=(\d{3})+$)/g,function($1){ + return $1+","; + }); + }) + return res; +} + +// ###,##0.00##% +export function formatNumber7(v) { + if (typeof(v) != "number") { + return v; + } + + let length = v.toString().split(".")[1].length; + v = v*100 + switch(length){ + case 0: + case 1: + case 2: + v = v.toFixed(2) + break; + case 3: + v = v.toFixed(3) + break; + default: + v = v.toFixed(4) + } + + let res = v.toString().replace(/\d+/, function(n){ // 先提取整数部分 + return n.replace(/(\d)(?=(\d{3})+$)/g,function($1){ + return $1+","; + }); + }) + return res+'%'; +} diff --git a/src/utils/i18n.js b/src/utils/i18n.js new file mode 100644 index 0000000..cf890be --- /dev/null +++ b/src/utils/i18n.js @@ -0,0 +1,95 @@ +import Vue from 'vue' +import si18n from './smart-vue-i18n/index' + +import enLocaleElement from "element-ui/lib/locale/lang/en"; +import zhLocaleElement from "element-ui/lib/locale/lang/zh-CN"; +import locale from "element-ui/lib/locale" + +import enLocale from "@/lang/en-US"; +import zhLocale from "@/lang/zh-CN"; +import enLocale_render from "@/lang/en-US_render"; +import zhLocale_render from "@/lang/zh-CN_render"; +import enLocale_extension from "@/lang/en-US_extension"; +import zhLocale_extension from "@/lang/zh-CN_extension"; + +const langResources = { + 'en-US': { + something: { + //... + }, + ...enLocaleElement, + ...enLocale, + ...enLocale_render, + ...enLocale_extension + }, + + 'zh-CN': { + something: { + //... + }, + ...zhLocaleElement, + ...zhLocale, + ...zhLocale_render, + ...zhLocale_extension + } +} + +// ********************* 下述代码参考element-ui/lib/locale/format.js begin *****************// + +const RE_NARGS = /(%|)\{([0-9a-zA-Z_]+)\}/g; +function hasOwn(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); +} + +const elLocalFormatter = function template(string, args) { + return string.replace(RE_NARGS, (match, prefix, i, index) => { + let result; + + if (string[index - 1] === '{' && + string[index + match.length] === '}') { + return i; + } else { + result = hasOwn(args, i) ? args[i] : null; + if (result === null || result === undefined) { + return ''; + } + + return result; + } + }) +} + +// ********************* 下述代码参考element-ui/lib/locale/format.js end ******************// + +Vue.use(si18n, { + lang: localStorage.getItem('v_form_locale') || 'zh-CN', + messages: langResources +}) + +locale.i18n((key, value) => { + let result = Vue.prototype.$st(key) + return elLocalFormatter(result, value) +}) + +export const changeLocale = function(langName) { + Vue.prototype.$si18n.setLang(langName) + localStorage.setItem('v_form_locale', langName) +} + +export const translate = function(key) { + return Vue.prototype.$st(key) +} + +export default { + methods: { + i18nt(key) { + return this.$st(key) + }, + + /* 如果key1不存在,则查找key2 */ + i18n2t(key1, key2) { + return this.$st2(key1, key2) + }, + + } +} diff --git a/src/utils/sfc-generator.js b/src/utils/sfc-generator.js new file mode 100644 index 0000000..314d055 --- /dev/null +++ b/src/utils/sfc-generator.js @@ -0,0 +1,583 @@ +import {isNotNull} from "@/utils/util"; +import {genVue2JS} from "@/utils/vue2js-generator"; +import {beautifierOpts} from "@/utils/beautifierLoader"; +import {genVue3JS} from "@/utils/vue3js-generator"; + +export function buildClassAttr(ctn, defaultClass) { + const cop = ctn.options + let gridClassArray = [] + !!defaultClass && gridClassArray.push(defaultClass) + !!cop.customClass && (cop.customClass.length > 0) && gridClassArray.push(cop.customClass.join(' ')) + return gridClassArray.length > 0 ? `class="${gridClassArray.join(' ')}"` : '' +} + +const containerTemplates = { //容器组件属性 + 'grid': (ctn, formConfig) => { + const gridClassAttr = buildClassAttr(ctn) + const gridTemplate = +` +${ctn.cols.map(col => { + const colOpt = col.options + const spanAttr = !!colOpt.responsive ? '' : `:span="${colOpt.span}"` + const mdAttr = !colOpt.responsive ? '' : `:md="${colOpt.md}"` + const smAttr = !colOpt.responsive ? '' : `:sm="${colOpt.sm}"` + const xsAttr = !colOpt.responsive ? '' : `:xs="${colOpt.xs}"` + const offsetAttr = !!colOpt.offset ? `:offset="${colOpt.offset}"` : '' + const pushAttr = !!colOpt.push ? `:push="${colOpt.push}"` : '' + const pullAttr = !!colOpt.pull ? `:pull="${colOpt.pull}"` : '' + const colClassAttr = buildClassAttr(col, 'grid-cell') + return ` + ${col.widgetList.map(cw => { + if (cw.category === 'container') { + return buildContainerWidget(cw, formConfig) + } else { + return buildFieldWidget(cw, formConfig) + } + }).join('') + } + ` + }).join('') +} +` + + return gridTemplate + }, + + 'table': (ctn, formConfig) => { + const tableClassAttr = buildClassAttr(ctn, 'table-layout') + const tableTemplate = +`
+ + ${ctn.rows.map(tr => { + return `${ + tr.cols.filter(td => !td.merged).map(td => { + const tdOpt = td.options + const tdClassAttr = buildClassAttr(td, 'table-cell') + const colspanAttr = (!isNaN(tdOpt.colspan) && (tdOpt.colspan !== 1)) ? `colspan="${tdOpt.colspan}"` : '' + const rowspanAttr = (!isNaN(tdOpt.rowspan) && (tdOpt.rowspan !== 1)) ? `rowspan="${tdOpt.rowspan}"` : '' + + let tdStyleArray = [] + !!tdOpt.cellWidth && tdStyleArray.push('width: ' + tdOpt.cellWidth + ' !important') + !!tdOpt.cellHeight && tdStyleArray.push('height: ' + tdOpt.cellHeight + ' !important') + let tdStyleAttr = (tdStyleArray.length > 0) ? `style="${tdStyleArray.join(';')}"` : '' + + return `` + }).join('') + }` + }).join('') + } +
${td.widgetList.map(tw => { + if (tw.category === 'container') { + return buildContainerWidget(tw, formConfig) + } else { + return buildFieldWidget(tw, formConfig) + } + }).join('') + } +
+
` + return tableTemplate + }, + + 'tab': (ctn, formConfig) => { + const tabClassAttr = buildClassAttr(ctn) + const vModel = ctn.tabs && (ctn.tabs.length > 0) ? `v-model="${ctn.options.name}ActiveTab"` : '' + const tabTemplate = +`
+ + ${ctn.tabs.map(tab => { + const tabOpt = tab.options + const disabledAttr = (tabOpt.disabled === true) ? `disabled` : '' + return ` + ${tab.widgetList.map(tw => { + if (tw.category === 'container') { + return buildContainerWidget(tw, formConfig) + } else { + return buildFieldWidget(tw, formConfig) + } + }).join('') + }` + }).join('')} + +
` + + return tabTemplate + }, + + 'sub-form': (ctn, formConfig) => { + //TODO: + }, + +} + +export function buildContainerWidget(widget, formConfig) { + return containerTemplates[widget.type] ? containerTemplates[widget.type](widget, formConfig) : null +} + +function getElAttrs(widget, formConfig) { //获取El组件属性 + let wop = widget.options + return { + vModel: `v-model="${formConfig.modelName}.${wop.name}"`, + readonly: wop.readonly ? `readonly="true"` : '', + disabled: wop.disabled ? `:disabled="true"` : '', + size: !!wop.size ? `size="${wop.size}"` : '', + type: !!wop.type ? `type="${wop.type === 'number' ? 'text' : wop.type}"` : '', + showPassword: !!wop.showPassword ? `:show-password="${wop.showPassword}"` : '', + placeholder: !!wop.placeholder ? `placeholder="${wop.placeholder}"` : '', + rows: (isNotNull(wop.rows) && !isNaN(wop.rows)) ? `rows="${wop.rows}"` : '', + clearable: !!wop.clearable ? 'clearable' : '', + minlength: (isNotNull(wop.minLength) && !isNaN(wop.minLength)) ? `:minlength="${wop.minLength}"` : '', + maxlength: (isNotNull(wop.maxLength) && !isNaN(wop.maxLength)) ? `:maxlength="${wop.maxLength}"` : '', + showWordLimit: !!wop.showWordLimit ? `:show-word-limit="true"`: '', + prefixIcon: !!wop.prefixIcon ? `prefix-icon="${wop.prefixIcon}"` : '', + suffixIcon: !!wop.suffixIcon ? `suffix-icon="${wop.suffixIcon}"` : '', + controlsPosition: wop.controlsPosition === 'right' ? `controls-position="right"` : '', + min: (isNotNull(wop.min) && !isNaN(wop.min)) ? `:min="${wop.min}"` : '', + max: (isNotNull(wop.max) && !isNaN(wop.max)) ? `:max="${wop.max}"` : '', + precision: (isNotNull(wop.precision) && !isNaN(wop.precision)) ? `:precision="${wop.precision}"` : '', + step: (isNotNull(wop.step) && !isNaN(wop.step)) ? `:step="${wop.step}"` : '', + filterable: !!wop.filterable ? `filterable` : '', + allowCreate: !!wop.allowCreate ? `allow-create` : '', + defaultFirstOption: (!!wop.filterable && !!wop.allowCreate) ? `default-first-option` : '', + multiple: !!wop.multiple ? `multiple` : '', + multipleLimit: (!isNaN(wop.multipleLimit) && (wop.multipleLimit > 0)) ? `:multiple-limit="${wop.multipleLimit}"` : '', + automaticDropdown: !!wop.automaticDropdown ? `automatic-dropdown` : '', + remote: !!wop.remote ? `remote` : '', + format: !!wop.format ? `format="${wop.format}"` : '', + valueFormat: !!wop.valueFormat ? `value-format="${wop.valueFormat}"` : '', + editable: !!wop.editable ? `:editable="${wop.editable}"` : '', + startPlaceholder: !!wop.startPlaceholder ? `start-placeholder="${wop.startPlaceholder}"` : '', + endPlaceholder: !!wop.endPlaceholder ? `end-placeholder="${wop.endPlaceholder}"` : '', + + activeText: !!wop.activeText ? `active-text="${wop.activeText}"` : '', + inactiveText: !!wop.inactiveText ? `inactive-text="${wop.inactiveText}"` : '', + activeColor: !!wop.activeColor ? `active-color="${wop.activeColor}"` : '', + inactiveColor: !!wop.inactiveColor ? `inactive-color="${wop.inactiveColor}"` : '', + switchWidth: (!isNaN(wop.switchWidth) && (wop.switchWidth !== 40)) ? `:width="${wop.switchWidth}"` : '', + + rateMax: (!isNaN(wop.max) && (wop.max !== 5)) ? `:max="${wop.max}"` : '', + lowThreshold: (!isNaN(wop.lowThreshold) && (wop.lowThreshold !== 2)) ? `:low-threshold="${wop.lowThreshold}"` : '', + highThreshold: (!isNaN(wop.highThreshold) && (wop.highThreshold !== 4)) ? `:high-threshold="${wop.highThreshold}"` : '', + allowHalf: !!wop.allowHalf ? `allow-half` : '', + showText: !!wop.showText ? `show-text` : '', + showScore: !!wop.showScore ? `show-score` : '', + + sliderMin: (!isNaN(wop.min) && (wop.min !== 0)) ? `:min="${wop.min}"` : '', + sliderMax: (!isNaN(wop.max) && (wop.max !== 100)) ? `:max="${wop.max}"` : '', + sliderStep: (!isNaN(wop.step) && (wop.step !== 1)) ? `:step="${wop.step}"` : '', + sliderRange: !!wop.range ? `range` : '', + sliderVertical: !!wop.vertical ? `vertical` : '', + + uploadAction: !!wop.uploadURL ? `action="${wop.uploadURL}"` : '', + withCredentials: !!wop.withCredentials ? `with-credentials` : '', + multipleSelect: !!wop.multipleSelect ? `multiple` : '', + showFileList: !!wop.showFileList ? `show-file-list` : '', + limit: !isNaN(wop.limit) ? `:limit="${wop.limit}"` : '', + uploadTipSlotChild: !!wop.uploadTip ? `` : '', + pictureUploadIconChild: ``, + fileUploadIconChild: ``, + + buttonType: !!wop.type ? `type="${wop.type}"` : '', + buttonPlain: !!wop.plain ? `plain` : '', + buttonRound: !!wop.round ? `round` : '', + buttonCircle: !!wop.circle ? `circle` : '', + buttonIcon: !!wop.icon ? `icon="${wop.icon}"` : '', + + contentPosition: (!!wop.contentPosition && (wop.contentPosition !== 'center')) ? `content-position="${wop.contentPosition}"` : '', + + appendButtonChild: !!wop.appendButton ? `` : '', + } +} + +function buildRadioChildren(widget, formConfig) { + let wop = widget.options + const childTag = !!wop.buttonStyle ? 'el-radio-button' : 'el-radio' + const borderAttr = !!wop.border ? `border` : '' + const styleAttr = `style="{display: ${wop.displayStyle}}"` + return `<${childTag} v-for="(item, index) in ${wop.name}Options" :key="index" :label="item.value" + :disabled="item.disabled" ${borderAttr} ${styleAttr}>{{item.label}}` +} + +function buildCheckboxChildren(widget, formConfig) { + let wop = widget.options + const childTag = !!wop.buttonStyle ? 'el-checkbox-button' : 'el-checkbox' + const borderAttr = !!wop.border ? `border` : '' + const styleAttr = `style="{display: ${wop.displayStyle}}"` + return `<${childTag} v-for="(item, index) in ${wop.name}Options" :key="index" :label="item.value" + :disabled="item.disabled" ${borderAttr} ${styleAttr}>{{item.label}}` +} + +function buildSelectChildren(widget, formConfig) { + let wop = widget.options + const childTag = 'el-option' + return `<${childTag} v-for="(item, index) in ${wop.name}Options" :key="index" :label="item.label" + :value="item.value" :disabled="item.disabled">` +} + +const elTemplates = { //字段组件属性 + 'input': (widget, formConfig) => { + const {vModel, readonly, disabled, size, type, showPassword, placeholder, clearable, + minlength, maxlength, showWordLimit, prefixIcon, suffixIcon, appendButtonChild} = getElAttrs(widget, formConfig) + return `${appendButtonChild}` + }, + + 'textarea': (widget, formConfig) => { + const {vModel, readonly, disabled, size, type, showPassword, placeholder, rows, clearable, + minlength, maxlength, showWordLimit} = getElAttrs(widget, formConfig) + return `` + }, + + 'number': (widget, formConfig) => { + const {vModel, disabled, size, type, showPassword, placeholder, controlsPosition, min, max, precision, step + } = getElAttrs(widget, formConfig) + return `` + }, + + 'radio': (widget, formConfig) => { + const {vModel, disabled, size} = getElAttrs(widget, formConfig) + const radioOptions = buildRadioChildren(widget, formConfig) + return `${radioOptions}` + }, + + 'checkbox': (widget, formConfig) => { + const {vModel, disabled, size} = getElAttrs(widget, formConfig) + const checkboxOptions = buildCheckboxChildren(widget, formConfig) + return `${checkboxOptions}` + }, + + 'select': (widget, formConfig) => { + const {vModel, disabled, size, clearable, filterable, allowCreate, defaultFirstOption, automaticDropdown, + multiple, multipleLimit, remote, placeholder} = getElAttrs(widget, formConfig) + const selectOptions = buildSelectChildren(widget, formConfig) + return `${selectOptions}` + }, + + 'time': (widget, formConfig) => { + const {vModel, readonly, disabled, size, placeholder, clearable, format, editable + } = getElAttrs(widget, formConfig) + return `` + }, + + 'time-range': (widget, formConfig) => { + const {vModel, readonly, disabled, size, startPlaceholder, endPlaceholder, clearable, format, editable + } = getElAttrs(widget, formConfig) + return `` + }, + + 'date': (widget, formConfig) => { + const {vModel, readonly, disabled, size, type, placeholder, clearable, format, valueFormat, editable + } = getElAttrs(widget, formConfig) + return `` + }, + + 'date-range': (widget, formConfig) => { + const {vModel, readonly, disabled, size, type, startPlaceholder, endPlaceholder, clearable, format, valueFormat, editable + } = getElAttrs(widget, formConfig) + return `` + }, + + 'switch': (widget, formConfig) => { + const {vModel, disabled, activeText, inactiveText, activeColor, inactiveColor, switchWidth + } = getElAttrs(widget, formConfig) + return `` + }, + + 'rate': (widget, formConfig) => { + const {vModel, disabled, rateMax, lowThreshold, highThreshold, allowHalf, showText, + showScore} = getElAttrs(widget, formConfig) + return `` + }, + + 'color': (widget, formConfig) => { + const {vModel, disabled, size + } = getElAttrs(widget, formConfig) + return `` + }, + + 'slider': (widget, formConfig) => { + const {vModel, disabled, sliderMin, sliderMax, sliderStep, sliderRange, sliderVertical + } = getElAttrs(widget, formConfig) + return `` + }, + + 'picture-upload': (widget, formConfig) => { + const {vModel, disabled, uploadAction, withCredentials, multipleSelect, showFileList, limit, + uploadTipSlotChild, pictureUploadIconChild} = getElAttrs(widget, formConfig) + let wop = widget.options + return `${uploadTipSlotChild} ${pictureUploadIconChild}` + }, + + 'file-upload': (widget, formConfig) => { + const {vModel, disabled, uploadAction, withCredentials, multipleSelect, showFileList, limit, + uploadTipSlotChild, fileUploadIconChild} = getElAttrs(widget, formConfig) + let wop = widget.options + return `${uploadTipSlotChild} ${fileUploadIconChild}` + }, + + 'rich-editor': (widget, formConfig) => { + const {vModel, disabled, placeholder + } = getElAttrs(widget, formConfig) + return `` + }, + + 'cascader': (widget, formConfig) => { + const {vModel, disabled, size, clearable, filterable, placeholder} = getElAttrs(widget, formConfig) + let wop = widget.options + const optionsAttr = `:options="${wop.name}Options"` + return `` + }, + + 'static-text': (widget, formConfig) => { + return `
${widget.options.textContent}
` + }, + + 'html-text': (widget, formConfig) => { + return `
` + }, + + 'button': (widget, formConfig) => { + const {buttonType, buttonPlain, buttonRound, buttonCircle, buttonIcon, disabled} = getElAttrs(widget, formConfig) + return `${widget.options.label}` + }, + + 'divider': (widget, formConfig) => { + const {contentPosition} = getElAttrs(widget, formConfig) + return `` + }, + +} + +export function buildFieldWidget(widget, formConfig) { + let wop = widget.options + const label = wop.labelHidden ? '' : wop.label + const labelWidthAttr = wop.labelHidden ? `label-width="0"` : (!!wop.labelWidth ? `label-width="${wop.labelWidth}px"` : '') + const labelTooltipAttr = wop.labelTooltip ? `title="${wop.labelTooltip}"` : '' + const propAttr = `prop="${wop.name}"` + + let classArray = [] + !!wop.required && classArray.push('required') + !!wop.customClass && (wop.customClass.length > 0) && classArray.push(wop.customClass.join(' ')) + if (!!wop.labelAlign) { + wop.labelAlign !== 'label-left-align' && classArray.push(wop.labelAlign) + } else if (!!widget.formItemFlag) { + //classArray.push(formConfig.labelAlign || 'label-left-align') + formConfig.labelAlign !== 'label-left-align' && classArray.push(formConfig.labelAlign) + } + if (!widget.formItemFlag) { + classArray.push('static-content-item') + } + const classAttr = (classArray.length > 0) ? `class="${classArray.join(' ')}"` : '' + + let customLabelDom = +`` + !wop.labelIconClass && (customLabelDom = '') + + const fwDom = elTemplates[widget.type] ? elTemplates[widget.type](widget, formConfig) : null + const isFormItem = !!widget.formItemFlag + const vShowAttr = !!wop.hidden ? `v-show="false"` : '' + return isFormItem ? +` + ${customLabelDom} + ${fwDom} +` + : +`
${fwDom}
` +} + +function genTemplate(formConfig, widgetList, vue3Flag = false) { + const submitAttr = !!vue3Flag ? `@submit.prevent` : `@submit.native.prevent` + let childrenList = [] + widgetList.forEach(wgt => { + if (wgt.category === 'container') { + childrenList.push( buildContainerWidget(wgt, formConfig) ) + } else { + childrenList.push( buildFieldWidget(wgt, formConfig) ) + } + }) + + const formTemplate = +` + ${!!childrenList ? childrenList.join('\n') : ''} +` + + return formTemplate +} + +const genGlobalCSS = function (formConfig) { + const globalCssTemplate = +` .el-input-number.full-width-input, .el-cascader.full-width-input { + width: 100% !important; + } + + .el-form-item--medium { + .el-radio { + line-height: 36px !important; + } + + .el-rate{ + margin-top: 8px; + } + } + + .el-form-item--small { + .el-radio { + line-height: 32px !important; + } + + .el-rate{ + margin-top: 6px; + } + } + + .el-form-item--mini { + .el-radio { + line-height: 28px !important; + } + + .el-rate{ + margin-top: 4px; + } + } + + .clear-fix:before, .clear-fix:after { + display: table; + content: ""; + } + + .clear-fix:after { + clear: both; + } + + .float-right { + float: right; + } + +${formConfig.cssCode}` + + return globalCssTemplate +} + +const genScopedCSS = function (formConfig, vue3Flag = false) { + //const vDeep = !!vue3Flag ? `::v-deep` : `:deep` + const cssTemplate = +` div.table-container { + table.table-layout { + width: 100%; + table-layout: fixed; + border-collapse: collapse; + + td.table-cell { + display: table-cell; + height: 36px; + border: 1px solid #e1e2e3; + } + } + } + + div.tab-container { + } + + .label-left-align ${!!vue3Flag ? `:deep(.el-form-item__label)` : `::v-deep .el-form-item__label`} { + text-align: left; + } + + .label-center-align ${!!vue3Flag ? `:deep(.el-form-item__label)` : `::v-deep .el-form-item__label`} { + text-align: center; + } + + .label-right-align ${!!vue3Flag ? `:deep(.el-form-item__label)` : `::v-deep .el-form-item__label`} { + text-align: right; + } + + .custom-label { + } + + .static-content-item { + min-height: 20px; + display: flex; + align-items: center; + + ${!!vue3Flag ? `:deep(.el-divider--horizontal)` : `::v-deep .el-divider--horizontal`} { + margin: 0; + } + }` + + return cssTemplate +} + +/** + * 注册容器组件的代码生成器 + * @param containerType 容器类型,必须唯一 + * @param ctGenerator 代码生成器函数,接收两个参数(containerWidget, formConfig),返回生成的容器组件代码 + */ +export const registerCWGenerator = function (containerType, ctGenerator) { + containerTemplates[containerType] = ctGenerator +} + +/** + * 注册字段组件的代码生成器 + * @param fieldType 字段类型,必须唯一 + * @param ftGenerator 代码生成器函数,接收两个参数(fieldWidget, formConfig),返回生成的字段组件代码 + */ +export const registerFWGenerator = function (fieldType, ftGenerator) { + elTemplates[fieldType] = ftGenerator +} + +export const genSFC = function (formConfig, widgetList, beautifier, vue3Flag = false) { + const html = beautifier.html(genTemplate(formConfig, widgetList, vue3Flag), beautifierOpts.html) + const js = beautifier.js(!!vue3Flag ? genVue3JS(formConfig, widgetList): genVue2JS(formConfig, widgetList), beautifierOpts.js) + const globalCss = beautifier.css(genGlobalCSS(formConfig), beautifierOpts.css) + const scopedCss = beautifier.css(genScopedCSS(formConfig, vue3Flag), beautifierOpts.css) + + return ` + + + + + + + +` +} diff --git a/src/utils/smart-vue-i18n/index.js b/src/utils/smart-vue-i18n/index.js new file mode 100644 index 0000000..2072cac --- /dev/null +++ b/src/utils/smart-vue-i18n/index.js @@ -0,0 +1,56 @@ +import {deepAssign, get} from './utils' + +const install = (Vue, options) => { + const proto = Vue.prototype + proto.$si18n = proto.$si18n || {} + // 初始化多语言 + deepAssign(proto.$si18n, options) + + const _vm = new Vue({ + data: options + }) + Object.defineProperty(Vue.prototype.$si18n, 'lang', { + get() { + return _vm.lang + } + }) + + proto.$st = (path, ...args) => { + let messages = _vm.messages[_vm.lang] + if (!proto.$si18n.messages) { + if (process.env.NODE_ENV !== 'production') { + console.error('[yxI18n] Locale not correctly registered') + } + return () => path + } + //const message = get(messages, path) || get(messages, path) + const message = get(messages, path) + return typeof message === 'function' + ? message(...args) + : (message !== null ? message : path) + } + + proto.$st2 = (path, path2) => { + let messages = _vm.messages[_vm.lang] + const message = get(messages, path) + return (message !== null) ? message : get(messages, path2) + } + + proto.$si18n.add = (messages = {}) => { + deepAssign(proto.$si18n.messages, messages) + } + + proto.$si18n.setLang = lang => { + _vm.lang = lang + } + + Vue.mixin({ + beforeCreate() { + this.$options.i18n && this.$si18n.add(this.$options.i18n) + } + }) +} + +export default { + install +} diff --git a/src/utils/smart-vue-i18n/utils.js b/src/utils/smart-vue-i18n/utils.js new file mode 100644 index 0000000..0ae1609 --- /dev/null +++ b/src/utils/smart-vue-i18n/utils.js @@ -0,0 +1,47 @@ +// 值存在 +export function isDef(value) { + return value !== undefined && value !== null +} + +// 对象映射 'a.b' {a: {b: 'val'}} +export function get(object, path) { + const keys = path.split('.') + let result = object + + keys.forEach(key => { + result = isDef(result) && isDef(result[key]) ? result[key] : null + }) + + return result +} + +// 是否是对象 +export function isObj(x) { + const type = typeof x + return x !== null && (type === 'object' || type === 'function') +} + +// 深拷贝 +const { hasOwnProperty } = Object.prototype + +function assignKey(to, from, key) { + const val = from[key] + + if (!isDef(val)) { + return + } + + if (!hasOwnProperty.call(to, key) || !isObj(val)) { + to[key] = val + } else { + to[key] = deepAssign(Object(to[key]), from[key]) + } +} + +export function deepAssign(to, from) { + Object.keys(from).forEach(key => { + assignKey(to, from, key) + }) + + return to +} diff --git a/src/utils/util.js b/src/utils/util.js new file mode 100644 index 0000000..1f10847 --- /dev/null +++ b/src/utils/util.js @@ -0,0 +1,370 @@ +import Clipboard from 'clipboard' + +export function isNull(value) { + return (value === null) || (value === undefined); +} + +export function isNotNull(value) { + return (value !== null) && (value !== undefined); +} + +export function isEmptyStr(str) { + //return (str === undefined) || (!str) || (!/[^\s]/.test(str)); + return (str === undefined) || (!str && (str !== 0) && (str !== '0')) || (!/[^\s]/.test(str)); +} + +export const generateId = function() { + return Math.floor(Math.random() * 100000 + Math.random() * 20000 + Math.random() * 5000); +}; + +export const deepClone = function (origin) { + if (origin === undefined) { + return undefined + } + + return JSON.parse(JSON.stringify(origin)) +} + +export const overwriteObj = function(obj1, obj2) { /* 浅拷贝对象属性,obj2覆盖obj1 */ + // for (let prop in obj2) { + // if (obj2.hasOwnProperty(prop)) { + // obj1[prop] = obj2[prop] + // } + // } + + Object.keys(obj2).forEach(prop => { + obj1[prop] = obj2[prop] + }) +} + +export const addWindowResizeHandler = function (handler) { + let oldHandler = window.onresize + if (typeof window.onresize != 'function') { + window.onresize = handler + } else { + window.onresize = function () { + oldHandler() + handler() + } + } +} + +const createStyleSheet = function() { + let head = document.head || document.getElementsByTagName('head')[0]; + let style = document.createElement('style'); + style.type = 'text/css'; + head.appendChild(style); + return style.sheet; +} + +export const insertCustomCssToHead = function (cssCode, formId = '') { + let head = document.getElementsByTagName('head')[0] + let oldStyle = document.getElementById('vform-custom-css') + if (!!oldStyle) { + head.removeChild(oldStyle) //先清除后插入!! + } + if (!!formId) { + oldStyle = document.getElementById('vform-custom-css' + '-' + formId) + !!oldStyle && head.removeChild(oldStyle) //先清除后插入!! + } + + let newStyle = document.createElement('style') + newStyle.type = 'text/css' + newStyle.rel = 'stylesheet' + newStyle.id = !!formId ? 'vform-custom-css' + '-' + formId : 'vform-custom-css' + try { + newStyle.appendChild(document.createTextNode(cssCode)) + } catch(ex) { + newStyle.styleSheet.cssText = cssCode + } + + head.appendChild(newStyle) +} + +export const insertGlobalFunctionsToHtml = function (functionsCode, formId = '') { + let bodyEle = document.getElementsByTagName('body')[0] + let oldScriptEle = document.getElementById('v_form_global_functions') + !!oldScriptEle && bodyEle.removeChild(oldScriptEle) //先清除后插入!! + if (!!formId) { + oldScriptEle = document.getElementById('v_form_global_functions' + '-' + formId) + !!oldScriptEle && bodyEle.removeChild(oldScriptEle) //先清除后插入!! + } + + let newScriptEle = document.createElement('script') + newScriptEle.id = !!formId ? 'v_form_global_functions' + '-' + formId : 'v_form_global_functions' + newScriptEle.type = 'text/javascript' + newScriptEle.innerHTML = functionsCode + bodyEle.appendChild(newScriptEle) +} + +export const optionExists = function(optionsObj, optionName) { + if (!optionsObj) { + return false + } + + return Object.keys(optionsObj).indexOf(optionName) > -1 +} + +export const loadRemoteScript = function(srcPath, callback) { /*加载远程js,加载成功后执行回调函数*/ + let sid = encodeURIComponent(srcPath) + let oldScriptEle = document.getElementById(sid) + + if (!oldScriptEle) { + let s = document.createElement('script') + s.src = srcPath + s.id = sid + document.body.appendChild(s) + + s.onload = s.onreadystatechange = function (_, isAbort) { /* 借鉴自ace.js */ + if (isAbort || !s.readyState || s.readyState === "loaded" || s.readyState === "complete") { + s = s.onload = s.onreadystatechange = null + if (!isAbort) { + callback() + } + } + } + } +} + +export function traverseFieldWidgets(widgetList, handler, parent = null) { + if (!widgetList) { + return + } + + widgetList.forEach(w => { + if (w.formItemFlag) { + handler(w, parent) + } else if (w.type === 'grid') { + w.cols.forEach(col => { + traverseFieldWidgets(col.widgetList, handler, w) + }) + } else if (w.type === 'table') { + w.rows.forEach(row => { + row.cols.forEach(cell => { + traverseFieldWidgets(cell.widgetList, handler, w) + }) + }) + } else if (w.type === 'tab') { + w.tabs.forEach(tab => { + traverseFieldWidgets(tab.widgetList, handler, w) + }) + } else if (w.type === 'sub-form') { + traverseFieldWidgets(w.widgetList, handler, w) + } else if (w.category === 'container') { //自定义容器 + traverseFieldWidgets(w.widgetList, handler, w) + } + }) +} + +export function traverseContainerWidgets(widgetList, handler) { + if (!widgetList) { + return + } + + widgetList.forEach(w => { + if (w.category === 'container') { + handler(w) + } + + if (w.type === 'grid') { + w.cols.forEach(col => { + traverseContainerWidgets(col.widgetList, handler) + }) + } else if (w.type === 'table') { + w.rows.forEach(row => { + row.cols.forEach(cell => { + traverseContainerWidgets(cell.widgetList, handler) + }) + }) + } else if (w.type === 'tab') { + w.tabs.forEach(tab => { + traverseContainerWidgets(tab.widgetList, handler) + }) + } else if (w.type === 'sub-form') { + traverseContainerWidgets(w.widgetList, handler) + } else if (w.category === 'container') { //自定义容器 + traverseContainerWidgets(w.widgetList, handler) + } + }) +} + +export function traverseAllWidgets(widgetList, handler) { + if (!widgetList) { + return + } + + widgetList.forEach(w => { + handler(w) + + if (w.type === 'grid') { + w.cols.forEach(col => { + handler(col) + traverseAllWidgets(col.widgetList, handler) + }) + } else if (w.type === 'table') { + w.rows.forEach(row => { + row.cols.forEach(cell => { + handler(cell) + traverseAllWidgets(cell.widgetList, handler) + }) + }) + } else if (w.type === 'tab') { + w.tabs.forEach(tab => { + traverseAllWidgets(tab.widgetList, handler) + }) + } else if (w.type === 'sub-form') { + traverseAllWidgets(w.widgetList, handler) + } else if (w.category === 'container') { //自定义容器 + traverseAllWidgets(w.widgetList, handler) + } + }) +} + +function handleWidgetForTraverse(widget, handler) { + if (!!widget.category) { + traverseFieldWidgetsOfContainer(widget, handler) + } else if (widget.formItemFlag) { + handler(widget) + } +} + +/** + * 遍历容器内的字段组件 + * @param con + * @param handler + */ +export function traverseFieldWidgetsOfContainer(con, handler) { + if (con.type === 'grid') { + con.cols.forEach(col => { + col.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + }) + } else if (con.type === 'table') { + con.rows.forEach(row => { + row.cols.forEach(cell => { + cell.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + }) + }) + } else if (con.type === 'tab') { + con.tabs.forEach(tab => { + tab.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + }) + } else if (con.type === 'sub-form') { + con.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + } else if (con.category === 'container') { //自定义容器 + con.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + } +} + +/** + * 获取所有字段组件 + * @param widgetList + * @returns {[]} + */ +export function getAllFieldWidgets(widgetList) { + if (!widgetList) { + return [] + } + + let result = [] + let handlerFn = (w) => { + result.push({ + type: w.type, + name: w.options.name, + field: w + }) + } + traverseFieldWidgets(widgetList, handlerFn) + + return result +} + +/** + * 获取所有容器组件 + * @param widgetList + * @returns {[]} + */ +export function getAllContainerWidgets(widgetList) { + if (!widgetList) { + return [] + } + + let result = [] + let handlerFn = (w) => { + result.push({ + type: w.type, + name: w.options.name, + container: w + }) + } + traverseContainerWidgets(widgetList, handlerFn) + + return result +} + +export function copyToClipboard(content, clickEvent, $message, successMsg, errorMsg) { + const clipboard = new Clipboard(clickEvent.target, { + text: () => content + }) + + clipboard.on('success', () => { + $message.success(successMsg) + clipboard.destroy() + }) + + clipboard.on('error', () => { + $message.error(errorMsg) + clipboard.destroy() + }) + + clipboard.onClick(clickEvent) +} + +export function getQueryParam(variable) { + let query = window.location.search.substring(1); + let vars = query.split("&") + for (let i=0; i 0 && resultList.push(`${fop.name}: [${fieldRules.join(',')}],`) + } +} + +export function buildFieldOptionsFn(formConfig, widgetList, resultList) { + return function(fieldWidget) { + const fop = fieldWidget.options + const ft = fieldWidget.type + if ((ft === 'radio') || (ft === 'checkbox') || (ft === 'select') || (ft === 'cascader')) { + resultList.push(`${fop.name}Options: ${JSON.stringify(fop.optionItems)},`) + } + } +} + +export function buildUploadDataFn(formConfig, widgetList, resultList) { + return function(fieldWidget) { + const fop = fieldWidget.options + const ft = fieldWidget.type + if ((ft === 'picture-upload') || (ft === 'file-upload')) { + resultList.push(`${fop.name}FileList: [],`) + resultList.push(`${fop.name}UploadHeaders: {},`) + resultList.push(`${fop.name}UploadData: {},`) + } + } +} + +export function buildActiveTabs(formConfig, widgetList) { + let resultList = [] + const handlerFn = function (cw) { + const cop = cw.options + const ct = cw.type + if (ct === 'tab') { + cw.tabs.length > 0 && resultList.push(`'${cop.name}ActiveTab': '${cw.tabs[0].options.name}',`) + } + } + traverseContainerWidgets(widgetList, handlerFn) + + return resultList +} + +export const genVue2JS = function (formConfig, widgetList) { + let defaultValueList = [] + let rulesList = [] + let fieldOptions = [] + let uploadData = [] + traverseFieldWidgets(widgetList, (widget) => { + buildDefaultValueListFn(formConfig, widgetList, defaultValueList)(widget) + buildRulesListFn(formConfig, widgetList, rulesList)(widget) + buildFieldOptionsFn(formConfig, widgetList, fieldOptions)(widget) + buildUploadDataFn(formConfig, widgetList, uploadData)(widget) + }) + + const activeTabs = buildActiveTabs(formConfig, widgetList) + + const v2JSTemplate = +` export default { + components: {}, + props: {}, + data() { + return { + ${formConfig.modelName}: { + ${defaultValueList.join('\n')} + }, + + ${formConfig.rulesName}: { + ${rulesList.join('\n')} + }, + + ${activeTabs.join('\n')} + + ${fieldOptions.join('\n')} + + ${uploadData.join('\n')} + } + }, + computed: {}, + watch: {}, + created() { + }, + mounted() { + }, + methods: { + submitForm() { + this.$refs['vForm'].validate(valid => { + if (!valid) return + + //TODO: 提交表单 + }) + }, + + resetForm() { + this.$refs['vForm'].resetFields() + } + } + }` + + return v2JSTemplate +} diff --git a/src/utils/vue3js-generator.js b/src/utils/vue3js-generator.js new file mode 100644 index 0000000..9a2daa6 --- /dev/null +++ b/src/utils/vue3js-generator.js @@ -0,0 +1,70 @@ +import { + buildActiveTabs, + buildDefaultValueListFn, + buildFieldOptionsFn, + buildRulesListFn, buildUploadDataFn +} from "@/utils/vue2js-generator"; +import {traverseFieldWidgets} from "@/utils/util"; + +export const genVue3JS = function (formConfig, widgetList) { + let defaultValueList = [] + let rulesList = [] + let fieldOptions = [] + let uploadData = [] + traverseFieldWidgets(widgetList, (widget) => { + buildDefaultValueListFn(formConfig, widgetList, defaultValueList)(widget) + buildRulesListFn(formConfig, widgetList, rulesList)(widget) + buildFieldOptionsFn(formConfig, widgetList, fieldOptions)(widget) + buildUploadDataFn(formConfig, widgetList, uploadData)(widget) + }) + + const activeTabs = buildActiveTabs(formConfig, widgetList) + + const v3JSTemplate = +` import { defineComponent, toRefs, reactive, getCurrentInstance } from 'vue' + + export default defineComponent({ + components: {}, + props: {}, + setup() { + const state = reactive({ + ${formConfig.modelName}: { + ${defaultValueList.join('\n')} + }, + + ${formConfig.rulesName}: { + ${rulesList.join('\n')} + }, + + ${activeTabs.join('\n')} + + ${fieldOptions.join('\n')} + + ${uploadData.join('\n')} + }) + + const instance = getCurrentInstance() + + const submitForm = () => { + instance.proxy.$refs['vForm'].validate(valid => { + if (!valid) return + + //TODO: 提交表单 + }) + } + + const resetForm = () => { + instance.proxy.$refs['vForm'].resetFields() + } + + return { + ...toRefs(state), + submitForm, + resetForm + } + } + })` + + return v3JSTemplate +} + diff --git a/vue.config.js b/vue.config.js new file mode 100644 index 0000000..f0cc663 --- /dev/null +++ b/vue.config.js @@ -0,0 +1,93 @@ +'use strict' + +const path = require('path') +const IS_PROD = process.env.NODE_ENV === 'production' + +function resolve (dir) { + return path.join(__dirname, dir) +} + +const npmConfigArgv = (process.env.npm_config_argv === undefined) ? null : JSON.parse(process.env.npm_config_argv) +/* +console.log('npm config: ', npmConfigArgv) +const procArgv = process.argv +console.log('npm config: ', procArgv) +*/ +let buildProdFlag = false +if (!!npmConfigArgv) { + npmConfigArgv.original.forEach(cItem => { + if (cItem === 'build') { + buildProdFlag = true + } + }) +} + +const mvdir = require('mvdir'); +if (IS_PROD && buildProdFlag) { + mvdir('index_template/index_prod.html', 'public/index.html', { copy: true }); +} else { + mvdir('index_template/index_dev.html', 'public/index.html', { copy: true }); +} + + +module.exports = { + publicPath: './', + assetsDir: './', + + /* 开启vue运行时模板编译功能!! */ + runtimeCompiler: true, + + lintOnSave: false, + + productionSourceMap: false, + + /* 指定node_modules目录中需要做babel转译的依赖库 */ + transpileDependencies: [ + 'element-ui', 'vuedraggable', + ], + + css: { + loaderOptions: { + scss: { + /* 自动引入全局scss文件 */ + prependData: ` + @import "./src/styles/global.scss"; + ` + } + } + }, + + configureWebpack: (config) => { + config.devtool = 'source-map' + config.output.libraryExport = 'default' /* 解决import UMD打包文件时, 组件install方法执行报错的问题!! */ + + if (IS_PROD && buildProdFlag) { /* 仅生产环境使用 */ + /* CDN打包,需要修改index.html加入CDN资源 */ + config.externals = { + 'vue': 'Vue', + 'element-ui': 'ELEMENT', + //'quill': 'Quill', + } + } + }, + + chainWebpack: config => { + /* 配置svg图标自动加载 begin */ + config.module + .rule('svg') + .exclude.add(resolve('src/icons')) + .end() + config.module + .rule('icons') + .test(/\.svg$/) + .include.add(resolve('src/icons')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ + symbolId: 'icon-[name]' + }) + /* 配置svg图标自动加载 end */ + }, + +}