Files
lucky_shop/components/ns-newform/ns-newform.vue
ZF sun fd6527aa38 refactor: 迁移ns-newform组件到标准components目录并更新引用
1. 将ns-newform组件从pages_tool/_components移动到项目标准components目录
2. 更新所有文件中对该组件的导入路径和文档引用
3. 优化diy-form组件的表单数据处理逻辑,兼容更多数据格式
2026-06-09 09:50:27 +08:00

1091 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="form-wrap form-component">
<view v-for="(item, index) in formData" :key="index">
<!-- 文本输入框 -->
<view v-if="item.controller == 'Text'" class="order-wrap">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="[nameWidthStyle, labelStyle]">
<text class="tit">{{ item.value.title }}</text>
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'align-left']">
<input
type="text"
:placeholder="item.value.placeholder"
placeholder-class="placeholder color-tip"
v-model="item.val"
/>
</view>
</view>
</view>
<!-- 多行文本输入框 -->
<view v-if="item.controller == 'Textarea'" class="order-wrap">
<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" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'align-left']">
<textarea
:placeholder="item.value.placeholder"
placeholder-class="placeholder color-tip"
v-model="item.val"
></textarea>
</view>
</view>
</view>
<!-- 下拉选择器 -->
<view v-if="item.controller == 'Select'" class="order-wrap">
<picker
mode="selector"
:range="item.value.options"
@change="pickerChange($event, index)"
>
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="[nameWidthStyle, labelStyle]">
<text class="tit">{{ item.value.title }}</text>
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'align-right']">
<text v-if="item.val != ''">{{ item.val }}</text>
<text v-else class="color-tip">请选择</text>
</view>
<text class="iconfont icon-right"></text>
</view>
</picker>
</view>
<!-- 复选框 -->
<view v-if="item.controller == 'Checkbox'" class="order-wrap">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="[nameWidthStyle, labelStyle]">
<text class="tit">{{ item.value.title }}</text>
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<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>
<view class="checkbox">
<text
:class="[
'iconfont',
!v.checked ? 'icon-fuxuankuang2' : '',
v.checked ? 'icon-fuxuankuang1 color-base-text' : ''
]"
></text>
{{ v.value }}
</view>
</label>
</checkbox-group>
</view>
</view>
</view>
<!-- 单选框 -->
<view v-if="item.controller == 'Radio'" class="order-wrap">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="[nameWidthStyle, labelStyle]">
<text class="tit">{{ item.value.title }}</text>
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<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>
<view class="radio-box">
<text
:class="[
'iconfont',
item.val != v.value ? 'icon-yuan_checkbox' : '',
item.val == v.value ? 'icon-yuan_checked color-base-text' : ''
]"
></text>
{{ v.value }}
</view>
</label>
</radio-group>
</view>
</view>
</view>
<!-- 图片上传 -->
<view v-if="item.controller == 'Img'" class="order-wrap">
<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" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<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>
</view>
<view class="img-box" @tap="addImg(index)">
<text class="iconfont icon-add1"></text>
</view>
</view>
</view>
</view>
<!-- 日期选择器 -->
<view v-if="item.controller == 'Date'" class="order-wrap">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="[nameWidthStyle, labelStyle]">
<text class="tit">{{ item.value.title }}</text>
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'box-flex', 'align-right']">
<picker
mode="date"
:value="item.val"
@change="bindDateChange($event, index)"
>
<view :class="['uni-input', !item.val ? 'color-tip' : '']">
{{ item.val ? item.val : item.value.placeholder }}
</view>
</picker>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
<!-- 日期范围选择器 -->
<view v-if="item.controller == 'Datelimit'" class="order-wrap">
<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" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'date-boxs', 'align-center']">
<view class="date-box">
<picker
mode="date"
:value="item.start_date"
@change="bindStartDateChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.start_date ? 'color-tip' : '']">
{{ item.start_date ? item.start_date : item.value.placeholder_start }}
</view>
</view>
</picker>
</view>
<view class="interval iconfont icon-jian"></view>
<view class="date-box">
<picker
mode="date"
:value="item.end_date"
@change="bindEndDateChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.end_date ? 'color-tip' : '']">
{{ item.end_date ? item.end_date : item.value.placeholder_end }}
</view>
</view>
</picker>
</view>
</view>
</view>
</view>
<!-- 时间选择器 -->
<view v-if="item.controller == 'Time'" class="order-wrap">
<view :class="['order-cell', { 'vertical-layout': mode === 'vertical' }]">
<view class="name" :style="[nameWidthStyle, labelStyle]">
<text class="tit">{{ item.value.title }}</text>
<text class="required" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'box-flex', 'align-right']">
<picker
mode="time"
:value="item.val"
@change="bindTimeChange($event, index)"
>
<view :class="['uni-input', !item.val ? 'color-tip' : '']">
{{ item.val ? item.val : item.value.placeholder }}
</view>
</picker>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
<!-- 时间范围选择器 -->
<view v-if="item.controller == 'Timelimit'" class="order-wrap">
<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" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'date-boxs', 'align-center']">
<view class="date-box">
<picker
mode="time"
:value="item.start_time"
@change="bindStartTimeChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.start_time ? 'color-tip' : '']">
{{ item.start_time ? item.start_time : item.value.placeholder_start }}
</view>
</view>
</picker>
</view>
<view class="interval iconfont icon-jian"></view>
<view class="date-box">
<picker
mode="time"
:value="item.end_time"
@change="bindEndTimeChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.end_time ? 'color-tip' : '']">
{{ item.end_time ? item.end_time : item.value.placeholder_end }}
</view>
</view>
</picker>
</view>
</view>
</view>
</view>
<!-- 城市选择器 -->
<view v-if="item.controller == 'City'" class="order-wrap">
<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" :style="{ color: requiredColor }">{{ item.value.required ? '*' : '' }}</text>
</view>
<view :class="['box', 'align-right']">
<pick-regions
:defaultRegions="item.default_regions"
:selectArr="item.select_arr"
@getRegions="handleGetRegions($event, index)"
>
<view :class="['select-address', !item.val ? 'empty' : '', !item.val ? 'color-tip' : '']">
{{ item.val ? item.val : (item.select_arr == '2' ? '请选择省市' : '请选择省市区/县') }}
</view>
</pick-regions>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'ns-newform',
props: {
data: {
type: Array,
default: () => []
},
customAttr: {
type: Object,
default: () => ({})
},
mode: {
type: String,
default: 'horizontal',
validator: (value) => !value || ['horizontal', 'vertical'].includes(value)
},
labelWidthMode: {
type: String,
default: 'auto',
validator: (value) => !value || ['auto', 'fixed'].includes(value)
},
labelFixedWidth: {
type: [String, Number],
default: 180
},
labelFontSize: {
type: [String, Number],
default: 26
},
labelColor: {
type: String,
default: '#303133'
},
requiredColor: {
type: String,
default: '#F56C6C'
}
},
data() {
return {
formData: [],
maxLabelWidth: 0
}
},
created() {
// 避免直接修改 prop,初始化本地数据
this.initFormData();
},
mounted() {
this.$nextTick(() => {
this.calculateMaxLabelWidth();
});
},
watch: {
data: {
handler() {
this.initFormData();
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, 60);
maxWidth = Math.min(maxWidth, 160);
this.maxLabelWidth = maxWidth;
},
initFormData() {
// 深拷贝 prop 数据到本地状态
this.formData = JSON.parse(JSON.stringify(this.data || []));
this.processFormData();
},
setFormData() {
// 重置为初始值
this.initFormData();
},
processFormData() {
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) => {
let optionItem = {};
optionItem.value = option;
optionItem.checked = false;
if (item.controller == 'Radio') {
if ((!item.val && index == 0) || (item.val && item.val == option)) {
optionItem.checked = true;
item.val = option;
}
}
if (item.controller == 'Checkbox' && item.val) {
let valArray = item.val.split(',');
optionItem.checked = valArray.indexOf(option) != -1;
}
item.option_lists.push(optionItem);
});
}
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) {
item.val = this.getDate();
} else {
item.val = item.value.default;
}
} else {
item.val = '';
}
}
if (item.controller == 'Datelimit') {
if (item.val) {
let dateArray = item.val.split(' - ');
item.start_date = dateArray[0];
item.end_date = dateArray[1];
} else {
item.val = '';
if (item.value.is_show_default_start) {
if (item.value.is_current_start) {
item.start_date = this.getDate();
} else {
item.start_date = item.value.default_start;
}
} else {
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;
}
}
if (item.start_date && item.end_date) {
item.val = item.start_date + ' - ' + item.end_date;
}
}
}
if (item.controller == 'Time' && !item.val) {
if (item.value.is_show_default) {
if (item.value.is_current) {
item.val = this.getTime();
} else {
item.val = item.value.default;
}
} else {
item.val = '';
}
}
if (item.controller == 'Timelimit') {
if (item.val) {
let timeArray = item.val.split(' - ');
item.start_time = timeArray[0];
item.end_time = timeArray[1];
} else {
item.val = '';
if (item.value.is_show_default_start) {
if (item.value.is_current_start) {
item.start_time = this.getTime();
} else {
item.start_time = item.value.default_start;
}
} else {
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;
}
}
if (item.start_time && item.end_time) {
item.val = item.start_time + ' - ' + item.end_time;
}
}
}
if (item.controller == 'City') {
item.full_address = '';
item.select_arr = item.value.default_type == 1 ? '2' : '3';
if (item.val) {
item.default_regions = item.val.split('-');
} else {
item.default_regions = [];
}
}
});
},
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 });
return false;
}
if (item.name == 'ID_CARD' && !/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(item.val)) {
if (!item.value.required) {
this.$util.showToast({ title: '身份证输入不合法' });
return false;
}
if (item.val != '') {
this.$util.showToast({ title: '身份证输入不合法' });
return false;
}
}
if (item.name == 'MOBILE' && !this.$util.verifyMobile(item.val)) {
if (!item.value.required) {
this.$util.showToast({ title: '手机号输入不合法' });
return false;
}
if (item.val != '') {
this.$util.showToast({ title: '手机号输入不合法' });
return false;
}
}
}
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 });
return false;
}
if (this.$util.timeTurnTimeStamp(item.start_date) > this.$util.timeTurnTimeStamp(item.end_date)) {
this.$util.showToast({ title: '结束日期不能小于开始日期' });
return false;
}
}
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 });
return false;
}
if (item.start_time >= item.end_time) {
this.$util.showToast({ title: '结束时间必须大于开始时间' });
return false;
}
}
if (item.controller == 'City' && item.value.required && !item.val) {
this.$util.showToast({ title: '请选择' + item.value.title });
return false;
}
}
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) => {
option.checked = event.detail.value.indexOf(option.value) != -1;
});
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) {
if (res.length > 0) {
res.forEach(function(img) {
if (self.formData[index].img_lists.length >= Number(self.formData[index].value.max_count)) {
self.$util.showToast({ title: '最多上传' + self.formData[index].value.max_count + '张图片' });
return false;
}
self.formData[index].img_lists.push(img);
});
self.formData[index].val = self.formData[index].img_lists.toString();
self.$forceUpdate();
}
});
},
addImg(index) {
let self = this;
if (this.formData[index].img_lists.length >= Number(this.formData[index].value.max_count)) {
this.$util.showToast({ title: '最多上传' + this.formData[index].value.max_count + '张图片' });
return false;
}
this.$util.upload(Number(this.formData[index].value.max_count), { path: 'evaluateimg' }, function(res) {
if (res.length > 0) {
res.forEach(function(img) {
self.formData[index].img_lists.push(img);
});
self.formData[index].val = self.formData[index].img_lists.toString();
self.$forceUpdate();
}
});
},
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();
let month = date.getMonth() + 1;
let day = date.getDate();
month = month > 9 ? month : '0' + month;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
},
getTime() {
let date = new Date();
let hours = date.getHours();
let minutes = date.getMinutes();
hours = hours > 9 ? hours : '0' + hours;
minutes = minutes > 9 ? minutes : '0' + minutes;
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 : '';
this.formData[index].val += regions[1] != undefined ? '-' + regions[1].label : '';
this.formData[index].val += regions[2] != undefined ? '-' + regions[2].label : '';
this.$forceUpdate();
}
}
}
</script>
<style lang="scss" scoped>
.form-wrap {
background: #ffffff;
}
.order-wrap {
padding: 4rpx 14rpx;
transition: all 0.3s ease;
position: relative;
&::after {
content: '';
position: absolute;
left: 14rpx;
bottom: 0;
right: 14rpx;
height: 1rpx;
background: #f0f0f0;
}
&:last-child {
margin-bottom: 0;
border-bottom: 0;
&::after {
display: none;
}
}
.order-cell {
display: flex;
align-items: center;
background: #fff;
position: relative;
padding: 0;
min-height: 60rpx;
// 水平布局(默认):标签自动宽度(以最大为准),根据组件特性对齐
&:not(.vertical-layout) {
.name {
flex-shrink: 0;
margin-bottom: 0;
margin-right: 16rpx;
}
}
&.vertical-layout {
flex-direction: column;
align-items: flex-start;
.name {
width: 100%;
margin-bottom: 12rpx;
margin-right: 0;
}
.box {
width: 100%;
}
}
&.textarea {
align-items: flex-start;
.name {
padding-top: 16rpx;
height: auto;
line-height: 44rpx;
}
}
&.clear-flex {
display: block;
.box {
margin-top: 12rpx;
text-align: left;
}
}
&:last-child {
margin-bottom: 0;
}
&.align-top {
align-items: flex-start;
}
text {
font-size: 28rpx;
}
.name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
height: 60rpx;
line-height: 60rpx;
.tit {
text-align: left;
font-size: 26rpx;
color: #1f2937;
font-weight: 500;
letter-spacing: 0.2rpx;
text {
font-size: 26rpx;
}
}
.required {
color: #ef4444;
font-size: 28rpx;
margin-left: 4rpx;
display: inline-block;
vertical-align: middle;
}
}
.box {
flex: 1;
padding: 0;
line-height: inherit;
// 对齐方式
&.align-left {
text-align: left;
}
&.align-right {
text-align: right;
}
&.align-center {
text-align: center;
}
input {
font-size: 26rpx;
text-align: left;
height: 60rpx;
border: 2rpx solid #f3f4f6;
border-radius: 10rpx;
line-height: 60rpx;
padding: 0 16rpx;
background: #f9fafb;
color: #1f2937;
transition: all 0.3s ease;
&:focus {
background: #fff;
border-color: #3b82f6;
box-shadow: 0 0 0 4rpx rgba(59, 130, 246, 0.08);
}
&::placeholder {
color: #9ca3af;
}
}
textarea {
font-size: 26rpx;
width: 100%;
min-height: 180rpx;
line-height: 40rpx;
text-align: left;
border: 2rpx solid #f3f4f6;
border-radius: 10rpx;
padding: 12rpx 16rpx;
background: #f9fafb;
color: #1f2937;
transition: all 0.3s ease;
box-sizing: border-box;
height: auto;
&:focus {
background: #fff;
border-color: #3b82f6;
box-shadow: 0 0 0 4rpx rgba(59, 130, 246, 0.08);
}
&::placeholder {
color: #9ca3af;
}
}
.uni-input, .select-address {
display: inline-block;
padding: 8rpx 16rpx;
border-radius: 10rpx;
background: #f9fafb;
border: 2rpx solid #f3f4f6;
color: #1f2937;
font-size: 26rpx;
transition: all 0.3s ease;
min-height: 60rpx;
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: 0;
padding: 6rpx 14rpx;
border: 2rpx solid #e5e7eb;
border-radius: 6rpx;
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: 0;
display: flex;
justify-content: center;
align-items: center;
width: 120rpx;
height: 120rpx;
border: 2rpx dashed #d1d5db;
border-radius: 8rpx;
position: relative;
background: #f9fafb;
transition: all 0.3s ease;
overflow: hidden;
&:active {
background: #f3f4f6;
border-color: #3b82f6;
}
.icon-guanbi {
position: absolute;
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: 48rpx;
color: #9ca3af;
}
}
}
&.date-boxs {
display: flex;
align-items: center;
.date-box {
flex: 1;
.picker-box {
.uni-input {
width: 100%;
box-sizing: border-box;
}
}
}
.interval {
padding: 0 16rpx;
color: #9ca3af;
font-size: 32rpx;
}
}
}
.icon-right {
color: #9ca3af;
font-size: 32rpx;
margin-left: 12rpx;
}
}
}
</style>