Commit 70f019f639cc14bdaf50ad0a3b988ec43da13369

Authored by Aaron.Liu
1 parent 6d738c29
Exists in master and in 1 other branch legacy

新增cform组件及修改点备注

examples/views/index.vue
... ... @@ -60,6 +60,10 @@
60 60 <div class="cpt-content">
61 61 <eagle-tree-select v-model="treeSelectValue" :dataSource="treeSelectDataSource"></eagle-tree-select>
62 62 </div>
  63 + <div class="cpt-title">表单生成器 eagle-form</div>
  64 + <div class="cpt-content">
  65 + <eagle-cform v-model="formValue" :list="formList"></eagle-cform>
  66 + </div>
63 67 </div>
64 68 </template>
65 69  
... ... @@ -73,6 +77,10 @@ export default {
73 77 treeSelectValue: undefined,
74 78 treeSelectDataSource: [
75 79 { id: 0, label: '一级菜单', children: [{ id: 1, label: '二级菜单-1' }, { id: 2, label: '二级菜单-2', children: [{ id: 3, label: '三级菜单' }] }] }
  80 + ],
  81 + formValue: {},
  82 + formList: [
  83 + { type: 'el-input' }
76 84 ]
77 85 }
78 86 },
... ...
packages/cform/index.vue 0 → 100644
... ... @@ -0,0 +1,271 @@
  1 +<style scoped>
  2 +.edit-form {
  3 + padding-right: 30px;
  4 +}
  5 +.group-title {
  6 + font-weight: bold;
  7 + padding: 15px 5px;
  8 + border-bottom: 1px solid #d9d9d9;
  9 + margin-bottom: 30px;
  10 + /* margin-top: 15px;
  11 + margin-bottom: 30px; */
  12 +}
  13 +/* .group-title:first-child {
  14 + margin-top: 0px;
  15 +} */
  16 +
  17 +.group-content {
  18 + margin: 15px 0px;
  19 +}
  20 +</style>
  21 +
  22 +<template>
  23 + <el-form class="edit-form" size="small" ref="form" :model="model" :label-width="labelWidth">
  24 + <template v-if="groupList.group">
  25 + <!-- 这里可以合为一个代码段判断 -->
  26 + <template v-for="(data, index) in groupList.data">
  27 + <template v-if="data.list.length > 0">
  28 + <!-- 这里可以判断是否满足分组条件决定显示title,另外下面content的class也可以判断,div可以换满span的col代替 -->
  29 + <!-- 加上选项tips提示判断,类似avue -->
  30 + <div class="group-title" :key="index + 'title'">{{ data.title }}</div>
  31 + <el-row class="group-content" :key="index + 'list'" :gutter="15">
  32 + <template v-for="(item, index) in data.list">
  33 + <el-col v-if="componentVisible(item.visible)" v-show="componentShow(item.show)" :key="index + 'data'" :span="!item.span ? 24 : item.span">
  34 + <el-form-item :label="item.label" :label-width="item.label ? undefined : item.labelWidth || '0px'" :prop="item.key" :rules="item.rules">
  35 + <component @input="(e) => handleComponentInput(e, item)" :is="item.type" @change="(e) => handleComponentChange(e, item)" v-on="handleComponentOn(item)" :style="componentStyle(item.style)" v-model="model[item.key]" v-bind="componentProps(item)"></component>
  36 + </el-form-item>
  37 + </el-col>
  38 + </template>
  39 + </el-row>
  40 + </template>
  41 + </template>
  42 + </template>
  43 + <template v-else>
  44 + <el-row :gutter="15">
  45 + <template v-for="(item, index) in list">
  46 + <el-col v-if="componentVisible(item.visible)" v-show="componentShow(item.show)" :key="index" :span="!item.span ? 24 : item.span">
  47 + <el-form-item :label="item.label" :label-width="item.label ? undefined : item.labelWidth || '0px'" :prop="item.key" :rules="item.rules">
  48 + <component @input="(e) => handleComponentInput(e, item)" :is="item.type" @change="(e) => handleComponentChange(e, item)" v-on="handleComponentOn(item)" :style="componentStyle(item.style)" v-model="model[item.key]" v-bind="componentProps(item)"></component>
  49 + </el-form-item>
  50 + </el-col>
  51 + </template>
  52 + </el-row>
  53 + </template>
  54 + <!-- 使用slot,不用slot时可定义对齐位置 -->
  55 + <div style="text-align: right">
  56 + <el-button type="primary" size="small" :loading="submitLoading" @click="handleSubmit">确定</el-button>
  57 + <el-button plain size="small" @click="handleCancel" style="margin-left: 8px">取消</el-button>
  58 + </div>
  59 + </el-form>
  60 +</template>
  61 +
  62 +<script>
  63 +export default { // ------------------------------------ 解决外部的v-model绑定值失效问题
  64 + name: 'Cform',
  65 + props: {
  66 + // 用于实例化本组件绑定v-model的值
  67 + value: {
  68 + type: Object,
  69 + default: () => {
  70 + return {};
  71 + }
  72 + },
  73 + // 配置列表 --------------------------------------------可换成对象,传list的同时传其它参数?是否跟formProps重复???
  74 + list: {
  75 + type: Array,
  76 + required: true
  77 + },
  78 + // 提交加载状态
  79 + submitLoading: Boolean, // --------------------------------- isLoading 或者loading,考虑骨架屏?
  80 + // 表单模式,一般结合外部模态框判断新增或修改使用 ------------------------------尽量去掉mode,在外部隐藏时销毁组件,避免历史值遗留问题
  81 + mode: String,
  82 + // 标签宽度 ------------------------------- form的props可以用单独的字段如formProps表示,动态传入,使用v-bind绑定
  83 + labelWidth: {
  84 + type: String,
  85 + default: '90px'
  86 + }
  87 + },
  88 + data() {
  89 + return {
  90 + // 编辑器表单模型
  91 + model: {}
  92 + };
  93 + },
  94 + watch: {
  95 + value: function(val) {
  96 + if (val) {
  97 + Object.keys(this.model).forEach(key => {
  98 + this.model[key] = val[key];
  99 + });
  100 + }
  101 + },
  102 + // 配置列表又改动时初始化表单模型
  103 + list: function(value) {
  104 + this.initModel(value);
  105 + const obj = {};
  106 + this.list.forEach(data => {
  107 + if (data.group) {
  108 + obj[data.group] = true;
  109 + }
  110 + });
  111 + }
  112 + },
  113 + computed: {
  114 + groupList() {
  115 + const obj = {};
  116 + this.list.forEach(data => {
  117 + if (data.group) {
  118 + if (!obj[data.group]) {
  119 + obj[data.group] = [];
  120 + }
  121 + obj[data.group].push(data);
  122 + }
  123 + });
  124 + return {
  125 + group: Object.keys(obj).length > 0,
  126 + data: Object.keys(obj).map(key => {
  127 + return { title: key, list: obj[key] };
  128 + })
  129 + };
  130 + }
  131 + },
  132 + created() {
  133 + // 初始化表单模型
  134 + this.initModel(this.list);
  135 + },
  136 + methods: {
  137 + handleComponentInput(e, item) {
  138 + if (item.oninput) {
  139 + item.oninput(e, this.model, this.mode);
  140 + }
  141 + this.emitModel();
  142 + },
  143 + handleComponentChange(e, item) {
  144 + if (item.onchange) {
  145 + item.onchange(e, this.model, this.mode);
  146 + }
  147 + },
  148 + handleComponentOn(item) {
  149 + if (item.on) {
  150 + if (typeof item.on === 'function') {
  151 + return item.on(this.model, this.mode);
  152 + } else {
  153 + return item.on
  154 + }
  155 + } else {
  156 + return undefined
  157 + }
  158 + },
  159 + // 向上推送表单值到实例化的组件的v-model中
  160 + emitModel() {
  161 + const result = {};
  162 + Object.keys(this.model).forEach(key => {
  163 + if (this.componentIsVisible(key)) {
  164 + let value = this.model[key];
  165 + if (this.model[key] === null) {
  166 + value = undefined;
  167 + }
  168 + result[key] = value;
  169 + }
  170 + });
  171 + this.$emit("input", result);
  172 + },
  173 + // 初始化表单模型
  174 + initModel(list) {
  175 + const model = {};
  176 + list.forEach(item => {
  177 + model[item.key] = item.default;
  178 + });
  179 + this.model = model;
  180 + this.emitModel();
  181 + },
  182 + // 设置表单模型值
  183 + setValue(value) {
  184 + this.reset();
  185 + Object.keys(value).forEach(key => {
  186 + this.model[key] = value[key];
  187 + });
  188 + this.emitModel();
  189 + },
  190 + // 判断名称为key的组件v-if是否为true
  191 + componentIsVisible(key) {
  192 + let visible = true;
  193 + this.list.forEach((item) => {
  194 + if (item.key === key) {
  195 + if (typeof item.visible === 'function') {
  196 + visible = item.visible(this.model, this.mode);
  197 + } else {
  198 + visible = item.visible === undefined ? true : item.visible;
  199 + }
  200 + }
  201 + });
  202 + return visible;
  203 + },
  204 + // 判断组件v-if状态
  205 + componentVisible(visible = true) {
  206 + let componentVisible = visible;
  207 + if (typeof visible === 'function') {
  208 + componentVisible = visible(this.model, this.mode);
  209 + }
  210 + return componentVisible;
  211 + },
  212 + // 判断组件v-show状态
  213 + componentShow(show = true) {
  214 + let componentShow = show;
  215 + if (typeof show === 'function') {
  216 + componentShow = show(this.model, this.mode);
  217 + }
  218 + return componentShow;
  219 + },
  220 + // 判断组件参数
  221 + componentProps(item) {
  222 + const { props = {}, propsEditor = {} } = item;
  223 + let connectedProps = { ...props, ...propsEditor };
  224 + Object.keys(connectedProps).forEach(key => {
  225 + if (typeof connectedProps[key] === 'function') {
  226 + connectedProps[key] = connectedProps[key](this.model, this.mode);
  227 + }
  228 + });
  229 + return connectedProps;
  230 + },
  231 + // 判断组件样式
  232 + componentStyle(style = {}) {
  233 + return {
  234 + width: "100%",
  235 + ...style
  236 + };
  237 + },
  238 + // 点击确定提交表单的操作
  239 + handleSubmit(name) {
  240 + this.$refs.form.validate(valid => {
  241 + if (valid) {
  242 + const result = {};
  243 + Object.keys(this.model).forEach(key => {
  244 + if (this.componentIsVisible(key)) {
  245 + let value = this.model[key];
  246 + if (this.model[key] === null) {
  247 + value = undefined;
  248 + }
  249 + result[key] = value;
  250 + }
  251 + });
  252 + this.$emit("submit", result);
  253 + }
  254 + });
  255 + },
  256 + // 重置表单
  257 + reset() {
  258 + Object.keys(this.model).forEach(key => {
  259 + this.model[key] = (this.list.find(item => item.key === key) || {}).default;
  260 + });
  261 + this.$nextTick(() => {
  262 + this.$refs.form.clearValidate();
  263 + });
  264 + },
  265 + // 点击取消的操作
  266 + handleCancel() {
  267 + this.$emit("cancel");
  268 + }
  269 + }
  270 +};
  271 +</script>
