├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── JSON-Schema.md ├── README.md ├── babel.config.js ├── dist ├── README.md └── package.json ├── jest.config.js ├── npm ├── README.md ├── index.js └── package.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ ├── Formdesign │ │ ├── iconfont │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ │ ├── index.vue │ │ └── meta │ │ │ ├── base.js │ │ │ ├── button.js │ │ │ ├── canvas.js │ │ │ ├── cascader.js │ │ │ ├── checkbox.js │ │ │ ├── collapse.js │ │ │ ├── colorpicker.js │ │ │ ├── datetimepicker.js │ │ │ ├── grid.js │ │ │ ├── icon.js │ │ │ ├── input.js │ │ │ ├── inputnumber.js │ │ │ ├── ipinput.js │ │ │ ├── layout.js │ │ │ ├── radio.js │ │ │ ├── rate.js │ │ │ ├── select.js │ │ │ ├── slider.js │ │ │ ├── slot.js │ │ │ ├── switch.js │ │ │ ├── tabs.js │ │ │ ├── timepicker.js │ │ │ ├── transfer.js │ │ │ └── upload.js │ ├── Richform │ │ ├── actions.vue │ │ ├── autoLayout.vue │ │ ├── field.vue │ │ ├── group │ │ │ ├── collapse.vue │ │ │ ├── default.vue │ │ │ ├── grid.vue │ │ │ └── tabs.vue │ │ ├── index.vue │ │ ├── layout.vue │ │ ├── utils │ │ │ ├── commonMixin.js │ │ │ ├── defaultData.js │ │ │ ├── design.scss │ │ │ ├── designMixin.js │ │ │ ├── eventbus.js │ │ │ ├── http.js │ │ │ ├── index.js │ │ │ ├── themeMixin.js │ │ │ └── validator.js │ │ ├── vars.scss │ │ └── widgets │ │ │ ├── baseMixin.js │ │ │ ├── button.vue │ │ │ ├── cascader.vue │ │ │ ├── checkbox.vue │ │ │ ├── colorpicker.vue │ │ │ ├── components │ │ │ ├── Input │ │ │ │ └── index.vue │ │ │ └── IpInput │ │ │ │ └── index.vue │ │ │ ├── datetimepicker.vue │ │ │ ├── draggablelist.vue │ │ │ ├── expression.vue │ │ │ ├── icon.vue │ │ │ ├── input.vue │ │ │ ├── inputnumber.vue │ │ │ ├── ipinput.vue │ │ │ ├── map.vue │ │ │ ├── multiexp.vue │ │ │ ├── radio.vue │ │ │ ├── rate.vue │ │ │ ├── select.vue │ │ │ ├── slider.vue │ │ │ ├── slot.vue │ │ │ ├── switch.vue │ │ │ ├── text.vue │ │ │ ├── timepicker.vue │ │ │ ├── timeselect.vue │ │ │ ├── transfer.vue │ │ │ ├── tree.vue │ │ │ └── upload.vue │ ├── SplitLayout │ │ ├── index.vue │ │ └── mixin.scss │ ├── Teleport │ │ └── index.vue │ └── index.js ├── i18n │ ├── index.js │ └── lang │ │ ├── en.js │ │ ├── vi.js │ │ └── zh-CN.js ├── main.js ├── package.json ├── pages │ ├── deep-values.vue │ ├── form-design.vue │ └── richform.vue └── router │ └── index.js └── vue.config.js /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | src/assets 3 | public 4 | dist 5 | src 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | parser: 'babel-eslint', 5 | sourceType: 'module' 6 | }, 7 | env: { 8 | browser: true, 9 | node: true, 10 | es6: true, 11 | }, 12 | extends: ['plugin:vue/recommended', 'eslint:recommended'], 13 | 14 | // add your custom rules here 15 | //it is base on https://github.com/vuejs/eslint-config-vue 16 | rules: { 17 | "vue/max-attributes-per-line": [2, { 18 | "singleline": 10, 19 | "multiline": { 20 | "max": 1, 21 | "allowFirstLine": false 22 | } 23 | }], 24 | "vue/singleline-html-element-content-newline": "off", 25 | "vue/multiline-html-element-content-newline":"off", 26 | "vue/name-property-casing": ["error", "PascalCase"], 27 | "vue/no-v-html": "off", 28 | 'accessor-pairs': 2, 29 | 'arrow-spacing': [2, { 30 | 'before': true, 31 | 'after': true 32 | }], 33 | 'block-spacing': [2, 'always'], 34 | 'brace-style': [2, '1tbs', { 35 | 'allowSingleLine': true 36 | }], 37 | 'camelcase': [0, { 38 | 'properties': 'always' 39 | }], 40 | 'comma-dangle': [2, 'never'], 41 | 'comma-spacing': [2, { 42 | 'before': false, 43 | 'after': true 44 | }], 45 | 'comma-style': [2, 'last'], 46 | 'constructor-super': 2, 47 | 'curly': [2, 'multi-line'], 48 | 'dot-location': [2, 'property'], 49 | 'eol-last': 2, 50 | 'eqeqeq': ["error", "always", {"null": "ignore"}], 51 | 'generator-star-spacing': [2, { 52 | 'before': true, 53 | 'after': true 54 | }], 55 | 'handle-callback-err': [2, '^(err|error)$'], 56 | 'indent': [2, 2, { 57 | 'SwitchCase': 1 58 | }], 59 | 'jsx-quotes': [2, 'prefer-single'], 60 | 'key-spacing': [2, { 61 | 'beforeColon': false, 62 | 'afterColon': true 63 | }], 64 | 'keyword-spacing': [2, { 65 | 'before': true, 66 | 'after': true 67 | }], 68 | 'new-cap': [2, { 69 | 'newIsCap': true, 70 | 'capIsNew': false 71 | }], 72 | 'new-parens': 2, 73 | 'no-array-constructor': 2, 74 | 'no-caller': 2, 75 | 'no-console': 'off', 76 | 'no-class-assign': 2, 77 | 'no-cond-assign': 2, 78 | 'no-const-assign': 2, 79 | 'no-control-regex': 0, 80 | 'no-delete-var': 2, 81 | 'no-dupe-args': 2, 82 | 'no-dupe-class-members': 2, 83 | 'no-dupe-keys': 2, 84 | 'no-duplicate-case': 2, 85 | 'no-empty-character-class': 2, 86 | 'no-empty-pattern': 2, 87 | 'no-eval': 2, 88 | 'no-ex-assign': 2, 89 | 'no-extend-native': 2, 90 | 'no-extra-bind': 2, 91 | 'no-extra-boolean-cast': 2, 92 | 'no-extra-parens': [2, 'functions'], 93 | 'no-fallthrough': 2, 94 | 'no-floating-decimal': 2, 95 | 'no-func-assign': 2, 96 | 'no-implied-eval': 2, 97 | 'no-inner-declarations': [2, 'functions'], 98 | 'no-invalid-regexp': 2, 99 | 'no-irregular-whitespace': 2, 100 | 'no-iterator': 2, 101 | 'no-label-var': 2, 102 | 'no-labels': [2, { 103 | 'allowLoop': false, 104 | 'allowSwitch': false 105 | }], 106 | 'no-lone-blocks': 2, 107 | 'no-mixed-spaces-and-tabs': 2, 108 | 'no-multi-spaces': 2, 109 | 'no-multi-str': 2, 110 | 'no-multiple-empty-lines': [2, { 111 | 'max': 1 112 | }], 113 | 'no-native-reassign': 2, 114 | 'no-negated-in-lhs': 2, 115 | 'no-new-object': 2, 116 | 'no-new-require': 2, 117 | 'no-new-symbol': 2, 118 | 'no-new-wrappers': 2, 119 | 'no-obj-calls': 2, 120 | 'no-octal': 2, 121 | 'no-octal-escape': 2, 122 | 'no-path-concat': 2, 123 | 'no-proto': 2, 124 | 'no-redeclare': 2, 125 | 'no-regex-spaces': 2, 126 | 'no-return-assign': [2, 'except-parens'], 127 | 'no-self-assign': 2, 128 | 'no-self-compare': 2, 129 | 'no-sequences': 2, 130 | 'no-shadow-restricted-names': 2, 131 | 'no-spaced-func': 2, 132 | 'no-sparse-arrays': 2, 133 | 'no-this-before-super': 2, 134 | 'no-throw-literal': 2, 135 | 'no-trailing-spaces': 2, 136 | 'no-undef': 2, 137 | 'no-undef-init': 2, 138 | 'no-unexpected-multiline': 2, 139 | 'no-unmodified-loop-condition': 2, 140 | 'no-unneeded-ternary': [2, { 141 | 'defaultAssignment': false 142 | }], 143 | 'no-unreachable': 2, 144 | 'no-unsafe-finally': 2, 145 | 'no-unused-vars': [2, { 146 | 'vars': 'all', 147 | 'args': 'none' 148 | }], 149 | 'no-useless-call': 2, 150 | 'no-useless-computed-key': 2, 151 | 'no-useless-constructor': 2, 152 | 'no-useless-escape': 0, 153 | 'no-whitespace-before-property': 2, 154 | 'no-with': 2, 155 | 'one-var': [2, { 156 | 'initialized': 'never' 157 | }], 158 | 'operator-linebreak': [2, 'after', { 159 | 'overrides': { 160 | '?': 'before', 161 | ':': 'before' 162 | } 163 | }], 164 | 'padded-blocks': [2, 'never'], 165 | 'quotes': [2, 'single', { 166 | 'avoidEscape': true, 167 | 'allowTemplateLiterals': true 168 | }], 169 | 'semi': [2, 'never'], 170 | 'semi-spacing': [2, { 171 | 'before': false, 172 | 'after': true 173 | }], 174 | 'space-before-blocks': [2, 'always'], 175 | // 'space-before-function-paren': [2, 'never'], 176 | 'space-in-parens': [2, 'never'], 177 | 'space-infix-ops': 2, 178 | 'space-unary-ops': [2, { 179 | 'words': true, 180 | 'nonwords': false 181 | }], 182 | 'spaced-comment': [2, 'always', { 183 | 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] 184 | }], 185 | 'template-curly-spacing': [2, 'never'], 186 | 'use-isnan': 2, 187 | 'valid-typeof': 2, 188 | 'wrap-iife': [2, 'any'], 189 | 'yield-star-spacing': [2, 'both'], 190 | 'yoda': [2, 'never'], 191 | 'prefer-const': 2, 192 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 193 | 'object-curly-spacing': [2, 'always', { 194 | objectsInObjects: false 195 | }], 196 | 'array-bracket-spacing': [2, 'never'] 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist/lib 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # richform 2 | 3 | ## 主要功能 4 | * richform表单组件 5 | * 数据驱动 6 | * 校验规则采用标准的JsonSchema,[JsonSchema文档](https://github.com/jingyuLin1999/richform/blob/main/JSON-Schema.md) 7 | * 可拓展性,widgets下可自定义一些子组件 8 | * 表单设计器 9 | * 基于richform表单的拓展,可动态设计表单 10 | * 表单设计所见即所得 11 | * 可设置字段属性和校验规则 12 | * 签核流程 13 | * 基于RichForm和表单设计器的拓展 14 | * 流程配置。动态添加节点,设计各节点的签核顺序,串并联签核 15 | * 节点个性化。每个节点表单用RichForm显示,数据来源于表单设计器的设计结果 16 | * 节点属性。签核人设置、签核类型(会签,串签)、出口配置 17 | * 已签核状态显示 18 | * 错误处理 19 | 20 | ## 支持vue2.x 21 | vue3.x 请见[richform-plus](https://github.com/jingyuLin1999/richform-plus) 22 | 23 | ## 预览 24 | 25 | ### 在线预览 26 | 27 | [表单设计器](http://156.232.10.2/richform/#/) 28 | 29 | [富表单完整功能](http://156.232.10.2/richform/#/richform) 30 | 31 | ### 本地预览 32 | ``` 33 | npm install 34 | 35 | npm run serve 36 | ``` 37 | [表单设计器](http://localhost:8080/#/ ) 38 | http://localhost:8080/#/ 39 | 40 | [富表单完整功能](http://localhost:8080/#/form-design ) 41 | http://localhost:8080/#/form-design 42 | 43 | ## 用法 44 | ``` 45 | npm i richform -S 46 | ``` 47 | 48 | ```html 49 |
50 |
51 | 52 |
53 |
54 | 55 |
56 |
57 | ``` 58 | 59 | ```js 60 | import { RichForm, FormDesign } from "richform"; 61 | export default { 62 | components: { RichForm,FormDesign}, 63 | data() { 64 | return { 65 | schema: {}, // 验证规则 66 | values: {}, // 表单的值 67 | form: { 68 | border: true, // 显示边框 69 | grid: false, // 表单内部栅栏 70 | labelSuffix: ":", // 字段标题后缀内容,默认' : ' 71 | labelWidth: "110px", // 标签宽度,默认50px 72 | validator: "input", // submit 73 | labelAlign: "right", // 标签对齐, 默认右对齐, 可选左对齐left 74 | labelInline: true, // 字段标题显示位置, 默认true左侧left,false显示在top上方 75 | actions: [ 76 | //声明显示在下方和动作按钮 77 | { 78 | name: "reset", // 按键的唯一标识符 79 | type: "primary", // 按键类型,默认为primary,具体可见element button 80 | title: "重置", // 按键的文字 81 | icon: "el-icon-star-off", // 按键图标 具体可见element icon 82 | right: true, // 如果=true,则显示在右侧 83 | visible: true, // 按键是否可见,同时满足readonly===false和设置为true才会显示,默认为true 84 | tips: "提示信息", // 鼠标悬浮在按键的提示信息 85 | top: true, // 是否在上面, false则在下面 86 | size: "medium" // medium / small / mini, 若未指明,则等同于form.size 87 | }, 88 | { 89 | name: "submit", // 按键的唯一标识符 90 | type: "info", // 按键类型,默认为primary,具体可见element button 91 | title: "提交", // 按键的文字 92 | icon: "", // 按键图标 具体可见element icon 93 | right: true, // 如果=true,则显示在右侧 94 | visible: true, // 按键是否可见,同时满足readonly===false和设置为true才会显示,默认为true 95 | tips: "提示信息", // 鼠标悬浮在按键的提示信息 96 | top: true, // 是否在上面, false则在下面 97 | size: "medium" // medium / small / mini, 若未指明,则等同于form.size 98 | } 99 | ], 100 | layout: [ 101 | { 102 | title: "名称对方", 103 | widget: "input", 104 | name: "input", // values的箭值,必须有 105 | type: "text", 106 | }, 107 | // 更多子组件请见widgets介绍,或者看完整功能 108 | ] 109 | } 110 | } 111 | } 112 | } 113 | ``` 114 | 115 | ## 特殊功能 116 | 1、字段选项依赖 117 | ```js 118 | { 119 | title: "下拉选框B", 120 | widget: "select", 121 | name: "selectB", 122 | description: "我的选项依赖于【下拉选框A】", 123 | dict: { 124 | "selectA==选项1": [ 125 | { 126 | value: "选项1", 127 | label: "根据[下拉选框A]的值变化A", 128 | }, 129 | { 130 | value: "选项2", 131 | label: "根据[下拉选框A]的值变化B", 132 | }, 133 | ], 134 | "selectA == 选项2": "http://localhost:8080/#/form-design", 135 | "input == 123456": [ 136 | { 137 | value: "input等于123456", 138 | label: "input等于123456", 139 | }, 140 | ], 141 | }, 142 | options: [ 143 | { 144 | value: "选项1", 145 | label: "黄金糕", 146 | }, 147 | { 148 | value: "选项2", 149 | label: "双皮奶", 150 | }, 151 | ], 152 | } 153 | ``` 154 | 补充说明 155 | 当两个select的选项互相依赖时,箭值为条件,值可以有三种形式,若是url则获取数据,若是数组则直接赋值给options 156 | ```js 157 | dict: "http://localhost:8080/#/form-design", // 获取到的值会直接覆盖options 158 | dict: { 159 | [<字段名name> == 'A']: "https://shandawang.com/dict/province", // 字典, 160 | [<字段名name> == 'B']: [{},{}], // options 161 | [<字段名name> == 'any']: "https://shandawang.com/dict/province", // 若等于any且值是url,<字段名name>的值只要变化,就会带上<字段名name>值到后端过滤获取字典 162 | [<字段名name> == 'any']: {filterKey: "id"}, // 若等于any且值是对象,filterKey字段和options都必须有。<字段名name>的值只要变化,就会带上<字段名name>值到options中过滤。有一种特殊应用,当被依赖的字段值变化了,根据被依赖选项({label,value,other})的某个字段的值到当前options过滤,此时可配beRelyFilterKey如 {filterKey: "id",beRelyFilterKey: "other"} 163 | } 164 | ``` 165 | 2、字段隐藏依赖 166 | ```js 167 | { 168 | title: "名称对方", 169 | widget: "input", 170 | name: "input", 171 | type: "textarea", 172 | hideRely: "radioA==单选框B", 173 | } 174 | ``` 175 | 补充说明 176 | ```js 177 | hideRely:<字段名称nameA> == 'C', // 可以是单值 178 | hideRely:[ // 也可以是多值,只要满足一个条件,就隐藏,且后面条件不会再校验 179 | <字段名称nameA> == 'C', 180 | <字段名称nameB> == 'D', 181 | ] 182 | ``` 183 | 3、更多widgets配置详情 184 | 请见src/pages/richform.vue 185 | 186 | ## 深度编辑 187 | values可能是深度嵌套如下 188 | ```js 189 | { 190 | title: { 191 | text: "ECharts 入门示例", 192 | subtext: "Living Expenses in Shenzhen", 193 | }, 194 | legend: { 195 | orient: "horizontal", // vertical/horizontal 196 | left: 0, 197 | // top: 0, 198 | bottom: 0, 199 | }, 200 | } 201 | ``` 202 | 要编辑这种valuse可开启deepValues: true 203 | ```html 204 | 205 | ``` 206 | 此时在定义form的name字段和shema结构,需要与values的结构对应 207 | ```js 208 | layout: [{ 209 | title: "标题", 210 | widget: "input", 211 | name: "title.text", 212 | }] 213 | ``` 214 | [例子](http://117.73.12.76/demo/richform/#/deep-values ) 215 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "@vue/app", 5 | { 6 | "useBuiltIns": "entry", 7 | polyfills: [ 8 | 'es6.promise', 9 | 'es6.symbol' 10 | ] 11 | } 12 | ] 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | # richform 2 | 3 | ## 主要功能 4 | * richform表单组件 5 | * 数据驱动 6 | * 校验规则采用标准的JsonSchema,[JsonSchema文档](https://github.com/jingyuLin1999/richform/blob/main/JSON-Schema.md) 7 | * 可拓展性,widgets下可自定义一些子组件 8 | * 表单设计器 9 | * 基于richform表单的拓展,可动态设计表单 10 | * 表单设计所见即所得 11 | * 可设置字段属性和校验规则 12 | * 签核流程 13 | * 基于RichForm和表单设计器的拓展 14 | * 流程配置。动态添加节点,设计各节点的签核顺序,串并联签核 15 | * 节点个性化。每个节点表单用RichForm显示,数据来源于表单设计器的设计结果 16 | * 节点属性。签核人设置、签核类型(会签,串签)、出口配置 17 | * 已签核状态显示 18 | * 错误处理 19 | 20 | ## 支持vue2.x 21 | vue3.x 请见[richform-plus](https://github.com/jingyuLin1999/richform-plus) 22 | 23 | ## 预览 24 | 25 | ### 在线预览 26 | 27 | [表单设计器](http://117.73.12.76/demo/richform/#/ ) 28 | 29 | [富表单完整功能](http://117.73.12.76/demo/richform/#/form-design ) 30 | 31 | ### 本地预览 32 | ``` 33 | npm install 34 | 35 | npm run serve 36 | ``` 37 | [表单设计器](http://localhost:8080/#/ ) 38 | http://localhost:8080/#/ 39 | 40 | [富表单完整功能](http://localhost:8080/#/form-design ) 41 | http://localhost:8080/#/form-design 42 | 43 | ## 用法 44 | ``` 45 | npm i richform -S 46 | ``` 47 | 48 | ```html 49 |
50 |
51 | 52 |
53 |
54 | 55 |
56 |
57 | ``` 58 | 59 | ```js 60 | import { RichForm, FormDesign } from "richform"; 61 | export default { 62 | components: { RichForm,FormDesign}, 63 | data() { 64 | return { 65 | schema: {}, // 验证规则 66 | values: {}, // 表单的值 67 | form: { 68 | border: true, // 显示边框 69 | grid: false, // 表单内部栅栏 70 | labelSuffix: ":", // 字段标题后缀内容,默认' : ' 71 | labelWidth: "110px", // 标签宽度,默认50px 72 | validator: "input", // submit 73 | labelAlign: "right", // 标签对齐, 默认右对齐, 可选左对齐left 74 | labelInline: true, // 字段标题显示位置, 默认true左侧left,false显示在top上方 75 | actions: [ 76 | //声明显示在下方和动作按钮 77 | { 78 | name: "reset", // 按键的唯一标识符 79 | type: "primary", // 按键类型,默认为primary,具体可见element button 80 | title: "重置", // 按键的文字 81 | icon: "el-icon-star-off", // 按键图标 具体可见element icon 82 | right: true, // 如果=true,则显示在右侧 83 | visible: true, // 按键是否可见,同时满足readonly===false和设置为true才会显示,默认为true 84 | tips: "提示信息", // 鼠标悬浮在按键的提示信息 85 | top: true, // 是否在上面, false则在下面 86 | size: "medium" // medium / small / mini, 若未指明,则等同于form.size 87 | }, 88 | { 89 | name: "submit", // 按键的唯一标识符 90 | type: "info", // 按键类型,默认为primary,具体可见element button 91 | title: "提交", // 按键的文字 92 | icon: "", // 按键图标 具体可见element icon 93 | right: true, // 如果=true,则显示在右侧 94 | visible: true, // 按键是否可见,同时满足readonly===false和设置为true才会显示,默认为true 95 | tips: "提示信息", // 鼠标悬浮在按键的提示信息 96 | top: true, // 是否在上面, false则在下面 97 | size: "medium" // medium / small / mini, 若未指明,则等同于form.size 98 | } 99 | ], 100 | layout: [ 101 | { 102 | title: "名称对方", 103 | widget: "input", 104 | name: "input", // values的箭值,必须有 105 | type: "text", 106 | }, 107 | // 更多子组件请见widgets介绍,或者看完整功能 108 | ] 109 | } 110 | } 111 | } 112 | } 113 | ``` 114 | 115 | ## 特殊功能 116 | 1、字段选项依赖 117 | ```js 118 | { 119 | title: "下拉选框B", 120 | widget: "select", 121 | name: "selectB", 122 | description: "我的选项依赖于【下拉选框A】", 123 | dict: { 124 | "selectA==选项1": [ 125 | { 126 | value: "选项1", 127 | label: "根据[下拉选框A]的值变化A", 128 | }, 129 | { 130 | value: "选项2", 131 | label: "根据[下拉选框A]的值变化B", 132 | }, 133 | ], 134 | "selectA == 选项2": "http://localhost:8080/#/form-design", 135 | "input == 123456": [ 136 | { 137 | value: "input等于123456", 138 | label: "input等于123456", 139 | }, 140 | ], 141 | }, 142 | options: [ 143 | { 144 | value: "选项1", 145 | label: "黄金糕", 146 | }, 147 | { 148 | value: "选项2", 149 | label: "双皮奶", 150 | }, 151 | ], 152 | } 153 | ``` 154 | 补充说明 155 | 当两个select的选项互相依赖时,箭值为条件,值可以有三种形式,若是url则获取数据,若是数组则直接赋值给options 156 | ```js 157 | dict: "http://localhost:8080/#/form-design", // 获取到的值会直接覆盖options 158 | dict: { 159 | [<字段名name> == 'A']: "https://shandawang.com/dict/province", // 字典, 160 | [<字段名name> == 'B']: [{},{}], // options 161 | [<字段名name> == 'any']: "https://shandawang.com/dict/province", // 若等于any且值是url,<字段名name>的值只要变化,就会带上<字段名name>值到后端过滤获取字典 162 | [<字段名name> == 'any']: {filterKey: "id"}, // 若等于any且值是对象,filterKey字段和options都必须有。<字段名name>的值只要变化,就会带上<字段名name>值到options中过滤。有一种特殊应用,当被依赖的字段值变化了,根据被依赖选项({label,value,other})的某个字段的值到当前options过滤,此时可配beRelyFilterKey如 {filterKey: "id",beRelyFilterKey: "other"} 163 | } 164 | ``` 165 | 2、字段隐藏依赖 166 | ```js 167 | { 168 | title: "名称对方", 169 | widget: "input", 170 | name: "input", 171 | type: "textarea", 172 | hideRely: "radioA==单选框B", 173 | } 174 | ``` 175 | 补充说明 176 | ```js 177 | hideRely:<字段名称nameA> == 'C', // 可以是单值 178 | hideRely:[ // 也可以是多值,只要满足一个条件,就隐藏,且后面条件不会再校验 179 | <字段名称nameA> == 'C', 180 | <字段名称nameB> == 'D', 181 | ] 182 | ``` 183 | 3、更多widgets配置详情 184 | 请见src/pages/richform.vue 185 | 186 | ## 深度编辑 187 | values可能是深度嵌套如下 188 | ```js 189 | { 190 | title: { 191 | text: "ECharts 入门示例", 192 | subtext: "Living Expenses in Shenzhen", 193 | }, 194 | legend: { 195 | orient: "horizontal", // vertical/horizontal 196 | left: 0, 197 | // top: 0, 198 | bottom: 0, 199 | }, 200 | } 201 | ``` 202 | 要编辑这种valuse可开启deepValues: true 203 | ```html 204 | 205 | ``` 206 | 此时在定义form的name字段和shema结构,需要与values的结构对应 207 | ```js 208 | layout: [{ 209 | title: "标题", 210 | widget: "input", 211 | name: "title.text", 212 | }] 213 | ``` 214 | [例子](http://117.73.12.76/demo/richform/#/deep-values ) 215 | -------------------------------------------------------------------------------- /dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "richform", 3 | "version": "0.11.50", 4 | "private": false, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "build:prod": "vue-cli-service build --target lib --name richform src/components/index.js", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "main": "lib/richform.umd.min.js", 12 | "module": "lib/richform.umd.min.js", 13 | "dependencies": { 14 | "ajv": "^6.12.6", 15 | "ajv-errors": "^1.0.1", 16 | "axios": "^0.21.1", 17 | "core-js": "^3.6.5", 18 | "element-resize-detector": "^1.2.4", 19 | "element-ui": "^2.15.6", 20 | "jquery": "^3.6.0", 21 | "ramda": "^0.27.1", 22 | "vue-baidu-map": "^0.21.22", 23 | "vue-i18n": "^8.28.2", 24 | "vue-scrollto": "^2.20.0", 25 | "vue2-perfect-scrollbar": "^1.5.0", 26 | "vuedraggable": "^2.24.3", 27 | "vxe-table": "^3.4.15", 28 | "xe-utils": "^3.5.4" 29 | }, 30 | "eslintConfig": { 31 | "root": true, 32 | "env": { 33 | "node": true 34 | }, 35 | "extends": [ 36 | "plugin:vue/essential", 37 | "eslint:recommended" 38 | ], 39 | "parserOptions": { 40 | "parser": "babel-eslint" 41 | }, 42 | "rules": { 43 | "generator-star-spacing": "off", 44 | "no-tabs": "off", 45 | "no-unused-vars": "off", 46 | "no-console": "off", 47 | "no-irregular-whitespace": "off", 48 | "no-debugger": "off" 49 | } 50 | }, 51 | "files": [ 52 | "dist", 53 | "src/i18n/lang" 54 | ], 55 | "browserslist": [ 56 | "> 1%", 57 | "last 2 versions" 58 | ], 59 | "author": "ljy", 60 | "license": "ISC", 61 | "repository": { 62 | "type": "git", 63 | "url": "git+https://github.com/jingyuLin1999/richform" 64 | } 65 | } -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], 3 | transform: { 4 | '^.+\\.vue$': 'vue-jest', 5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 6 | 'jest-transform-stub', 7 | '^.+\\.jsx?$': 'babel-jest' 8 | }, 9 | moduleNameMapper: { 10 | '^@/(.*)$': '/src/$1' 11 | }, 12 | snapshotSerializers: ['jest-serializer-vue'], 13 | testMatch: [ 14 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 15 | ], 16 | collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'], 17 | coverageDirectory: '/tests/unit/coverage', 18 | // 'collectCoverage': true, 19 | 'coverageReporters': [ 20 | 'lcov', 21 | 'text-summary' 22 | ], 23 | testURL: 'http://localhost/' 24 | } 25 | -------------------------------------------------------------------------------- /npm/README.md: -------------------------------------------------------------------------------- 1 | # richform 2 | 3 | ## 主要功能 4 | * richform表单组件 5 | * 数据驱动 6 | * 校验规则采用标准的JsonSchema,[JsonSchema文档](https://github.com/jingyuLin1999/richform/blob/main/JSON-Schema.md) 7 | * 可拓展性,widgets下可自定义一些子组件 8 | * 表单设计器 9 | * 基于richform表单的拓展,可动态设计表单 10 | * 表单设计所见即所得 11 | * 可设置字段属性和校验规则 12 | * 签核流程 13 | * 基于RichForm和表单设计器的拓展 14 | * 流程配置。动态添加节点,设计各节点的签核顺序,串并联签核 15 | * 节点个性化。每个节点表单用RichForm显示,数据来源于表单设计器的设计结果 16 | * 节点属性。签核人设置、签核类型(会签,串签)、出口配置 17 | * 已签核状态显示 18 | * 错误处理 19 | 20 | ## 支持vue2.x 21 | vue3.x 请见[richform-plus](https://github.com/jingyuLin1999/richform-plus) 22 | 23 | ## 预览 24 | 25 | ### 在线预览 26 | 27 | [表单设计器](http://117.73.12.76/demo/richform/#/ ) 28 | 29 | [富表单完整功能](http://117.73.12.76/demo/richform/#/form-design ) 30 | 31 | ### 本地预览 32 | ``` 33 | npm install 34 | 35 | npm run serve 36 | ``` 37 | [表单设计器](http://localhost:8080/#/ ) 38 | http://localhost:8080/#/ 39 | 40 | [富表单完整功能](http://localhost:8080/#/form-design ) 41 | http://localhost:8080/#/form-design 42 | 43 | ## 用法 44 | ``` 45 | npm i richform -S 46 | ``` 47 | 48 | ```html 49 |
50 |
51 | 52 |
53 |
54 | 55 |
56 |
57 | ``` 58 | 59 | ```js 60 | import { RichForm, FormDesign } from "richform"; 61 | export default { 62 | components: { RichForm,FormDesign}, 63 | data() { 64 | return { 65 | schema: {}, // 验证规则 66 | values: {}, // 表单的值 67 | form: { 68 | border: true, // 显示边框 69 | grid: false, // 表单内部栅栏 70 | labelSuffix: ":", // 字段标题后缀内容,默认' : ' 71 | labelWidth: "110px", // 标签宽度,默认50px 72 | validator: "input", // submit 73 | labelAlign: "right", // 标签对齐, 默认右对齐, 可选左对齐left 74 | labelInline: true, // 字段标题显示位置, 默认true左侧left,false显示在top上方 75 | actions: [ 76 | //声明显示在下方和动作按钮 77 | { 78 | name: "reset", // 按键的唯一标识符 79 | type: "primary", // 按键类型,默认为primary,具体可见element button 80 | title: "重置", // 按键的文字 81 | icon: "el-icon-star-off", // 按键图标 具体可见element icon 82 | right: true, // 如果=true,则显示在右侧 83 | visible: true, // 按键是否可见,同时满足readonly===false和设置为true才会显示,默认为true 84 | tips: "提示信息", // 鼠标悬浮在按键的提示信息 85 | top: true, // 是否在上面, false则在下面 86 | size: "medium" // medium / small / mini, 若未指明,则等同于form.size 87 | }, 88 | { 89 | name: "submit", // 按键的唯一标识符 90 | type: "info", // 按键类型,默认为primary,具体可见element button 91 | title: "提交", // 按键的文字 92 | icon: "", // 按键图标 具体可见element icon 93 | right: true, // 如果=true,则显示在右侧 94 | visible: true, // 按键是否可见,同时满足readonly===false和设置为true才会显示,默认为true 95 | tips: "提示信息", // 鼠标悬浮在按键的提示信息 96 | top: true, // 是否在上面, false则在下面 97 | size: "medium" // medium / small / mini, 若未指明,则等同于form.size 98 | } 99 | ], 100 | layout: [ 101 | { 102 | title: "名称对方", 103 | widget: "input", 104 | name: "input", // values的箭值,必须有 105 | type: "text", 106 | }, 107 | // 更多子组件请见widgets介绍,或者看完整功能 108 | ] 109 | } 110 | } 111 | } 112 | } 113 | ``` 114 | 115 | ## 特殊功能 116 | 1、字段选项依赖 117 | ```js 118 | { 119 | title: "下拉选框B", 120 | widget: "select", 121 | name: "selectB", 122 | description: "我的选项依赖于【下拉选框A】", 123 | dict: { 124 | "selectA==选项1": [ 125 | { 126 | value: "选项1", 127 | label: "根据[下拉选框A]的值变化A", 128 | }, 129 | { 130 | value: "选项2", 131 | label: "根据[下拉选框A]的值变化B", 132 | }, 133 | ], 134 | "selectA == 选项2": "http://localhost:8080/#/form-design", 135 | "input == 123456": [ 136 | { 137 | value: "input等于123456", 138 | label: "input等于123456", 139 | }, 140 | ], 141 | }, 142 | options: [ 143 | { 144 | value: "选项1", 145 | label: "黄金糕", 146 | }, 147 | { 148 | value: "选项2", 149 | label: "双皮奶", 150 | }, 151 | ], 152 | } 153 | ``` 154 | 补充说明 155 | 当两个select的选项互相依赖时,箭值为条件,值可以有三种形式,若是url则获取数据,若是数组则直接赋值给options 156 | ```js 157 | dict: "http://localhost:8080/#/form-design", // 获取到的值会直接覆盖options 158 | dict: { 159 | [<字段名name> == 'A']: "https://shandawang.com/dict/province", // 字典, 160 | [<字段名name> == 'B']: [{},{}], // options 161 | [<字段名name> == 'any']: "https://shandawang.com/dict/province", // 若等于any且值是url,<字段名name>的值只要变化,就会带上<字段名name>值到后端过滤获取字典 162 | [<字段名name> == 'any']: {filterKey: "id"}, // 若等于any且值是对象,filterKey字段和options都必须有。<字段名name>的值只要变化,就会带上<字段名name>值到options中过滤。有一种特殊应用,当被依赖的字段值变化了,根据被依赖选项({label,value,other})的某个字段的值到当前options过滤,此时可配beRelyFilterKey如 {filterKey: "id",beRelyFilterKey: "other"} 163 | } 164 | ``` 165 | 2、字段隐藏依赖 166 | ```js 167 | { 168 | title: "名称对方", 169 | widget: "input", 170 | name: "input", 171 | type: "textarea", 172 | hideRely: "radioA==单选框B", 173 | } 174 | ``` 175 | 补充说明 176 | ```js 177 | hideRely:<字段名称nameA> == 'C', // 可以是单值 178 | hideRely:[ // 也可以是多值,只要满足一个条件,就隐藏,且后面条件不会再校验 179 | <字段名称nameA> == 'C', 180 | <字段名称nameB> == 'D', 181 | ] 182 | ``` 183 | 3、更多widgets配置详情 184 | 请见src/pages/richform.vue 185 | 186 | ## 深度编辑 187 | values可能是深度嵌套如下 188 | ```js 189 | { 190 | title: { 191 | text: "ECharts 入门示例", 192 | subtext: "Living Expenses in Shenzhen", 193 | }, 194 | legend: { 195 | orient: "horizontal", // vertical/horizontal 196 | left: 0, 197 | // top: 0, 198 | bottom: 0, 199 | }, 200 | } 201 | ``` 202 | 要编辑这种valuse可开启deepValues: true 203 | ```html 204 | 205 | ``` 206 | 此时在定义form的name字段和shema结构,需要与values的结构对应 207 | ```js 208 | layout: [{ 209 | title: "标题", 210 | widget: "input", 211 | name: "title.text", 212 | }] 213 | ``` 214 | [例子](http://117.73.12.76/demo/richform/#/deep-values ) 215 | -------------------------------------------------------------------------------- /npm/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function localize_zh(errors) { 3 | if (!(errors && errors.length)) return; 4 | for (var i = 0; i < errors.length; i++) { 5 | var e = errors[i]; 6 | var out; 7 | switch (e.keyword) { 8 | case '$ref': 9 | out = 'Không thể tìm thấy tài liệu tham khảo' + (e.params.ref); 10 | break; 11 | case 'additionalItems': 12 | out = ''; 13 | var n = e.params.limit; 14 | out += 'Không được phép nhiều hơn' + (n) + 'phần tử'; 15 | break; 16 | case 'additionalProperties': 17 | out = 'Không cho phép thuộc tính bên ngoài'; 18 | break; 19 | case 'anyOf': 20 | out = 'Dữ liệu phải là một trong những dữ liệu được chỉ định bởi AnyOf'; 21 | break; 22 | case 'const': 23 | out = 'Phải bằng hằng số'; 24 | break; 25 | case 'contains': 26 | out = 'Nên chứa một mục hợp lệ'; 27 | break; 28 | case 'custom': 29 | out = 'Nên thông qua xác minh từ khóa' + (e.keyword); 30 | break; 31 | case 'dependencies': 32 | out = ''; 33 | var n = e.params.depsCount; 34 | out += 'Nên có thuộc tính phụ thuộc cho thuộc tính ' + (e.params.property) + ":" + (e.params.deps); 35 | break; 36 | case 'enum': 37 | out = 'Phải là một trong những giá trị liệt kê mặc định'; 38 | break; 39 | case 'exclusiveMaximum': 40 | out = ''; 41 | var cond = e.params.comparison + " " + e.params.limit; 42 | out += 'Nên là ' + (cond); 43 | break; 44 | case 'exclusiveMinimum': 45 | out = ''; 46 | var cond = e.params.comparison + " " + e.params.limit; 47 | out += 'Nên là ' + (cond); 48 | break; 49 | case 'false schema': 50 | out = 'Lỗi mẫu Boolean'; 51 | break; 52 | case 'format': 53 | out = 'Phải phù hợp với định dạng "' + (e.params.format) + '"'; 54 | break; 55 | case 'formatExclusiveMaximum': 56 | out = 'formatExclusiveMaximum Phải là giá trị Boolean'; 57 | break; 58 | case 'formatExclusiveMinimum': 59 | out = 'formatExclusiveMinimum Phải là giá trị Boolean'; 60 | break; 61 | case 'formatMaximum': 62 | out = ''; 63 | var cond = e.params.comparison + " " + e.params.limit; 64 | out += 'Nên là ' + (cond); 65 | break; 66 | case 'formatMinimum': 67 | out = ''; 68 | var cond = e.params.comparison + " " + e.params.limit; 69 | out += 'Nên là ' + (cond); 70 | break; 71 | case 'if': 72 | out = 'nên phù hợp với mẫu "' + (e.params.failingKeyword) + '" '; 73 | break; 74 | case 'maximum': 75 | out = ''; 76 | var cond = e.params.comparison + " " + e.params.limit; 77 | out += 'Nên là ' + (cond); 78 | break; 79 | case 'maxItems': 80 | out = ''; 81 | var n = e.params.limit; 82 | out += 'Không nên có nhiều hơn ' + (n) + ' mục'; 83 | break; 84 | case 'maxLength': 85 | out = ''; 86 | var n = e.params.limit; 87 | out += 'Không được nhiều hơn ' + (n) + ' ký tự'; 88 | break; 89 | case 'maxProperties': 90 | out = ''; 91 | var n = e.params.limit; 92 | out += 'Không được có nhiều hơn ' + (n) + ' thuộc tính'; 93 | break; 94 | case 'minimum': 95 | out = ''; 96 | var cond = e.params.comparison + " " + e.params.limit; 97 | out += 'Nên là ' + (cond); 98 | break; 99 | case 'minItems': 100 | out = ''; 101 | var n = e.params.limit; 102 | out += 'Không được ít hơn ' + (n) + ' mục'; 103 | break; 104 | case 'minLength': 105 | out = ''; 106 | var n = e.params.limit; 107 | out += 'Không được ít hơn ' + (n) + ' ký tự'; 108 | break; 109 | case 'minProperties': 110 | out = ''; 111 | var n = e.params.limit; 112 | out += 'Không được có ít hơn ' + (n) + ' thuộc tính'; 113 | break; 114 | case 'multipleOf': 115 | out = 'Phải là bội số nguyên của ' + (e.params.multipleOf); 116 | break; 117 | case 'not': 118 | out = 'không nên phù hợp "not" schema'; 119 | break; 120 | case 'oneOf': 121 | out = 'Chỉ có thể khớp với một trong "oneOf"'; 122 | break; 123 | case 'pattern': 124 | out = 'nên phù hợp với mẫu "' + (e.params.pattern) + '"'; 125 | break; 126 | case 'patternRequired': 127 | out = 'Cần có mẫu khớp thuộc tính ' + (e.params.missingPattern); 128 | break; 129 | case 'propertyNames': 130 | out = 'Tên thuộc tính không hợp lệ \'' + (e.params.propertyName); 131 | break; 132 | case 'required': 133 | out = 'Nên có thuộc tính bắt buộc ' + (e.params.missingProperty); 134 | break; 135 | case 'switch': 136 | out = 'không thông qua hiệu nghiệm "switch" vì' + (e.params.caseIndex) + ' thất bại '; 137 | break; 138 | case 'type': 139 | out = 'Nên thuộc loại ' + (e.params.type); 140 | break; 141 | case 'uniqueItems': 142 | out = 'Không được trùng lặp (mục (' + (e.params.j) + ') và (' + (e.params.i) + ') là trùng lặp)'; 143 | break; 144 | default: 145 | continue; 146 | } 147 | e.message = out; 148 | } 149 | }; 150 | -------------------------------------------------------------------------------- /npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "richform", 3 | "version": "0.11.50", 4 | "private": false, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "build:prod": "vue-cli-service build --target lib --name richform src/components/index.js", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "main": "lib/richform.umd.min.js", 12 | "module": "lib/richform.umd.min.js", 13 | "dependencies": { 14 | "ajv": "^6.12.6", 15 | "ajv-errors": "^1.0.1", 16 | "axios": "^0.21.1", 17 | "core-js": "^3.6.5", 18 | "element-resize-detector": "^1.2.4", 19 | "element-ui": "^2.15.6", 20 | "jquery": "^3.6.0", 21 | "ramda": "^0.27.1", 22 | "vue-baidu-map": "^0.21.22", 23 | "vue-i18n": "^8.28.2", 24 | "vue-scrollto": "^2.20.0", 25 | "vue2-perfect-scrollbar": "^1.5.0", 26 | "vuedraggable": "^2.24.3", 27 | "vxe-table": "^3.4.15", 28 | "xe-utils": "^3.5.4" 29 | }, 30 | "devDependencies": { 31 | "@vue/babel-preset-app": "^5.0.8", 32 | "@vue/cli-plugin-babel": "~4.5.0", 33 | "@vue/cli-plugin-eslint": "~4.5.0", 34 | "@vue/cli-service": "~4.5.0", 35 | "babel-eslint": "^10.1.0", 36 | "babel-polyfill": "^6.26.0", 37 | "es6-promise": "^4.2.8", 38 | "eslint": "^6.7.2", 39 | "eslint-plugin-vue": "^6.2.2", 40 | "node-sass": "^6.0.1", 41 | "sass-loader": "^10.3.1", 42 | "vue-template-compiler": "^2.6.11" 43 | }, 44 | "eslintConfig": { 45 | "root": true, 46 | "env": { 47 | "node": true 48 | }, 49 | "extends": [ 50 | "plugin:vue/essential", 51 | "eslint:recommended" 52 | ], 53 | "parserOptions": { 54 | "parser": "babel-eslint" 55 | }, 56 | "rules": { 57 | "generator-star-spacing": "off", 58 | "no-tabs": "off", 59 | "no-unused-vars": "off", 60 | "no-console": "off", 61 | "no-irregular-whitespace": "off", 62 | "no-debugger": "off" 63 | } 64 | }, 65 | "files": [ 66 | "dist", 67 | "package.json", 68 | "README.md", 69 | "src/i18n/lang" 70 | ], 71 | "browserslist": [ 72 | "> 1%", 73 | "last 2 versions" 74 | ], 75 | "author": "ljy", 76 | "license": "ISC", 77 | "repository": { 78 | "type": "git", 79 | "url": "git+https://github.com/jingyuLin1999/echarts-designer" 80 | } 81 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "richform", 3 | "version": "0.11.50", 4 | "private": false, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "build:prod": "vue-cli-service build --target lib --name richform src/components/index.js", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "main": "dist/richform.umd.min.js", 12 | "module": "dist/richform.umd.min.js", 13 | "dependencies": { 14 | "ajv": "^6.12.6", 15 | "ajv-errors": "^1.0.1", 16 | "ajv-i18n": "^3.3.0", 17 | "axios": "^0.21.4", 18 | "core-js": "^3.6.5", 19 | "element-resize-detector": "^1.2.4", 20 | "element-ui": "^2.15.6", 21 | "jquery": "^3.6.0", 22 | "ramda": "^0.27.1", 23 | "vue": "^2.6.11", 24 | "vue-baidu-map": "^0.21.22", 25 | "vue-i18n": "^8.28.2", 26 | "vue-router": "^3.5.2", 27 | "vue-scrollto": "^2.20.0", 28 | "vue2-perfect-scrollbar": "^1.5.0", 29 | "vuedraggable": "^2.24.3", 30 | "vxe-table": "^3.4.15", 31 | "xe-utils": "^3.5.4" 32 | }, 33 | "devDependencies": { 34 | "@vue/babel-preset-app": "^5.0.8", 35 | "@vue/cli-plugin-babel": "~4.5.0", 36 | "@vue/cli-plugin-eslint": "~4.5.0", 37 | "@vue/cli-service": "~4.5.0", 38 | "babel-eslint": "^10.1.0", 39 | "babel-polyfill": "^6.26.0", 40 | "es6-promise": "^4.2.8", 41 | "eslint": "^6.7.2", 42 | "eslint-plugin-vue": "^6.2.2", 43 | "node-sass": "^6.0.1", 44 | "sass-loader": "^10.3.1", 45 | "vue-template-compiler": "^2.6.11" 46 | }, 47 | "eslintConfig": { 48 | "root": true, 49 | "env": { 50 | "node": true 51 | }, 52 | "extends": [ 53 | "plugin:vue/essential", 54 | "eslint:recommended" 55 | ], 56 | "parserOptions": { 57 | "parser": "babel-eslint" 58 | }, 59 | "rules": { 60 | "generator-star-spacing": "off", 61 | "no-tabs": "off", 62 | "no-unused-vars": "off", 63 | "no-console": "off", 64 | "no-irregular-whitespace": "off", 65 | "no-debugger": "off" 66 | } 67 | }, 68 | "files": [ 69 | "dist", 70 | "package.json", 71 | "README.md", 72 | "src/i18n/lang" 73 | ], 74 | "browserslist": [ 75 | "> 1%", 76 | "last 2 versions" 77 | ], 78 | "author": "ljy", 79 | "license": "ISC", 80 | "repository": { 81 | "type": "git", 82 | "url": "git+https://github.com/jingyuLin1999/richform" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingyuLin1999/richform/46d4f2445f27aa81c072207b44eed535efdea23e/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 29 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingyuLin1999/richform/46d4f2445f27aa81c072207b44eed535efdea23e/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/Formdesign/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingyuLin1999/richform/46d4f2445f27aa81c072207b44eed535efdea23e/src/components/Formdesign/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/components/Formdesign/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingyuLin1999/richform/46d4f2445f27aa81c072207b44eed535efdea23e/src/components/Formdesign/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/components/Formdesign/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingyuLin1999/richform/46d4f2445f27aa81c072207b44eed535efdea23e/src/components/Formdesign/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/components/Formdesign/meta/base.js: -------------------------------------------------------------------------------- 1 | export const baseForm = { 2 | border: false, // 显示边框 3 | grid: false, // 表单内部栅栏 4 | labelSuffix: ":", // 字段标题后缀内容,默认' : ' 5 | labelWidth: "100px", // 标签宽度,默认50px 6 | validator: "input", // submit 7 | labelAlign: "right", // 标签对齐, 默认右对齐, 可选左对齐left 8 | labelInline: true, // 字段标题显示位置, 默认true左侧left,false显示在top上方 9 | colors: { 10 | btnBgColor: "" 11 | } 12 | } 13 | 14 | export const baseValues = { 15 | title: "", 16 | } 17 | 18 | export const baseLayout = [ 19 | { 20 | title: "名称", 21 | name: "name", 22 | size: "small", 23 | widget: "select", 24 | filterable: true, 25 | allowCreate: true, 26 | description: "对应数据库字段", 27 | options: [], 28 | }, 29 | { 30 | title: "标题", 31 | name: "title", 32 | size: "small", 33 | widget: "input" 34 | }, 35 | { 36 | title: "隐藏", 37 | name: "hideRely", 38 | size: "small", 39 | widget: "draggablelist", 40 | // description: "隐藏依赖设置", 41 | template: "", 42 | default: [], 43 | strAttr: { 44 | widget: "expression", 45 | key: { 46 | title: "字段", 47 | show: true, 48 | order: 1, 49 | options: [], 50 | }, 51 | val: { 52 | title: "值", 53 | show: true, 54 | order: 3, 55 | options: [], 56 | }, 57 | } 58 | } 59 | ] 60 | 61 | export const baseRules = { 62 | ...baseForm, 63 | layout: [ 64 | { 65 | title: "类型", 66 | widget: "select", 67 | name: "type", 68 | size: "small", 69 | options: [ 70 | { value: "string", label: "字符串" }, 71 | ], 72 | }, 73 | ] 74 | } -------------------------------------------------------------------------------- /src/components/Formdesign/meta/canvas.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | type: "text", // text,textarea 4 | placeholder: "请输入内容", 5 | disabled: false, // 禁用状态 6 | clearable: true, // 7 | showPassword: false, // 密码框 8 | prefixIcon: "", // 当type等于text有效。前置图标 el-icon-search 9 | suffixIcon: "", // 当type等于text有效。后置图标 el-icon-date 10 | rows: 4, // 当type等于textarea有效 11 | autosize: false, // 当type等于textarea有效。根据内容自动设置高度,也可接受一个对象 { minRows: 2, maxRows: 4} 12 | prepend: "", // 当type等于text有效。 13 | append: "", // 当type等于text有效。 14 | size: "", // large、small 和 mini 15 | maxLength: null, 16 | minLength: null, 17 | * 18 | */ 19 | import { baseForm, baseLayout } from "./base" 20 | export const attribute = { 21 | schema: { 22 | 23 | }, 24 | values: { 25 | 26 | }, 27 | form: { 28 | ...baseForm, 29 | layout: [ 30 | { 31 | title: "表边框", 32 | widget: "select", 33 | name: "border", 34 | size: "small", 35 | options: [ 36 | { 37 | value: true, 38 | label: "是", 39 | }, 40 | { 41 | value: false, 42 | label: "否", 43 | }, 44 | ], 45 | }, 46 | { 47 | title: "表栅栏", 48 | widget: "select", 49 | name: "grid", 50 | size: "small", 51 | options: [ 52 | { 53 | value: true, 54 | label: "是", 55 | }, 56 | { 57 | value: false, 58 | label: "否", 59 | }, 60 | ], 61 | }, 62 | { 63 | title: "对齐方式", 64 | widget: "select", 65 | name: "labelAlign", 66 | size: "small", 67 | options: [ 68 | { 69 | value: "right", 70 | label: "靠右", 71 | }, 72 | { 73 | value: "left", 74 | label: "靠左", 75 | } 76 | ], 77 | }, 78 | { 79 | title: "标签后缀", 80 | widget: "input", 81 | name: "labelSuffix", 82 | size: "small", 83 | }, 84 | { 85 | title: "标签宽度", 86 | widget: "input", 87 | name: "labelWidth", 88 | size: "small", 89 | }, 90 | { 91 | title: "行显示", 92 | widget: "select", 93 | name: "labelInline", 94 | size: "small", 95 | options: [ 96 | { value: true, label: "是" }, 97 | { value: false, label: "否" } 98 | ], 99 | }, 100 | { 101 | widget: "grid", 102 | title: "颜色设置", 103 | showTitle: false, 104 | isClicked: false, 105 | fields: [ 106 | [ 107 | { 108 | title: "主题", 109 | widget: "colorpicker", 110 | name: "colors.theme", 111 | }, 112 | { 113 | title: "按钮字体", 114 | widget: "colorpicker", 115 | name: "colors.btnColor", 116 | }, 117 | { 118 | title: "激活字体", 119 | widget: "colorpicker", 120 | name: "colors.activeColor", 121 | }, 122 | { 123 | title: "多选选项背景", 124 | widget: "colorpicker", 125 | name: "colors.multiOptionBgColor", 126 | }, 127 | ], 128 | [ 129 | { 130 | title: "字体", 131 | widget: "colorpicker", 132 | name: "colors.fontColor", 133 | }, 134 | { 135 | title: "按钮背景", 136 | widget: "colorpicker", 137 | name: "colors.btnBgColor", 138 | }, 139 | { 140 | title: "日期范围背景", 141 | widget: "colorpicker", 142 | name: "colors.dateRangeBgColor", 143 | }, 144 | ] 145 | ] 146 | }, 147 | // { 148 | // title: "恢复主题", 149 | // widget: "button", 150 | // name: "resetTheme", 151 | // size: "small", 152 | // type: "primary" 153 | // }, 154 | ], 155 | } 156 | } 157 | 158 | export const rules = { 159 | schema: {}, 160 | values: { 161 | }, 162 | form: { 163 | ...baseForm, 164 | layout: [] 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/cascader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | disabled: false, 4 | placeholder: "", 5 | filterable: true, // 搜索功能 6 | clearable: true, 7 | separator: "/", // 分隔符 8 | showAllLevels: true, // 结果显示所以级别如:a/b/c 9 | propValue: "value", 10 | propLabel: "label", 11 | expandTrigger: "hover", // click / hover 12 | checkStrictly: false, // 父子节点不互相关联 13 | multiple: false, // 可通过 props.multiple = true 来开启多选模 14 | * 15 | */ 16 | import { baseForm, baseLayout } from "./base" 17 | export const attribute = { 18 | schema: { 19 | 20 | }, 21 | values: { 22 | 23 | }, 24 | form: { 25 | ...baseForm, 26 | layout: [ 27 | ...baseLayout, 28 | { 29 | title: "触发方式", 30 | widget: "select", 31 | name: "expandTrigger", 32 | size: "small", 33 | options: [ 34 | { 35 | value: "hover", 36 | label: "悬停", 37 | }, 38 | { 39 | value: "click ", 40 | label: "点击", 41 | }, 42 | ], 43 | }, 44 | { 45 | title: "标签键值", 46 | widget: "input", 47 | name: "propLabel", 48 | size: "small" 49 | }, 50 | { 51 | title: "值键值", 52 | widget: "input", 53 | name: "propValue", 54 | size: "small" 55 | }, 56 | { 57 | widget: "grid", 58 | title: "栅格布局", 59 | showTitle: false, 60 | isClicked: false, 61 | fields: [ 62 | [ 63 | { 64 | name: "clearable", 65 | title: "可清空", 66 | widget: "switch", 67 | width: 40, // 宽度 68 | activeColor: "#13ce66", // 激活背景颜色 69 | inactiveColor: "#ccc", // 取消背景颜色 70 | activeValue: true, // 打开的值,支持Boolean, String或Number 71 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 72 | }, 73 | { 74 | name: "filterable", 75 | title: "过滤", 76 | widget: "switch", 77 | width: 40, // 宽度 78 | activeColor: "#13ce66", // 激活背景颜色 79 | inactiveColor: "#ccc", // 取消背景颜色 80 | activeValue: true, // 打开的值,支持Boolean, String或Number 81 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 82 | }, 83 | { 84 | name: "multiple", 85 | title: "多选", 86 | widget: "switch", 87 | width: 40, // 宽度 88 | activeColor: "#13ce66", // 激活背景颜色 89 | inactiveColor: "#ccc", // 取消背景颜色 90 | activeValue: true, // 打开的值,支持Boolean, String或Number 91 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 92 | } 93 | ], [ 94 | { 95 | name: "disabled", 96 | title: "禁用", 97 | widget: "switch", 98 | width: 40, // 宽度 99 | activeColor: "#13ce66", // 激活背景颜色 100 | inactiveColor: "#ccc", // 取消背景颜色 101 | activeValue: true, // 打开的值,支持Boolean, String或Number 102 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 103 | }, 104 | { 105 | name: "showAllLevels", 106 | title: "所有级别", 107 | widget: "switch", 108 | width: 40, // 宽度 109 | activeColor: "#13ce66", // 激活背景颜色 110 | inactiveColor: "#ccc", // 取消背景颜色 111 | activeValue: true, // 打开的值,支持Boolean, String或Number 112 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 113 | }, 114 | { 115 | name: "checkStrictly", 116 | title: "严格模式", 117 | widget: "switch", 118 | width: 40, // 宽度 119 | activeColor: "#13ce66", // 激活背景颜色 120 | inactiveColor: "#ccc", // 取消背景颜色 121 | activeValue: true, // 打开的值,支持Boolean, String或Number 122 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 123 | }, 124 | ] 125 | ] 126 | }, 127 | { 128 | title: "分隔符", 129 | widget: "input", 130 | name: "separator", 131 | size: "small", 132 | hideRely: "showAllLevels==false", 133 | }, 134 | { 135 | title: "数据配置", 136 | widget: "tree", 137 | name: "options", 138 | addSibling: true, 139 | editable: true, 140 | deletable: true, 141 | addable: true, 142 | draggable: true, // 开启拖拽 143 | isShowIcon: false, 144 | showAddTemplate: true, 145 | }, 146 | ], 147 | } 148 | } 149 | 150 | export const rules = { 151 | schema: {}, 152 | values: {}, 153 | form: { 154 | ...baseForm, 155 | layout: [] 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/checkbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | isGroup: false, // 为true时,options有效即多选框组生效,value必须为array 4 | isButton: false, // 功能:指明多选框组为按钮形式 5 | max: 10000, // 生效:多选框组 功能:规定可以选择的范围 6 | min: 0, // 生效:多选框组 功能:规定可以选择的范围 7 | disabled: false, // 生效:多选框组或单个 说明:优先级高于子checkbox 8 | border: false, 9 | size: "", // medium / small / mini 说明:仅对按钮形式或带有边框的Checkbox有效 10 | textColor: "#ffffff", // 按钮有效 11 | fill: "#409EFF", // 按钮有效 12 | chooseAll: false, 13 | * 14 | */ 15 | import { baseForm, baseLayout } from "./base" 16 | export const attribute = { 17 | schema: { 18 | 19 | }, 20 | values: { 21 | 22 | }, 23 | form: { 24 | ...baseForm, 25 | layout: [ 26 | ...baseLayout, 27 | { 28 | title: "尺寸", 29 | widget: "select", 30 | name: "size", 31 | size: "small", 32 | options: [ 33 | { 34 | value: "medium", 35 | label: "大", 36 | }, 37 | { 38 | value: "small ", 39 | label: "中", 40 | }, 41 | { 42 | value: "mini", 43 | label: "小", 44 | }, 45 | ], 46 | }, 47 | { 48 | title: "选项", 49 | widget: "draggablelist", 50 | name: "options", 51 | template: { title: "", name: "" }, 52 | attribute: { 53 | title: { widget: "input", placeholder: "", editable: true }, 54 | name: { widget: "input", placeholder: "", editable: true }, 55 | }, 56 | default: [] 57 | }, 58 | { 59 | widget: "grid", 60 | title: "栅格布局", 61 | showTitle: false, 62 | isClicked: false, 63 | fields: [ 64 | [ 65 | { 66 | name: "isGroup", 67 | title: "多选框组", 68 | widget: "switch", 69 | width: 40, // 宽度 70 | activeColor: "#13ce66", // 激活背景颜色 71 | inactiveColor: "#ccc", // 取消背景颜色 72 | activeValue: true, // 打开的值,支持Boolean, String或Number 73 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 74 | }, 75 | { 76 | name: "disabled", 77 | title: "禁用", 78 | widget: "switch", 79 | width: 40, // 宽度 80 | activeColor: "#13ce66", // 激活背景颜色 81 | inactiveColor: "#ccc", // 取消背景颜色 82 | activeValue: true, // 打开的值,支持Boolean, String或Number 83 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 84 | }, 85 | { 86 | title: "字体颜色", 87 | widget: "colorpicker", 88 | name: "textColor", 89 | hideRely: "isButton==false", 90 | }, 91 | ], [ 92 | { 93 | name: "isButton", 94 | title: "按钮", 95 | widget: "switch", 96 | width: 40, // 宽度 97 | activeColor: "#13ce66", // 激活背景颜色 98 | inactiveColor: "#ccc", // 取消背景颜色 99 | activeValue: true, // 打开的值,支持Boolean, String或Number 100 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 101 | }, 102 | { 103 | name: "border", 104 | title: "边界", 105 | widget: "switch", 106 | width: 40, // 宽度 107 | activeColor: "#13ce66", // 激活背景颜色 108 | inactiveColor: "#ccc", // 取消背景颜色 109 | activeValue: true, // 打开的值,支持Boolean, String或Number 110 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 111 | }, 112 | { 113 | title: "填充颜色", 114 | widget: "colorpicker", 115 | name: "fill", 116 | hideRely: "isButton==false", 117 | }, 118 | ] 119 | ] 120 | }, 121 | ], 122 | } 123 | } 124 | 125 | export const rules = { 126 | schema: {}, 127 | values: { 128 | 129 | }, 130 | form: { 131 | ...baseForm, 132 | layout: [ 133 | 134 | ] 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/collapse.js: -------------------------------------------------------------------------------- 1 | import { baseForm, baseLayout } from "./base" 2 | export const attribute = { 3 | schema: { 4 | 5 | }, 6 | values: { 7 | 8 | }, 9 | form: { 10 | ...baseForm, 11 | layout: [ 12 | { 13 | title: "标题", 14 | name: "title", 15 | size: "small", 16 | widget: "input" 17 | }, 18 | ], 19 | } 20 | } 21 | 22 | export const rules = { 23 | schema: {}, 24 | values: {}, 25 | form: { 26 | ...baseForm 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/colorpicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | predefineColors: ["#409EFF", "#f00"], // 预定义颜色 4 | disabled: false, 5 | size: "small", // 选项: medium / small / mini 6 | showAlpha: false, 7 | popperClass: "", 8 | colorFormat: "", //单位选项:hsl / hsv / hex / rgb 说明:写入 v-model 的颜色的格式 9 | defaultColor: "#1278F6", 10 | * 11 | */ 12 | import { baseForm, baseLayout } from "./base" 13 | export const attribute = { 14 | schema: { 15 | 16 | }, 17 | values: { 18 | 19 | }, 20 | form: { 21 | ...baseForm, 22 | layout: [ 23 | ...baseLayout, 24 | { 25 | title: "单位", // 优先级小于shema中定义的title 26 | widget: "select", 27 | name: "selectMultiple", 28 | filterable: true, 29 | size: "small", 30 | options: [ 31 | { 32 | value: "hsl", 33 | label: "hsl", 34 | }, 35 | { 36 | value: "hsv", 37 | label: "hsv", 38 | }, 39 | { 40 | value: "hex", 41 | label: "hex", 42 | }, 43 | { 44 | value: "rgb", 45 | label: "rgb", 46 | }, 47 | ], 48 | }, 49 | { 50 | title: "默认颜色", 51 | widget: "colorpicker", 52 | name: "default", 53 | default: "#f00" 54 | }, 55 | { 56 | widget: "grid", 57 | title: "栅格布局", 58 | showTitle: false, 59 | isClicked: false, 60 | fields: [ 61 | [ 62 | { 63 | name: "disabled", 64 | title: "禁用", 65 | widget: "switch", 66 | width: 40, // 宽度 67 | activeColor: "#13ce66", // 激活背景颜色 68 | inactiveColor: "#ccc", // 取消背景颜色 69 | activeValue: true, // 打开的值,支持Boolean, String或Number 70 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 71 | } 72 | ], [ 73 | { 74 | name: "showAlpha", 75 | title: "透明度", 76 | widget: "switch", 77 | width: 40, // 宽度 78 | activeColor: "#13ce66", // 激活背景颜色 79 | inactiveColor: "#ccc", // 取消背景颜色 80 | activeValue: true, // 打开的值,支持Boolean, String或Number 81 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 82 | } 83 | ] 84 | ] 85 | }, 86 | ], 87 | } 88 | } 89 | 90 | export const rules = { 91 | schema: {}, 92 | values: { 93 | type: "string", 94 | }, 95 | form: { 96 | ...baseForm, 97 | layout: [ 98 | 99 | ] 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/datetimepicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | title: "日期选择器", 4 | type: "daterange", // year/month/date/dates/ week/datetime/datetimerange/daterange/monthrange 5 | readOnly: false, 6 | disabled: false, 7 | clearable: true, // 是否显示清除按钮 8 | size: "", // medium / small / mini 9 | editable: false, // 文本框可输入 10 | placeholder: "请选择", // 单个 11 | format: "", // 显示的格式,注意和type配套 12 | valueFormat: "yyyy-MM-dd", // yyyy-MM-dd/timestamp 指定值的格式 13 | arrowControl: true, 14 | rangeSeparator: "至", // 选择范围时的分隔符 15 | startPlaceholder: "开始时间", 16 | endPlaceholder: "结束时间", 17 | pickerOptions: {}, 18 | * 19 | */ 20 | import { baseForm, baseLayout } from "./base" 21 | export const attribute = { 22 | schema: { 23 | 24 | }, 25 | values: { 26 | 27 | }, 28 | form: { 29 | ...baseForm, 30 | layout: [ 31 | ...baseLayout, 32 | { 33 | title: "类型", 34 | widget: "select", 35 | name: "type", 36 | size: "small", 37 | options: [ 38 | { 39 | value: "year", 40 | label: "年", 41 | }, 42 | { 43 | value: "month", 44 | label: "月", 45 | }, 46 | { 47 | value: "date", 48 | label: "日期", 49 | }, 50 | { 51 | value: "dates", 52 | label: "多个日期", 53 | }, 54 | { 55 | value: "week", 56 | label: "星期", 57 | }, 58 | { 59 | value: "datetime", 60 | label: "日期时间", 61 | }, 62 | { 63 | value: "datetimerange", 64 | label: "日期时间范围", 65 | }, 66 | { 67 | value: "daterange", 68 | label: "日期范围", 69 | }, 70 | { 71 | value: "monthrange", 72 | label: "月份范围", 73 | }, 74 | ], 75 | }, 76 | { 77 | title: "尺寸", 78 | widget: "select", 79 | name: "size", 80 | size: "small", 81 | options: [ 82 | { 83 | value: "medium", 84 | label: "大", 85 | }, 86 | { 87 | value: "small ", 88 | label: "中", 89 | }, 90 | { 91 | value: "mini", 92 | label: "小", 93 | }, 94 | ], 95 | }, 96 | { 97 | title: "占位符", 98 | name: "placeholder", 99 | size: "small", 100 | widget: "input" 101 | }, 102 | { 103 | widget: "input", 104 | title: "开始占位符", 105 | name: "startPlaceholder", 106 | size: "small" 107 | }, 108 | { 109 | widget: "input", 110 | title: "结束占位符", 111 | name: "endPlaceholder", 112 | size: "small" 113 | }, 114 | { 115 | widget: "input", 116 | title: "分隔符", 117 | name: "rangeSeparator", 118 | size: "small" 119 | }, 120 | { 121 | widget: "grid", 122 | title: "栅格布局", 123 | showTitle: false, 124 | isClicked: false, 125 | fields: [ 126 | [ 127 | { 128 | name: "readOnly", 129 | title: "只读", 130 | widget: "switch", 131 | width: 40, // 宽度 132 | activeColor: "#13ce66", // 激活背景颜色 133 | inactiveColor: "#ccc", // 取消背景颜色 134 | activeValue: true, // 打开的值,支持Boolean, String或Number 135 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 136 | hideRely: "type==textarea", 137 | }, 138 | { 139 | name: "clearable", 140 | title: "可清除", 141 | widget: "switch", 142 | width: 40, // 宽度 143 | activeColor: "#13ce66", // 激活背景颜色 144 | inactiveColor: "#ccc", // 取消背景颜色 145 | activeValue: true, // 打开的值,支持Boolean, String或Number 146 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 147 | hideRely: "type==textarea", 148 | } 149 | ], [ 150 | { 151 | name: "disabled", 152 | title: "禁用", 153 | widget: "switch", 154 | width: 40, // 宽度 155 | activeColor: "#13ce66", // 激活背景颜色 156 | inactiveColor: "#ccc", // 取消背景颜色 157 | activeValue: true, // 打开的值,支持Boolean, String或Number 158 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 159 | hideRely: "type==textarea", 160 | }, 161 | { 162 | name: "arrowControl", 163 | title: "箭头", 164 | widget: "switch", 165 | width: 40, // 宽度 166 | activeColor: "#13ce66", // 激活背景颜色 167 | inactiveColor: "#ccc", // 取消背景颜色 168 | activeValue: true, // 打开的值,支持Boolean, String或Number 169 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 170 | hideRely: "type==textarea", 171 | } 172 | ] 173 | ] 174 | }, 175 | ], 176 | } 177 | } 178 | 179 | export const rules = { 180 | schema: {}, 181 | values: { 182 | }, 183 | form: { 184 | ...baseForm, 185 | layout: [] 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/grid.js: -------------------------------------------------------------------------------- 1 | import { baseForm, baseLayout } from "./base" 2 | export const attribute = { 3 | schema: { 4 | 5 | }, 6 | values: { 7 | 8 | }, 9 | form: { 10 | ...baseForm, 11 | layout: [ 12 | ...baseLayout, 13 | { 14 | title: "比例", 15 | name: "ratio", 16 | widget: "input", 17 | description: "和列数对应,中间用英文字符:隔开", 18 | size: "small", 19 | placeholder: "如: 1:1" 20 | }, 21 | { 22 | title: "列数", 23 | name: "fields", 24 | widget: "draggablelist", 25 | template: [] 26 | }, 27 | ], 28 | } 29 | } 30 | 31 | export const rules = { 32 | schema: {}, 33 | values: { 34 | 35 | }, 36 | form: { 37 | ...baseForm, 38 | layout: [ 39 | 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/icon.js: -------------------------------------------------------------------------------- 1 | import { baseForm, baseLayout } from "./base" 2 | export const attribute = { 3 | schema: { 4 | 5 | }, 6 | values: {}, 7 | form: { 8 | ...baseForm, 9 | layout: [ 10 | ...baseLayout, 11 | { 12 | title: "尺寸", 13 | widget: "select", 14 | name: "size", 15 | size: "small", 16 | options: [ 17 | { 18 | value: "medium", 19 | label: "大", 20 | }, 21 | { 22 | value: "small ", 23 | label: "中", 24 | }, 25 | { 26 | value: "mini", 27 | label: "小", 28 | }, 29 | ], 30 | }, 31 | { 32 | title: "禁用", 33 | widget: "select", 34 | name: "disabled", 35 | size: "small", 36 | options: [ 37 | { 38 | value: true, 39 | label: "是", 40 | }, 41 | { 42 | value: false, 43 | label: "否", 44 | } 45 | ], 46 | }, 47 | { 48 | title: "字体大小", 49 | widget: "input", 50 | name: "fontSize", 51 | size: "small" 52 | }, 53 | ], 54 | } 55 | } 56 | 57 | export const rules = { 58 | schema: {}, 59 | values: {}, 60 | form: { 61 | ...baseForm, 62 | layout: [] 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/input.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | type: "text", // text,textarea 4 | placeholder: "请输入内容", 5 | disabled: false, // 禁用状态 6 | clearable: true, // 7 | showPassword: false, // 密码框 8 | prefixIcon: "", // 当type等于text有效。前置图标 el-icon-search 9 | suffixIcon: "", // 当type等于text有效。后置图标 el-icon-date 10 | rows: 4, // 当type等于textarea有效 11 | autosize: false, // 当type等于textarea有效。根据内容自动设置高度,也可接受一个对象 { minRows: 2, maxRows: 4} 12 | prepend: "", // 当type等于text有效。 13 | append: "", // 当type等于text有效。 14 | size: "", // large、small 和 mini 15 | maxLength: null, 16 | minLength: null, 17 | * 18 | */ 19 | import { baseForm, baseLayout } from "./base" 20 | export const attribute = { 21 | schema: { 22 | 23 | }, 24 | values: { 25 | 26 | }, 27 | form: { 28 | ...baseForm, 29 | layout: [ 30 | ...baseLayout, 31 | { 32 | title: "占位符", 33 | name: "placeholder", 34 | size: "small", 35 | widget: "input" 36 | }, 37 | { 38 | title: "类型", 39 | widget: "select", 40 | name: "type", 41 | size: "small", 42 | options: [ 43 | { 44 | value: "text", 45 | label: "文本", 46 | }, 47 | { 48 | value: "textarea", 49 | label: "多行文本框", 50 | }, 51 | ], 52 | }, 53 | { 54 | title: "尺寸", 55 | widget: "select", 56 | name: "size", 57 | size: "small", 58 | options: [ 59 | { 60 | value: "medium", 61 | label: "大", 62 | }, 63 | { 64 | value: "small ", 65 | label: "中", 66 | }, 67 | { 68 | value: "mini", 69 | label: "小", 70 | }, 71 | ], 72 | }, 73 | { 74 | title: "禁用", 75 | widget: "select", 76 | name: "disabled", 77 | size: "small", 78 | options: [ 79 | { 80 | value: true, 81 | label: "是", 82 | }, 83 | { 84 | value: false, 85 | label: "否", 86 | } 87 | ], 88 | }, 89 | { 90 | widget: "grid", 91 | title: "栅格布局", 92 | showTitle: false, 93 | isClicked: false, 94 | fields: [ 95 | [ 96 | { 97 | name: "clearable", 98 | title: "可清空", 99 | widget: "switch", 100 | width: 40, // 宽度 101 | activeColor: "#13ce66", // 激活背景颜色 102 | inactiveColor: "#ccc", // 取消背景颜色 103 | activeValue: true, // 打开的值,支持Boolean, String或Number 104 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 105 | hideRely: "type==textarea", 106 | } 107 | ], [ 108 | { 109 | name: "showPassword", 110 | title: "密码框", 111 | widget: "switch", 112 | width: 40, // 宽度 113 | activeColor: "#13ce66", // 激活背景颜色 114 | inactiveColor: "#ccc", // 取消背景颜色 115 | activeValue: true, // 打开的值,支持Boolean, String或Number 116 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 117 | hideRely: "type==textarea", 118 | } 119 | ] 120 | ] 121 | }, 122 | ], 123 | } 124 | } 125 | 126 | export const rules = { 127 | schema: {}, 128 | values: { 129 | type: "string", 130 | }, 131 | form: { 132 | ...baseForm, 133 | layout: [ 134 | { 135 | title: "类型", 136 | widget: "select", 137 | name: "type", 138 | size: "small", 139 | options: [ 140 | { 141 | value: "string", 142 | label: "字符串", 143 | }, 144 | { 145 | value: "number", 146 | label: "数字", 147 | }, 148 | ], 149 | }, 150 | { 151 | title: "最小值", 152 | name: "minimum", 153 | widget: "inputnumber", 154 | step: 1, // 步数 155 | min: 0, 156 | default: 0, 157 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 158 | precision: undefined, // 精度,设置计数器最小值 159 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 160 | size: "mini", 161 | hideRely: "type==string", 162 | }, 163 | { 164 | title: "最大值", 165 | name: "maximum", 166 | widget: "inputnumber", 167 | step: 1, // 步数 168 | min: 0, 169 | default: 255, 170 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 171 | precision: undefined, // 精度,设置计数器最小值 172 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 173 | size: "mini", 174 | hideRely: "type==string", 175 | }, 176 | { 177 | title: "最小长度", 178 | name: "minLength", 179 | widget: "inputnumber", 180 | step: 1, // 步数 181 | min: 0, 182 | max: 255, 183 | default: 0, 184 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 185 | precision: undefined, // 精度,设置计数器最小值 186 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 187 | size: "mini", 188 | hideRely: "type==number", 189 | }, 190 | { 191 | title: "最大长度", 192 | name: "maxLength", 193 | widget: "inputnumber", 194 | step: 1, // 步数 195 | min: 0, 196 | max: 255, 197 | default: 255, 198 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 199 | precision: undefined, // 精度,设置计数器最小值 200 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 201 | size: "mini", 202 | hideRely: "type==number", 203 | }, 204 | 205 | ] 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/inputnumber.js: -------------------------------------------------------------------------------- 1 | /** 2 | disabled: false, 3 | step: 1, // 步数 4 | min: undefined, 5 | max: undefined, 6 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 7 | precision: undefined, // 精度,设置计数器最小值 8 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 9 | size: "", 10 | */ 11 | 12 | import { baseForm, baseLayout } from "./base"; 13 | 14 | export const attribute = { 15 | values: { 16 | step: 1, 17 | min: 0, 18 | max: 256, 19 | disabled: false, 20 | }, 21 | form: { 22 | ...baseForm, 23 | layout: [ 24 | ...baseLayout, 25 | { 26 | title: "尺寸", 27 | widget: "select", 28 | name: "size", 29 | size: "small", 30 | options: [ 31 | { 32 | value: "medium", 33 | label: "大", 34 | }, 35 | { 36 | value: "small ", 37 | label: "中", 38 | }, 39 | { 40 | value: "mini", 41 | label: "小", 42 | }, 43 | ], 44 | }, 45 | { 46 | title: "按钮位置", 47 | widget: "select", 48 | name: "controlsPosition", 49 | size: "small", 50 | options: [ 51 | { 52 | value: "", 53 | label: "默认", 54 | }, 55 | { 56 | value: "right", 57 | label: "右边", 58 | }, 59 | ], 60 | }, 61 | { 62 | title: "禁用", 63 | widget: "select", 64 | name: "disabled", 65 | size: "small", 66 | options: [ 67 | { 68 | value: true, 69 | label: "是", 70 | }, 71 | { 72 | value: false, 73 | label: "否", 74 | }, 75 | ], 76 | }, 77 | { 78 | name: "step", 79 | title: "步经", 80 | widget: "inputnumber", 81 | step: 1, 82 | controlsPosition: "", 83 | size: "small", 84 | }, 85 | { 86 | name: "min", 87 | title: "最小", 88 | widget: "inputnumber", 89 | step: 1, 90 | controlsPosition: "", 91 | size: "small", 92 | }, 93 | { 94 | name: "max", 95 | title: "最大", 96 | widget: "inputnumber", 97 | step: 1, 98 | controlsPosition: "", 99 | size: "small", 100 | }, 101 | // { 102 | // name: "stepStrictly", 103 | // title: "严格步经", 104 | // widget: "switch", 105 | // description: "只能输入 步经 的倍数" 106 | // }, 107 | ], 108 | } 109 | } 110 | 111 | export const rules = { 112 | schema: {}, 113 | values: {}, 114 | form: { 115 | ...baseForm, 116 | layout: [ 117 | { 118 | title: "最小值", 119 | name: "minimum", 120 | widget: "inputnumber", 121 | step: 1, // 步数 122 | min: 0, 123 | default: 0, 124 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 125 | precision: undefined, // 精度,设置计数器最小值 126 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 127 | size: "mini", 128 | }, 129 | { 130 | title: "最大值", 131 | name: "maximum", 132 | widget: "inputnumber", 133 | step: 1, // 步数 134 | min: 0, 135 | default: 255, 136 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 137 | precision: undefined, // 精度,设置计数器最小值 138 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 139 | size: "mini", 140 | }, 141 | ] 142 | } 143 | } -------------------------------------------------------------------------------- /src/components/Formdesign/meta/ipinput.js: -------------------------------------------------------------------------------- 1 | import { baseForm, baseLayout } from "./base" 2 | export const attribute = { 3 | schema: { 4 | 5 | }, 6 | values: { 7 | 8 | }, 9 | form: { 10 | ...baseForm, 11 | layout: [ 12 | ...baseLayout, 13 | // { 14 | // title: "前置内容", 15 | // name: "prepend", 16 | // size: "small", 17 | // widget: "input" 18 | // }, 19 | // { 20 | // title: "后置内容", 21 | // name: "append", 22 | // size: "small", 23 | // widget: "input" 24 | // }, 25 | ], 26 | } 27 | } 28 | 29 | export const rules = { 30 | schema: {}, 31 | values: {}, 32 | form: { 33 | ...baseForm, 34 | layout: [] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/radio.js: -------------------------------------------------------------------------------- 1 | /** 2 | isGroup: true, 3 | isButton: false, 4 | disabled: true, 5 | border: false, 6 | size: "", // medium / small / mini 7 | textColor: "", // 当isButton为true时有效 8 | fill: "", // 当isButton为true时有效 9 | */ 10 | 11 | import { baseForm, baseLayout } from "./base"; 12 | 13 | export const attribute = { 14 | values: {}, 15 | form: { 16 | ...baseForm, 17 | layout: [ 18 | ...baseLayout, 19 | { 20 | title: "尺寸", 21 | widget: "select", 22 | name: "size", 23 | size: "small", 24 | options: [ 25 | { 26 | value: "medium", 27 | label: "大", 28 | }, 29 | { 30 | value: "small ", 31 | label: "中", 32 | }, 33 | { 34 | value: "mini", 35 | label: "小", 36 | }, 37 | ], 38 | }, 39 | { 40 | title: "选项", 41 | widget: "draggablelist", 42 | name: "options", 43 | template: { title: "", name: "" }, 44 | attribute: { 45 | title: { widget: "input", placeholder: "", editable: true }, 46 | name: { widget: "input", placeholder: "", editable: true }, 47 | }, 48 | }, 49 | { 50 | widget: "grid", 51 | showTitle: false, 52 | isClicked: false, 53 | fields: [ 54 | [ 55 | { 56 | name: "isButton", 57 | title: "按钮", 58 | widget: "switch", 59 | width: 40, // 宽度 60 | activeColor: "#13ce66", // 激活背景颜色 61 | inactiveColor: "#ccc", // 取消背景颜色 62 | activeValue: true, // 打开的值,支持Boolean, String或Number 63 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 64 | }, 65 | { 66 | name: "border", 67 | title: "边框", 68 | widget: "switch", 69 | width: 40, // 宽度 70 | activeColor: "#13ce66", // 激活背景颜色 71 | inactiveColor: "#ccc", // 取消背景颜色 72 | activeValue: true, // 打开的值,支持Boolean, String或Number 73 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 74 | } 75 | ], 76 | [ 77 | { 78 | name: "isGroup", 79 | title: "分组", 80 | widget: "switch", 81 | width: 40, // 宽度 82 | activeColor: "#13ce66", // 激活背景颜色 83 | inactiveColor: "#ccc", // 取消背景颜色 84 | activeValue: true, // 打开的值,支持Boolean, String或Number 85 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 86 | }, 87 | { 88 | name: "disabled", 89 | title: "禁用", 90 | widget: "switch", 91 | width: 40, // 宽度 92 | activeColor: "#13ce66", // 激活背景颜色 93 | inactiveColor: "#ccc", // 取消背景颜色 94 | activeValue: true, // 打开的值,支持Boolean, String或Number 95 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 96 | } 97 | ], 98 | ] 99 | } 100 | ], 101 | } 102 | } 103 | 104 | export const rules = { 105 | schema: {}, 106 | values: {}, 107 | form: { 108 | ...baseForm, 109 | layout: [ 110 | { 111 | title: "类型", 112 | widget: "select", 113 | name: "type", 114 | size: "small", 115 | default: "string", 116 | options: [ 117 | { 118 | value: "string", 119 | label: "字符串", 120 | }, 121 | { 122 | value: "number", 123 | label: "数字", 124 | }, 125 | ], 126 | }, 127 | ] 128 | } 129 | } -------------------------------------------------------------------------------- /src/components/Formdesign/meta/rate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | disabled: false, 4 | colors: ["#99A9BF", "#F7BA2A", "#FF9900"], // 等同于 { 2: '#99A9BF', 4: { value: '#F7BA2A', excluded: true }, 5: '#FF9900' } 5 | showText: false, 6 | texts: ["极差", "失望", "一般", "满意", "惊喜"], // 1、showText为true有效 2、数组长度要和max对应 7 | showScore: false, // texts优先级大于texts 8 | textColor: "#ff9900", // 字体颜色 9 | max: 5, // 最大分值,即有几个星星 10 | allowHalf: false, // 是否允许半选 11 | scoreTemplate: `${this.value}`, // 显示模板,优先级大于value,默认等于value 12 | lowThreshold: 2, 13 | highThreshold: 4, 14 | * 15 | */ 16 | import { baseForm, baseLayout } from "./base" 17 | export const attribute = { 18 | schema: { 19 | 20 | }, 21 | values: { 22 | 23 | }, 24 | form: { 25 | ...baseForm, 26 | layout: [ 27 | ...baseLayout, 28 | { 29 | name: "max", 30 | title: "最大分值", 31 | widget: "inputnumber", 32 | }, 33 | { 34 | name: "showText", 35 | title: "显示文本", 36 | widget: "switch", 37 | width: 40, // 宽度 38 | activeColor: "#13ce66", // 激活背景颜色 39 | inactiveColor: "#ccc", // 取消背景颜色 40 | activeValue: true, // 打开的值,支持Boolean, String或Number 41 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 42 | }, 43 | { 44 | title: "选项", 45 | widget: "draggablelist", 46 | name: "texts", 47 | template: "", 48 | default: [], 49 | hideRely: "showText==false", 50 | description: "个数和最大分值对应" 51 | }, 52 | { 53 | widget: "grid", 54 | title: "栅格布局", 55 | showTitle: false, 56 | isClicked: false, 57 | fields: [ 58 | [ 59 | { 60 | name: "allowHalf", 61 | title: "半选", 62 | widget: "switch", 63 | width: 40, // 宽度 64 | activeColor: "#13ce66", // 激活背景颜色 65 | inactiveColor: "#ccc", // 取消背景颜色 66 | activeValue: true, // 打开的值,支持Boolean, String或Number 67 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 68 | }, 69 | ], [ 70 | { 71 | name: "disabled", 72 | title: "禁用", 73 | widget: "switch", 74 | width: 40, // 宽度 75 | activeColor: "#13ce66", // 激活背景颜色 76 | inactiveColor: "#ccc", // 取消背景颜色 77 | activeValue: true, // 打开的值,支持Boolean, String或Number 78 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 79 | }, 80 | ] 81 | ] 82 | }, 83 | ], 84 | } 85 | } 86 | 87 | export const rules = { 88 | schema: {}, 89 | values: { 90 | 91 | }, 92 | form: { 93 | ...baseForm, 94 | layout: [ 95 | 96 | ] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/select.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | isGroup: false, // 是否分组 4 | placeholder: "请选择", 5 | size: "", 6 | disabled: false, // 说明:当该属性在字典中,则禁用对应的选项。若在field.disable则禁用整个选择器 7 | clearable: false, // 说明:可清空选项 注意:仅单选有效 8 | multiple: false, // 说明:是否支持多选 9 | collapseTags: false, // 多选用tags显示 10 | filterable: false, // 说明:搜索label 11 | allowCreate: false, // 说明:是否允许创建条目,谨慎使用 注意:filterable为true时有效 12 | */ 13 | 14 | import { baseForm, baseLayout } from "./base"; 15 | 16 | export const attribute = { 17 | schema: {}, 18 | values: { 19 | // type: "string" 20 | }, 21 | form: { 22 | ...baseForm, 23 | layout: [ 24 | ...baseLayout, 25 | { 26 | title: "占位符", 27 | name: "placeholder", 28 | size: "small", 29 | widget: "input" 30 | }, 31 | { 32 | title: "尺寸", 33 | widget: "select", 34 | name: "size", 35 | size: "small", 36 | options: [ 37 | { 38 | value: "medium", 39 | label: "大", 40 | }, 41 | { 42 | value: "small ", 43 | label: "中", 44 | }, 45 | { 46 | value: "mini", 47 | label: "小", 48 | }, 49 | ], 50 | }, 51 | { 52 | title: "选项", 53 | widget: "draggablelist", 54 | name: "options", 55 | default: [] 56 | }, 57 | { 58 | widget: "grid", 59 | showTitle: false, 60 | isClicked: false, 61 | fields: [ 62 | [ 63 | { 64 | name: "isGroup", 65 | title: "分组", 66 | widget: "switch", 67 | width: 40, // 宽度 68 | activeColor: "#13ce66", // 激活背景颜色 69 | inactiveColor: "#ccc", // 取消背景颜色 70 | activeValue: true, // 打开的值,支持Boolean, String或Number 71 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 72 | description: "分组option结构特殊,具体请见element" 73 | } 74 | ], [ 75 | { 76 | name: "disabled", 77 | title: "禁用", 78 | widget: "switch", 79 | width: 40, // 宽度 80 | activeColor: "#13ce66", // 激活背景颜色 81 | inactiveColor: "#ccc", // 取消背景颜色 82 | activeValue: true, // 打开的值,支持Boolean, String或Number 83 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 84 | } 85 | ] 86 | ] 87 | }, 88 | { 89 | widget: "grid", 90 | showTitle: false, 91 | isClicked: false, 92 | fields: [ 93 | [ 94 | { 95 | name: "clearable", 96 | title: "可清空", 97 | widget: "switch", 98 | width: 40, // 宽度 99 | activeColor: "#13ce66", // 激活背景颜色 100 | inactiveColor: "#ccc", // 取消背景颜色 101 | activeValue: true, // 打开的值,支持Boolean, String或Number 102 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 103 | } 104 | ], [ 105 | { 106 | name: "multiple", 107 | title: "多选", 108 | widget: "switch", 109 | width: 40, // 宽度 110 | activeColor: "#13ce66", // 激活背景颜色 111 | inactiveColor: "#ccc", // 取消背景颜色 112 | activeValue: true, // 打开的值,支持Boolean, String或Number 113 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 114 | hideRely: "type==string" 115 | } 116 | ] 117 | ] 118 | }, 119 | ], 120 | } 121 | } 122 | 123 | export const rules = { 124 | schema: {}, 125 | values: { 126 | type: "string" 127 | }, 128 | form: { 129 | ...baseForm, 130 | layout: [ 131 | { 132 | title: "类型", 133 | widget: "select", 134 | name: "type", 135 | size: "small", 136 | options: [ 137 | { 138 | value: "string", 139 | label: "字符串", 140 | }, 141 | { 142 | value: "array", 143 | label: "数组", 144 | }, 145 | ], 146 | }, 147 | { 148 | title: "最小长度", 149 | name: "minLength", 150 | widget: "inputnumber", 151 | step: 1, // 步数 152 | min: undefined, 153 | max: undefined, 154 | stepStrictly: false, // 严格步数,只能输入 step 的倍数 155 | precision: undefined, // 精度,设置计数器最小值 156 | controlsPosition: "", // 按钮位置。计数器增减按钮的位置, 默认"", 可设置为 "right" 157 | size: "mini", 158 | } 159 | ] 160 | } 161 | } -------------------------------------------------------------------------------- /src/components/Formdesign/meta/slider.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | disabled: false, 4 | showTooltip: true, 5 | step: 1, // 步长 6 | minimum: 1, // 最小值 7 | maximum: 10, // 最大值 8 | showStop: false, // 显示间断点 9 | showInput: false, // 是否显示输入框,仅在非范围选择时有效 10 | inputSize: "", // large / medium / small / mini 11 | showInputControls: false, // 在显示输入框的情况下,是否显示输入框的控制按钮 12 | showRange: false, // 是否为范围选择,此时value必须为 [2,58] 13 | vertical: false, 14 | marks: {}, 15 | height: "200px", // vertical 为true时,必须设置高度 16 | * 17 | */ 18 | import { baseForm, baseLayout } from "./base" 19 | export const attribute = { 20 | schema: { 21 | 22 | }, 23 | values: { 24 | 25 | }, 26 | form: { 27 | ...baseForm, 28 | layout: [ 29 | ...baseLayout, 30 | { 31 | title: "步长", 32 | widget: "inputnumber", 33 | name: "step", 34 | step: 1, 35 | default: 1, 36 | }, 37 | { 38 | title: "最小值", 39 | widget: "inputnumber", 40 | name: "minimum", 41 | step: 1, 42 | }, 43 | { 44 | title: "最大值", 45 | widget: "inputnumber", 46 | name: "maximum", 47 | step: 1, 48 | }, 49 | { 50 | widget: "grid", 51 | title: "栅格布局", 52 | showTitle: false, 53 | isClicked: false, 54 | fields: [ 55 | [ 56 | { 57 | name: "disabled", 58 | title: "禁用", 59 | widget: "switch", 60 | width: 40, // 宽度 61 | activeColor: "#13ce66", // 激活背景颜色 62 | inactiveColor: "#ccc", // 取消背景颜色 63 | activeValue: true, // 打开的值,支持Boolean, String或Number 64 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 65 | } 66 | ], [ 67 | { 68 | name: "showStop", 69 | title: "间断点", 70 | widget: "switch", 71 | width: 40, // 宽度 72 | activeColor: "#13ce66", // 激活背景颜色 73 | inactiveColor: "#ccc", // 取消背景颜色 74 | activeValue: true, // 打开的值,支持Boolean, String或Number 75 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 76 | } 77 | ] 78 | ] 79 | }, 80 | { 81 | widget: "grid", 82 | title: "栅格布局", 83 | showTitle: false, 84 | isClicked: false, 85 | fields: [ 86 | [ 87 | { 88 | name: "showInput", 89 | title: "显示输入框", 90 | widget: "switch", 91 | width: 40, // 宽度 92 | activeColor: "#13ce66", // 激活背景颜色 93 | inactiveColor: "#ccc", // 取消背景颜色 94 | activeValue: true, // 打开的值,支持Boolean, String或Number 95 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 96 | } 97 | ], [ 98 | { 99 | name: "showInputControls", 100 | title: "控制按钮", 101 | widget: "switch", 102 | width: 40, // 宽度 103 | activeColor: "#13ce66", // 激活背景颜色 104 | inactiveColor: "#ccc", // 取消背景颜色 105 | activeValue: true, // 打开的值,支持Boolean, String或Number 106 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 107 | hideRely: "showInput == false", 108 | } 109 | ] 110 | ] 111 | }, 112 | { 113 | widget: "grid", 114 | title: "栅格布局", 115 | showTitle: false, 116 | isClicked: false, 117 | fields: [ 118 | [ 119 | { 120 | name: "vertical", 121 | title: "竖排列", 122 | widget: "switch", 123 | width: 40, // 宽度 124 | activeColor: "#13ce66", // 激活背景颜色 125 | inactiveColor: "#ccc", // 取消背景颜色 126 | activeValue: true, // 打开的值,支持Boolean, String或Number 127 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 128 | } 129 | ], [ 130 | { 131 | name: "height", 132 | title: "高度", 133 | widget: "input", 134 | size: "small", 135 | hideRely: "vertical == false", 136 | } 137 | ] 138 | ] 139 | }, 140 | { 141 | title: "尺寸", 142 | widget: "select", 143 | name: "inputSize", 144 | size: "small", 145 | hideRely: "showInput == false", 146 | options: [ 147 | { 148 | value: "large", 149 | label: "超大", 150 | }, 151 | { 152 | value: "medium", 153 | label: "大", 154 | }, 155 | { 156 | value: "small", 157 | label: "中", 158 | }, 159 | { 160 | value: "mini", 161 | label: "小", 162 | }, 163 | ], 164 | }, 165 | ], 166 | } 167 | } 168 | 169 | export const rules = { 170 | schema: {}, 171 | values: { 172 | 173 | }, 174 | form: { 175 | ...baseForm, 176 | layout: [ 177 | 178 | ] 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/slot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | html 4 | * 5 | */ 6 | import { baseForm, baseLayout } from "./base" 7 | export const attribute = { 8 | schema: { 9 | 10 | }, 11 | values: { 12 | 13 | }, 14 | form: { 15 | ...baseForm, 16 | layout: [ 17 | ...baseLayout, 18 | { 19 | title: "文本", 20 | name: "html", 21 | widget: "input", 22 | type: "textarea" 23 | }, 24 | ] 25 | } 26 | } 27 | 28 | export const rules = { 29 | schema: {}, 30 | values: {}, 31 | form: { 32 | ...baseForm, 33 | layout: [] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/switch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | disabled: false, 4 | width: 40, // 宽度 5 | activeColor: "#13ce66", // 激活背景颜色 6 | inactiveColor: "#ff4949", // 取消背景颜色 7 | activeText: "", // 激活文本 8 | inactiveText: "", // 取消文本 9 | activeValue: true, // 打开的值,支持Boolean, String或Number 10 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 11 | activeIconClass: "", 12 | inactiveIconClass: "", 13 | * 14 | */ 15 | import { baseForm, baseLayout } from "./base" 16 | export const attribute = { 17 | schema: { 18 | 19 | }, 20 | values: { 21 | 22 | }, 23 | form: { 24 | ...baseForm, 25 | layout: [ 26 | ...baseLayout, 27 | { 28 | title: "开值", 29 | widget: "input", 30 | size: "small", 31 | name: "activeValue" 32 | }, 33 | { 34 | title: "关值", 35 | widget: "input", 36 | size: "small", 37 | name: "inactiveValue", 38 | }, 39 | { 40 | title: "激活文本", 41 | widget: "input", 42 | size: "small", 43 | name: "activeText", 44 | }, 45 | { 46 | title: "取消文本", 47 | widget: "input", 48 | size: "small", 49 | name: "inactiveText", 50 | }, 51 | { 52 | title: "禁用", 53 | widget: "switch", 54 | name: "disabled", 55 | }, 56 | { 57 | title: "宽度", 58 | widget: "inputnumber", 59 | size: "small", 60 | name: "width", 61 | }, 62 | ], 63 | } 64 | } 65 | 66 | export const rules = { 67 | schema: {}, 68 | values: { 69 | 70 | }, 71 | form: { 72 | ...baseForm, 73 | layout: [ 74 | { 75 | title: "类型", 76 | widget: "select", 77 | name: "type", 78 | size: "small", 79 | default: "number", 80 | options: [ 81 | { 82 | value: "string", 83 | label: "字符串", 84 | }, 85 | { 86 | value: "number", 87 | label: "数字", 88 | }, 89 | { 90 | value: "boolean", 91 | label: "布尔", 92 | }, 93 | ], 94 | }, 95 | ] 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/tabs.js: -------------------------------------------------------------------------------- 1 | import { baseForm, baseLayout } from "./base" 2 | export const attribute = { 3 | schema: { 4 | $schema: "http://json-schema.org/draft-07/schema#", 5 | title: "设备属性", 6 | description: "A product from Acme's catalog", 7 | type: "object", 8 | properties: { 9 | tabs: { 10 | type: "array" 11 | } 12 | } 13 | }, 14 | values: { 15 | 16 | }, 17 | form: { 18 | ...baseForm, 19 | layout: [ 20 | { 21 | idKey: "name", 22 | title: "标签", 23 | name: "tabs", 24 | widget: "draggablelist", 25 | template: { label: "标签页一", fields: [] }, 26 | attribute: { 27 | label: { widget: "input", placeholder: "", editable: true }, 28 | name: { widget: "input", placeholder: "", editable: true }, 29 | value: { widget: "", placeholder: "", editable: false }, 30 | }, 31 | }, 32 | ], 33 | } 34 | } 35 | 36 | export const rules = { 37 | schema: {}, 38 | values: {}, 39 | form: { 40 | ...baseForm 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/timepicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | isPicker: true, // 是否为 timepicker 时间任意。timeselect固定时间,由pickerOptions设定 4 | readOnly: false, 5 | disabled: false, 6 | clearable: true, // 是否显示清除按钮 7 | size: "", // medium / small / mini 8 | editable: false, // 文本框可输入 9 | placeholder: "请选择", // 单个 10 | valueFormat: "HH:mm:ss", 11 | isRange: false, // isRange下面三个有效 12 | arrowControl: true, 13 | rangeSeparator: "至", // 选择范围时的分隔符 14 | startPlaceholder: "开始时间", 15 | endPlaceholder: "结束时间", 16 | pickerOptions: { 17 | // timeselect 有效 18 | start: "08:30", 19 | step: "00:15", 20 | end: "18:30", 21 | }, 22 | * 23 | */ 24 | import { baseForm, baseLayout } from "./base" 25 | export const attribute = { 26 | schema: { 27 | $schema: "http://json-schema.org/draft-07/schema#", 28 | title: "设备属性", 29 | description: "A product from Acme's catalog", 30 | type: "object", 31 | properties: { 32 | isRange: { 33 | require: true, 34 | description: "该字段选择后不可更改,否则会因为字段类型错误而报错", 35 | } 36 | } 37 | }, 38 | values: {}, 39 | form: { 40 | ...baseForm, 41 | layout: [ 42 | ...baseLayout, 43 | { 44 | title: "范围选择", 45 | widget: "select", 46 | name: "isRange", 47 | size: "small", 48 | options: [ 49 | { 50 | value: true, 51 | label: "是", 52 | }, 53 | { 54 | value: false, 55 | label: "否", 56 | } 57 | ], 58 | }, 59 | { 60 | title: "尺寸", 61 | widget: "select", 62 | name: "size", 63 | size: "small", 64 | options: [ 65 | { 66 | value: "medium", 67 | label: "大", 68 | }, 69 | { 70 | value: "small", 71 | label: "中", 72 | }, 73 | { 74 | value: "mini", 75 | label: "小", 76 | }, 77 | ], 78 | }, 79 | { 80 | widget: "input", 81 | title: "开始占位符", 82 | name: "startPlaceholder", 83 | hideRely: "isRange==false", 84 | size: "small" 85 | }, 86 | { 87 | widget: "input", 88 | title: "结束占位符", 89 | name: "endPlaceholder", 90 | hideRely: "isRange==false", 91 | size: "small" 92 | }, 93 | { 94 | widget: "input", 95 | title: "分隔符", 96 | name: "rangeSeparator", 97 | hideRely: "isRange==false", 98 | size: "small" 99 | }, 100 | { 101 | widget: "grid", 102 | title: "栅格布局", 103 | showTitle: false, 104 | isClicked: false, 105 | fields: [ 106 | [ 107 | { 108 | name: "readOnly", 109 | title: "只看", 110 | widget: "switch", 111 | width: 40, // 宽度 112 | activeColor: "#13ce66", // 激活背景颜色 113 | inactiveColor: "#ccc", // 取消背景颜色 114 | activeValue: true, // 打开的值,支持Boolean, String或Number 115 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 116 | }, 117 | { 118 | name: "clearable", 119 | title: "清除按钮", 120 | widget: "switch", 121 | width: 40, // 宽度 122 | activeColor: "#13ce66", // 激活背景颜色 123 | inactiveColor: "#ccc", // 取消背景颜色 124 | activeValue: true, // 打开的值,支持Boolean, String或Number 125 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 126 | } 127 | ], [ 128 | { 129 | name: "disabled", 130 | title: "禁用", 131 | widget: "switch", 132 | width: 40, // 宽度 133 | activeColor: "#13ce66", // 激活背景颜色 134 | inactiveColor: "#ccc", // 取消背景颜色 135 | activeValue: true, // 打开的值,支持Boolean, String或Number 136 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 137 | }, 138 | { 139 | name: "arrowControl", 140 | title: "可控", 141 | widget: "switch", 142 | width: 40, // 宽度 143 | activeColor: "#13ce66", // 激活背景颜色 144 | inactiveColor: "#ccc", // 取消背景颜色 145 | activeValue: true, // 打开的值,支持Boolean, String或Number 146 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 147 | }, 148 | ] 149 | ] 150 | }, 151 | ], 152 | } 153 | } 154 | 155 | export const rules = { 156 | schema: {}, 157 | values: { 158 | 159 | }, 160 | form: { 161 | ...baseForm, 162 | layout: [ 163 | // { 164 | // title: "类型", 165 | // widget: "select", 166 | // name: "type", 167 | // size: "small", 168 | // options: [ 169 | // { 170 | // value: "string", 171 | // label: "字符串", 172 | // }, 173 | // { 174 | // value: "number", 175 | // label: "数字", 176 | // }, 177 | // ], 178 | // }, 179 | ] 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/transfer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | placeholder: "", 4 | filterable: false, // 是否过滤 5 | titles: ["Source1", "Target"], // 标题 6 | buttonTexts: [], // "到左边", "到右边" 7 | * 8 | */ 9 | import { baseForm, baseLayout } from "./base" 10 | export const attribute = { 11 | schema: { 12 | 13 | }, 14 | values: { 15 | 16 | }, 17 | form: { 18 | ...baseForm, 19 | layout: [ 20 | ...baseLayout, 21 | { 22 | name: "filterable", 23 | title: "过滤", 24 | widget: "switch", 25 | width: 40, // 宽度 26 | activeColor: "#13ce66", // 激活背景颜色 27 | inactiveColor: "#ccc", // 取消背景颜色 28 | activeValue: true, // 打开的值,支持Boolean, String或Number 29 | inactiveValue: false, // 关闭的值,支持Boolean, String或Number 30 | }, 31 | { 32 | title: "标题", 33 | widget: "draggablelist", 34 | name: "titles", 35 | template: "", 36 | default: [], 37 | }, 38 | { 39 | title: "选项", 40 | widget: "draggablelist", 41 | name: "options", 42 | template: { label: "", key: "" }, 43 | attribute: { 44 | label: { widget: "input", placeholder: "", editable: true }, 45 | key: { widget: "input", placeholder: "", editable: true }, 46 | value: { widget: "", placeholder: "", editable: false }, 47 | }, 48 | default: [], 49 | }, 50 | { 51 | title: "按钮", 52 | widget: "draggablelist", 53 | name: "buttonTexts", 54 | template: "", 55 | default: [], 56 | }, 57 | ], 58 | } 59 | } 60 | 61 | export const rules = { 62 | schema: {}, 63 | values: { 64 | 65 | }, 66 | form: { 67 | ...baseForm, 68 | layout: [ 69 | 70 | ] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/components/Formdesign/meta/upload.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | title: "上传", 4 | name: "imageFile", 5 | tips: "", // 提示 6 | listType: "picture-card", // 可选 text/picture/picture-card 7 | actions: "http://127.0.0.1:8080/manage/minio/upload.do", // 上传路径 8 | deleteUrl: "http://127.0.0.1:8080/manage/minio/removeFile.do", // 删除路径 9 | draggable: true, // 是否可拖拽 10 | multiple: true, // 多选 11 | autoUpload: true, // 是否在选取文件后立即进行上传 12 | limit: 3, // 上传限制 13 | disabled: false, 14 | showFileList: true, // 是否显示已上传文件列表 15 | * 16 | */ 17 | import { baseForm, baseLayout } from "./base" 18 | export const attribute = { 19 | schema: { 20 | 21 | }, 22 | values: { 23 | 24 | }, 25 | form: { 26 | ...baseForm, 27 | layout: [ 28 | ...baseLayout, 29 | { 30 | title: "提示语", 31 | name: "tips", 32 | size: "small", 33 | widget: "input" 34 | }, 35 | { 36 | title: "类型", 37 | widget: "select", 38 | name: "listType", 39 | size: "small", 40 | options: [ 41 | { 42 | value: "text", 43 | label: "拖拽上传", 44 | }, 45 | { 46 | value: "picture", 47 | label: "图片列表", 48 | }, 49 | { 50 | value: "picture-card", 51 | label: "照片墙", 52 | }, 53 | ], 54 | }, 55 | { 56 | title: "上传URL", 57 | name: "actions", 58 | size: "small", 59 | widget: "input", 60 | }, 61 | { 62 | title: "删除URL", 63 | name: "deleteUrl", 64 | size: "small", 65 | widget: "input" 66 | }, 67 | { 68 | title: "可拖拽", 69 | widget: "select", 70 | name: "draggable", 71 | size: "small", 72 | options: [ 73 | { value: true, label: "是" }, 74 | { value: false, label: "否" }, 75 | ], 76 | }, 77 | { 78 | title: "多选", 79 | widget: "select", 80 | name: "multiple", 81 | size: "small", 82 | options: [ 83 | { value: true, label: "是" }, 84 | { value: false, label: "否" }, 85 | ], 86 | }, 87 | { 88 | title: "立即上传", 89 | widget: "select", 90 | name: "autoUpload", 91 | size: "small", 92 | options: [ 93 | { value: true, label: "是" }, 94 | { value: false, label: "否" }, 95 | ], 96 | }, 97 | { 98 | title: "禁用", 99 | widget: "select", 100 | name: "disabled", 101 | size: "small", 102 | options: [ 103 | { value: true, label: "是" }, 104 | { value: false, label: "否" }, 105 | ], 106 | }, 107 | 108 | { 109 | title: "显示上传列表", 110 | widget: "select", 111 | name: "showFileList", 112 | size: "small", 113 | options: [ 114 | { value: true, label: "是" }, 115 | { value: false, label: "否" }, 116 | ], 117 | } 118 | ], 119 | } 120 | } 121 | 122 | export const rules = { 123 | schema: {}, 124 | values: {}, 125 | form: { 126 | ...baseForm, 127 | layout: [] 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/components/Richform/actions.vue: -------------------------------------------------------------------------------- 1 | 2 | 36 | 37 | 70 | 71 | 80 | -------------------------------------------------------------------------------- /src/components/Richform/autoLayout.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/Richform/group/collapse.vue: -------------------------------------------------------------------------------- 1 | 2 | 43 | 44 | 78 | 79 | -------------------------------------------------------------------------------- /src/components/Richform/group/default.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 26 | -------------------------------------------------------------------------------- /src/components/Richform/group/grid.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 73 | 74 | -------------------------------------------------------------------------------- /src/components/Richform/group/tabs.vue: -------------------------------------------------------------------------------- 1 | 2 | 33 | 34 | 59 | 60 | -------------------------------------------------------------------------------- /src/components/Richform/layout.vue: -------------------------------------------------------------------------------- 1 | 57 | 58 | 93 | 94 | -------------------------------------------------------------------------------- /src/components/Richform/utils/defaultData.js: -------------------------------------------------------------------------------- 1 | export const defaultForm = { 2 | border: false, // 显示边框 3 | grid: false, // 表单内部栅栏 4 | labelSuffix: ":", // 字段标题后缀内容,默认' : ' 5 | labelWidth: "100px", // 标签宽度,默认50px 6 | validator: "input", // submit 7 | labelAlign: "right", // 标签对齐, 默认右对齐, 可选左对齐left 8 | labelInline: true, // 字段标题显示位置, 默认true左侧left,false显示在top上方 9 | colors: { // 主题颜色 10 | theme: "", // #121B2C 11 | fontColor: "", // #F8F4F4 12 | btnColor: "", // #F8F4F4 13 | btnBgColor: "", // #040C19 14 | activeColor: "", // #4F9FFE 15 | dateRangeBgColor: "", // #999 16 | multiOptionBgColor: "" // #ddd 17 | }, 18 | } 19 | 20 | export const defaultSchema = { 21 | $schema: "http://json-schema.org/draft-07/schema#", 22 | title: "richform attribute", 23 | description: "", 24 | type: "object", 25 | properties: {}, 26 | errorMessage: {}, 27 | if: {}, 28 | then: {}, 29 | else: {}, 30 | allOf: [], 31 | anyOf: [], 32 | oneOf: [], 33 | required: [], 34 | } 35 | -------------------------------------------------------------------------------- /src/components/Richform/utils/design.scss: -------------------------------------------------------------------------------- 1 | .richform { 2 | // 操作 3 | .design-draggable, 4 | .design-delete, 5 | .design-copy { 6 | display: inline-block; 7 | position: absolute; 8 | width: 22px; 9 | height: 26px; 10 | line-height: 26px; 11 | color: #fff; 12 | background: #409eff; 13 | text-align: center; 14 | cursor: pointer; 15 | z-index: 99999; 16 | } 17 | .design-draggable { 18 | left: 0; 19 | top: 0; 20 | z-index: 99; 21 | cursor: move; 22 | } 23 | .design-copy { 24 | right: 27px; 25 | bottom: 0; 26 | z-index: 99; 27 | } 28 | .design-delete { 29 | right: 3px; 30 | bottom: 0; 31 | z-index: 99; 32 | } 33 | // 拖拽过程配置 34 | .design-draggable-ghost { 35 | border-top: 5px solid #f56c6c; 36 | } 37 | // https://github.com/SortableJS/Vue.Draggable/issues/1008#issuecomment-782545024 38 | .base-component-item { 39 | width: 100%; 40 | display: inline-block; 41 | text-indent: -9999px; 42 | } 43 | .design-sortable-drag { 44 | background: #f4dec9; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/components/Richform/utils/designMixin.js: -------------------------------------------------------------------------------- 1 | import eventbus from "./eventbus"; 2 | export default { 3 | props: { 4 | schema: { type: Object, default: () => ({}) }, 5 | values: { type: Object, default: () => ({}) }, 6 | form: { type: Object, default: () => ({}) }, 7 | isDesign: { type: Boolean, default: false }, 8 | fieldErrors: { type: Object, default: () => ({}) }, 9 | hideFields: { type: Object, default: () => ({}) }, 10 | colors: { type: Object, default: () => ({}) }, 11 | isDark: { type: Boolean, default: false }, 12 | isFriendValue: { type: Boolean, default: true }, 13 | }, 14 | inject: ["formId"], 15 | data() { 16 | return { 17 | designValid: true, 18 | } 19 | }, 20 | created() { 21 | this.$nextTick(() => { 22 | // this.onScrollToBottom(); 23 | }) 24 | }, 25 | methods: { 26 | emit() { 27 | if (arguments.length > 0) { 28 | arguments[0] = `${this.formId}:${arguments[0]}`; 29 | eventbus.$emit(...arguments); 30 | } 31 | }, 32 | // 监听事件,滚动条滑动到最底部 33 | onScrollToBottom() { 34 | const ele = document.getElementById("form-design-center").parentNode; 35 | let scrollToBottomInterval; 36 | ele.onmouseenter = () => { 37 | scrollToBottomInterval = setInterval(function () { 38 | //设置滚动条到最底部 39 | if (ele.scrollHeight > ele.clientHeight) { 40 | ele.scrollTop = ele.scrollHeight; 41 | } 42 | }, 20); 43 | }; 44 | ele.onmouseout = () => { 45 | clearInterval(scrollToBottomInterval); 46 | } 47 | window.addEventListener("mousewheel", () => { 48 | clearInterval(scrollToBottomInterval); 49 | }, false); 50 | }, 51 | // 项目点击事件 52 | onClickedItem(item) { 53 | if (!this.isDesign) return; 54 | this.emit("design:clicked", item); 55 | }, 56 | // 项目删除动作 57 | onDeleteItem(form, field) { 58 | if (!this.isDesign) return; 59 | this.iterationFind(form.layout, field) 60 | }, 61 | // 递归查找并删除 62 | iterationFind(obj, target) { 63 | for (let key in obj) { 64 | if (typeof obj[key] === "object" && obj[key] !== null) { 65 | if (JSON.stringify(obj[key]) == JSON.stringify(target)) { 66 | this.$delete(obj, key); 67 | } 68 | this.iterationFind(obj[key], target) 69 | } 70 | } 71 | }, 72 | // 复制 73 | onCopyItem(item) { 74 | if (!this.isDesign) return; 75 | this.emit("design:copyItem", item); 76 | }, 77 | // 拖拽参数配置 78 | getDragOptions() { 79 | return { 80 | group: "formdesign", // 两个draggable要相互拖拽必须相同 81 | sort: true, // 是否允许排序 82 | disabled: false, 83 | animation: 0, // 过度 84 | easing: "cubic-bezier(1, 0, 0, 1)", // 动画效果 85 | handle: ".design-handle-move", // 可拖拽类,用于限定区域 86 | dragClass: "design-sortable-drag", // 排序背景显示 87 | ghostClass: "design-draggable-ghost", 88 | emptyInsertThreshold: 6, // 首个拖进来占位,该值不能太大,否则会发生抖动情况 89 | invertSwap: false, 90 | // direction: 'vertical', 91 | swapThreshold: 0.5, 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/components/Richform/utils/eventbus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | let eventbus= new Vue() 4 | 5 | export default eventbus 6 | 7 | -------------------------------------------------------------------------------- /src/components/Richform/utils/http.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { Message } from 'element-ui' 3 | 4 | // create an axios instance 5 | const service = axios.create({ 6 | timeout: 5000 // request timeout 7 | }) 8 | 9 | // request interceptor 10 | service.interceptors.request.use( 11 | config => { 12 | const authKey = sessionStorage.getItem("richform-key"); 13 | const authValue = sessionStorage.getItem("richform-value"); 14 | if (authKey == "" || authValue == "") console.warn("未定义token信息") 15 | else config.headers[authKey] = authValue 16 | return config; 17 | }, 18 | error => { 19 | // do something with request error 20 | console.log(error) // for debug 21 | return Promise.reject(error) 22 | } 23 | ) 24 | 25 | // response interceptor 26 | service.interceptors.response.use( 27 | response => { 28 | const { data, status } = response 29 | if (status != 200) { 30 | Message({ message: res.msg || 'Error', type: 'error', duration: 5 * 1000 }) 31 | return Promise.reject(new Error(res.msg || 'Error')) 32 | } 33 | return data 34 | }, 35 | error => { 36 | console.log('err' + error) // for debug 37 | return Promise.reject(error) 38 | } 39 | ) 40 | 41 | export default service 42 | -------------------------------------------------------------------------------- /src/components/Richform/utils/index.js: -------------------------------------------------------------------------------- 1 | import request from "./http" 2 | 3 | export function isUrl(url) { 4 | let Exp = /^(https?:\/\/)([0-9a-z.]+)(:[0-9]+)?([/0-9a-z.]+)?(\?[0-9a-z&=]+)?(#[0-9-a-z]+)?/i; 5 | return Exp.test(url); 6 | } 7 | 8 | export function loadDict(url, data, method) { 9 | return request({ 10 | url, 11 | method: method, 12 | [method == "post" ? "data" : "params"]: data 13 | }) 14 | } 15 | 16 | // 将字符串转成对象,若转失败则直接返回源字符串 17 | export function strToObj(str) { 18 | try { 19 | return /^{.*}$/.test(str) || /^\[.*\]$/.test(str) ? JSON.parse(str) : str; 20 | } catch { 21 | return str 22 | } 23 | } 24 | 25 | export function deleteIteration(obj = {}, keys = []) { 26 | if (keys.length == 1) { 27 | delete obj[keys[0]]; 28 | return; 29 | } 30 | obj = obj[keys[0]]; 31 | keys.shift(); 32 | return deleteIteration(obj, keys); 33 | } 34 | 35 | export function debounce(delay, callback) { 36 | let lastTime 37 | 38 | return function () { 39 | clearTimeout(lastTime) 40 | 41 | const [that, args] = [this, arguments] 42 | 43 | lastTime = setTimeout(() => { 44 | callback.apply(that, args) 45 | }, delay) 46 | } 47 | } 48 | 49 | export function observerDomResize(dom, callback) { 50 | const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver 51 | 52 | const observer = new MutationObserver(callback) 53 | 54 | observer.observe(dom, { attributes: true, attributeFilter: ['style'], attributeOldValue: true, subtree: true, }) 55 | 56 | return observer 57 | } 58 | 59 | /** 60 | * @description Get the rgb value of the hex color 61 | * @param {String} color Hex color 62 | * @return {Array} Rgb value of the color 63 | */ 64 | export function getRgbValueFromHex(color) { 65 | color = color.replace('#', ''); 66 | if (color.length === 3) color = Array.from(color).map(function (hexNum) { 67 | return hexNum + hexNum; 68 | }).join(''); 69 | color = color.split(''); 70 | return new Array(3).fill(0).map(function (t, i) { 71 | return parseInt("0x".concat(color[i * 2]).concat(color[i * 2 + 1])); 72 | }); 73 | } -------------------------------------------------------------------------------- /src/components/Richform/utils/themeMixin.js: -------------------------------------------------------------------------------- 1 | const ORIGINAL_THEME = '#409EFF' // default color 2 | 3 | export default { 4 | data() { 5 | return { 6 | originalColors: ['#409EFF', "#303133", "#606266", "#DCDFE6", "#E4E7ED", "#EBEEF5", "#F2F6FC", "#f4f4f5", "#fff", "#fff", "#fff", "#F5F7FA", "#303133"], 7 | } 8 | }, 9 | watch: { 10 | "form.colors": { 11 | handler(newVal) { 12 | // 将新的颜色派发保存以便下一轮替换 13 | if (typeof newVal != "object") return; 14 | this.pickColors(); 15 | }, 16 | deep: true, 17 | immediate: true, 18 | } 19 | }, 20 | methods: { 21 | pickColors() { 22 | this.$nextTick(() => { 23 | const oldVal = ORIGINAL_THEME 24 | let styles = [].slice.call(document.querySelectorAll('style')).filter(style => { 25 | const text = style.innerText 26 | return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text) 27 | }) 28 | styles.forEach((style) => { 29 | const { innerText } = style 30 | if (typeof innerText !== 'string') return 31 | style.innerText = this.replaceStyle(innerText); 32 | }) 33 | if (styles) this.updateOriginalColors(); 34 | }) 35 | }, 36 | updateOriginalColors() { 37 | let { theme, fontColor, btnColor, activeColor, btnBgColor, dateRangeBgColor, multiOptionBgColor } = this.friendForm.colors; 38 | if (activeColor) this.originalColors[0] = activeColor; 39 | if (fontColor) { 40 | this.originalColors[1] = fontColor; 41 | this.originalColors[2] = fontColor; 42 | this.originalColors[3] = fontColor; 43 | this.originalColors[4] = fontColor; 44 | this.originalColors[5] = fontColor; 45 | this.originalColors[12] = theme; 46 | } 47 | if (dateRangeBgColor) this.originalColors[6] = dateRangeBgColor; 48 | if (multiOptionBgColor) this.originalColors[7] = multiOptionBgColor; 49 | if (theme) { 50 | this.originalColors[8] = theme; 51 | this.originalColors[9] = theme; 52 | } 53 | if (btnColor) this.originalColors[10] = btnColor; 54 | if (btnBgColor) this.originalColors[11] = btnBgColor; 55 | 56 | }, 57 | replaceStyle(style) { 58 | let newStyle = style; 59 | let { originalColors } = this; 60 | let { activeColor, theme, fontColor, btnColor, btnBgColor, dateRangeBgColor, multiOptionBgColor } = this.friendForm.colors; 61 | if (activeColor.length > 0) // brand color 62 | // brand color 63 | newStyle = newStyle.replace(new RegExp(originalColors[0], 'ig'), activeColor) // 复选框,tab,选中的背景颜色 64 | if (fontColor.length > 0) { 65 | newStyle = newStyle.replace(new RegExp(`background:${originalColors[12]}`, 'ig'), 'background:' + theme) // tooltip背景颜色 66 | // font color 67 | newStyle = newStyle.replace(new RegExp(originalColors[1], 'ig'), fontColor) // 未被选中的状态,字体颜色 68 | newStyle = newStyle.replace(new RegExp(originalColors[2], 'ig'), fontColor) // 未被选中字体颜色,即字体颜色,非button ---白色 69 | // border color 70 | newStyle = newStyle.replace(new RegExp(originalColors[3], 'ig'), fontColor) // border 默认颜色 71 | newStyle = newStyle.replace(new RegExp(originalColors[4], 'ig'), fontColor) // border颜色 聚焦后的颜色 72 | newStyle = newStyle.replace(new RegExp(originalColors[5], 'ig'), fontColor) // 穿梭框边颜色 73 | } 74 | if (dateRangeBgColor.length > 0) 75 | newStyle = newStyle.replace(new RegExp(originalColors[6], 'ig'), dateRangeBgColor) // 日期范围背景 76 | if (multiOptionBgColor.length > 0) 77 | newStyle = newStyle.replace(new RegExp(originalColors[7], 'ig'), multiOptionBgColor) // 下拉框,多选的选项颜色 78 | if (theme.length > 0) { 79 | // background color 80 | newStyle = newStyle.replace(new RegExp(`background:${originalColors[8]}`, 'ig'), 'background:' + theme) // 下同 81 | newStyle = newStyle.replace(new RegExp(`background-color:${originalColors[9]}`, 'ig'), 'background-color:' + theme) 82 | } 83 | if (btnColor.length > 0) 84 | newStyle = newStyle.replace(new RegExp(`color:${originalColors[10]}`, 'ig'), 'color:' + btnColor) // 按钮和滑块的字体颜色 85 | if (btnBgColor.length > 0) 86 | newStyle = newStyle.replace(new RegExp(originalColors[11], 'ig'), btnBgColor) // 穿梭框头部和inputnumber两边的颜色,下拉hover的背景颜色 87 | 88 | return newStyle 89 | }, 90 | } 91 | } -------------------------------------------------------------------------------- /src/components/Richform/utils/validator.js: -------------------------------------------------------------------------------- 1 | const Ajv = require("ajv") 2 | const ajvI18n = require("ajv-i18n") 3 | 4 | // https://ajv.js.org/api.html 5 | const ajv = new Ajv({ 6 | removeAdditional: true, 7 | useDefaults: true, // 校验时会自动填入缺省值 8 | coerceTypes: false, // 强制类型转换,如type="boolean",而value="其他类型",会被转换为boolean, 9 | allErrors: true, // 是否显示所有的错误,否则则显示单条数据 10 | jsonPointers: true, 11 | strict: false, // 严格模式,若开启,则schema中不能自定义字段 12 | }) 13 | require("ajv-errors")(ajv, { singleError: false }); // 自定义错误信息 14 | 15 | // 将语言名称统一处理 16 | const langMap = { 17 | 'zh-cn': 'zh', 18 | 'en': 'en' 19 | } 20 | 21 | export const localize = function (errors, lang = "zh-cn") { 22 | let curLang = lang.toLowerCase() 23 | if (curLang in langMap) curLang = langMap[curLang] // 更名 24 | try { 25 | return ajvI18n[curLang](errors) 26 | } catch (e) { 27 | return ajvI18n.en(errors) 28 | } 29 | } 30 | ajv.localize = localize 31 | 32 | 33 | export default ajv -------------------------------------------------------------------------------- /src/components/Richform/vars.scss: -------------------------------------------------------------------------------- 1 | $form-font-size: 13px; 2 | $field-font-color: #303133; 3 | $form-border-color: #ddd; 4 | $color: #409eff; 5 | $active-border-color: #4F9FFE; 6 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/button.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 73 | 74 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/cascader.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 167 | 168 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/checkbox.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 111 | 112 | 121 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/colorpicker.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/components/Input/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 38 | 39 | 41 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/datetimepicker.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 118 | 119 | 129 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/input.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 79 | 80 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/inputnumber.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 40 | 45 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/ipinput.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 42 | 43 | 58 | 59 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/map.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 156 | 157 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/multiexp.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/radio.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 88 | 89 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/rate.vue: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/select.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 174 | 175 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/slider.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 49 | 50 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/slot.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | 24 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/switch.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 44 | 45 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/text.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 21 | -------------------------------------------------------------------------------- /src/components/Richform/widgets/transfer.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 38 | 39 | 41 | -------------------------------------------------------------------------------- /src/components/SplitLayout/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | 14 | &::-webkit-scrollbar { 15 | width: 6px; 16 | } 17 | 18 | &::-webkit-scrollbar-thumb { 19 | background: #99a9bf; 20 | border-radius: 20px; 21 | } 22 | } 23 | 24 | @mixin relative { 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | } 29 | 30 | @mixin pct($pct) { 31 | width: #{$pct}; 32 | position: relative; 33 | margin: 0 auto; 34 | } 35 | 36 | @mixin triangle($width, $height, $color, $direction) { 37 | $width: $width/2; 38 | $color-border-style: $height solid $color; 39 | $transparent-border-style: $width solid transparent; 40 | height: 0; 41 | width: 0; 42 | 43 | @if $direction==up { 44 | border-bottom: $color-border-style; 45 | border-left: $transparent-border-style; 46 | border-right: $transparent-border-style; 47 | } 48 | 49 | @else if $direction==right { 50 | border-left: $color-border-style; 51 | border-top: $transparent-border-style; 52 | border-bottom: $transparent-border-style; 53 | } 54 | 55 | @else if $direction==down { 56 | border-top: $color-border-style; 57 | border-left: $transparent-border-style; 58 | border-right: $transparent-border-style; 59 | } 60 | 61 | @else if $direction==left { 62 | border-right: $color-border-style; 63 | border-top: $transparent-border-style; 64 | border-bottom: $transparent-border-style; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/components/Teleport/index.vue: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import RichForm from "./Richform/index.vue" 4 | Vue.component("RichForm", RichForm) 5 | 6 | import FormDesign, { FormMetas } from "./Formdesign/index.vue" 7 | Vue.component("FormDesign", FormDesign) 8 | 9 | import SplitLayout from "./SplitLayout/index.vue" 10 | Vue.component("SplitLayout", SplitLayout) 11 | 12 | export { RichForm, FormDesign, FormMetas, SplitLayout } -------------------------------------------------------------------------------- /src/i18n/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | Vue.use(VueI18n) 4 | 5 | const langFiles = require.context('./lang', true, /\.js$/) 6 | 7 | const langs = langFiles.keys().reduce((modules, modulePath) => { 8 | const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') 9 | const value = langFiles(modulePath) 10 | modules[moduleName] = value.default; 11 | return modules 12 | }, {}) 13 | 14 | const i18n = new VueI18n({ 15 | warnHtmlMessage: false, 16 | locale: localStorage.getItem("lang") || "zh-CN", 17 | globalInjection: true, 18 | legacy: false, 19 | messages: langs 20 | }) 21 | 22 | export default i18n -------------------------------------------------------------------------------- /src/i18n/lang/en.js: -------------------------------------------------------------------------------- 1 | import elementEn from 'element-ui/lib/locale/lang/en' 2 | export default { 3 | // ...elementEn, 4 | lang: "english", 5 | 6 | } -------------------------------------------------------------------------------- /src/i18n/lang/vi.js: -------------------------------------------------------------------------------- 1 | import elementVi from 'element-ui/lib/locale/lang/vi' 2 | export default { 3 | // ...elementVi, 4 | lang: "vi", 5 | 6 | } -------------------------------------------------------------------------------- /src/i18n/lang/zh-CN.js: -------------------------------------------------------------------------------- 1 | import elementZhCn from 'element-ui/lib/locale/lang/zh-CN' 2 | export default { 3 | // ...elementZhCn, 4 | lang: "简体中文", // 这个写对应国语言 5 | } -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import i18n from '@/i18n' 3 | import App from './App.vue' 4 | import 'babel-polyfill' 5 | import Es6Promise from 'es6-promise' 6 | require('es6-promise').polyfill() 7 | Es6Promise.polyfill() 8 | 9 | Vue.config.productionTip = false 10 | import router from './router' 11 | 12 | new Vue({ 13 | router, 14 | i18n, 15 | render: h => h(App), 16 | }).$mount('#app') 17 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "ajv-i18n": "^4.0.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/pages/deep-values.vue: -------------------------------------------------------------------------------- 1 | 2 | 22 | 46 | 47 | 212 | 213 | 219 | 220 | -------------------------------------------------------------------------------- /src/pages/form-design.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 26 | 27 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | const constRouter = [ 7 | { 8 | path: '/form-design', 9 | name: 'richform', 10 | component: () => import('@/pages/richform') 11 | }, 12 | { 13 | path: '/', 14 | name: 'form-design', 15 | component: () => import('@/pages/form-design') 16 | }, 17 | { 18 | path: '/deep-values', 19 | name: 'deep-values', 20 | component: () => import('@/pages/deep-values') 21 | } 22 | ] 23 | 24 | const router = new Router({ 25 | // mode: 'history', 26 | routes: constRouter 27 | }) 28 | 29 | export default router -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const isBuild = process.argv.includes("build") 4 | 5 | function resolve(dir) { 6 | return path.join(__dirname, dir); 7 | } 8 | 9 | module.exports = { 10 | publicPath: '', 11 | outputDir: 'dist/lib', 12 | assetsDir: 'static', 13 | productionSourceMap: false, 14 | css: { extract: false }, 15 | configureWebpack: { 16 | // provide the app's title in webpack's name field, so that 17 | // it can be accessed in index.html to inject the correct title. 18 | name: 'richform', 19 | resolve: { 20 | alias: { 21 | '@': resolve('src') 22 | } 23 | }, 24 | //警告 webpack 的性能提示 25 | performance: { 26 | hints: 'warning', 27 | //入口起点的最大体积 28 | maxEntrypointSize: 100000, 29 | //生成文件的最大体积 30 | maxAssetSize: 600000, 31 | }, 32 | plugins: [], 33 | externals: isBuild ? { 34 | "ajv": "ajv", 35 | "ajv-errors": "ajv-errors", 36 | // "ajv-i18n": "ajv-i18n", 37 | "axios": "axios", 38 | "element-resize-detector": "element-resize-detector", 39 | "core-js": "core-js", 40 | "element-ui": "element-ui", 41 | "jquery": "jquery", 42 | "ramda": "ramda", 43 | "vue": "vue", 44 | "vue-baidu-map": "vue-baidu-map", 45 | "vue-i18n": "vue-i18n", 46 | "vue-router": "vue-router", 47 | "vue-scrollto": "vue-scrollto", 48 | "vue2-perfect-scrollbar": "vue2-perfect-scrollbar", 49 | "vuedraggable": "vuedraggable", 50 | "vxe-table": "vxe-table", 51 | "xe-utils": "xe-utils" 52 | } : {} 53 | }, 54 | // to handle element icon error in build. 55 | chainWebpack: config => { 56 | config.module.rule('compile') 57 | .test(/\.js$/) 58 | .include 59 | .add(resolve('src')) 60 | .add(resolve('test')) 61 | .add(resolve('node_modules/webpack-dev-server/client')) 62 | .add(resolve('node_modules')) 63 | .end() 64 | .use('babel') 65 | .loader('babel-loader') 66 | .options({ 67 | presets: [ 68 | ['@babel/preset-env', { 69 | modules: false 70 | }] 71 | ] 72 | }) 73 | config.module 74 | .rule("fonts") 75 | .test(/.(ttf|otf|eot|woff|woff2)$/) 76 | .use("url-loader") 77 | .loader("url-loader") 78 | .tap(options => { 79 | options = { 80 | // limit: 10000, 81 | name: '/static/fonts/[name].[ext]', 82 | } 83 | return options 84 | }) 85 | .end() 86 | } 87 | } --------------------------------------------------------------------------------