This commit is contained in:
parent
6aa66ce311
commit
6b659a6878
|
|
@ -1,122 +1,49 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="form-image">
|
<ali-oss-uploader v-model="currentValue" :max-count="maxCount" :max-size="maxSize" accept="image/*" :userId="userId"
|
||||||
<view class="image-list">
|
:type="ossType" width="100%" @input="onInput" @change="onChange" />
|
||||||
<view v-for="(item, index) in imageList" :key="index" class="image-item">
|
|
||||||
<image :src="item" mode="aspectFill" class="preview-image" @click="previewImage(index)" />
|
|
||||||
<view class="delete-btn" @click.stop="deleteImage(index)">
|
|
||||||
<text class="delete-icon">×</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view v-if="imageList.length < maxCount" class="image-item add-btn" @click="chooseImage">
|
|
||||||
<text class="add-icon">+</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import AliOssUploader from '../ali-oss-uploader/ali-oss-uploader.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FormItemImage',
|
name: 'FormItemImage',
|
||||||
|
components: { AliOssUploader },
|
||||||
props: {
|
props: {
|
||||||
value: { type: Array, default: function () { return []; } },
|
value: { type: Array, default: function () { return []; } },
|
||||||
maxCount: { type: Number, default: 9 }
|
maxCount: { type: Number, default: 9 },
|
||||||
|
maxSize: { type: Number, default: 5 }
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
imageList: []
|
currentValue: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
userId: function () {
|
||||||
|
return this.$store && this.$store.state && this.$store.state.sjInfo
|
||||||
|
? this.$store.state.sjInfo.id : null;
|
||||||
|
},
|
||||||
|
ossType: function () {
|
||||||
|
var artisanType = getApp().globalData ? getApp().globalData.artisanType : 0;
|
||||||
|
return (artisanType || 0) + 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value: {
|
value: {
|
||||||
handler: function (val) {
|
handler: function (val) {
|
||||||
this.imageList = Array.isArray(val) ? val.slice() : [];
|
this.currentValue = Array.isArray(val) ? val.slice() : [];
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
chooseImage: function () {
|
onInput: function (list) {
|
||||||
var remaining = this.maxCount - this.imageList.length;
|
this.$emit('input', list);
|
||||||
if (remaining <= 0) return;
|
|
||||||
var self = this;
|
|
||||||
uni.chooseImage({
|
|
||||||
count: remaining,
|
|
||||||
sizeType: ['compressed'],
|
|
||||||
sourceType: ['album', 'camera'],
|
|
||||||
success: function (res) {
|
|
||||||
self.imageList = self.imageList.concat(res.tempFilePaths);
|
|
||||||
self.$emit('input', self.imageList);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
deleteImage: function (index) {
|
onChange: function (list) {
|
||||||
this.imageList.splice(index, 1);
|
this.$emit('change', list);
|
||||||
this.$emit('input', this.imageList);
|
|
||||||
},
|
|
||||||
previewImage: function (index) {
|
|
||||||
uni.previewImage({
|
|
||||||
urls: this.imageList,
|
|
||||||
current: index
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.form-image {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-item {
|
|
||||||
width: 200rpx;
|
|
||||||
height: 200rpx;
|
|
||||||
margin-right: 10rpx;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-image {
|
|
||||||
width: 200rpx;
|
|
||||||
height: 200rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-btn {
|
|
||||||
position: absolute;
|
|
||||||
top: -20rpx;
|
|
||||||
right: -20rpx;
|
|
||||||
width: 40rpx;
|
|
||||||
height: 40rpx;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-icon {
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 32rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-btn {
|
|
||||||
background-color: #ffffff;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border: 2rpx dashed #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-icon {
|
|
||||||
font-size: 60rpx;
|
|
||||||
color: #999999;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,59 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="form-video">
|
<view>
|
||||||
<view v-if="videoUrl" class="video-preview">
|
<ali-oss-uploader v-if="!currentValue" :max-count="1" :max-size="maxSize" accept="video/*" :userId="userId"
|
||||||
<video :src="videoUrl" class="preview-video" controls />
|
:type="ossType" width="100%" @input="onInput" @change="onChange" />
|
||||||
|
<view v-else class="video-wrapper">
|
||||||
|
<video :src="currentValue" class="preview-video" controls />
|
||||||
<view class="delete-btn" @click="deleteVideo">
|
<view class="delete-btn" @click="deleteVideo">
|
||||||
<text class="delete-icon">×</text>
|
<text class="delete-icon">×</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-else class="upload-btn" @click="chooseVideo">
|
|
||||||
<text class="plus-icon">+</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import AliOssUploader from '../ali-oss-uploader/ali-oss-uploader.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FormItemVideo',
|
name: 'FormItemVideo',
|
||||||
|
components: { AliOssUploader },
|
||||||
props: {
|
props: {
|
||||||
value: { type: String, default: '' }
|
value: { type: String, default: '' },
|
||||||
|
maxSize: { type: Number, default: 100 }
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
videoUrl: ''
|
currentValue: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
userId: function () {
|
||||||
|
return this.$store && this.$store.state && this.$store.state.sjInfo
|
||||||
|
? this.$store.state.sjInfo.id : null;
|
||||||
|
},
|
||||||
|
ossType: function () {
|
||||||
|
var artisanType = getApp().globalData ? getApp().globalData.artisanType : 0;
|
||||||
|
return (artisanType || 0) + 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value: {
|
value: {
|
||||||
handler: function (val) {
|
handler: function (val) {
|
||||||
this.videoUrl = val || '';
|
this.currentValue = val || '';
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
chooseVideo: function () {
|
onInput: function (val) {
|
||||||
var self = this;
|
this.currentValue = val;
|
||||||
uni.chooseVideo({
|
this.$emit('input', val);
|
||||||
sourceType: ['album', 'camera'],
|
},
|
||||||
maxDuration: 60,
|
onChange: function (val) {
|
||||||
success: function (res) {
|
this.$emit('change', val);
|
||||||
self.videoUrl = res.tempFilePath;
|
|
||||||
self.$emit('input', self.videoUrl);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
deleteVideo: function () {
|
deleteVideo: function () {
|
||||||
this.videoUrl = '';
|
this.currentValue = '';
|
||||||
this.$emit('input', '');
|
this.$emit('input', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,14 +61,10 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.form-video {
|
.video-wrapper {
|
||||||
width: 100%;
|
position: relative;
|
||||||
}
|
|
||||||
|
|
||||||
.video-preview {
|
|
||||||
width: 200rpx;
|
width: 200rpx;
|
||||||
height: 200rpx;
|
height: 200rpx;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-video {
|
.preview-video {
|
||||||
|
|
@ -70,35 +75,22 @@ export default {
|
||||||
|
|
||||||
.delete-btn {
|
.delete-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -20rpx;
|
top: -10rpx;
|
||||||
right: -20rpx;
|
right: -10rpx;
|
||||||
width: 40rpx;
|
width: 40rpx;
|
||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: #ff4d4f;
|
||||||
|
color: white;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete-icon {
|
.delete-icon {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-btn {
|
|
||||||
width: 200rpx;
|
|
||||||
height: 200rpx;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border: 2rpx dashed #dddddd;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.plus-icon {
|
|
||||||
font-size: 60rpx;
|
|
||||||
color: #999999;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,89 +1,118 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="dynamic-form">
|
<view class="dynamic-form">
|
||||||
<view v-for="(field, index) in fields" :key="field.key" class="form-section">
|
<view v-for="(group, gi) in fields" :key="gi" class="form-group">
|
||||||
<!-- 单行文本 -->
|
<!-- single -->
|
||||||
<view v-if="field.type === 'text'" class="form-item">
|
<block v-if="group.type === 'single'">
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
<view v-if="group.field.type === 'text'" class="form-item">
|
||||||
<input type="text" :value="formData[field.key]" :placeholder="field.placeholder" placeholder-class="placeholder"
|
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label }}</text>
|
||||||
class="form-input" @input="onInput(field.key, $event)" />
|
<input type="text" :value="formData[group.field.key]" :placeholder="group.field.placeholder"
|
||||||
</view>
|
placeholder-class="placeholder" class="form-input" @input="onInput(group.field.key, $event)" />
|
||||||
|
</view>
|
||||||
<!-- 多行文本 -->
|
<view v-else-if="group.field.type === 'number'" class="form-item" :style="group.field.tip ? 'flex-wrap: wrap;' : ''">
|
||||||
<view v-else-if="field.type === 'textarea'" class="detail-card">
|
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label }}</text>
|
||||||
<view class="detail-row">
|
<input type="digit" :value="formData[group.field.key]" :placeholder="group.field.placeholder"
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
placeholder-class="placeholder" class="form-input" @input="onInput(group.field.key, $event)" />
|
||||||
<view class="detail-textarea-wrap">
|
<text v-if="group.field.tips && !group.field.tip" class="form-tips">{{ group.field.tips }}</text>
|
||||||
<textarea class="detail-textarea" :value="formData[field.key]" :placeholder="field.placeholder"
|
<view v-if="group.field.tip" class="price-tip">
|
||||||
placeholder-class="placeholder" maxlength="200" @input="onInput(field.key, $event)" />
|
<text class="price-tip-card">{{ group.field.tip }}</text>
|
||||||
<text class="detail-count">{{ (formData[field.key] || '').length }}/200</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
<view v-else-if="group.field.type === 'image_multi'" class="form-item-up upload-item">
|
||||||
|
<view>
|
||||||
<!-- 数字输入 -->
|
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label }}</text>
|
||||||
<view v-else-if="field.type === 'number'" class="form-item" :style="field.tip ? 'flex-wrap: wrap;' : ''">
|
<text class="upload-tip">(仅可上传{{ group.field.maxCount || 9 }}个图片)</text>
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
</view>
|
||||||
<input type="digit" :value="formData[field.key]" :placeholder="field.placeholder"
|
<view class="upload-content">
|
||||||
placeholder-class="placeholder" class="form-input" @input="onInput(field.key, $event)" />
|
<form-item-image :value="formData[group.field.key]" :maxCount="group.field.maxCount || 9"
|
||||||
<text v-if="field.tips && !field.tip" class="form-tips">{{ field.tips }}</text>
|
@input="onInput(group.field.key, $event)" />
|
||||||
<view v-if="field.tip" class="price-tip">
|
</view>
|
||||||
<text class="price-tip-card">{{ field.tip }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
<view v-else-if="group.field.type === 'video'" class="form-item-up upload-item">
|
||||||
|
<view>
|
||||||
<!-- 多图上传 -->
|
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label }}</text>
|
||||||
<view v-else-if="field.type === 'image_multi'" class="form-item-up upload-item">
|
<text class="upload-tip">(仅可上传1个视频)</text>
|
||||||
<view>
|
</view>
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
<view class="upload-content">
|
||||||
<text class="upload-tip">(仅可上传{{ field.maxCount || 9 }}个图片)</text>
|
<form-item-video :value="formData[group.field.key]" @input="onInput(group.field.key, $event)" />
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="upload-content">
|
<view v-else-if="group.field.type === 'richtext_editor'" class="form-item">
|
||||||
<form-item-image :value="formData[field.key]" :maxCount="field.maxCount || 9"
|
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label }}</text>
|
||||||
@input="onInput(field.key, $event)" />
|
<form-item-richtext :value="formData[group.field.key]" @input="onInput(group.field.key, $event)" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</block>
|
||||||
|
<!-- section -->
|
||||||
<!-- 视频上传 -->
|
<view v-if="group.type === 'section'" class="section-card">
|
||||||
<view v-else-if="field.type === 'video'" class="form-item-up upload-item">
|
<view v-if="group.sectionTitle" class="section-title-bar">
|
||||||
<view>
|
<text class="section-title">{{ group.sectionTitle }}</text>
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
|
||||||
<text class="upload-tip">(仅可上传1个视频)</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="upload-content">
|
<view v-for="(field, fi) in group.fields" :key="field.key || fi" class="section-field">
|
||||||
<form-item-video :value="formData[field.key]" @input="onInput(field.key, $event)" />
|
<view v-if="field.type === 'text'" class="form-item no-bg">
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<input type="text" :value="formData[field.key]" :placeholder="field.placeholder"
|
||||||
|
placeholder-class="placeholder" class="form-input" @input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'textarea'" class="detail-row">
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<view class="detail-textarea-wrap">
|
||||||
|
<textarea class="detail-textarea" :value="formData[field.key]" :placeholder="field.placeholder"
|
||||||
|
placeholder-class="placeholder" maxlength="200" @input="onInput(field.key, $event)" />
|
||||||
|
<text class="detail-count">{{ (formData[field.key] || "").length }}/200</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'number'" class="form-item no-bg" :style="field.tip ? 'flex-wrap: wrap;' : ''">
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<input type="digit" :value="formData[field.key]" :placeholder="field.placeholder"
|
||||||
|
placeholder-class="placeholder" class="form-input" @input="onInput(field.key, $event)" />
|
||||||
|
<text v-if="field.tips && !field.tip" class="form-tips">{{ field.tips }}</text>
|
||||||
|
<view v-if="field.tip" class="price-tip">
|
||||||
|
<text class="price-tip-card">{{ field.tip }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'select'" class="form-item no-bg">
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<form-item-select :value="formData[field.key]" :options="field.options || []" :placeholder="field.placeholder"
|
||||||
|
@input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'single_select'" class="form-item no-bg" style="flex-wrap: wrap;">
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<view class="select-options">
|
||||||
|
<form-item-radio :value="formData[field.key]" :options="field.options || []"
|
||||||
|
@input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'multi_select'" class="form-item no-bg" style="flex-wrap: wrap;">
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<view class="select-options">
|
||||||
|
<form-item-checkbox :value="formData[field.key]" :options="field.options || []"
|
||||||
|
:maxCount="field.maxCount || 0" @input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'image_multi'" class="form-item-up upload-item no-bg">
|
||||||
|
<view>
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<text class="upload-tip">(仅可上传{{ field.maxCount || 9 }}个图片)</text>
|
||||||
|
</view>
|
||||||
|
<view class="upload-content">
|
||||||
|
<form-item-image :value="formData[field.key]" :maxCount="field.maxCount || 9"
|
||||||
|
@input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'video'" class="form-item-up upload-item no-bg">
|
||||||
|
<view>
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<text class="upload-tip">(仅可上传1个视频)</text>
|
||||||
|
</view>
|
||||||
|
<view class="upload-content">
|
||||||
|
<form-item-video :value="formData[field.key]" @input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="field.type === 'richtext_editor'" class="form-item no-bg">
|
||||||
|
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||||
|
<form-item-richtext :value="formData[field.key]" @input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 下拉选择 -->
|
|
||||||
<view v-else-if="field.type === 'select'" class="form-item">
|
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
|
||||||
<form-item-select :value="formData[field.key]" :options="field.options || []" :placeholder="field.placeholder"
|
|
||||||
@input="onInput(field.key, $event)" />
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 单选 -->
|
|
||||||
<view v-else-if="field.type === 'single_select'" class="form-item" style="flex-wrap: wrap;">
|
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
|
||||||
<view class="select-options">
|
|
||||||
<form-item-radio :value="formData[field.key]" :options="field.options || []"
|
|
||||||
@input="onInput(field.key, $event)" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 多选 -->
|
|
||||||
<view v-else-if="field.type === 'multi_select'" class="form-item" style="flex-wrap: wrap;">
|
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
|
||||||
<view class="select-options">
|
|
||||||
<form-item-checkbox :value="formData[field.key]" :options="field.options || []"
|
|
||||||
:maxCount="field.maxCount || 0" @input="onInput(field.key, $event)" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 图文编辑器 -->
|
|
||||||
<view v-else-if="field.type === 'richtext_editor'" class="form-item">
|
|
||||||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
|
||||||
<form-item-richtext :value="formData[field.key]" @input="onInput(field.key, $event)" />
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -138,15 +167,13 @@ export default {
|
||||||
handler: function () {
|
handler: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
var data = {};
|
var data = {};
|
||||||
this.fields.forEach(function (field) {
|
this.fields.forEach(function (group) {
|
||||||
if (self.formData[field.key] !== undefined) {
|
if (group.type === 'single' && group.field) {
|
||||||
data[field.key] = self.formData[field.key];
|
self._initFieldData(data, group.field);
|
||||||
} else if (field.default_value !== undefined) {
|
} else if (group.type === 'section' && group.fields) {
|
||||||
data[field.key] = field.default_value;
|
group.fields.forEach(function (field) {
|
||||||
} else if (field.type === 'multi_select' || field.type === 'image_multi') {
|
self._initFieldData(data, field);
|
||||||
data[field.key] = [];
|
});
|
||||||
} else {
|
|
||||||
data[field.key] = '';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.formData = Object.assign({}, this.formData, data);
|
this.formData = Object.assign({}, this.formData, data);
|
||||||
|
|
@ -155,6 +182,17 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
_initFieldData: function (data, field) {
|
||||||
|
if (this.formData[field.key] !== undefined) {
|
||||||
|
data[field.key] = this.formData[field.key];
|
||||||
|
} else if (field.default_value !== undefined) {
|
||||||
|
data[field.key] = field.default_value;
|
||||||
|
} else if (field.type === 'multi_select' || field.type === 'image_multi') {
|
||||||
|
data[field.key] = [];
|
||||||
|
} else {
|
||||||
|
data[field.key] = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
onInput: function (key, event) {
|
onInput: function (key, event) {
|
||||||
var value = event;
|
var value = event;
|
||||||
if (event && event.target && event.target.value !== undefined) {
|
if (event && event.target && event.target.value !== undefined) {
|
||||||
|
|
@ -169,15 +207,24 @@ export default {
|
||||||
validate: function () {
|
validate: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
for (var i = 0; i < this.fields.length; i++) {
|
for (var i = 0; i < this.fields.length; i++) {
|
||||||
var field = this.fields[i];
|
var group = this.fields[i];
|
||||||
if (field.is_required === true) {
|
var fieldsToCheck = [];
|
||||||
var value = self.formData[field.key];
|
if (group.type === 'single' && group.field) {
|
||||||
if (!value || (Array.isArray(value) && value.length === 0)) {
|
fieldsToCheck.push(group.field);
|
||||||
uni.showToast({
|
} else if (group.type === 'section' && group.fields) {
|
||||||
title: field.label + '不能为空',
|
fieldsToCheck = group.fields;
|
||||||
icon: 'none'
|
}
|
||||||
});
|
for (var j = 0; j < fieldsToCheck.length; j++) {
|
||||||
return false;
|
var field = fieldsToCheck[j];
|
||||||
|
if (field.is_required === true) {
|
||||||
|
var value = self.formData[field.key];
|
||||||
|
if (!value || (Array.isArray(value) && value.length === 0)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: field.label + '不能为空',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +239,7 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-section {
|
.form-group {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,8 +268,8 @@ export default {
|
||||||
|
|
||||||
.form-tips {
|
.form-tips {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #999999;
|
color: #333333;
|
||||||
margin-left: 10rpx;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-tip {
|
.price-tip {
|
||||||
|
|
@ -272,17 +319,55 @@ export default {
|
||||||
margin-top: 16rpx;
|
margin-top: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-card {
|
.section-card {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
padding: 0 24rpx 8rpx;
|
padding: 0 24rpx 24rpx;
|
||||||
margin-bottom: 24rpx;
|
margin-bottom: 24rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* section内字段间距20rpx,通过section-field包装器控制 */
|
||||||
|
.section-field + .section-field {
|
||||||
|
padding-top: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* section内字段去掉独立白色背景和底部间距 */
|
||||||
|
.section-card .form-item,
|
||||||
|
.section-card .form-item-up {
|
||||||
|
background-color: transparent;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-card .detail-row {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title-bar {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
padding: 24rpx 0 20rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
line-height: 40rpx;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.detail-row {
|
.detail-row {
|
||||||
padding: 24rpx 0 36rpx;
|
padding: 20rpx 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row:first-child {
|
||||||
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-row .form-label {
|
.detail-row .form-label {
|
||||||
|
|
|
||||||
|
|
@ -106,12 +106,15 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
uni.$on("updateGraphicDetails", (data) => {
|
|
||||||
this.$set(this.formData, "graphic_details", JSON.stringify(data));
|
|
||||||
// 这里可以添加其他处理逻辑
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
|
// 监听图文详情编辑回调(在onLoad注册,确保navigateBack时能收到事件)
|
||||||
|
uni.$on("updateGraphicDetails", (data) => {
|
||||||
|
// 替换整个formData对象引用,确保dynamic-form的watch.value能触发
|
||||||
|
this.formData = Object.assign({}, this.formData, {
|
||||||
|
graphic_details: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
});
|
||||||
this.state = options.state || "";
|
this.state = options.state || "";
|
||||||
// 接收分类参数
|
// 接收分类参数
|
||||||
if (options.first_class_id) {
|
if (options.first_class_id) {
|
||||||
|
|
@ -130,6 +133,9 @@ export default {
|
||||||
const notShow = uni.getStorageSync('addServiceReminderNotShow');
|
const notShow = uni.getStorageSync('addServiceReminderNotShow');
|
||||||
this.getUserInfo();
|
this.getUserInfo();
|
||||||
},
|
},
|
||||||
|
onUnload() {
|
||||||
|
uni.$off("updateGraphicDetails");
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showShopPrice() {
|
showShopPrice() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -147,39 +153,155 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 字段类型映射:接口类型 -> dynamic-form类型
|
||||||
|
mapFieldType(fieldType) {
|
||||||
|
const typeMap = {
|
||||||
|
'text': 'text',
|
||||||
|
'number': 'number',
|
||||||
|
'image_multi': 'image_multi',
|
||||||
|
'video': 'video',
|
||||||
|
'richtext_editor': 'richtext_editor',
|
||||||
|
'select': 'select',
|
||||||
|
'single_select': 'single_select',
|
||||||
|
'multi_select': 'multi_select',
|
||||||
|
'textarea': 'textarea',
|
||||||
|
};
|
||||||
|
return typeMap[fieldType] || 'text';
|
||||||
|
},
|
||||||
|
|
||||||
|
// 将接口config_data转换为dynamic-form需要的分组格式
|
||||||
|
transformConfigToFields(configData) {
|
||||||
|
const groups = [];
|
||||||
|
let customFieldIndex = 0;
|
||||||
|
|
||||||
|
// 1. 处理presetFields(预设字段)- 每个字段独立一组
|
||||||
|
if (configData.presetFields && Array.isArray(configData.presetFields)) {
|
||||||
|
configData.presetFields.forEach((preset) => {
|
||||||
|
if (!preset.enabled) return;
|
||||||
|
|
||||||
|
const field = {
|
||||||
|
key: preset.key,
|
||||||
|
type: this.mapFieldType(preset.fieldType),
|
||||||
|
label: preset.title,
|
||||||
|
is_required: preset.required,
|
||||||
|
placeholder: preset.placeholder || `请输入${preset.title}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (preset.showHint && preset.hint) {
|
||||||
|
field.tip = preset.hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preset.key === 'line_price' || preset.key === 'server_price') {
|
||||||
|
field.tips = '(元)';
|
||||||
|
field.tip = preset.key === 'line_price' ? '服务的基础定价,未参与任何优惠的价格' : '服务参与单品优惠后的价格';
|
||||||
|
} else if (preset.key === 'server_time') {
|
||||||
|
field.placeholder = '请输入服务时长';
|
||||||
|
field.tips = '分钟';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preset.maxCount) {
|
||||||
|
field.maxCount = preset.maxCount;
|
||||||
|
}
|
||||||
|
if (preset.maxLength && preset.fieldType === 'text') {
|
||||||
|
field.maxLength = preset.maxLength;
|
||||||
|
}
|
||||||
|
if (preset.maxFileSize) {
|
||||||
|
field.maxFileSize = preset.maxFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
field._hasOriginalKey = !!preset.key;
|
||||||
|
groups.push({ type: 'single', field });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 处理sections(区段)- 整个section为一组
|
||||||
|
if (configData.sections && Array.isArray(configData.sections)) {
|
||||||
|
configData.sections.forEach((section) => {
|
||||||
|
const sectionFields = [];
|
||||||
|
if (section.fields && Array.isArray(section.fields)) {
|
||||||
|
section.fields.forEach((sectionField) => {
|
||||||
|
const fieldKey = sectionField.key || `custom_${sectionField.id || customFieldIndex++}`;
|
||||||
|
|
||||||
|
const field = {
|
||||||
|
key: fieldKey,
|
||||||
|
type: this.mapFieldType(sectionField.fieldType),
|
||||||
|
label: sectionField.title,
|
||||||
|
is_required: sectionField.required,
|
||||||
|
placeholder: sectionField.placeholder || `请输入${sectionField.title}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (sectionField.key === 'server_time') {
|
||||||
|
field.placeholder = '请输入服务时长';
|
||||||
|
field.tips = '分钟';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectionField.options && Array.isArray(sectionField.options) && sectionField.options.length > 0) {
|
||||||
|
field.options = sectionField.options;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectionField.maxCount && (sectionField.fieldType === 'multi_select' || sectionField.fieldType === 'image_multi')) {
|
||||||
|
field.maxCount = sectionField.maxCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectionField.maxLength && (sectionField.fieldType === 'text' || sectionField.fieldType === 'textarea')) {
|
||||||
|
field.maxLength = sectionField.maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectionField.maxLength && sectionField.fieldType === 'number') {
|
||||||
|
field.maxLength = sectionField.maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectionField.maxFileSize) {
|
||||||
|
field.maxFileSize = sectionField.maxFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
field._hasOriginalKey = !!sectionField.key;
|
||||||
|
field._original = {
|
||||||
|
id: sectionField.id,
|
||||||
|
sectionId: section.id,
|
||||||
|
sectionType: section.sectionType,
|
||||||
|
userDefined: sectionField.userDefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
sectionFields.push(field);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
groups.push({
|
||||||
|
type: 'section',
|
||||||
|
sectionTitle: section.sectionTitle || '',
|
||||||
|
fields: sectionFields,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
},
|
||||||
|
|
||||||
// 获取服务模板
|
// 获取服务模板
|
||||||
async getTemplate() {
|
async getTemplate() {
|
||||||
// 模拟数据
|
|
||||||
const mockFields = [
|
|
||||||
{ key: 'title', type: 'text', label: '服务名称', is_required: true, placeholder: '请输入服务名称' },
|
|
||||||
{ key: 'service_price', type: 'number', label: '服务定价', is_required: true, placeholder: '请输入定价,最多两位小数', tips: '(元)', tip: '服务的基础定价,未参与任何优惠的价格' },
|
|
||||||
{ key: 'sale_price', type: 'number', label: '服务售价', is_required: true, placeholder: '请输入售价,最多两位小数', tips: '(元)', tip: '服务参与单品优惠后的价格' },
|
|
||||||
{ key: 'service_time', type: 'number', label: '服务时长', is_required: true, placeholder: '请输入服务时间', tips: '(分钟)' },
|
|
||||||
{ key: 'effect', type: 'textarea', label: '服务功效', is_required: true, placeholder: '请输入服务功效' },
|
|
||||||
{ key: 'crowd', type: 'textarea', label: '适用人群', is_required: true, placeholder: '请输入不适用人群,例如:未成年人/孕妇不适用' },
|
|
||||||
{ key: 'product', type: 'textarea', label: '产品清单', is_required: false, placeholder: '请输入产品清单' },
|
|
||||||
{ key: 'scope', type: 'textarea', label: '适用范围', is_required: false, placeholder: '请输入使用时间/适用人数' },
|
|
||||||
{ key: 'tips_text', type: 'textarea', label: '温馨提示', is_required: false, placeholder: '请输入其他注意事项' },
|
|
||||||
{ key: 'images', type: 'image_multi', label: '服务图片', is_required: true, maxCount: 9 },
|
|
||||||
{ key: 'video', type: 'video', label: '上传短视频', is_required: false },
|
|
||||||
{ key: 'service_type', type: 'single_select', label: '服务类型', is_required: true, options: ['到店服务', '上门服务'] },
|
|
||||||
{ key: 'features', type: 'multi_select', label: '服务特色', is_required: false, options: ['一对一服务', '免费咨询', '售后保障'], maxCount: 2 },
|
|
||||||
{ key: 'graphic_details', type: 'richtext_editor', label: '图文详情', is_required: false },
|
|
||||||
];
|
|
||||||
try {
|
try {
|
||||||
const res = await request.post("/sj/servers/getTemplate", {
|
const res = await request.post("/sj/servers/getTemplate", {
|
||||||
first_class_id: this.formData.first_class_id,
|
first_class_id: this.formData.first_class_id,
|
||||||
});
|
});
|
||||||
if (res.data && res.data.fields && res.data.fields.length > 0) {
|
console.log("模板接口返回数据:", res);
|
||||||
|
if (res.data && res.data.config_data) {
|
||||||
|
// 使用接口返回的config_data转换为表单字段
|
||||||
|
// config_data 可能是字符串,需要解析
|
||||||
|
const configData = typeof res.data.config_data === 'string'
|
||||||
|
? JSON.parse(res.data.config_data)
|
||||||
|
: res.data.config_data;
|
||||||
|
console.log("解析后的config_data:", configData);
|
||||||
|
console.log("presetFields类型:", typeof configData.presetFields, Array.isArray(configData.presetFields));
|
||||||
|
const fields = this.transformConfigToFields(configData);
|
||||||
|
console.log("转换后的fields数组:", fields, "长度:", fields.length);
|
||||||
|
this.formFields = fields;
|
||||||
|
} else if (res.data && res.data.fields && res.data.fields.length > 0) {
|
||||||
|
// 兼容旧格式
|
||||||
this.formFields = res.data.fields;
|
this.formFields = res.data.fields;
|
||||||
} else {
|
|
||||||
// 接口返回空数据时使用模拟数据
|
|
||||||
this.formFields = mockFields;
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("获取模板失败", e);
|
console.error("获取模板失败", e);
|
||||||
// 接口失败时使用模拟数据
|
|
||||||
this.formFields = mockFields;
|
|
||||||
}
|
}
|
||||||
// 初始化表单数据
|
// 初始化表单数据
|
||||||
const initialData = {};
|
const initialData = {};
|
||||||
|
|
@ -261,36 +383,35 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
syncDetailForm() {
|
syncDetailForm() {
|
||||||
// 将 detailForm 的值映射到 formData 的新字段
|
// 双向同步:如果formData有值(来自dynamic-form),同步到detailForm;否则从detailForm同步到formData
|
||||||
this.formData.efficacy = (this.detailForm.effect || "").trim();
|
if (this.formData.efficacy) {
|
||||||
this.formData.crowd = (this.detailForm.crowd || "").trim();
|
this.detailForm.effect = this.formData.efficacy;
|
||||||
this.formData.product = (this.detailForm.product || "").trim();
|
} else {
|
||||||
this.formData.scope = (this.detailForm.scope || "").trim();
|
this.formData.efficacy = (this.detailForm.effect || "").trim();
|
||||||
this.formData.prompt = (this.detailForm.tips || "").trim();
|
}
|
||||||
|
if (this.formData.crowd) {
|
||||||
|
this.detailForm.crowd = this.formData.crowd;
|
||||||
|
} else {
|
||||||
|
this.formData.crowd = (this.detailForm.crowd || "").trim();
|
||||||
|
}
|
||||||
|
if (this.formData.product) {
|
||||||
|
this.detailForm.product = this.formData.product;
|
||||||
|
} else {
|
||||||
|
this.formData.product = (this.detailForm.product || "").trim();
|
||||||
|
}
|
||||||
|
if (this.formData.scope) {
|
||||||
|
this.detailForm.scope = this.formData.scope;
|
||||||
|
} else {
|
||||||
|
this.formData.scope = (this.detailForm.scope || "").trim();
|
||||||
|
}
|
||||||
|
if (this.formData.prompt) {
|
||||||
|
this.detailForm.tips = this.formData.prompt;
|
||||||
|
} else {
|
||||||
|
this.formData.prompt = (this.detailForm.tips || "").trim();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
checkDetailForm() {
|
checkDetailForm() {
|
||||||
if (!this.detailForm.effect || !this.detailForm.effect.trim()) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "请输入服务功效",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!this.detailForm.crowd || !this.detailForm.crowd.trim()) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "请输入适用人群",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// if (!this.detailForm.product || !this.detailForm.product.trim()) {
|
|
||||||
// uni.showToast({
|
|
||||||
// title: "请输入产品清单",
|
|
||||||
// icon: "none",
|
|
||||||
// });
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -498,103 +619,116 @@ export default {
|
||||||
});
|
});
|
||||||
}, 500),
|
}, 500),
|
||||||
|
|
||||||
|
// 验证动态表单字段
|
||||||
|
validateDynamicForm() {
|
||||||
|
// 遍历 formGroups(分组结构)按顺序验证必填项
|
||||||
|
for (let i = 0; i < this.formFields.length; i++) {
|
||||||
|
const group = this.formFields[i];
|
||||||
|
const fieldsToCheck = [];
|
||||||
|
if (group.type === 'single' && group.field) {
|
||||||
|
fieldsToCheck.push(group.field);
|
||||||
|
} else if (group.type === 'section' && group.fields) {
|
||||||
|
fieldsToCheck.push(...group.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < fieldsToCheck.length; j++) {
|
||||||
|
const field = fieldsToCheck[j];
|
||||||
|
if (!field.is_required) continue;
|
||||||
|
|
||||||
|
const value = this.formData[field.key];
|
||||||
|
const isEmpty = value === undefined || value === null || value === '' ||
|
||||||
|
(Array.isArray(value) && value.length === 0);
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
// 根据字段类型显示不同的提示语
|
||||||
|
const prefix = (field.type === 'image_multi' || field.type === 'video') ? '请上传' : '请输入';
|
||||||
|
uni.showToast({
|
||||||
|
title: `${prefix}${field.label}`,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务时长特殊验证
|
||||||
|
if (field.key === 'server_time') {
|
||||||
|
if (value < 10) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "服务时长最短为10分钟",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (value > 240) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "服务时长最长为240分钟",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
// 构建提交数据:有key的字段直接作为参数,没有key的字段放入intro数组
|
||||||
|
buildSubmitData() {
|
||||||
|
const submitData = {};
|
||||||
|
const introArr = [];
|
||||||
|
|
||||||
|
// 添加固定字段
|
||||||
|
if (this.formData.id) submitData.id = this.formData.id;
|
||||||
|
if (this.formData.first_class_id) submitData.first_class_id = this.formData.first_class_id;
|
||||||
|
if (this.formData.second_class_id) submitData.second_class_id = this.formData.second_class_id;
|
||||||
|
submitData.server_kind = this.formData.server_kind || getApp().globalData.artisanType;
|
||||||
|
|
||||||
|
// 遍历分组,按顺序处理字段
|
||||||
|
for (let i = 0; i < this.formFields.length; i++) {
|
||||||
|
const group = this.formFields[i];
|
||||||
|
let fieldsToProcess = [];
|
||||||
|
if (group.type === 'single' && group.field) {
|
||||||
|
fieldsToProcess.push(group.field);
|
||||||
|
} else if (group.type === 'section' && group.fields) {
|
||||||
|
fieldsToProcess = group.fields;
|
||||||
|
}
|
||||||
|
for (let j = 0; j < fieldsToProcess.length; j++) {
|
||||||
|
const field = fieldsToProcess[j];
|
||||||
|
const value = this.formData[field.key];
|
||||||
|
if (value === undefined || value === null || value === '') continue;
|
||||||
|
if (Array.isArray(value) && value.length === 0) continue;
|
||||||
|
|
||||||
|
if (field._hasOriginalKey) {
|
||||||
|
// 有key的字段直接作为请求参数
|
||||||
|
submitData[field.key] = value;
|
||||||
|
} else {
|
||||||
|
// 没有key的字段放入intro数组
|
||||||
|
introArr.push({
|
||||||
|
id: field._original ? field._original.id : field.key,
|
||||||
|
title: field.label,
|
||||||
|
value: value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (introArr.length > 0) {
|
||||||
|
submitData.intro = JSON.stringify(introArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return submitData;
|
||||||
|
},
|
||||||
|
|
||||||
// 提交表单
|
// 提交表单
|
||||||
submitForm: debounce(function () {
|
submitForm: debounce(function () {
|
||||||
if (this.isAdd) return;
|
if (this.isAdd) return;
|
||||||
this.syncDetailForm();
|
|
||||||
// 表单验证
|
|
||||||
|
|
||||||
if (!this.formData.title) {
|
// 先同步服务简介数据到formData
|
||||||
uni.showToast({
|
|
||||||
title: "请输入服务名称",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.formData.line_price) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '请输入服务定价',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!this.formData.server_price) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '请输入服务售价',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.formData.server_time) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "请输入服务时长",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.formData.server_time < 10) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "服务时长最短为10分钟",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.formData.server_time > 240) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "服务时长最长为240分钟",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.formData.sj_see && this.artisanType == 1) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "请选择是否允许在门店端售卖",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查服务简介
|
|
||||||
if (!this.checkDetailForm()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.syncDetailForm();
|
this.syncDetailForm();
|
||||||
|
|
||||||
// 检查服务流程数组
|
// 验证动态表单字段
|
||||||
if (this.formData.process && this.formData.process.length > 0) {
|
if (!this.validateDynamicForm()) {
|
||||||
for (let item of this.formData.process) {
|
|
||||||
if (!item.text) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "请完善服务流程内容",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uni.showToast({
|
|
||||||
title: "请添加服务流程内容",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查视频和图片
|
|
||||||
// if (!this.formData.video) {
|
|
||||||
// uni.showToast({
|
|
||||||
// title: '请上传服务视频',
|
|
||||||
// icon: 'none'
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
if (!this.formData.photo || this.formData.photo.length === 0) {
|
|
||||||
uni.showToast({
|
|
||||||
title: "请上传服务图片",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.artisanType == 2) {
|
if (this.artisanType == 2) {
|
||||||
delete this.formData.sj_see;
|
delete this.formData.sj_see;
|
||||||
}
|
}
|
||||||
|
|
@ -607,16 +741,8 @@ export default {
|
||||||
url = "/user/serverupdate";
|
url = "/user/serverupdate";
|
||||||
}
|
}
|
||||||
console.log(this.formData, '-0-0-0-0-0-');
|
console.log(this.formData, '-0-0-0-0-0-');
|
||||||
delete this.formData.shop_business_time
|
const submitData = this.buildSubmitData();
|
||||||
delete this.formData.shop_head_photo
|
request.post(url, submitData).then((res) => {
|
||||||
delete this.formData.shop_address
|
|
||||||
delete this.formData.shop_dependency
|
|
||||||
delete this.formData.shop_class
|
|
||||||
delete this.formData.team_buy
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
request.post(url, this.formData).then((res) => {
|
|
||||||
if (res.state == 1) {
|
if (res.state == 1) {
|
||||||
const pages = getCurrentPages();
|
const pages = getCurrentPages();
|
||||||
const prevPage = pages[pages.length - 2]; // 上一个页面
|
const prevPage = pages[pages.length - 2]; // 上一个页面
|
||||||
|
|
|
||||||
|
|
@ -120,13 +120,13 @@ const request = async (options, isUpdate) => {
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
// baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
//baseURL = 'http://116.63.163.121:96'; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = "http://116.63.163.121:96"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
// baseURL = "https://app.mrrweb.com.cn";
|
// baseURL = "https://app.mrrweb.com.cn";
|
||||||
} else {
|
} else {
|
||||||
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
// baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
//baseURL = 'http://116.63.163.121:96'; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = "http://116.63.163.121:96"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
// baseURL = "https://app.mrrweb.com.cn";
|
// baseURL = "https://app.mrrweb.com.cn";
|
||||||
|
|
||||||
console.log("生产环境");
|
console.log("生产环境");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue