Commit 29f4d36e325f0fe92462dbced55ad1bba4c9be83

Authored by ly525
1 parent 10cf6788

feat(plugin) add form submit button

front-end/h5/src/components/core/models/element.js
1 import { parsePx } from '../../../utils/element.js' 1 import { parsePx } from '../../../utils/element.js'
2 2
  3 +// #! 编辑状态,不可以点击的按钮,因为点击按钮会触发一些默认行为,比如表单提交等
  4 +const disabledPluginsForEditMode = ['lbp-form-input', 'lbp-form-button']
3 const clone = (value) => JSON.parse(JSON.stringify(value)) 5 const clone = (value) => JSON.parse(JSON.stringify(value))
4 6
5 const defaultProps = { 7 const defaultProps = {
@@ -78,7 +80,7 @@ class Element { @@ -78,7 +80,7 @@ class Element {
78 getProps ({ mode = 'edit' } = {}) { 80 getProps ({ mode = 'edit' } = {}) {
79 return { 81 return {
80 ...this.pluginProps, 82 ...this.pluginProps,
81 - disabled: this.name === 'lbp-form-input' && mode === 'edit' 83 + disabled: disabledPluginsForEditMode.includes(this.name) && mode === 'edit'
82 } 84 }
83 } 85 }
84 86
@@ -90,6 +92,22 @@ class Element { @@ -90,6 +92,22 @@ class Element {
90 92
91 } 93 }
92 94
  95 + getAttrs () {
  96 + return {
  97 + 'data-uuid': this.uuid
  98 + }
  99 + }
  100 +
  101 + getPreviewData () {
  102 + const style = this.getStyle({ position: 'absolute' })
  103 + const data = {
  104 + style,
  105 + props: this.getProps({ mode: 'preview' }),
  106 + attrs: this.getAttrs()
  107 + }
  108 + return data
  109 + }
  110 +
93 clone ({ zindex }) { 111 clone ({ zindex }) {
94 return new Element({ 112 return new Element({
95 zindex, 113 zindex,
front-end/h5/src/components/plugins/lbp-form-button.js 0 → 100644
  1 +export default {
  2 + render () {
  3 + const {
  4 + color,
  5 + textAlign,
  6 + backgroundColor,
  7 + fontSize,
  8 + lineHeight,
  9 + borderColor,
  10 + borderRadius,
  11 + borderWidth,
  12 + text,
  13 + disabled
  14 + } = this
  15 +
  16 + const style = {
  17 + color,
  18 + textAlign,
  19 + backgroundColor,
  20 + fontSize: fontSize,
  21 + lineHeight: lineHeight + 'em',
  22 + borderColor,
  23 + borderRadius: borderRadius + 'px',
  24 + borderWidth: borderWidth + 'px',
  25 + textDecoration: 'none',
  26 + disabled
  27 + }
  28 + return (
  29 + <button
  30 + style={style}
  31 + onClick={this.handleClick}
  32 + >{text}</button>)
  33 + },
  34 + name: 'lbp-form-button',
  35 + props: {
  36 + text: {
  37 + type: String,
  38 + default: '按钮'
  39 + },
  40 + type: {
  41 + type: String,
  42 + default: 'text'
  43 + },
  44 + placeholder: {
  45 + type: String,
  46 + default: '请填写提示文字'
  47 + },
  48 + required: {
  49 + type: Boolean,
  50 + default: false
  51 + },
  52 + disabled: {
  53 + type: Boolean,
  54 + default: false
  55 + },
  56 + backgroundColor: {
  57 + type: String,
  58 + default: 'transparent'
  59 + },
  60 + color: {
  61 + type: String,
  62 + default: 'black'
  63 + },
  64 + fontSize: {
  65 + type: Number,
  66 + default: 14
  67 + },
  68 + lineHeight: {
  69 + type: Number,
  70 + default: 1
  71 + },
  72 + borderWidth: {
  73 + type: Number,
  74 + default: 1
  75 + },
  76 + borderRadius: {
  77 + type: Number,
  78 + default: 0
  79 + },
  80 + borderColor: {
  81 + type: String,
  82 + default: '#ced4da'
  83 + },
  84 + textAlign: {
  85 + type: String,
  86 + default: 'center'
  87 + }
  88 + // pageMode: {
  89 + // type: String,
  90 + // default: 'edit'
  91 + // }
  92 + },
  93 + methods: {
  94 + handleClick () {
  95 + debugger
  96 + if (this.disabled) return
  97 +
  98 + // #!zh: data-type=lbp-form-input 在 lbp-form-input 组件中定义
  99 + let inputs = document.querySelectorAll("[data-type^='lbp-form-input']")
  100 + if (!inputs.length) return
  101 + const self = this
  102 + let formData = new FormData()
  103 + inputs.forEach(input => formData.append(input.dataset.uuid, input.value))
  104 + const req = new XMLHttpRequest()
  105 + req.onreadystatechange = function () {
  106 + if (req.readyState === 4) {
  107 + const message = req.status === 200 ? '提交成功' : '提交失败'
  108 + self.$message.info(message)
  109 + }
  110 + }
  111 +
  112 + // #!zh: vuex.module.editor.setWork 中定义
  113 + const workId = window.__work.id
  114 + // TODO #!zh: 可以动态配置表单提交地址
  115 + req.open('post', `/works/form/submit/${workId}`, true)
  116 + req.send(formData)
  117 + }
  118 + },
  119 + editorConfig: {
  120 + propsConfig: {
  121 + text: {
  122 + type: 'a-input',
  123 + label: '按钮文字',
  124 + require: true,
  125 + defaultPropValue: '按钮'
  126 + },
  127 + fontSize: {
  128 + type: 'a-input-number',
  129 + label: '字号(px)',
  130 + require: true,
  131 + prop: {
  132 + step: 1,
  133 + min: 12,
  134 + max: 144
  135 + },
  136 + defaultPropValue: 14
  137 + },
  138 + color: {
  139 + type: 'a-input',
  140 + label: '文字颜色',
  141 + // !#zh 为编辑组件指定 prop
  142 + prop: {
  143 + type: 'color'
  144 + },
  145 + require: true,
  146 + defaultPropValue: 'black'
  147 + },
  148 + backgroundColor: {
  149 + type: 'a-input', // lbs-color-picker
  150 + label: '背景颜色',
  151 + prop: {
  152 + type: 'color'
  153 + },
  154 + require: true,
  155 + defaultPropValue: '#ffffff' // TODO why logogram for color does't work?
  156 + },
  157 + borderColor: {
  158 + type: 'a-input', // lbs-color-picker
  159 + label: '边框颜色',
  160 + prop: {
  161 + type: 'color'
  162 + },
  163 + require: true,
  164 + defaultPropValue: '#eeeeee'
  165 + },
  166 + borderWidth: {
  167 + type: 'a-input-number',
  168 + label: '边框宽度(px)',
  169 + require: true,
  170 + prop: {
  171 + step: 1,
  172 + min: 1,
  173 + max: 10
  174 + },
  175 + defaultPropValue: 1
  176 + },
  177 + borderRadius: {
  178 + type: 'a-input-number',
  179 + label: '圆角(px)',
  180 + require: true,
  181 + prop: {
  182 + step: 0.1,
  183 + min: 0,
  184 + max: 10
  185 + },
  186 + defaultPropValue: 0
  187 + },
  188 + lineHeight: {
  189 + type: 'a-input-number',
  190 + label: '行高',
  191 + require: true,
  192 + prop: {
  193 + step: 0.1,
  194 + min: 0.1,
  195 + max: 10
  196 + },
  197 + defaultPropValue: 1
  198 + },
  199 + textAlign: {
  200 + /**
  201 + * #!en: you can also config type like below:
  202 + * #!zh: 可以直接这样写:
  203 + textAlign: {
  204 + type: component(component definition json/自定义的组件,比如下面的 components[''lbs-text-align'])
  205 + }
  206 +
  207 + * more explanation
  208 + textAlign: {
  209 + type: {
  210 + render() {},
  211 + props: {},
  212 + methods: {},
  213 + }
  214 + }
  215 + * #!en: reference: how to judge the tag is custom component or a HTML element in React or Vue?
  216 + * !#zh:
  217 + * 思路来源:
  218 + * React 中 深入JSX 中,如何判断 h(tag) 中的 tag 是自定义组件还是普通 HTML 元素呢?React 是判断该 tag 是否为 function 来实现的
  219 + * Vue 中的自定义组件 是一个普通的 JSON 对象,最后自定义组件被转换成了函数,输入是 JSON 输出是 函数,可以看看 Vue 中 createElement 也就是 h 的实现·
  220 + * 参见:http://hcysun.me/2018/01/05/%E6%8E%A2%E7%B4%A2Vue%E9%AB%98%E9%98%B6%E7%BB%84%E4%BB%B6/
  221 + */
  222 + type: 'lbs-text-align',
  223 + label: '文字对齐',
  224 + require: true,
  225 + defaultPropValue: 'center'
  226 + }
  227 + },
  228 + components: {
  229 + 'lbs-text-align': {
  230 + template: `
  231 + <div class="wrap">
  232 + <a-radio-group v-model="value_" size="small">
  233 + <a-tooltip effect="dark" :content="item.label" placement="top" :key="index" v-for="(item, index) in textAlignTabs">
  234 + <a-radio-button :label="item.value">
  235 + <!-- issue #8 -->
  236 + <i :class="['fa', 'fa-align-'+item.value]" aria-hidden="true"></i>
  237 + </a-radio-button>
  238 + </a-tooltip>
  239 + </a-radio-group>
  240 + </div>`,
  241 + props: {
  242 + value: {
  243 + type: [String, Number]
  244 + }
  245 + },
  246 + data: () => ({
  247 + textAlignTabs: [{
  248 + label: '左对齐',
  249 + value: 'left'
  250 + },
  251 + {
  252 + label: '居中对齐',
  253 + value: 'center'
  254 + },
  255 + {
  256 + label: '右对齐',
  257 + value: 'right'
  258 + }]
  259 + }),
  260 + computed: {
  261 + value_: {
  262 + // TODO 关于箭头函数中的this:这里不能写成箭头函数,否则 this 为 undefined,为何?
  263 + // http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/
  264 + // https://tangxiaolang101.github.io/2016/08/01/%E6%B7%B1%E5%85%A5%E6%8E%A2%E8%AE%A8JavaScript%E7%9A%84%E6%89%A7%E8%A1%8C%E7%8E%AF%E5%A2%83%E5%92%8C%E6%A0%88%EF%BC%88What%20is%20the%20Execution%20Context%20&%20Stack%20in%20JavaScript%EF%BC%89/
  265 + get () {
  266 + return this.value
  267 + },
  268 + set (val) {
  269 + this.$emit('input', val)
  270 + }
  271 + }
  272 + }
  273 + },
  274 + 'lbs-select-input-type': {
  275 + props: ['value'],
  276 + computed: {
  277 + value_: {
  278 + get () {
  279 + return this.value
  280 + },
  281 + set (val) {
  282 + this.$emit('input', val)
  283 + }
  284 + }
  285 + },
  286 + template: `
  287 + <a-select v-model="value_" placeholder="类型">
  288 + <a-option
  289 + v-for="item in options"
  290 + :key="item.value"
  291 + :label="item.label"
  292 + :value="item.value">
  293 + </a-option>
  294 + </a-select>
  295 + `,
  296 + data: () => ({
  297 + options: [
  298 + {
  299 + label: '文字',
  300 + value: 'text'
  301 + },
  302 + {
  303 + label: '密码',
  304 + value: 'password'
  305 + },
  306 + {
  307 + label: '日期',
  308 + value: 'date'
  309 + },
  310 + {
  311 + label: '邮箱',
  312 + value: 'email'
  313 + },
  314 + {
  315 + label: '手机号',
  316 + value: 'tel'
  317 + }
  318 + ]
  319 + })
  320 + }
  321 + }
  322 + }
  323 +}
front-end/h5/src/components/plugins/lbp-form-input.js
@@ -19,7 +19,7 @@ export default { @@ -19,7 +19,7 @@ export default {
19 name={this.name} 19 name={this.name}
20 placeholder={this.placeholder} 20 placeholder={this.placeholder}
21 autocomplete="off" 21 autocomplete="off"
22 - data-type="form-input" 22 + data-type="lbp-form-input" // 点击[表单提交]按钮的时候,找到data-type为:lbp-form-input 的输入框,并将其值添加到formData,提交到后台
23 /> 23 />
24 }, 24 },
25 props: { 25 props: {
front-end/h5/src/mixins/load-plugins.js
@@ -3,6 +3,7 @@ import LbpButton from &#39;../components/plugins/lbp-button&#39; @@ -3,6 +3,7 @@ import LbpButton from &#39;../components/plugins/lbp-button&#39;
3 import LbpPicture from '../components/plugins/lbp-picture' 3 import LbpPicture from '../components/plugins/lbp-picture'
4 import LbpText from '../components/plugins/lbp-text' 4 import LbpText from '../components/plugins/lbp-text'
5 import LbpFormInput from '../components/plugins/lbp-form-input' 5 import LbpFormInput from '../components/plugins/lbp-form-input'
  6 +import LbpFormButton from '../components/plugins/lbp-form-button'
6 7
7 export const pluginsList = [ 8 export const pluginsList = [
8 { 9 {
@@ -39,14 +40,14 @@ export const pluginsList = [ @@ -39,14 +40,14 @@ export const pluginsList = [
39 component: LbpFormInput, 40 component: LbpFormInput,
40 visible: true, 41 visible: true,
41 name: LbpFormInput.name 42 name: LbpFormInput.name
  43 + },
  44 + {
  45 + title: '表单提交',
  46 + icon: 'hand-pointer-o',
  47 + component: LbpFormButton,
  48 + visible: true,
  49 + name: LbpFormButton.name
42 } 50 }
43 - // {  
44 - // title: '表单提交',  
45 - // icon: 'hand-pointer-o',  
46 - // component: LbpFormButton,  
47 - // visible: true,  
48 - // name: LbpFormButton.name  
49 - // },  
50 ] 51 ]
51 52
52 export default { 53 export default {