0 272 \ No newline at end of file
... ...
packages/dist-picker/dist-picker-inner.vue
... ... @@ -114,7 +114,7 @@ export default {
114 114 }
115 115 },
116 116 created() {
117   - if (this.type != 'mobile') {
  117 + if (this.type !== 'mobile') {
118 118 this.provinces = this.getDistricts()
119 119 this.cities = this.province ? this.getDistricts(this.getAreaCode(this.determineType(this.province))) : []
120 120 this.areas = this.city ? this.getDistricts(this.getAreaCode(this.determineType(this.city), this.area)) : []
... ... @@ -140,11 +140,11 @@ export default {
140 140 },
141 141 currentCity(value) {
142 142 this.$emit('city', this.setData(value, this.currentProvince))
143   - if (value != this.placeholders.city && this.hideArea) this.emit('selected')
  143 + if (value !== this.placeholders.city && this.hideArea) this.emit('selected')
144 144 },
145 145 currentArea(value) {
146 146 this.$emit('area', this.setData(value, this.currentProvince))
147   - if (value != this.placeholders.area) this.emit('selected')
  147 + if (value !== this.placeholders.area) this.emit('selected')
148 148 },
149 149 province(value) {
150 150 this.currentProvince = this.province || this.placeholders.province
... ... @@ -240,7 +240,7 @@ export default {
240 240 if (codes.length > 1) {
241 241 let index
242 242 codes.forEach((item, i) => {
243   - if (item.slice(0, 2) == preCode) {
  243 + if (item.slice(0, 2) === preCode) {
244 244 index = i
245 245 }
246 246 })
... ...
packages/editor/index.vue
... ... @@ -93,16 +93,16 @@ export default {
93 93 container: [
94 94 ['bold', 'italic', 'underline', 'strike'],
95 95 ['blockquote', 'code-block'],
96   - [{'header': 1}, {'header': 2}],
97   - [{'list': 'ordered'}, {'list': 'bullet'}],
98   - [{'script': 'sub'}, {'script': 'super'}],
99   - [{'indent': '-1'}, {'indent': '+1'}],
100   - [{'direction': 'rtl'}],
101   - [{'size': ['12px', '14px', '16px', '18px', '20px', '24px', '32px']}],
102   - [{'header': [1, 2, 3, 4, 5, 6, false]}],
103   - [{'color': []}, {'background': []}],
104   - [{'font': ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif']}],
105   - [{'align': []}],
  96 + [{ 'header': 1 }, { 'header': 2 }],
  97 + [{ 'list': 'ordered' }, { 'list': 'bullet' }],
  98 + [{ 'script': 'sub' }, { 'script': 'super' }],
  99 + [{ 'indent': '-1' }, { 'indent': '+1' }],
  100 + [{ 'direction': 'rtl' }],
  101 + [{ 'size': ['12px', '14px', '16px', '18px', '20px', '24px', '32px'] }],
  102 + [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
  103 + [{ 'color': [] }, { 'background': [] }],
  104 + [{ 'font': ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif'] }],
  105 + [{ 'align': [] }],
106 106 ['clean'],
107 107 ['link', 'image', 'video']
108 108 ],
... ...
packages/index.js
... ... @@ -3,6 +3,7 @@ import Confirm from &#39;./confirm&#39;
3 3 import DistPicker from './dist-picker'
4 4 import Editor from './editor'
5 5 import FileUpload from './file-upload'
  6 +import Cform from './cform'
6 7 import ImageUpload from './Image-upload'
7 8 import ImageUploadMultiple from './Image-upload/multiple'
8 9 import ImageView from './image-view'
... ... @@ -13,6 +14,7 @@ import SwitchButton from &#39;./switch-button&#39;
13 14 import TreeSelect from './tree-select'
14 15  
15 16 const components = {
  17 + Cform,
16 18 Code,
17 19 Confirm,
18 20 DistPicker,
... ...