545 lines
20 KiB
Vue
545 lines
20 KiB
Vue
<!--
|
||
* @name: 自定义表单组件
|
||
* @author: zhangpengcheng
|
||
* @date: 2022-08-24
|
||
-->
|
||
<template>
|
||
<el-form validate-on-rule-change :model="ruleForm" :rules="rules" label-position="top" ref="ruleForm"
|
||
label-width="100px">
|
||
<el-row :gutter="24" v-for="(item, index) in formRow" :key="index" style="margin-bottom: 17px;">
|
||
<el-col v-for="(row, indexRow) in item.elCol" :span="row.span ? row.span : spanNumber" :key="indexRow">
|
||
<el-form-item :prop="row.prop" :style="`display: flex;margin-bottom: ${marginBottom}px;`"
|
||
v-if="row.show != false" :class="(rules[row.prop] ? 'ruleFormClass ' : '')">
|
||
<!-- <span class="label" slot="label" style="width: 25%;">{{row.label}}</span> -->
|
||
<div class="single label" v-if="row.label" slot="label"
|
||
:style="`width: ${spanWidth};` + `justify-content: ${justifyContent};`" flex>
|
||
<span class="label">{{ row.label }}</span>
|
||
</div>
|
||
<el-input v-model="ruleForm[row.prop]" v-if="row.tag === 'password'" type="password" show-password clearable auto-complete="off" placeholder="密码" @keyup.enter.native="handleLogin" :disabled="row.disabled ? row.disabled : false">
|
||
<svg-icon
|
||
slot="prefix"
|
||
icon-class="password"
|
||
class="el-input__icon input-icon"
|
||
/>
|
||
</el-input>
|
||
<el-input v-model="ruleForm[row.prop]" clearable :disabled="row.disabled ? row.disabled : false"
|
||
:rows="row.rows ? row.rows : 2" :type="row.type ? row.type : 'text'" :maxlength="row.maxlength ? row.maxlength : ''"
|
||
:placeholder="!row.placeholder ? '请输入' : row.placeholder" v-if="row.tag === 'elInput'"
|
||
@blur="searchByStationName(row.prop)" min="1" @input="row.rules ? integerNumber(row) : ''">
|
||
</el-input>
|
||
<el-input-number v-if="row.tag === 'elInputNumber'" v-model="ruleForm[row.prop]"style="width: 100%;"
|
||
:disabled="row.disabled ? row.disabled : false" :precision="row.precisionNum ? row.precisionNum : 0"
|
||
:step="row.stepNum ? row.stepNum : 1" @change="handleChange" :min="0"
|
||
:max="row.maxNum ? row.maxNum : 99999"
|
||
:label="!row.placeholder ? '描述文字' : row.placeholder"></el-input-number>
|
||
<!-- <div v-if="row.prop=='address'" id="container"
|
||
style="display:none;margin-top:30px;width: 730px;margin:0 auto;height: 590px;border: 1px solid gray;overflow:hidden;">
|
||
</div> -->
|
||
<el-switch v-if="row.tag === 'elSwitch'" v-model="ruleForm[row.prop]" :active-text="row.activeText"
|
||
@change="switchChange($event, index, indexRow, row)" :inactive-text="row.inactiveText"
|
||
:active-value="row.activeValue ? row.activeValue : true"
|
||
:inactive-value="row.inactiveValue || row.inactiveValue == 0 ? row.inactiveValue : false">
|
||
</el-switch>
|
||
<el-date-picker v-model="ruleForm[row.prop]" v-if="row.tag === 'elDatePicker'" class="w-100"
|
||
:class="{ one: row.type ? 'date' : row.type }" :disabled="row.disabled ? row.disabled : false"
|
||
:value-format="!row.valueFormat ? 'yyyy-MM-dd' : row.valueFormat" range-separator="至"
|
||
start-placeholder="开始日期" end-placeholder="结束日期" :type="!row.type ? 'date' : row.type"
|
||
:placeholder="!row.placeholder ? '请选择' : row.placeholder">
|
||
</el-date-picker>
|
||
<el-radio-group v-model="ruleForm[row.prop]" v-if="row.tag === 'elRadio'" @input="changeRadio($event,index,indexRow,row)"
|
||
:disabled="row.disabled ? row.disabled : false">
|
||
<el-radio v-for="el in row.options" :label="el.value" :key="el.value">{{ el.label }}</el-radio>
|
||
</el-radio-group>
|
||
<div @click="elDialogClick(row, index, indexRow)" @mouseover="elDialogHover(row)"
|
||
@mouseleave="elDialogLeave(row)" v-if="row.tag === 'elDialog'" class="elDialog"
|
||
:style="{ 'background-color': row.disabled ? '#F5FAF7' : '#fff', 'curpur': row.disabled ? 'pointer' : 'default' }">
|
||
<!-- ,background-color:row.disabled?'#c0c4cc':'#fff' -->
|
||
<p :style="{ color: ruleForm[row.prop] ? '#000' : '#c0c4cc' }" class="showText"
|
||
@click="elDialogClick(row, index, indexRow)">{{ ruleForm[row.prop] ? ruleForm[row.prop] :
|
||
'请点击选择' }}
|
||
<!-- <el-input v-model="ruleForm[row.prop]"></el-input> -->
|
||
</p>
|
||
<!-- <i class="el-icon-more " v-if="row.elDialogHoverType"></i> -->
|
||
<i class="el-icon-more " @click="elDialogClick(row, index, indexRow)"
|
||
v-if="!row.disabled && !ruleForm[row.prop]"></i>
|
||
<i class="el-icon-circle-close " v-if="!row.disabled && ruleForm[row.prop] && row.elDialogHoverType"
|
||
@click.stop="resetField(row.prop)" style="margin-left: 10px;"></i>
|
||
</div>
|
||
<div v-if="row.tag === 'elLook'">
|
||
{{ ruleForm[row.prop] }}
|
||
</div>
|
||
<el-select class="w-100" v-model="ruleForm[row.prop]" filterable
|
||
@change="selectChange($event, index, indexRow, row.options)" :disabled="row.disabled?row.disabled:false"
|
||
:clearable="row.clearable ? row.clearable : true"
|
||
:placeholder="!row.placeholder ? '请选择' : row.placeholder" v-if="row.tag === 'elSelect'">
|
||
<el-option v-for="(el, index) in row.options"
|
||
:key="!row.optionValue ? el['value'] : el[row.optionValue]"
|
||
:label="!row.optionLabel ? el['label'] : el[row.optionLabel]"
|
||
:value="!row.optionValue ? el['value'] : el[row.optionValue]">
|
||
</el-option>
|
||
</el-select>
|
||
<el-select class="w-100" v-model="ruleForm[row.prop]" multiple :disabled="row.disabled?row.disabled:false"
|
||
:clearable="row.clearable" :placeholder="!row.placeholder ? '请选择' : row.placeholder"
|
||
v-if="row.tag === 'elMultiple'">
|
||
<el-option v-for="el in row.options" :key="!row.optionValue ? el['value'] : el[row.optionValue]"
|
||
:label="!row.optionLabel ? el['label'] : el[row.optionLabel]"
|
||
:value="!row.optionValue ? el['value'] : el[row.optionValue]">
|
||
</el-option>
|
||
</el-select>
|
||
<treeselect v-if="row.tag === 'elTreeSelect'" v-model="ruleForm[row.prop]" :normalizer="normalizer"
|
||
:options="delTreeChildren(row.options)" :multiple="row.multiple?row.multiple:false"
|
||
:disabled="row.disabled?row.disabled:false" @clear="treeSelectClear" ref="selectTree"
|
||
:placeholder="!row.placeholder?'请选择':row.placeholder" @select="selectTree" />
|
||
<slot :name="row.slotName" v-if="row.tag === 'elSlot'" :row="ruleForm"></slot>
|
||
<!-- <upload-file v-if="row.tag === 'uploadFile'" :showImgPath="ruleForm[row.prop]" ref="imgFile"
|
||
@onImage="row.prop == 'beforeImgList'? getbeforeImgList:row.prop == 'materialsList'? getmaterialsList:row.prop == 'getmaterialsListAfter'?getmaterialsListAfter:getImage "></upload-file> -->
|
||
<!-- <custom-cascader :name="row.prop" :field="row.prop" :ref="row.prop" class="w-100"
|
||
v-if="row.tag === 'customCascader'" @onChange="getCascader"></custom-cascader> -->
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<slot name="main"></slot>
|
||
<el-form-item v-if="isFunBtn" style="margin-top: 12px;">
|
||
<!-- flex="cross:center main:center" -->
|
||
<div flex="main:right">
|
||
<el-button class="saveBtn" type="primary" @click="submitForm('ruleForm')">提交</el-button>
|
||
<el-button @click="resetForm('ruleForm')">重置</el-button>
|
||
</div>
|
||
</el-form-item>
|
||
</el-form>
|
||
</template>
|
||
|
||
<script>
|
||
// import uploadFile from "@/components/uploadFile";
|
||
// import customCascader from "@/components/customCascader";
|
||
import {
|
||
checkMobile
|
||
} from '@/utils/util'
|
||
export default {
|
||
components: {
|
||
// uploadFile,
|
||
// customCascader
|
||
},
|
||
props: {
|
||
// 表单显示格式
|
||
spanNumber: {
|
||
type: Number,
|
||
default: 12
|
||
},
|
||
spanWidth: {
|
||
type: String,
|
||
default: '90px'
|
||
},
|
||
// 表单验证规则
|
||
rules: {
|
||
type: Object,
|
||
default: () => {
|
||
return {}
|
||
}
|
||
},
|
||
// 表单页面结构数据
|
||
formRow: {
|
||
type: Array,
|
||
default: () => {
|
||
return []
|
||
}
|
||
},
|
||
// 是否禁用
|
||
disabled: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 是否显示操作按钮
|
||
isFunBtn: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
formdata: {
|
||
type: Object,
|
||
},
|
||
justifyContent: {
|
||
type: String,
|
||
default: 'flex-start'
|
||
},
|
||
marginBottom: {
|
||
type: String,
|
||
default: '0'
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
// 表单数据
|
||
ruleForm: {},
|
||
}
|
||
},
|
||
watch: {
|
||
ruleForm: {
|
||
immediate: true, // 立即执行
|
||
deep: true, // 深度监听复杂类型内变化
|
||
handler(newVal, oldVal) {
|
||
this.$emit('dataChanges')
|
||
}
|
||
}
|
||
},
|
||
created() { },
|
||
mounted() {
|
||
// this.ruleForm = this.formdata
|
||
},
|
||
computed: {},
|
||
methods: {
|
||
integerNumber(row) {
|
||
// row.rules?(v)=>()):''
|
||
// @input="(v)=>(row.row.number=v.replace(/[^\d]/g,''))"
|
||
// if(this.ruleForm[row.prop].replace(/[^\d]/g,'')){
|
||
// return this.ruleForm[row.prop].replace(/[^\d]/g,'')
|
||
//
|
||
// integer整数
|
||
if (row.rulesName == 'integer') {
|
||
this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(/[^\d]/g, '')
|
||
}
|
||
// decimal小数
|
||
if (row.rulesName == 'decimal') {
|
||
this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(/[^\d.]/g, '').replace(/\.{2,}/g, '.')
|
||
.replace('.', '$#$')
|
||
.replace(/\./g, '').replace('$#$', '.').replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3').replace(
|
||
/^\./g, '')
|
||
}
|
||
// 身份证
|
||
if (row.rulesName == 'identity') {
|
||
this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(
|
||
/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
|
||
'')
|
||
}
|
||
// 手机号
|
||
if (row.rulesName == 'phone') {
|
||
this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(/^1(3|4|5|7|8|9)\\d{9}$/, '')
|
||
// this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(/^1[3,4,5,6,7,8,9][0-9]{9}$/, '')
|
||
// this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(/1(\d{2})\d{4}(\d{4})/g,'').replace(/[^\d]/g, '')
|
||
// this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(/\.{11,}/g, '')
|
||
// /^1[3|4|5|6|7|8|9][0-9]\d{8}$/
|
||
}
|
||
// 邮箱
|
||
if (row.rulesName == 'eMail') {
|
||
this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(
|
||
/^([0-9a-zA-Z_\.\-\])+\@([0-9a-zA-Z_\.\-\])+\.([a-zA-Z]+)$/, '')
|
||
}
|
||
// this.ruleForm[row.prop] = this.ruleForm[row.prop].replace(/[^\d]/g,'')
|
||
},
|
||
//根据地址获取经纬度
|
||
searchByStationName(type) {
|
||
if (type == 'address') {
|
||
let address = this.ruleForm[type]
|
||
let that = this
|
||
var map = new BMap.Map("container");
|
||
map.centerAndZoom(address, 18);
|
||
map.enableScrollWheelZoom(); //启用滚轮放大缩小,默认禁用
|
||
map.enableContinuousZoom(); //启用地图惯性拖拽,默认禁用
|
||
map.addControl(new BMap.NavigationControl()); //添加默认缩放平移控件
|
||
map.addControl(new BMap.OverviewMapControl()); //添加默认缩略地图控件
|
||
map.addControl(new BMap.OverviewMapControl({
|
||
isOpen: true,
|
||
anchor: BMAP_ANCHOR_BOTTOM_RIGHT
|
||
})); //右下角,打开
|
||
var localSearch = new BMap.LocalSearch(map);
|
||
localSearch.enableAutoViewport(); //允许自动调节窗体大小
|
||
map.clearOverlays(); //清空原来的标注
|
||
var keyword = address
|
||
localSearch.setSearchCompleteCallback(function (searchResult) {
|
||
var poi = searchResult.getPoi(0);
|
||
map.centerAndZoom(poi.point, 13);
|
||
var marker = new BMap.Marker(new BMap.Point(poi.point.lng, poi.point
|
||
.lat)); // 创建标注,为要查询的地方对应的经纬度
|
||
map.addOverlay(marker);
|
||
var content = keyword + "<br/><br/>经度:" + poi.point.lng + "<br/>纬度:" + poi.point.lat;
|
||
that.ruleForm['lng'] = poi.point.lng
|
||
that.ruleForm['lat'] = poi.point.lat
|
||
var infoWindow = new BMap.InfoWindow("<p style='font-size:14px;'>" + content + "</p>");
|
||
marker.addEventListener("click", function () {
|
||
this.openInfoWindow(infoWindow);
|
||
});
|
||
// marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳动的动画
|
||
});
|
||
localSearch.search(keyword);
|
||
}
|
||
|
||
},
|
||
//计步器
|
||
handleChange(val) {
|
||
this.$emit('handleChange', val)
|
||
},
|
||
// 获取图片
|
||
getImage(imagePath) {
|
||
let licenseImg = imagePath.join(",")
|
||
},
|
||
// 处置前照片
|
||
getbeforeImgList(imagePath) {
|
||
let licenseImg = imagePath.join(",")
|
||
this.$set(this.ruleForm, 'beforeImgList', licenseImg)
|
||
},
|
||
// 处置材料
|
||
getmaterialsList(imagePath) {
|
||
let licenseImg = imagePath.join(",")
|
||
this.$set(this.ruleForm, 'materialsList', licenseImg)
|
||
},
|
||
// 处置后材料
|
||
getmaterialsListAfter(imagePath) {
|
||
let licenseImg = imagePath.join(",")
|
||
this.$set(this.ruleForm, 'materialsListAfter', licenseImg)
|
||
},
|
||
revealPhoto(licenseImg) {
|
||
this.$refs.imgFile.revealImg(licenseImg)
|
||
},
|
||
// 回显数据
|
||
echoFromData(echoData, otherField) {
|
||
let jsonData = []
|
||
this.formRow.forEach(item => {
|
||
jsonData.push(item.elCol)
|
||
})
|
||
let newJson = [].concat.apply([], jsonData)
|
||
newJson.forEach(item => {
|
||
if (this.ruleForm.factoryInFlag == 1) {
|
||
for (let i = 0; i < this.formRow[8].elCol.length; i++) { }
|
||
}
|
||
if (this.ruleForm.factoryInFlag == 0) {
|
||
for (let i = 0; i < this.formRow[8].elCol.length; i++) { }
|
||
}
|
||
this.$set(this.ruleForm, item.prop, echoData[item.prop])
|
||
})
|
||
// 回显自定义多级选择组件
|
||
if (typeof otherField == 'object') {
|
||
this.$refs[otherField.props][0].setEchoData(echoData[otherField.field])
|
||
}
|
||
},
|
||
// 获取指定字段参数
|
||
//参数propLabel , 值value
|
||
getField(propLabel, value) {
|
||
this.$set(this.ruleForm, propLabel, value)
|
||
},
|
||
//弹窗赋值
|
||
choiceAssignment(value) {
|
||
this.ruleForm = Object.assign({}, value)
|
||
// this.$forceUpdate()
|
||
},
|
||
incomingParameters(vale) {
|
||
let ruleLength = 0
|
||
let valeLength = 0
|
||
for (let i in vale) {
|
||
valeLength = valeLength + 1
|
||
}
|
||
for (let i in this.ruleForm) {
|
||
ruleLength = ruleLength + 1
|
||
}
|
||
// if(ruleLength == valeLength){
|
||
// this.choiceAssignment(vale)
|
||
// }else{
|
||
// for(let i in vale){
|
||
// this.getField(i,vale[i])
|
||
// }
|
||
// }
|
||
for (let i in vale) {
|
||
this.getField(i, vale[i])
|
||
}
|
||
},
|
||
resetFormPlus(formName) {
|
||
for (let i in this.$refs[formName]) {
|
||
this.getField(i, '')
|
||
}
|
||
},
|
||
// 重置表单字段
|
||
resetField(field) {
|
||
if (this.ruleForm[field]) {
|
||
this.$set(this.ruleForm, field, '')
|
||
this.$refs['ruleForm'].clearValidate(field); // 清除表单特定属性
|
||
}
|
||
},
|
||
resetFields() {
|
||
this.choiceAssignment({})
|
||
this.$refs.ruleForm.resetFields();
|
||
},
|
||
// 下拉框更改,可根据 index 与 indexRow 定位具体位置
|
||
selectChange(val, index, indexRow, options) {
|
||
let obj = {}
|
||
options.forEach((item) => {
|
||
if (item.value == val) {
|
||
obj = item
|
||
}
|
||
})
|
||
this.$emit('onSelect', val, index, indexRow, obj)
|
||
this.$forceUpdate();
|
||
},
|
||
switchChange(val, index, indexRow, row) {
|
||
this.$emit('switchChange', val, index, indexRow, row)
|
||
},
|
||
// 自定义级联选择器返回值
|
||
getCascader(value, field) {
|
||
this.$set(this.ruleForm, field, value)
|
||
},
|
||
// 表单提交
|
||
submitForm(formName) {
|
||
this.$refs[formName].validate((valid) => {
|
||
if (valid) {
|
||
this.$emit('onSubmit', this.ruleForm)
|
||
} else {
|
||
console.log('error submit!!');
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
// 表单重置
|
||
resetForm(formName) {
|
||
this.choiceAssignment({})
|
||
this.$emit('resetForm')
|
||
// this.$refs[formName].resetFields();
|
||
},
|
||
clearCheck(propName) {
|
||
this.ruleForm[propName] = ''
|
||
},
|
||
elDialogClick(row, index, indexRow) {
|
||
if (row.disabled) {
|
||
return
|
||
}
|
||
// row.prop
|
||
this.$emit('elDialogClick', row, index)
|
||
},
|
||
elDialogHover(row) {
|
||
row.elDialogHoverType = true
|
||
},
|
||
elDialogLeave(row) {
|
||
// row.elDialogHoverType = false
|
||
},
|
||
// 单选按钮组input事件
|
||
changeRadio(val, index, indexRow, row){
|
||
this.$emit('onChangeRadio', val, index, indexRow, row)
|
||
},
|
||
normalizer(node,row) {
|
||
//去掉children=null的属性
|
||
if (node.children == null || node.children == 'null') {
|
||
delete node.children
|
||
}
|
||
// return{
|
||
// ...node,
|
||
// label:nodeLabel
|
||
// }
|
||
},
|
||
selectTree(node, instanceId) {
|
||
this.$emit('selectTree', node)
|
||
},
|
||
treeSelectClear(){
|
||
this.$refs.selectTree.clear()
|
||
}
|
||
},
|
||
}
|
||
</script>
|
||
<style>
|
||
.el-form-item__label {
|
||
/* width: 25%; */
|
||
line-height: 1.2;
|
||
|
||
}
|
||
|
||
.el-form-item--medium .el-form-item__content {
|
||
/* line-height: 36px; */
|
||
flex: 1
|
||
}
|
||
|
||
.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before {
|
||
margin-right: 0;
|
||
content: ''
|
||
}
|
||
</style>
|
||
<style scoped lang='scss'>
|
||
::v-deep textarea.el-textarea__inner{
|
||
min-height: 100px !important;
|
||
}
|
||
.label {
|
||
/* @include fontBase(16px, #333333) ; */
|
||
color: #333;
|
||
font-size: 13px;
|
||
/* width: 90px; */
|
||
text-align: right;
|
||
padding-right: 5px;
|
||
}
|
||
|
||
>>>.el-form-item__label {
|
||
width: 100px;
|
||
text-align: right !important;
|
||
margin-right: 10px !important;
|
||
padding: 0 !important;
|
||
}
|
||
|
||
::v-deep .el-form-item__label:before {
|
||
display: none;
|
||
}
|
||
|
||
::v-deep .el-form-item__content {
|
||
margin-left: 10px;
|
||
width: calc(100% - 100px);
|
||
}
|
||
|
||
.w-100 {
|
||
width: 100%;
|
||
}
|
||
|
||
.saveBtn {
|
||
/* width: 410px; */
|
||
}
|
||
|
||
.one {
|
||
width: calc(100% - 15px) !important;
|
||
}
|
||
|
||
.elDialog {
|
||
display: flex;
|
||
width: 100%;
|
||
/* width: calc(100% - 14px);1 */
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
border: 1px solid #DCDFE6;
|
||
border-radius: 8px;
|
||
padding: 0 15px;
|
||
cursor: pointer;
|
||
|
||
i {
|
||
color: #c0c4cc
|
||
}
|
||
}
|
||
|
||
.showText {
|
||
/* width: 100%; */
|
||
/* width: calc(100% - 110px); */
|
||
/*让长段文本不换行*/
|
||
white-space: nowrap;
|
||
/*设置文本超出元素宽度部分隐藏*/
|
||
overflow-x: hidden;
|
||
/*设置文本超出部分用省略号显示*/
|
||
text-overflow: ellipsis;
|
||
|
||
}
|
||
|
||
.ruleFormClass {
|
||
::v-deep .el-input__inner {
|
||
border-color: #E6A23C !important
|
||
}
|
||
|
||
.elDialog {
|
||
border-color: #E6A23C !important
|
||
}
|
||
|
||
::v-deep .el-radio__inner {
|
||
border-color: #E6A23C !important
|
||
}
|
||
|
||
.el-radio.is-bordered {
|
||
border-color: #E6A23C !important
|
||
}
|
||
|
||
::v-deep .vue-treeselect__control {
|
||
border-color: #E6A23C !important
|
||
}
|
||
|
||
::v-deep .el-textarea__inner {
|
||
border-color: #E6A23C !important
|
||
}
|
||
}
|
||
</style>
|