refactor(diy-form): 重构自定义表单组件,替换为通用表单组件
1. 替换硬编码表单项为可配置的ns-newform组件 2. 支持横向/纵向两种布局模式 3. 添加表单Banner、提示语配置能力 4. 统一表单提交逻辑,新增表单校验和重置功能 5. 优化ns-newform组件样式与交互细节
This commit is contained in:
@@ -1,47 +1,36 @@
|
||||
<template>
|
||||
<view data-component-name="diy-form" class="diy-from" :style="style">
|
||||
<view class="fui-cell-group">
|
||||
<view class="fui-cell ">
|
||||
<view class="fui-cell-label ">您的姓名</view>
|
||||
<view class="fui-cell-info">
|
||||
<input v-model="Form.realname" class="fui-input" placeholder="请输入您的姓名" value=""></input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fui-cell ">
|
||||
<view class="fui-cell-label">手机号码</view>
|
||||
<view class="fui-cell-info">
|
||||
<input v-model="Form.mobile" class="fui-input" maxlength="11" placeholder="请输入您的手机号"
|
||||
type="number"></input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fui-cell ">
|
||||
<view class="fui-cell-label">您的邮箱</view>
|
||||
<view class="fui-cell-info">
|
||||
<input v-model="Form.mailbox" class="fui-input" placeholder="请输入您的邮箱" type="text"></input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fui-cell">
|
||||
<view class="fui-cell-label">所在城市</view>
|
||||
<view class="fui-cell-info">
|
||||
<input v-model="Form.citys" class="fui-input" placeholder="请输入您的所在地" value=""></input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fui-cell">
|
||||
<view class="fui-cell-label">备注</view>
|
||||
<view class="fui-cell-info">
|
||||
<input v-model="Form.remark" class="fui-input" placeholder="请输入备注" value=""></input>
|
||||
</view>
|
||||
</view>
|
||||
<view data-component-name="diy-form" class="diy-from" :class="[formLayoutClass]" :style="style">
|
||||
<!-- Banner -->
|
||||
<view v-if="value.show_banner && value.form_banner" class="form-banner">
|
||||
<image :src="$util.img(value.form_banner)" mode="widthFix" class="banner-img" />
|
||||
</view>
|
||||
<view @tap.stop="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
|
||||
<!-- 提示语 -->
|
||||
<view v-if="value.show_tip && value.form_tip" class="form-tip">{{ value.form_tip }}</view>
|
||||
<!-- 表单组件 -->
|
||||
<ns-newform
|
||||
:data="formComponents"
|
||||
:customAttr="value"
|
||||
:mode="value.form_layout === 'vertical' ? 'vertical' : 'horizontal'"
|
||||
:labelWidthMode="value.label_width_mode"
|
||||
:labelFixedWidth="value.label_fixed_width"
|
||||
:labelFontSize="value.label_font_size"
|
||||
:labelColor="value.label_color"
|
||||
:requiredColor="value.required_color"
|
||||
ref="nsNewform"
|
||||
/>
|
||||
<!-- 提交按钮 -->
|
||||
<view @click.stop="submitForm" class="fui-btn btn-danger block mtop">提交信息</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 自定义表单
|
||||
import DiyMinx from './minx.js'
|
||||
import NsNewform from '../pages_tool/_components/ns-newform/ns-newform.vue'
|
||||
|
||||
export default {
|
||||
name: 'diy-from',
|
||||
components: { NsNewform },
|
||||
props: {
|
||||
value: {
|
||||
type: Object
|
||||
@@ -50,54 +39,94 @@ export default {
|
||||
mixins: [DiyMinx],
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
markers: [],
|
||||
Form: {
|
||||
realname: '',
|
||||
mobile: '',
|
||||
mailbox: '',
|
||||
citys: '',
|
||||
remark: '',
|
||||
}
|
||||
formComponents: [] // 转换后的表单组件
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.initForm();
|
||||
},
|
||||
watch: {
|
||||
// 组件刷新监听
|
||||
componentRefresh: function (nval) {
|
||||
// this.getDataList();
|
||||
'value.formComponents': {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.initForm();
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
markerst() {
|
||||
return [{
|
||||
id: 1,
|
||||
latitude: this.value.list[0].lat,
|
||||
longitude: this.value.list[0].lng
|
||||
}]
|
||||
},
|
||||
style() {
|
||||
var css = '';
|
||||
css += 'background-color:' + this.value.contentBgColor + ';';
|
||||
if (this.value.elementAngle == 'round') {
|
||||
if (this.value.elementAngle === 'round') {
|
||||
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
|
||||
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
|
||||
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
|
||||
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
|
||||
}
|
||||
return css;
|
||||
},
|
||||
formLayoutClass() {
|
||||
return this.value.form_layout === 'vertical' ? 'form-vertical' : 'form-horizontal';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitform() {
|
||||
// 初始化表单 - 将 diy-form 的数据格式转换成 ns-newform 的格式
|
||||
initForm() {
|
||||
var components = this.value.formComponents || [];
|
||||
// 转换格式:type -> controller
|
||||
this.formComponents = components.map(function(item) {
|
||||
return {
|
||||
controller: item.type,
|
||||
value: item.value,
|
||||
val: item.value.default || '' // 添加初始值
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
// 提交表单
|
||||
submitForm() {
|
||||
var self = this;
|
||||
// 使用 ns-newform 的验证
|
||||
if (this.$refs.nsNewform && this.$refs.nsNewform.verify) {
|
||||
var verifyResult = this.$refs.nsNewform.verify();
|
||||
if (!verifyResult) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取表单数据
|
||||
var submitData = {};
|
||||
if (this.$refs.nsNewform && this.$refs.nsNewform.formData) {
|
||||
this.$refs.nsNewform.formData.forEach(function(item, index) {
|
||||
submitData[index] = item.val;
|
||||
});
|
||||
}
|
||||
|
||||
// 提交到后端
|
||||
this.$api.sendRequest({
|
||||
url: '/api/member/information',
|
||||
data: this.Form,
|
||||
success: res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
url: '/form/api/form/create',
|
||||
data: {
|
||||
form_id: this.value.form_id || 0,
|
||||
form_data: JSON.stringify(submitData),
|
||||
component_id: this.value.id || '',
|
||||
form_name: this.value.form_name || '默认表单'
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'success'
|
||||
});
|
||||
// 重置表单
|
||||
if (self.$refs.nsNewform && self.$refs.nsNewform.setFormData) {
|
||||
self.$refs.nsNewform.setFormData();
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.message || '提交失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -108,7 +137,29 @@ export default {
|
||||
<style lang="scss">
|
||||
.diy-from {
|
||||
background: #fff;
|
||||
padding-bottom: 20rpx;
|
||||
padding: 0 30rpx 20rpx;
|
||||
border-radius: 10rpx;
|
||||
|
||||
.form-banner {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
margin: 0 -30rpx;
|
||||
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.form-tip {
|
||||
padding: 30rpx 0;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.fui-btn {
|
||||
margin: 30rpx 0 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<view v-for="(item, index) in formData" :key="index">
|
||||
<!-- 文本输入框 -->
|
||||
<view v-if="item.controller == 'Text'" class="order-wrap">
|
||||
<view class="order-cell">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box">
|
||||
<view :class="['box', 'align-left']">
|
||||
<input
|
||||
type="text"
|
||||
:placeholder="item.value.placeholder"
|
||||
@@ -21,12 +21,12 @@
|
||||
|
||||
<!-- 多行文本输入框 -->
|
||||
<view v-if="item.controller == 'Textarea'" class="order-wrap">
|
||||
<view class="order-cell flex-box textarea">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', 'flex-box', 'textarea', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box">
|
||||
<view :class="['box', 'align-left']">
|
||||
<textarea
|
||||
:placeholder="item.value.placeholder"
|
||||
placeholder-class="placeholder color-tip"
|
||||
@@ -43,12 +43,12 @@
|
||||
:range="item.value.options"
|
||||
@change="pickerChange($event, index)"
|
||||
>
|
||||
<view class="order-cell">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box">
|
||||
<view :class="['box', 'align-right']">
|
||||
<text v-if="item.val != ''">{{ item.val }}</text>
|
||||
<text v-else class="color-tip">请选择</text>
|
||||
</view>
|
||||
@@ -59,12 +59,12 @@
|
||||
|
||||
<!-- 复选框 -->
|
||||
<view v-if="item.controller == 'Checkbox'" class="order-wrap">
|
||||
<view class="order-cell">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box check-group-box">
|
||||
<view :class="['box', 'check-group-box', 'align-left']">
|
||||
<checkbox-group @change="checkboxChange($event, index)">
|
||||
<label v-for="(v, k) in item.option_lists" :key="k">
|
||||
<checkbox :value="v.value" :checked="v.checked"></checkbox>
|
||||
@@ -86,12 +86,12 @@
|
||||
|
||||
<!-- 单选框 -->
|
||||
<view v-if="item.controller == 'Radio'" class="order-wrap">
|
||||
<view class="order-cell">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box radio-group-box">
|
||||
<view :class="['box', 'radio-group-box', 'align-left']">
|
||||
<radio-group @change="radioChange($event, index)">
|
||||
<label v-for="(v, k) in item.option_lists" :key="k">
|
||||
<radio :value="v.value" :checked="item.val == v.value"></radio>
|
||||
@@ -113,12 +113,12 @@
|
||||
|
||||
<!-- 图片上传 -->
|
||||
<view v-if="item.controller == 'Img'" class="order-wrap">
|
||||
<view class="order-cell flex-box">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', 'flex-box', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box img-boxs">
|
||||
<view :class="['box', 'img-boxs', 'align-left']">
|
||||
<view v-for="(v, k) in item.img_lists" :key="k" class="img-box" @tap="uploadImg(index)">
|
||||
<image :src="$util.img(v)" mode="aspectFill" show-menu-by-longpress></image>
|
||||
<text class="iconfont icon-guanbi" @tap.stop="delImg(k, index)"></text>
|
||||
@@ -132,12 +132,12 @@
|
||||
|
||||
<!-- 日期选择器 -->
|
||||
<view v-if="item.controller == 'Date'" class="order-wrap">
|
||||
<view class="order-cell">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box box-flex">
|
||||
<view :class="['box', 'box-flex', 'align-right']">
|
||||
<picker
|
||||
mode="date"
|
||||
:value="item.val"
|
||||
@@ -154,12 +154,12 @@
|
||||
|
||||
<!-- 日期范围选择器 -->
|
||||
<view v-if="item.controller == 'Datelimit'" class="order-wrap">
|
||||
<view class="order-cell flex-box">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', 'flex-box', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box date-boxs">
|
||||
<view :class="['box', 'date-boxs', 'align-center']">
|
||||
<view class="date-box">
|
||||
<picker
|
||||
mode="date"
|
||||
@@ -193,12 +193,12 @@
|
||||
|
||||
<!-- 时间选择器 -->
|
||||
<view v-if="item.controller == 'Time'" class="order-wrap">
|
||||
<view class="order-cell">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box box-flex">
|
||||
<view :class="['box', 'box-flex', 'align-right']">
|
||||
<picker
|
||||
mode="time"
|
||||
:value="item.val"
|
||||
@@ -215,12 +215,12 @@
|
||||
|
||||
<!-- 时间范围选择器 -->
|
||||
<view v-if="item.controller == 'Timelimit'" class="order-wrap">
|
||||
<view class="order-cell flex-box">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', 'flex-box', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box date-boxs">
|
||||
<view :class="['box', 'date-boxs', 'align-center']">
|
||||
<view class="date-box">
|
||||
<picker
|
||||
mode="time"
|
||||
@@ -254,12 +254,12 @@
|
||||
|
||||
<!-- 城市选择器 -->
|
||||
<view v-if="item.controller == 'City'" class="order-wrap">
|
||||
<view class="order-cell box-flex">
|
||||
<view class="name">
|
||||
<view :class="['order-cell', 'box-flex', { 'vertical-layout': mode === 'vertical' }]">
|
||||
<view class="name" :style="[nameWidthStyle, labelStyle]">
|
||||
<text class="tit">{{ item.value.title }}</text>
|
||||
<text class="required">{{ item.value.required ? '*' : '' }}</text>
|
||||
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
|
||||
</view>
|
||||
<view class="box">
|
||||
<view :class="['box', 'align-right']">
|
||||
<pick-regions
|
||||
:defaultRegions="item.default_regions"
|
||||
:selectArr="item.select_arr"
|
||||
@@ -288,34 +288,129 @@ export default {
|
||||
customAttr: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'horizontal',
|
||||
validator: (value) => ['horizontal', 'vertical'].includes(value)
|
||||
},
|
||||
labelWidthMode: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
validator: (value) => ['auto', 'fixed'].includes(value)
|
||||
},
|
||||
labelFixedWidth: {
|
||||
type: [String, Number],
|
||||
default: 180
|
||||
},
|
||||
labelFontSize: {
|
||||
type: [String, Number],
|
||||
default: 30
|
||||
},
|
||||
labelColor: {
|
||||
type: String,
|
||||
default: '#303133'
|
||||
},
|
||||
requiredColor: {
|
||||
type: String,
|
||||
default: '#F56C6C'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formData: this.data
|
||||
formData: this.data,
|
||||
maxLabelWidth: 0
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.setFormData();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.calculateMaxLabelWidth();
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
handler() {
|
||||
this.setFormData();
|
||||
this.$nextTick(() => {
|
||||
this.calculateMaxLabelWidth();
|
||||
});
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
nameWidthStyle() {
|
||||
if (this.mode === 'vertical') {
|
||||
return {};
|
||||
}
|
||||
let width;
|
||||
if (this.labelWidthMode === 'fixed') {
|
||||
width = `${this.labelFixedWidth}rpx`;
|
||||
} else {
|
||||
width = this.maxLabelWidth ? `${this.maxLabelWidth}rpx` : 'auto';
|
||||
}
|
||||
return {
|
||||
width: width
|
||||
};
|
||||
},
|
||||
labelStyle() {
|
||||
let style = {};
|
||||
let fontSize = this.labelFontSize;
|
||||
if (typeof fontSize === 'number') {
|
||||
fontSize = `${fontSize}rpx`;
|
||||
} else if (typeof fontSize === 'string' && !fontSize.endsWith('rpx') && !fontSize.endsWith('px')) {
|
||||
fontSize = `${fontSize}rpx`;
|
||||
}
|
||||
style.fontSize = fontSize;
|
||||
style.color = this.labelColor;
|
||||
return style;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculateMaxLabelWidth() {
|
||||
if (this.mode === 'vertical' || !this.formData || this.formData.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let maxWidth = 0;
|
||||
|
||||
this.formData.forEach((item) => {
|
||||
if (item.value && item.value.title) {
|
||||
let text = item.value.title;
|
||||
if (item.value.required) {
|
||||
text += '*';
|
||||
}
|
||||
let width = 0;
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const char = text[i];
|
||||
if (/[\u4e00-\u9fa5]/.test(char)) {
|
||||
width += 1;
|
||||
} else {
|
||||
width += 0.5;
|
||||
}
|
||||
}
|
||||
const fontSize = parseInt(this.labelFontSize) || 30;
|
||||
width = width * fontSize * 0.85 + 30;
|
||||
maxWidth = Math.max(maxWidth, width);
|
||||
}
|
||||
});
|
||||
|
||||
maxWidth = Math.max(maxWidth, 80);
|
||||
maxWidth = Math.min(maxWidth, 200);
|
||||
|
||||
this.maxLabelWidth = maxWidth;
|
||||
},
|
||||
|
||||
setFormData() {
|
||||
this.formData = this.data;
|
||||
this.formData.forEach((item) => {
|
||||
// 初始化默认值
|
||||
if (!item.val) {
|
||||
item.val = item.value.default ? item.value.default : '';
|
||||
}
|
||||
|
||||
// 处理选项列表
|
||||
if (item.value.options) {
|
||||
item.option_lists = [];
|
||||
item.value.options.forEach((option, index) => {
|
||||
@@ -339,12 +434,10 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
// 处理图片列表
|
||||
if (item.controller == 'Img') {
|
||||
item.img_lists = item.val ? item.val.split(',') : [];
|
||||
}
|
||||
|
||||
// 处理日期
|
||||
if (item.controller == 'Date' && !item.val) {
|
||||
if (item.value.is_show_default) {
|
||||
if (item.value.is_current) {
|
||||
@@ -357,7 +450,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理日期范围
|
||||
if (item.controller == 'Datelimit') {
|
||||
if (item.val) {
|
||||
let dateArray = item.val.split(' - ');
|
||||
@@ -366,7 +458,6 @@ export default {
|
||||
} else {
|
||||
item.val = '';
|
||||
|
||||
// 开始日期
|
||||
if (item.value.is_show_default_start) {
|
||||
if (item.value.is_current_start) {
|
||||
item.start_date = this.getDate();
|
||||
@@ -377,15 +468,12 @@ export default {
|
||||
item.start_date = '';
|
||||
}
|
||||
|
||||
// 结束日期
|
||||
if (item.value.is_show_default_end) {
|
||||
if (item.value.is_current_end) {
|
||||
item.end_date = this.getDate();
|
||||
} else {
|
||||
item.end_date = item.value.default_end;
|
||||
}
|
||||
} else {
|
||||
item.end_date = '';
|
||||
}
|
||||
|
||||
if (item.start_date && item.end_date) {
|
||||
@@ -394,7 +482,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理时间
|
||||
if (item.controller == 'Time' && !item.val) {
|
||||
if (item.value.is_show_default) {
|
||||
if (item.value.is_current) {
|
||||
@@ -407,7 +494,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理时间范围
|
||||
if (item.controller == 'Timelimit') {
|
||||
if (item.val) {
|
||||
let timeArray = item.val.split(' - ');
|
||||
@@ -416,7 +502,6 @@ export default {
|
||||
} else {
|
||||
item.val = '';
|
||||
|
||||
// 开始时间
|
||||
if (item.value.is_show_default_start) {
|
||||
if (item.value.is_current_start) {
|
||||
item.start_time = this.getTime();
|
||||
@@ -427,15 +512,12 @@ export default {
|
||||
item.start_time = '';
|
||||
}
|
||||
|
||||
// 结束时间
|
||||
if (item.value.is_show_default_end) {
|
||||
if (item.value.is_current_end) {
|
||||
item.end_time = this.getTime();
|
||||
} else {
|
||||
item.end_time = item.value.default_end;
|
||||
}
|
||||
} else {
|
||||
item.end_time = '';
|
||||
}
|
||||
|
||||
if (item.start_time && item.end_time) {
|
||||
@@ -444,7 +526,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理城市选择
|
||||
if (item.controller == 'City') {
|
||||
item.full_address = '';
|
||||
item.select_arr = item.value.default_type == 1 ? '2' : '3';
|
||||
@@ -457,12 +538,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
// 表单验证
|
||||
verify() {
|
||||
for (let i = 0; i < this.formData.length; i++) {
|
||||
let item = this.formData[i];
|
||||
|
||||
// 文本验证
|
||||
if (item.controller == 'Text') {
|
||||
if (item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请输入' + item.value.title });
|
||||
@@ -492,37 +571,31 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 多行文本验证
|
||||
if (item.controller == 'Textarea' && item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请输入' + item.value.title });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 下拉选择验证
|
||||
if (item.controller == 'Select' && item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请选择' + item.value.title });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 复选框验证
|
||||
if (item.controller == 'Checkbox' && item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请至少选择一个' + item.value.title });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 图片上传验证
|
||||
if (item.controller == 'Img' && item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请至少上传一张' + item.value.title });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 日期验证
|
||||
if (item.controller == 'Date' && item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请选择' + item.value.title });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 日期范围验证
|
||||
if (item.controller == 'Datelimit') {
|
||||
if (item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请选择' + item.value.title });
|
||||
@@ -535,13 +608,11 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 时间验证
|
||||
if (item.controller == 'Time' && item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请选择' + item.value.title });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 时间范围验证
|
||||
if (item.controller == 'Timelimit') {
|
||||
if (item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请选择' + item.value.title });
|
||||
@@ -554,7 +625,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 城市选择验证
|
||||
if (item.controller == 'City' && item.value.required && !item.val) {
|
||||
this.$util.showToast({ title: '请选择' + item.value.title });
|
||||
return false;
|
||||
@@ -564,13 +634,11 @@ export default {
|
||||
return this.formData;
|
||||
},
|
||||
|
||||
// 下拉选择改变
|
||||
pickerChange(event, index) {
|
||||
this.formData[index].val = this.data[index].value.options[event.detail.value];
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 复选框改变
|
||||
checkboxChange(event, index) {
|
||||
this.formData[index].val = event.detail.value.toString();
|
||||
this.formData[index].option_lists.forEach((option) => {
|
||||
@@ -579,13 +647,11 @@ export default {
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 单选框改变
|
||||
radioChange(event, index) {
|
||||
this.formData[index].val = event.detail.value;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 上传图片
|
||||
uploadImg(index) {
|
||||
let self = this;
|
||||
this.$util.upload(Number(this.formData[index].value.max_count), { path: 'evaluateimg' }, function(res) {
|
||||
@@ -603,7 +669,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
// 添加图片
|
||||
addImg(index) {
|
||||
let self = this;
|
||||
if (this.formData[index].img_lists.length >= Number(this.formData[index].value.max_count)) {
|
||||
@@ -622,14 +687,12 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
// 删除图片
|
||||
delImg(imgIndex, formIndex) {
|
||||
this.formData[formIndex].img_lists.splice(imgIndex, 1);
|
||||
this.formData[formIndex].val = this.formData[formIndex].img_lists.toString();
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 获取当前日期
|
||||
getDate() {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear();
|
||||
@@ -640,7 +703,6 @@ export default {
|
||||
return `${year}-${month}-${day}`;
|
||||
},
|
||||
|
||||
// 获取当前时间
|
||||
getTime() {
|
||||
let date = new Date();
|
||||
let hours = date.getHours();
|
||||
@@ -650,46 +712,39 @@ export default {
|
||||
return `${hours}:${minutes}`;
|
||||
},
|
||||
|
||||
// 日期改变
|
||||
bindDateChange(event, index) {
|
||||
this.formData[index].val = event.detail.value;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 开始日期改变
|
||||
bindStartDateChange(event, index) {
|
||||
this.$set(this.formData[index], 'start_date', event.detail.value);
|
||||
this.$set(this.formData[index], 'val', this.formData[index].start_date + ' - ' + this.formData[index].end_date);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 结束日期改变
|
||||
bindEndDateChange(event, index) {
|
||||
this.$set(this.formData[index], 'end_date', event.detail.value);
|
||||
this.$set(this.formData[index], 'val', this.formData[index].start_date + ' - ' + this.formData[index].end_date);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 时间改变
|
||||
bindTimeChange(event, index) {
|
||||
this.formData[index].val = event.detail.value;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 开始时间改变
|
||||
bindStartTimeChange(event, index) {
|
||||
this.formData[index].start_time = event.detail.value;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 结束时间改变
|
||||
bindEndTimeChange(event, index) {
|
||||
this.formData[index].end_time = event.detail.value;
|
||||
this.formData[index].val = this.formData[index].start_time + ' - ' + this.formData[index].end_time;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
// 处理地区选择
|
||||
handleGetRegions(regions, index) {
|
||||
this.formData[index].val = '';
|
||||
this.formData[index].val += regions[0] != undefined ? regions[0].label : '';
|
||||
@@ -702,21 +757,67 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-wrap {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.order-wrap {
|
||||
padding: 20rpx 0;
|
||||
padding: 12rpx 0;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: 1rpx;
|
||||
background: linear-gradient(90deg, transparent, #f0f0f0, transparent);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom: 0;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.order-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
padding: 12rpx 0;
|
||||
|
||||
// 水平布局(默认):标签自动宽度(以最大为准),根据组件特性对齐
|
||||
&:not(.vertical-layout) {
|
||||
.name {
|
||||
flex-shrink: 0;
|
||||
margin-bottom: 0;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&.vertical-layout {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.name {
|
||||
width: 100%;
|
||||
margin-bottom: 16rpx;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.textarea {
|
||||
align-items: unset;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&.clear-flex {
|
||||
@@ -730,7 +831,6 @@ export default {
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom: solid 1px #eee;
|
||||
}
|
||||
|
||||
&.align-top {
|
||||
@@ -742,16 +842,16 @@ export default {
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 80vw;
|
||||
margin-bottom: 10rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
.tit {
|
||||
text-align: left;
|
||||
font-size: 32rpx;
|
||||
color: #888;
|
||||
font-size: 28rpx;
|
||||
color: #1f2937;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.3rpx;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
@@ -759,169 +859,208 @@ export default {
|
||||
}
|
||||
|
||||
.required {
|
||||
color: red;
|
||||
font-size: 28rpx;
|
||||
margin-left: 8rpx;
|
||||
width: 14rpx;
|
||||
text-align: left;
|
||||
color: #ef4444;
|
||||
font-size: 32rpx;
|
||||
margin-left: 4rpx;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
flex: 1;
|
||||
padding: 0 0rpx;
|
||||
padding: 0;
|
||||
line-height: inherit;
|
||||
text-align: left;
|
||||
|
||||
// 对齐方式
|
||||
&.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 28rpx;
|
||||
text-align: left;
|
||||
height: 70rpx;
|
||||
border: solid 2rpx #eee;
|
||||
line-height: 70rpx;
|
||||
padding: 0 16rpx;
|
||||
height: 80rpx;
|
||||
border: 2rpx solid #f3f4f6;
|
||||
border-radius: 16rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 24rpx;
|
||||
background: #f9fafb;
|
||||
color: #1f2937;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:focus {
|
||||
background: #fff;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 6rpx rgba(59, 130, 246, 0.08);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-size: 28rpx;
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
min-height: 160rpx;
|
||||
line-height: 44rpx;
|
||||
text-align: left;
|
||||
border: 2rpx solid #f3f4f6;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
background: #f9fafb;
|
||||
color: #1f2937;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:focus {
|
||||
background: #fff;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 6rpx rgba(59, 130, 246, 0.08);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
.uni-input, .select-address {
|
||||
display: inline-block;
|
||||
padding: 16rpx 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f9fafb;
|
||||
border: 2rpx solid #f3f4f6;
|
||||
color: #1f2937;
|
||||
font-size: 28rpx;
|
||||
transition: all 0.3s ease;
|
||||
min-height: 80rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.color-tip {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
&.empty {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
}
|
||||
|
||||
checkbox-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
radio-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
margin-right: 30rpx;
|
||||
margin: 0;
|
||||
padding: 12rpx 20rpx;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border-radius: 40rpx;
|
||||
background: #fff;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
}
|
||||
|
||||
&.img-boxs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
|
||||
.img-box {
|
||||
margin: 10rpx 20rpx 10rpx 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border: 1rpx solid #eee;
|
||||
border-radius: 4rpx;
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border: 2rpx dashed #d1d5db;
|
||||
border-radius: 16rpx;
|
||||
position: relative;
|
||||
background: #f9fafb;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
|
||||
&:active {
|
||||
background: #f3f4f6;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
.icon-guanbi {
|
||||
position: absolute;
|
||||
top: -14rpx;
|
||||
right: -14rpx;
|
||||
display: inline-block;
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
line-height: 28rpx;
|
||||
color: #909399;
|
||||
top: -10rpx;
|
||||
right: -10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
background: #ef4444;
|
||||
border-radius: 50%;
|
||||
font-size: 20rpx;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.icon-add1 {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 48rpx;
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.box-flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&.date-boxs {
|
||||
padding: 0 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.interval {
|
||||
margin: 0 12rpx;
|
||||
color: #000;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.date-box {
|
||||
flex: 1;
|
||||
|
||||
.picker-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.uni-input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.radio-group-box {
|
||||
radio {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.radio-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
|
||||
.iconfont {
|
||||
.interval {
|
||||
padding: 0 16rpx;
|
||||
color: #9ca3af;
|
||||
font-size: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.check-group-box {
|
||||
checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
|
||||
.iconfont {
|
||||
font-size: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: #909399;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.box-flex {
|
||||
picker {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-right {
|
||||
line-height: 1;
|
||||
position: unset;
|
||||
color: #9ca3af;
|
||||
font-size: 32rpx;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user