<template>
|
<div class="form-content">
|
<div class="title" v-if="title">
|
<SectionTitle :title="title"></SectionTitle>
|
</div>
|
<el-form
|
v-bind="$attrs"
|
:inline="inline"
|
:model="formValues"
|
ref="editForm"
|
:label-width="labelWidth"
|
:class="`form-cols-${inline ? showColumn : '0'}`"
|
size="small"
|
>
|
<el-form-item v-if="$slots.top" v-bind="topInfo">
|
<slot name="top"></slot>
|
</el-form-item>
|
|
<el-form-item
|
v-for="(item, index) in showList"
|
:prop="item.name"
|
:key="index"
|
v-show="!item.hide"
|
:label="formType === 'search' ? item.label : `${item.label}:`"
|
:rules="showFormRules[item.name] || null"
|
:class="[{'textarea-item': item.type === 'textarea' || item.isLong}, {'textarea-grid': item.multiRow }]"
|
>
|
<CommInput :info="item" :showList="showList" @updateValue="updateValue"></CommInput>
|
</el-form-item>
|
|
<el-form-item v-if="$slots.default">
|
<slot></slot>
|
</el-form-item>
|
|
<el-form-item v-if="buttons.length > 0" class="form-right">
|
<div class="from-buttons">
|
<p
|
v-for="(button, index) in buttons"
|
:key="typeof button.id === 'undefined' ? index : button.id"
|
>
|
<Fold
|
v-if="button.type === 'fold'"
|
:isShowDetail="isShowAll"
|
@handleClick="$emit('buttonAction', typeof button.id === 'undefined' ? index : button.id, button)"
|
></Fold>
|
<el-button
|
v-else
|
size="small"
|
class="normal-button"
|
@click="$emit('buttonAction', typeof button.id === 'undefined' ? index : button.id, button)"
|
:type="typeof button.type === 'undefined' ? 'primary' : button.type"
|
>{{button.text}}</el-button>
|
</p>
|
</div>
|
</el-form-item>
|
</el-form>
|
</div>
|
</template>
|
<script>
|
// 表单项-目前用于搜索部分
|
import { mapGetters } from 'vuex'
|
import CommInput from '@/components/CommInput'
|
import SectionTitle from '@/components/SectionTitle'
|
import Fold from '@/components/Fold'
|
export default {
|
components: {
|
CommInput,
|
SectionTitle,
|
Fold
|
},
|
props: {
|
/**
|
* list 表单数组(type: input, textarea, select, time, date, rangeDate)
|
* @example
|
* [ { "type": "input", "label": "申请编号:", "value": "", "name": "serialNo" }]
|
*/
|
list: {
|
type: [Object, Array],
|
default: v => []
|
},
|
|
formValues: {
|
type: Object,
|
default: () => ({})
|
},
|
|
formRules: {
|
type: Object,
|
default: () => ({})
|
},
|
|
/**
|
* buttons 按钮列表
|
* @example
|
* [ {"text": '搜索' }, {"type": "fold", text: '展开'}]
|
*/
|
buttons: {
|
type: Array,
|
default: v => []
|
},
|
|
// 是否展示全部表单项(控制展开与收起)
|
isShowAll: {
|
type: Boolean,
|
default: true
|
},
|
|
// 对应isShowAll为false的时候最多展示列表的个数
|
shortNum: {
|
type: Number,
|
default: 3
|
},
|
|
// 显示列数(固定列数,0为不设置固定值)
|
column: {
|
type: [String, Number],
|
default: 0
|
},
|
|
topInfo: {
|
type: Object,
|
default: () => ({})
|
},
|
|
inline: {
|
type: Boolean,
|
default: true
|
},
|
|
// 输入框或select的宽度
|
inputWidth: {
|
type: String,
|
default: '220px'
|
},
|
|
// 标题
|
title: {
|
type: String,
|
default: ''
|
},
|
|
// 默认日期格式
|
dateFormate: {
|
type: String,
|
default: 'YYYY/MM/DD'
|
},
|
|
// 默认错误提示信息
|
errorMsg: {
|
type: String,
|
default: '当前页面存在必填项未录入或数据录入错误,请检查!'
|
},
|
|
// { "tabName": "退款申请信息", "gray": "N", "visible": "Y", "edit": "N" }
|
conf: {
|
type: Object,
|
default: () => ({})
|
},
|
|
// form类型
|
// search:搜索条件类(屏幕适应缩放3-4个)
|
// edit:编辑类(屏幕适应缩放2-3个)
|
// info:编辑处理类(自动判断是否为readonly,屏幕适应缩放2-3个)
|
// text:文本展示类(不会有输入框,屏幕适应缩放2-3个)
|
formType: {
|
type: String,
|
default: 'edit'
|
}
|
},
|
data() {
|
return {
|
clientWidth: 0
|
}
|
},
|
mounted() {
|
window.addEventListener('resize', this.updateClientWidth)
|
this.updateClientWidth()
|
},
|
methods: {
|
updateClientWidth() {
|
const clientWidth = document.documentElement.clientWidth || 0
|
this.clientWidth = clientWidth
|
// console.log(this.clientWidth)
|
},
|
// 更新值
|
updateValue(val, item, parentName) {
|
const { list } = this
|
const { name } = item
|
const realName = parentName || name
|
|
const index = list.findIndex(
|
({ name: ItemName }) => ItemName === realName
|
)
|
if (index < 0) {
|
return false
|
}
|
|
if (parentName) {
|
const { children = [], ...other } = list[index]
|
const temList = children.reduce((pre, curr) => {
|
const { name: subName } = curr
|
if (subName === name) {
|
curr = { ...curr, value: this.computedValue(val, curr) }
|
}
|
pre.push({ ...curr })
|
return pre
|
}, [])
|
|
this.$emit('updateValue', index, { ...other, children: temList })
|
} else {
|
this.$emit('updateValue', index, {
|
...list[index],
|
value: this.computedValue(val, item)
|
})
|
}
|
},
|
|
// 输入格式错误校验
|
computedValue(val, item) {
|
// keepNum 根据传递的值控制保留多少为小数
|
const { isMoney, keepNum = 2 } = item
|
if (isMoney && typeof val !== 'object') {
|
if (/[,,]/.test(String(val))) {
|
val = String(val).replace(/[,,]/g, '')
|
}
|
// 非数字
|
if (isNaN(val) || Number(val) < 0 || /^0+\d/.test(val)) {
|
return ''
|
}
|
// 去除多余2位小数后的数字
|
if (/\.\d{3,}$/.test(String(val))) {
|
const arr = String(val).split('.')
|
return `${arr[0]}.${arr[1].substring(0, keepNum)}`
|
}
|
// 对带有isMoney属性的字段其结果去除左右空格
|
val = val.trim()
|
}
|
if (val instanceof Date) {
|
return this.$formateDate(val)
|
}
|
return val
|
},
|
|
/**
|
* isText 是否为文本类型
|
*/
|
getInfoList(list, isText = false) {
|
const { isEdit, isReadonly } = this
|
return list.map(item => {
|
const {
|
attrs = [],
|
type,
|
value = '',
|
descValue,
|
isMoney,
|
keepNum = 2
|
} = item
|
let result = {
|
...item
|
}
|
if (!isText && isEdit) {
|
const isReadonlyItem = attrs.some(
|
attr =>
|
(typeof attr === 'object' && attr.readonly) || attr === 'readonly'
|
)
|
if (isReadonly || isReadonlyItem) {
|
result.rules = []
|
if (isMoney && value.toString().trim() !== '') {
|
result.value = this.$utils.fMoney(item.value, keepNum)
|
}
|
if (!['input', 'textarea', 'customer'].includes(type)) {
|
result.type = 'input'
|
}
|
if (!isReadonlyItem) {
|
result.attrs = [...attrs, 'readonly']
|
}
|
if (typeof descValue !== 'undefined') {
|
result.value = descValue
|
}
|
}
|
} else {
|
if (type === 'textarea') {
|
result.isLong = true
|
}
|
if (typeof descValue !== 'undefined') {
|
result.value = descValue
|
}
|
result.rules = []
|
result.type = 'text'
|
}
|
return result
|
})
|
},
|
|
/**
|
* 表单校验,未通过校验返回false,通过返回数据
|
* deleteAttr 排除特定属性字段,如排除只读及disabled字段:['readonly', 'disabled']
|
*/
|
validate(deleteAttr) {
|
const { formValues, showList } = this
|
let info = false
|
this.$refs.editForm.validate(valid => {
|
if (valid) {
|
if (Array.isArray(deleteAttr) && deleteAttr.length > 0) {
|
info = Object.keys(formValues).reduce((pre, curr) => {
|
const item = showList.find(({ name }) => name === curr)
|
let isRemove = false
|
if (item) {
|
const { attrs = [] } = item
|
attrs.forEach(attrItem => {
|
if (
|
typeof attrItem === 'string' &&
|
deleteAttr.includes(attrItem)
|
) {
|
isRemove = true
|
}
|
if (
|
typeof attrItem === 'object' &&
|
Object.keys(attrItem).some(attrKey =>
|
deleteAttr.includes(attrKey)
|
)
|
) {
|
isRemove = true
|
}
|
})
|
}
|
if (!isRemove) {
|
pre[curr] = formValues[curr]
|
}
|
return pre
|
}, {})
|
} else {
|
info = formValues
|
}
|
}
|
})
|
return info
|
},
|
/**
|
* 重置
|
*/
|
resetFields() {
|
this.$refs.editForm.resetFields()
|
},
|
},
|
computed: {
|
showColumn() {
|
const { formType, column, clientWidth } = this
|
if (Number(column) !== 0) {
|
return Number(column)
|
}
|
const num = formType === 'search' ? 4 : 3
|
if (clientWidth > 1460) {
|
return num
|
}
|
return num - 1
|
},
|
isReadonly() {
|
const { isEdit, conf, formType } = this
|
const { edit } = conf
|
const readonly = typeof edit === 'string' && edit.toUpperCase() === 'N'
|
return isEdit && ['edit', 'info'].includes(formType) && readonly
|
},
|
showList() {
|
const { list, isShowAll, showColumn, formType } = this
|
let result = [...list]
|
if (!isShowAll) {
|
// search展开收起处理
|
result = result.slice(0, showColumn === 4 ? showColumn - 1 : showColumn)
|
}
|
return ['info', 'text'].includes(formType)
|
? this.getInfoList(result, formType === 'text')
|
: result
|
},
|
showFormRules() {
|
const { formRules, formType, isEdit, isReadonly } = this
|
return formType === 'info' && (!isEdit || isReadonly) ? {} : formRules
|
},
|
labelWidth() {
|
const { formType } = this
|
return formType === 'search' ? '84px' : '160px'
|
},
|
...mapGetters(['isEdit'])
|
}
|
}
|
</script>
|
<style lang="postcss" scoped>
|
.form-content {
|
& >>> .el-form {
|
display: grid;
|
padding-bottom: 6px;
|
& .el-form-item {
|
display: flex;
|
align-items: center;
|
padding-right: 40px;
|
margin: 0 0 24px 0;
|
& label {
|
padding: 0;
|
text-align: right;
|
margin-right: 10px;
|
line-height: 16px;
|
}
|
& .el-form-item__content {
|
flex: 1;
|
margin: 0;
|
}
|
&.right-item {
|
justify-content: right;
|
grid-column-start: 3;
|
grid-column-end: 4;
|
}
|
& .el-date-editor {
|
width: 100%;
|
}
|
& .el-input--small {
|
font-size: 14px;
|
}
|
& .el-select {
|
width: 100%;
|
}
|
}
|
& .form-sign {
|
& label::after {
|
content: ':';
|
}
|
}
|
}
|
|
& >>> .el-tag--info {
|
max-width: 94%;
|
overflow: hidden;
|
}
|
& >>> .el-select__tags-text {
|
display: inline-block;
|
max-width: 110px;
|
overflow: hidden;
|
white-space: nowrap;
|
text-overflow: ellipsis;
|
}
|
& .from-buttons {
|
/* padding-left: 82px; */
|
display: flex;
|
justify-content: flex-end;
|
& p {
|
margin: 0;
|
padding: 0;
|
}
|
& >>> .el-button {
|
height: 32px;
|
font-size: 12px;
|
margin-left: 12px;
|
}
|
& .normal-button {
|
height: 32px;
|
font-size: 14px;
|
margin-left: 22px;
|
}
|
& .el-button--primary {
|
background-color: #0081f0;
|
border-color: #0081f0;
|
}
|
}
|
& >>> .el-tag__close {
|
top: -5px;
|
right: -6px;
|
}
|
& >>> .el-form-item__label {
|
color: #888888;
|
}
|
& >>> .el-input__inner {
|
border-color: #eeeeee;
|
color: #222222;
|
}
|
|
& .is-error >>> .el-input__inner {
|
border-color: #f56c6c;
|
}
|
|
& .long-lable >>> .el-form-item__label {
|
line-height: 1.3em;
|
padding-top: 0;
|
}
|
& .textarea {
|
width: 100%;
|
& >>> textarea {
|
height: 100%;
|
}
|
}
|
& .range-separato {
|
width: 10px;
|
display: inline-block;
|
text-align: center;
|
}
|
& .range-input-item {
|
display: inline-block;
|
}
|
|
& .form-cols-1 {
|
grid-template-columns: 1fr;
|
& .textarea-item {
|
grid-column-start: 1;
|
grid-column-end: 1;
|
}
|
& .form-right {
|
grid-column-start: 1;
|
grid-column-end: 1;
|
}
|
}
|
|
& .form-cols-2 {
|
grid-template-columns: repeat(2, 1fr);
|
& .textarea-item {
|
grid-column-start: 1;
|
grid-column-end: 3;
|
}
|
& .form-right {
|
grid-column-start: 2;
|
grid-column-end: 3;
|
}
|
}
|
& .form-cols-3 {
|
grid-template-columns: repeat(3, 1fr);
|
& .textarea-item {
|
grid-column-start: 1;
|
grid-column-end: 4;
|
}
|
& .form-right {
|
grid-column-start: 3;
|
grid-column-end: 4;
|
}
|
}
|
|
& .form-cols-4,
|
& .form-cols-5 {
|
grid-template-columns: repeat(4, 1fr);
|
|
& .textarea-item {
|
grid-column-start: 1;
|
grid-column-end: 5;
|
}
|
& .form-right {
|
grid-column-start: 4;
|
grid-column-end: 5;
|
}
|
& .textarea-grid {
|
grid-column-start: 1;
|
grid-column-end: 1;
|
grid-row-end: span 3;
|
align-self: start;
|
&:nth-child(2) {
|
grid-column-start: 2;
|
grid-column-end: 2;
|
}
|
}
|
& .textarea-grid {
|
& >>> .el-textarea__inner{
|
height: 88px;
|
}
|
}
|
& .textarea-grid1 {
|
& >>> .el-textarea__inner{
|
height: 88px;
|
}
|
}
|
}
|
& .form-cols-5 {
|
grid-template-columns: repeat(5, 1fr);
|
& .form-right{
|
grid-column-start: 5;
|
}
|
|
& >>> .el-range-editor {
|
width: 215px!important;
|
}
|
}
|
}
|
</style>
|