-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
1,692 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/** | ||
* Created by denishuang on 2019/8/25. | ||
*/ | ||
|
||
import schema from 'async-validator' | ||
import array_normalize from '../../utils/array_normalize' | ||
|
||
export function joinErrors(errors) { | ||
let es = {} | ||
for (let n in errors) { | ||
es[n] = errors[n].join("") | ||
} | ||
return es | ||
} | ||
export function defaultWidget (f) { | ||
return f.type == 'boolean' ? 'checkbox' : (['date', 'datetime', 'time'].includes(f.type) ? f.type : ( ['integer', 'decimal'].includes(f.type) ? 'number' : 'text')) | ||
} | ||
|
||
export function defaultRuleType(f){ | ||
if (f.multiple) { | ||
return 'array' | ||
} | ||
if (f.choices && f.choices.length > 0) { | ||
return typeof f.choices[0][0] | ||
} | ||
return f.model ? 'number' : (['field', 'time'].includes(f.type) ? 'string' : (['integer', 'decimal'].includes(f.type) ? 'number' : f.type)) | ||
} | ||
|
||
export function defaultSpan(f){ | ||
return f.widget == 'textarea' ? {xs: 24, sm: 24, md: 24, lg: 24, xl: 24} : { | ||
xs: 24, | ||
sm: 24, | ||
md: 12, | ||
lg: 12, | ||
xl: 8 | ||
} | ||
} | ||
export function defaultRules(f){ | ||
let rs = [] | ||
if (f.required) { | ||
rs.push({ | ||
type: defaultRuleType(f), | ||
required: true, | ||
message: `不能为空` | ||
}) | ||
} | ||
if (f.min_length) { | ||
rs.push({min: f.min_length, message: `长度最小为${f.min_length}`}) | ||
} | ||
if (f.max_length) { | ||
rs.push({max: f.max_length, message: `长度最大为${f.max_length}`}) | ||
} | ||
return rs | ||
} | ||
export function normalizeItem(i){ | ||
let a = Object.assign({}, i) | ||
a.label = a.label || a.name | ||
a.rules = a.rules || defaultRules(a) | ||
a.widget = a.widget || defaultWidget(a) | ||
let sp = a.span | ||
a.span = sp && (typeof sp === 'number' && {xs: sp, sm: sp, md: sp, lg: sp, xl: sp} || sp) || {} | ||
a.span = Object.assign({}, defaultSpan(a), a.span) | ||
return a | ||
} | ||
export function normalizeItems(items){ | ||
return array_normalize(items,{}, normalizeItem) | ||
} | ||
export function getItemRules (items) { | ||
let d = {} | ||
Object.keys(items).forEach((i) => { | ||
let f = items[i] | ||
let n = f.name | ||
let rs = d[n] = f.rules || [] | ||
rs.concat(defaultRules(f)) | ||
|
||
}) | ||
return d | ||
|
||
} | ||
export default { | ||
defaultRules, | ||
defaultRuleType, | ||
defaultSpan, | ||
defaultWidget, | ||
normalizeItem, | ||
normalizeItems, | ||
getItemRules, | ||
joinErrors | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
<template> | ||
<el-form ref="form" :inline="elOptions.inline" :size="elOptions.size" :model="formValue" v-if="value" | ||
:inline-message="elOptions.inlineMessage" :hide-required-asterisk="elOptions.hideRequiredAsterisk" | ||
label-position="elOptions.labelPosition" | ||
:label-width="elOptions.labelWidth || elOptions.noLabel && '0px' || (!elOptions.inline && '160px')" | ||
v-loading="loading" :element-loading-text="loading"> | ||
|
||
<slot name="header"></slot> | ||
<el-alert :title="errors.non_field_errors" type="error" v-if="errors.non_field_errors" | ||
:closable="false"></el-alert> | ||
<el-row> | ||
<template v-for="f in formItems"> | ||
<el-col :xs="f.span.xs" :sm="f.span.sm" :md="f.span.md" :lg="f.span.lg" :xl="f.span.xl" | ||
:key="f.name" v-if="!elOptions.inline && !elOptions.oneColumn && f.widget !== 'hidden'"> | ||
<form-item :field="f" v-model="formValue" :options="options" :error="errors[f.name]"></form-item> | ||
</el-col> | ||
<form-item :field="f" v-model="formValue" :options="options" :error="errors[f.name]" v-else></form-item> | ||
|
||
</template> | ||
<slot name="submit"> | ||
<el-col :xs="elOptions.inline?12:24" :sm="elOptions.inline?8:24" :md="elOptions.inline?6:24" | ||
:lg="elOptions.inline?4:24" | ||
:xl="elOptions.inline?3:24" v-if="!elOptions.inline"> | ||
<el-form-item> | ||
<actions :items="_actions"></actions> | ||
</el-form-item> | ||
</el-col> | ||
<el-form-item v-else> | ||
<actions :items="_actions"></actions> | ||
</el-form-item> | ||
</slot> | ||
</el-row> | ||
</el-form> | ||
</template> | ||
<script> | ||
import server_response from '../../mixins/server_response' | ||
import schema from 'async-validator' | ||
import FormItem from './FormItem.vue' | ||
import Form from './Form' | ||
import Actions from '../layout/Actions.vue' | ||
export default{ | ||
mixins: [ | ||
server_response | ||
], | ||
props: { | ||
value: Object, | ||
actions: Array, | ||
items: {type: Array, default: () => []}, | ||
url: String, | ||
method: { | ||
type: String, default: 'post' | ||
}, | ||
options: { | ||
type: Object, | ||
default: () => { | ||
return {} | ||
} | ||
}, | ||
submit: Function, | ||
submitName: { | ||
type: String, default: '提交' | ||
} | ||
}, | ||
components: {FormItem, Actions}, | ||
data () { | ||
return { | ||
errors: {}, | ||
formValue: {}, | ||
formItems: [] | ||
} | ||
}, | ||
created () { | ||
this.formValue = this.value | ||
this.formItems = Form.normalizeItems(this.items) | ||
}, | ||
methods: { | ||
doSubmit () { | ||
this.$emit('beforesubmit', this.formValue) | ||
this.loading = `正在${this.submitName}` | ||
if (this.submit) { | ||
return this.submit() | ||
} else { | ||
let action = this.method === 'post' ? this.$http.post : this.$http.put | ||
return action(this.url, this.formValue).then(({data}) => { | ||
return data | ||
}) | ||
} | ||
}, | ||
onPosted(data){ | ||
this.loading = false | ||
this.$message({message: `${this.submitName}成功`, type: 'success'}) | ||
this.$emit("form-posted", data) | ||
return data | ||
}, | ||
onValidated (valid, notValidFields) { | ||
if (valid) { | ||
this.errors = {} | ||
} | ||
}, | ||
onSubmit () { | ||
return this.$refs.form.validate().then(this.onValidated).then(this.doSubmit).then(this.onPosted).catch(e => { | ||
if (e === false) { | ||
this.$message({message: '表单检验未通过,请按提示修改', type: 'error'}) | ||
} else { | ||
let error = this.onServerResponseError(e) | ||
if (error.code === 400) { | ||
this.errors = Form.joinErrors(error.msg) | ||
} | ||
} | ||
} | ||
) | ||
}, | ||
}, | ||
computed: { | ||
rules () { | ||
return Form.getItemRules(this.formItems) | ||
}, | ||
_actions () { | ||
return this.actions || [{name: 'submit', label: this.submitName, do: this.onSubmit}] | ||
}, | ||
elOptions () { | ||
return this.options.elForm || {} | ||
} | ||
}, | ||
watch: { | ||
value(val){ | ||
this.formValue = val | ||
}, | ||
items (val) { | ||
this.formItems = Form.normalizeItems(val) | ||
} | ||
} | ||
} | ||
</script> | ||
<style scoped></style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<template> | ||
<el-form-item :prop="field.name" :rules="field.rules" :label="field.label" :error="error" | ||
:ref="field.name" | ||
:style="options.noLabel && {} || options.itemStyle || {minWidth: '350px'}"> | ||
<template slot="label" v-if="!options.noLabel"> | ||
{{field.label}} | ||
<el-tooltip placement="top" v-if="field.help_text"> | ||
<div slot="content" v-html="field.help_text"></div> | ||
<i class="fa fa-info-circle bg-info"></i> | ||
</el-tooltip> | ||
</template> | ||
<template slot="label" v-else><span></span></template> | ||
<template> | ||
<form-widget v-model="value" :field="field"></form-widget> | ||
</template> | ||
</el-form-item> | ||
</template> | ||
<script> | ||
import FormWidget from '../widgets/FormWidget.vue' | ||
export default{ | ||
props: { | ||
field: Object, | ||
value: Object, | ||
options: { | ||
type: Object, | ||
default: () => { | ||
return {} | ||
} | ||
}, | ||
error: String | ||
}, | ||
data () { | ||
return {} | ||
}, | ||
components: { | ||
FormWidget, | ||
}, | ||
methods: {}, | ||
computed: {} | ||
} | ||
</script> | ||
<style scoped></style> |
Oops, something went wrong.