Feat:体验店入驻审核

This commit is contained in:
linxi
2026-03-12 12:29:27 +08:00
parent d0ca72c855
commit 6b849c5300
4 changed files with 966 additions and 0 deletions
+933
View File
@@ -0,0 +1,933 @@
<template>
<view class="container">
<view
v-if="form.reviewStatus === 2"
class="v12-pa-2 reason-box"
>
驳回原因: {{ form.reviewMsg }}
</view>
<view
v-if="form.isDraft === 0 && form.reviewStatus === 0"
class="v12-pa-2 reason-box"
>
审核中请耐心等待审核结果
</view>
<view class="form-item">
<view class="title">
<text class="required">* </text>
名称:
</view>
<view class="input">
<u-textarea
v-model="form.name"
border="none"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
placeholder="请输入名称"
:placeholder-style="inputPlaceholderStyle"
/>
</view>
</view>
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start">
<view>
<view class="title">
<text class="required">* </text>
主图:
</view>
<view class="input">
<u-upload
:fileList="coverImg.filter(item => item.url)"
:disabled="form.isDraft === 0 && (coverImg.length > 0 || form.reviewStatus === 0 || form.reviewStatus === 1)"
:deletable="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
:maxCount="1"
count="1"
name="coverImg"
multiple
@afterRead="afterRead($event, 'coverImg')"
@delete="deletePic($event, 'coverImg')"
/>
</view>
</view>
<view class="v12-ml-2">
<view class="title">
<text class="required">* </text>
头像:
</view>
<view class="input">
<u-upload
:fileList="avatarImg.filter(item => item.url)"
:disabled="form.isDraft === 0 && (avatarImg.length > 0 || form.reviewStatus === 0 || form.reviewStatus === 1)"
:deletable="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
:maxCount="1"
count="1"
name="avatarImg"
multiple
@afterRead="afterRead($event, 'avatarImg')"
@delete="deletePic($event, 'avatarImg')"
/>
</view>
</view>
</view>
<view class="form-item v12-mt-2">
<view class="title">
<text class="required">* </text>
轮播图:
</view>
<view class="input">
<u-upload
:fileList="bannerImg"
:disabled="form.isDraft === 0 && (bannerImg.length > 8 || form.reviewStatus === 0 || form.reviewStatus === 1)"
:deletable="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
:maxCount="9"
count="9"
name="bannerImg"
multiple
@afterRead="afterRead($event, 'bannerImg')"
@delete="deletePic($event, 'bannerImg')"
/>
</view>
</view>
<view class="form-item v12-mt-2">
<view class="title">
视频:
</view>
<view class="input">
<u-upload
v-if="videos.length === 0"
accept="video"
multiple
:max-count="1"
:fileList="videos"
:disabled="form.isDraft === 0 && (videos.length > 0 || form.reviewStatus === 0 || form.reviewStatus === 1)"
:deletable="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
count="1"
name="videoImg"
:previewFullImage="true"
@afterRead="afterRead($event, 'videos', 'video')"
@delete="deletePic($event, 'videos')"
/>
<view
v-else
class="video-wrapper"
>
<video
:src="videos[0].url"
:poster="videos[0].url + '?vframe/jpg/offset/1'"
:controls="false"
play-btn-position="center"
class="video-item"
/>
<view
v-if="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
class="delete-badge"
@click.stop="deleteVideo(0)"
>
x
</view>
</view>
</view>
</view>
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
公司名称
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<input
v-model="form.companyName"
type="text"
:placeholder-style="inputPlaceholderStyle"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
placeholder="请输入公司名称"
/>
</view>
</view>
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
店铺分类
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<picker
:value="experienceStoreCategoryIndex"
:range="experienceStoreCategoryList"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
range-key="name"
mode="selector"
@change="handleCategoryChange"
>
<view class="one-t">
<text :style="{'color': form.experienceStoreCategoryName ? '#333' : '#999999'}">
{{ form.experienceStoreCategoryName || '请选择店铺分类' }}
</text>
</view>
</picker>
</view>
</view>
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
简介
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<input
v-model="form.intro"
type="text"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
:placeholder-style="inputPlaceholderStyle"
placeholder="请输入简介"
/>
</view>
</view>
<u-divider />
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
联系人
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<input
v-model="form.contact"
type="text"
:placeholder-style="inputPlaceholderStyle"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
placeholder="请输入联系人姓名"
/>
</view>
</view>
<u-divider />
<view
class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center"
@click="showTimePicker"
>
<view class="title">
<text class="required">* </text>
营业时间
</view>
<view class="v12-ml-2">
<view>
<text :style="{'color': form.serviceTime ? '#333' : '#999999'}">
{{ form.serviceTime || '起始时间' }}
</text>
-
<text :style="{'color': form.serviceEndTime ? '#333' : '#999999'}">
{{ form.serviceEndTime || '结束时间' }}
</text>
</view>
<tpf-time-range
ref="TimePickerPopupRef"
startTime="00:00"
endTime="23:59"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
:startDefaultTime="form.serviceTime"
:endDefaultTime="form.serviceEndTime"
@timeRange="timeRange"
/>
</view>
</view>
<u-divider />
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
省市区
</view>
<view
class="v12-ml-2 one-t"
style="flex: 1;"
>
<CitySelect
ref="cityselect"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
:defaultValue="form.area || '请选择'"
:items="district"
@callback="resultCity"
/>
</view>
</view>
<u-divider />
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
详细地址
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<input
v-model="form.address"
:placeholder-style="inputPlaceholderStyle"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
type="text"
placeholder="请输入详细地址"
/>
</view>
</view>
<u-divider />
<view
class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center"
@click="chooLocation"
>
<view class="title">
<text class="required">* </text>
地理定位
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<u--text
v-if="form.position"
:text="form.position"
/>
<u--text
v-else
text="请选择"
color="#c0c4cc"
/>
</view>
</view>
<u-divider />
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
商家电话
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<u-input
v-model="form.phone"
type="text"
:placeholder-style="inputPlaceholderStyle"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
placeholder="请输入商家电话"
maxlength="11"
border="none"
>
<template slot="suffix">
<u-code
v-if="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
ref="uCode"
seconds="30"
changeText="X秒重新获取"
@change="codeChange"
/>
<u-button
v-if="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
:text="tips"
type="success"
color="#4A97FC"
@tap="getCode"
/>
</template>
</u-input>
</view>
</view>
<u-divider />
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
填写验证码
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<input
v-model="form.captcha"
type="text"
:placeholder-style="inputPlaceholderStyle"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
placeholder="请输入验证码"
/>
</view>
</view>
<u-divider />
<view class="form-item v12-mt-2 v12-d-flex v12-justify-start v12-align-center">
<view class="title">
<text class="required">* </text>
商家微信
</view>
<view
class="v12-ml-2"
style="flex: 1;"
>
<input
v-model="form.wechat"
type="text"
:placeholder-style="inputPlaceholderStyle"
placeholder="请输入微信号"
:disabled="form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)"
/>
</view>
</view>
<u-divider />
<view class="form-item v12-mt-2">
<view class="title">
<text class="required">* </text>
资质:
</view>
<view class="input">
<u-upload
:fileList="qualificationImg"
:disabled="(form.isDraft === 0 && (form.reviewStatus === 0 || form.reviewStatus === 1)) || qualificationImg.length > 98"
:deletable="form.isDraft === 1 || (form.reviewStatus !== 0 && form.reviewStatus !== 1)"
:maxCount="99"
count="99"
name="qualificationImg"
multiple
@afterRead="afterRead($event, 'qualificationImg')"
@delete="deletePic($event, 'qualificationImg')"
/>
</view>
</view>
<view v-if="form.isDraft === 0">
<view
class="v12-primary v12-white-text submit-btn"
:style="{'background': form.reviewStatus === 0 ? '#FA979F !important' : '#4A97FC'}"
@click="submitForm"
>
{{ form.reviewStatus === 0 ? '撤销申请' : form.reviewStatus === 2 ? '重新提交' : '提交审核' }}
</view>
</view>
<view v-if="form.isDraft === 1">
<view
class="v12-primary v12-white-text submit-btn"
@click="submitForm"
>
提交审核
</view>
</view>
<u-popup
:show="show"
mode="center"
round="10"
@close="show=false"
>
<view class="popup-body">
<view class="tc bold">
入驻申请须知
</view>
<view class="content">
<rich-text :nodes="notice" />
</view>
<view class="agree-box v12-mb-2">
<checkbox-group @change="changeAgree">
<label>
<checkbox
value="yes"
style="transform:scale(0.8)"
/>
</label>
<text>我已仔细阅读并同意</text>
</checkbox-group>
</view>
<u-button
type="error"
text="确定"
:disabled="!isAgree"
@click="savePopup"
/>
</view>
</u-popup>
</view>
</template>
<script>
import CitySelect from '@/components/CitySelect'
import { getCity, registerVerify } from '@/api/user'
import { uploadVideo, uploadImage } from '@/utils'
import {
getShopData,
saveExperienceStore,
saveExperienceStoreDraft,
getExperienceStoreCategoryList,
getExperienceStoreInfo,
removeApply
} from '@/api/join'
export default {
components: {
CitySelect
},
data() {
return {
isAgree: false,
show: false,
notice: '',
tips: '获取验证码',
inputPlaceholderStyle: {
fontSize: '32rpx'
},
coverImg: [],
avatarImg: [],
bannerImg: [],
videos: [],
district: [],
qualificationImg: [],
partnerId: 0,
experienceStoreCategoryList: [],
experienceStoreCategoryIndex: 0,
form: {
captcha: '',
name: '',
cover: '',
avatar: '',
banner: '',
video: '',
companyName: '',
experienceStoreCategoryId: null,
experienceStoreCategoryName: '',
serviceTime: '00:00',
serviceEndTime: '23:59',
provinceId: 0,
provinceName: '',
cityId: 0,
cityName: '',
areaId: 0,
areaName: '',
address: '',
longitude: 0,
latitude: 0,
contact: '',
phone: '',
wechat: '',
qualification: '',
intro: '',
reviewMsg: '',
reviewStatus: 1,
isDraft: 1,
position: '',
area: ''
}
}
},
onLoad(opts) {
this.partnerId = opts.partnerId
this.queryCity()
getShopData().then(({ data }) => {
this.notice = data.merchantApplyNotice
})
getExperienceStoreCategoryList().then(({ data }) => {
this.experienceStoreCategoryList = data || []
if (this.experienceStoreCategoryList.length > 0) {
this.experienceStoreCategoryIndex = 0
}
this.initInfo()
})
},
onUnload() {
this.saveDraft()
},
onHide() {
this.saveDraft()
},
methods: {
initInfo() {
getExperienceStoreInfo().then(res => {
const data = res.data || {}
const info = data.experienceStoreInfo || {}
if (!info || Object.keys(info).length === 0) {
this.form.isDraft = 1
this.show = true
return
}
this.form = { ...this.form, ...info }
this.coverImg = info.cover ? this.stringToMapArr(info.cover) : []
this.avatarImg = info.avatar ? this.stringToMapArr(info.avatar) : []
this.bannerImg = info.banner ? this.stringToMapArr(info.banner) : []
this.videos = info.video ? this.stringToMapArr(info.video) : []
this.qualificationImg = info.qualification ? this.stringToMapArr(info.qualification) : []
this.form.reviewStatus = data.reviewStatus != null ? data.reviewStatus : this.form.reviewStatus
this.form.reviewMsg = data.reviewMsg || ''
if (this.form.reviewStatus === 0 || this.form.reviewStatus === 1 || this.form.reviewStatus === 2) {
this.form.isDraft = 0
} else {
this.form.isDraft = 1
}
this.form.latitude = info.latitude || 0
this.form.longitude = info.longitude || 0
this.form.position = this.form.longitude && this.form.latitude
? this.$forceToDecimal(this.form.longitude, 6) + ',' + this.$forceToDecimal(this.form.latitude, 6)
: ''
this.form.area = `${this.form.provinceName || ''} ${this.form.cityName || ''} ${this.form.areaName || ''}`.trim()
if (this.experienceStoreCategoryList && this.experienceStoreCategoryList.length > 0) {
const idx = this.experienceStoreCategoryList.findIndex(item => item.id === this.form.experienceStoreCategoryId)
if (idx !== -1) {
this.experienceStoreCategoryIndex = idx
this.form.experienceStoreCategoryName = this.experienceStoreCategoryList[idx].name
}
}
if (this.form.isDraft === 1 && (this.form.reviewStatus === null || this.form.reviewStatus === undefined)) {
this.show = true
}
}).catch(() => {
this.form.isDraft = 1
this.show = true
})
},
changeAgree(e) {
this.isAgree = e.detail.value.includes('yes')
},
savePopup() {
this.show = false
},
stringToMapArr(str, split = ',') {
return str.split(split).map(item => ({ url: item }))
},
saveDraft() {
this.form.cover = this.coverImg.filter(item => item.url).map(item => item.url).join(',')
this.form.avatar = this.avatarImg.filter(item => item.url).map(item => item.url).join(',')
this.form.banner = this.bannerImg.filter(item => item.url).map(item => item.url).join(',')
this.form.video = this.videos.filter(item => item.url).map(item => item.url).join(',')
this.form.qualification = this.qualificationImg.filter(item => item.url).map(item => item.url).join(',')
const params = {
experienceStoreInfo: { ...this.form },
partnerId: this.partnerId
}
saveExperienceStoreDraft(params).catch(err => {
uni.$u.toast(err.msg)
})
},
handleCategoryChange(e) {
const idx = parseInt(e.detail.value)
this.experienceStoreCategoryIndex = idx
const item = this.experienceStoreCategoryList[idx]
if (item) {
this.form.experienceStoreCategoryId = item.id
this.form.experienceStoreCategoryName = item.name
}
},
submitForm() {
if (this.form.reviewStatus === 0 && this.form.isDraft === 0) {
this.revokeExperienceStore()
return
}
this.form.cover = this.coverImg.filter(item => item.url).map(item => item.url).join(',')
this.form.avatar = this.avatarImg.filter(item => item.url).map(item => item.url).join(',')
this.form.banner = this.bannerImg.filter(item => item.url).map(item => item.url).join(',')
this.form.video = this.videos.filter(item => item.url).map(item => item.url).join(',')
this.form.qualification = this.qualificationImg.filter(item => item.url).map(item => item.url).join(',')
if (!this.form.name) {
uni.$u.toast('请输入名称')
return
}
if (!this.form.cover) {
uni.$u.toast('请上传主图')
return
}
if (!this.form.avatar) {
uni.$u.toast('请上传头像')
return
}
if (!this.form.banner) {
uni.$u.toast('请上传轮播图')
return
}
if (!this.form.companyName) {
uni.$u.toast('请输入公司名称')
return
}
if (!this.form.experienceStoreCategoryId) {
uni.$u.toast('请选择店铺分类')
return
}
if (!this.form.intro) {
uni.$u.toast('请输入简介')
return
}
if (!this.form.serviceTime) {
uni.$u.toast('请选择营业开始时间')
return
}
if (!this.form.serviceEndTime) {
uni.$u.toast('请选择营业结束时间')
return
}
if (!this.form.provinceId) {
uni.$u.toast('请选择省份')
return
}
if (!this.form.cityId) {
uni.$u.toast('请选择城市')
return
}
if (!this.form.areaId) {
uni.$u.toast('请选择区域')
return
}
if (!this.form.address) {
uni.$u.toast('请输入详细地址')
return
}
if (!this.form.longitude || !this.form.latitude) {
uni.$u.toast('请选择物理位置')
return
}
if (!this.form.qualification) {
uni.$u.toast('请上传资质')
return
}
if (!this.form.contact) {
uni.$u.toast('请输入联系人姓名')
return
}
if (!this.form.phone) {
uni.$u.toast('请输入手机号')
return
}
if (!this.form.captcha) {
uni.$u.toast('请输入验证码')
return
}
if (!this.form.wechat) {
uni.$u.toast('请输入联系微信')
return
}
const params = {
experienceStoreInfo: { ...this.form },
partnerId: this.partnerId,
captcha: this.form.captcha
}
saveExperienceStore(params).then(res => {
if (res.status === 200) {
uni.showToast({
title: '您的入驻申请已提交成功,请耐心等待审核',
icon: 'none',
success: () => {
this.form.isDraft = 0
this.form.reviewStatus = 0
this.show = false
}
})
}
}).catch(err => {
uni.$u.toast(err.msg)
})
},
revokeExperienceStore() {
uni.showModal({
title: '提示',
content: '确定撤销申请吗?',
success: res => {
if (res.confirm) {
removeApply().then(result => {
if (result.status === 200) {
uni.$u.toast('撤销申请成功')
this.initInfo()
} else {
uni.$u.toast(result.msg || '撤销失败')
}
}).catch(err => {
uni.$u.toast(err.msg)
})
}
}
})
},
getCode() {
if (!this.form.phone) {
uni.$u.toast('请输入手机号')
return
}
if (this.form.phone.length !== 11) {
uni.$u.toast('请输入11位手机号')
return
}
if (this.$refs.uCode && this.$refs.uCode.canGetCode) {
uni.showLoading({
title: '正在获取验证码'
})
registerVerify({
phone: this.form.phone,
type: 'merchantExperienceStoreApply'
}).then(() => {
uni.hideLoading()
uni.$u.toast('验证码已发送')
this.$refs.uCode.start()
}).catch(err => {
uni.hideLoading()
uni.$u.toast(err.msg)
})
} else {
uni.$u.toast('倒计时结束后再发送')
}
},
codeChange(text) {
this.tips = text
},
chooLocation() {
if (this.form.isDraft === 0 && (this.form.reviewStatus === 0 || this.form.reviewStatus === 1)) {
return
}
uni.chooseLocation({
success: res => {
this.form.address = res.address
this.form.longitude = this.$forceToDecimal(res.longitude, 6)
this.form.latitude = this.$forceToDecimal(res.latitude, 6)
this.form.position = this.$forceToDecimal(res.longitude, 6) + ',' + this.$forceToDecimal(res.latitude, 6)
}
})
},
resultCity(values) {
const address = {
province: values.province.name || '',
city: values.city.name || '',
district: values.district.name || '',
provinceId: values.province.id,
cityId: values.city.id,
areaId: values.district.id
}
this.form.area = `${address.province || ''} ${address.city || ''} ${address.district || ''}`
this.form.areaName = address.district || ''
this.form.provinceName = address.province || ''
this.form.cityName = address.city || ''
this.form.provinceId = address.provinceId
this.form.cityId = address.cityId
this.form.areaId = address.areaId
},
queryCity() {
getCity().then(({ data }) => {
this.district = data
})
},
showTimePicker() {
if (this.form.isDraft === 0 && (this.form.reviewStatus === 0 || this.form.reviewStatus === 1)) {
return
}
this.$refs.TimePickerPopupRef.open()
},
timeRange(e) {
this.form.serviceTime = e[0]
this.form.serviceEndTime = e[1]
this.$forceUpdate()
},
afterRead(e, imgField, type) {
const uploadFunc = type === 'video' ? uploadVideo : uploadImage
if (e.file.length > 0) {
e.file.forEach(item => {
if (!item.url) return
uploadFunc(item.url, img => {
if (!img) return
this[imgField].push({ url: img })
})
})
}
},
deleteVideo(index) {
if (this.form.isDraft === 0 && (this.form.reviewStatus === 0 || this.form.reviewStatus === 1)) {
return
}
uni.showModal({
title: '确认删除',
content: '确定删除该视频?',
success: res => {
if (res.confirm) {
this.deletePic({ index }, 'videos')
}
}
})
},
deletePic(e, imgField) {
if (this.form.isDraft === 0 && (this.form.reviewStatus === 0 || this.form.reviewStatus === 1)) {
return
}
this[imgField].splice(e.index, 1)
}
}
}
</script>
<style scoped lang="scss">
.popup-body {
width: 80vw;
height: 80vh;
padding: 30rpx;
overflow: hidden;
}
.popup-body .content {
height: 52vh;
overflow-y: auto;
margin: 30rpx 0;
}
.popup-body .agree-box {
margin: 60rpx 0;
font-size: 28rpx;
color: #666;
}
.popup-body {
.title {
line-height: 80rpx;
text-align: center;
}
}
.container {
padding: 20rpx;
background: #fff;
}
.title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.required {
color: #c52733;
}
.input {
margin-top: 20rpx;
}
.submit-btn {
width: 100%;
height: 100rpx;
text-align: center;
line-height: 100rpx;
}
.reason-box {
background: rgba(255, 160, 167, 0.39);
border-radius: 8rpx;
color: #c52733;
font-size: 30rpx;
margin-bottom: 20rpx;
}
.title {
white-space: nowrap;
}
.video-item {
width: 160rpx;
height: 160rpx;
}
.video-wrapper {
position: relative;
display: inline-block;
}
.delete-badge {
position: absolute;
top: 0rpx;
right: 0rpx;
background: #000;
color: #fff;
padding: 2rpx 8rpx;
border-radius: 0 0 0rpx 200rpx;
font-size: 22rpx;
z-index: 10;
text-align: center;
}
</style>
<style>
.input .u-textarea {
background-color: #F3F3F3 !important;
}
</style>