|
|
@@ -0,0 +1,393 @@
|
|
|
+<template>
|
|
|
+ <view class="page">
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-title">选择申请角色 <text class="required">*</text></view>
|
|
|
+ <view class="role-grid">
|
|
|
+ <view
|
|
|
+ v-for="role in roleList"
|
|
|
+ :key="role.key"
|
|
|
+ class="role-card"
|
|
|
+ :class="{ selected: selectedRoles.indexOf(role.key) > -1 }"
|
|
|
+ @click="toggleRole(role.key)"
|
|
|
+ >
|
|
|
+ <text class="role-icon">{{ role.icon }}</text>
|
|
|
+ <text class="role-name">{{ role.name }}</text>
|
|
|
+ <text v-if="selectedRoles.indexOf(role.key) > -1" class="check-mark">✓</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-title">身份证信息</view>
|
|
|
+ <input class="input" v-model="form.idCard" placeholder="请输入身份证号码" maxlength="18" />
|
|
|
+ <view class="upload-row">
|
|
|
+ <view class="upload-item" @click="chooseIdCardImage('front')">
|
|
|
+ <image v-if="form.idCardFront" :src="form.idCardFront" mode="aspectFill" class="upload-preview" />
|
|
|
+ <view v-else class="upload-placeholder">
|
|
|
+ <text class="upload-icon">+</text>
|
|
|
+ <text class="upload-label">身份证正面</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="upload-item" @click="chooseIdCardImage('back')">
|
|
|
+ <image v-if="form.idCardBack" :src="form.idCardBack" mode="aspectFill" class="upload-preview" />
|
|
|
+ <view v-else class="upload-placeholder">
|
|
|
+ <text class="upload-icon">+</text>
|
|
|
+ <text class="upload-label">身份证反面</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-title">资质证书</view>
|
|
|
+ <view class="cert-list">
|
|
|
+ <view v-for="(img, idx) in form.certificateImages" :key="getCertKey(idx)" class="cert-item">
|
|
|
+ <image :src="img" mode="aspectFill" class="cert-preview" />
|
|
|
+ <text class="cert-del" @click="removeCert(idx)">×</text>
|
|
|
+ </view>
|
|
|
+ <view class="cert-add" @click="chooseCertificate">
|
|
|
+ <text class="upload-icon">+</text>
|
|
|
+ <text class="upload-label">添加证书</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-title">联系地址 <text class="required">*</text></view>
|
|
|
+ <AddressPicker ref="addressPicker" @change="onAddressChange" />
|
|
|
+ <input class="input" v-model="form.addressDetail" placeholder="详细地址(门牌号等)" />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <button class="submit-btn" :disabled="submitting" @click="handleSubmit">
|
|
|
+ {{ submitting ? '提交中...' : '提交申请' }}
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { submitServiceRoleApply, getMyServiceRoleApply, uploadServiceRoleImage } from '../../utils/api'
|
|
|
+import AddressPicker from '../../components/address-picker.vue'
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: { AddressPicker },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ roleList: [
|
|
|
+ { key: 'planner', name: '规划师', icon: '📋' },
|
|
|
+ { key: 'nutritionist', name: '营养师', icon: '🥗' },
|
|
|
+ { key: 'butler', name: '管家', icon: '🔔' },
|
|
|
+ { key: 'vendor', name: '服务商', icon: '🏪' },
|
|
|
+ { key: 'article_admin', name: '文章管理员', icon: '📝' },
|
|
|
+ { key: 'activity_provider', name: '活动提供商', icon: '🎪' }
|
|
|
+ ],
|
|
|
+ selectedRoles: [],
|
|
|
+ form: {
|
|
|
+ idCard: '',
|
|
|
+ idCardFront: '',
|
|
|
+ idCardBack: '',
|
|
|
+ certificateImages: [],
|
|
|
+ province: '',
|
|
|
+ city: '',
|
|
|
+ district: '',
|
|
|
+ street: '',
|
|
|
+ addressDetail: ''
|
|
|
+ },
|
|
|
+ submitting: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad() {
|
|
|
+ this.checkExistingApply()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async checkExistingApply() {
|
|
|
+ try {
|
|
|
+ const res = await getMyServiceRoleApply()
|
|
|
+ if (res.code === 200 && res.data && res.data.status === 0) {
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '您已提交过申请,请等待审核',
|
|
|
+ showCancel: false,
|
|
|
+ success: () => uni.navigateBack()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ // 忽略错误
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toggleRole(key) {
|
|
|
+ const idx = this.selectedRoles.indexOf(key)
|
|
|
+ if (idx > -1) {
|
|
|
+ this.selectedRoles.splice(idx, 1)
|
|
|
+ } else {
|
|
|
+ this.selectedRoles.push(key)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ chooseIdCardImage(side) {
|
|
|
+ uni.chooseImage({
|
|
|
+ count: 1,
|
|
|
+ sizeType: ['compressed'],
|
|
|
+ sourceType: ['album', 'camera'],
|
|
|
+ success: async (res) => {
|
|
|
+ uni.showLoading({ title: '上传中...' })
|
|
|
+ try {
|
|
|
+ const uploadRes = await uploadServiceRoleImage(res.tempFilePaths[0])
|
|
|
+ uni.hideLoading()
|
|
|
+ if (uploadRes.code === 200) {
|
|
|
+ if (side === 'front') {
|
|
|
+ this.form.idCardFront = uploadRes.data.url
|
|
|
+ } else {
|
|
|
+ this.form.idCardBack = uploadRes.data.url
|
|
|
+ }
|
|
|
+ uni.showToast({ title: '上传成功', icon: 'success' })
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: uploadRes.message || '上传失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({ title: '上传失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async chooseCertificate() {
|
|
|
+ uni.chooseImage({
|
|
|
+ count: 9,
|
|
|
+ sizeType: ['compressed'],
|
|
|
+ sourceType: ['album', 'camera'],
|
|
|
+ success: async (res) => {
|
|
|
+ uni.showLoading({ title: '上传中...' })
|
|
|
+ try {
|
|
|
+ for (const filePath of res.tempFilePaths) {
|
|
|
+ const uploadRes = await uploadServiceRoleImage(filePath)
|
|
|
+ if (uploadRes.code === 200) {
|
|
|
+ this.form.certificateImages.push(uploadRes.data.url)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({ title: '上传成功', icon: 'success' })
|
|
|
+ } catch (e) {
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({ title: '上传失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ removeCert(idx) {
|
|
|
+ this.form.certificateImages.splice(idx, 1)
|
|
|
+ },
|
|
|
+ getCertKey(idx) {
|
|
|
+ return 'cert-' + idx
|
|
|
+ },
|
|
|
+ onAddressChange(e) {
|
|
|
+ this.form.province = e.province || ''
|
|
|
+ this.form.city = e.city || ''
|
|
|
+ this.form.district = e.district || ''
|
|
|
+ this.form.street = e.street || ''
|
|
|
+ },
|
|
|
+ async handleSubmit() {
|
|
|
+ if (this.selectedRoles.length === 0) {
|
|
|
+ uni.showToast({ title: '请至少选择一个角色', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.form.idCardFront || !this.form.idCardBack) {
|
|
|
+ uni.showToast({ title: '请上传身份证正反面照片', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.form.province) {
|
|
|
+ uni.showToast({ title: '请选择联系地址', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ this.submitting = true
|
|
|
+ uni.showLoading({ title: '提交中...' })
|
|
|
+ try {
|
|
|
+ const res = await submitServiceRoleApply({
|
|
|
+ roles: this.selectedRoles,
|
|
|
+ idCard: this.form.idCard,
|
|
|
+ idCardImages: [this.form.idCardFront, this.form.idCardBack],
|
|
|
+ certificateImages: this.form.certificateImages,
|
|
|
+ province: this.form.province,
|
|
|
+ city: this.form.city,
|
|
|
+ district: this.form.district,
|
|
|
+ street: this.form.street,
|
|
|
+ addressDetail: this.form.addressDetail
|
|
|
+ })
|
|
|
+ uni.hideLoading()
|
|
|
+ if (res.code === 200) {
|
|
|
+ uni.showModal({
|
|
|
+ title: '提交成功',
|
|
|
+ content: '申请已提交,请等待后台审核',
|
|
|
+ showCancel: false,
|
|
|
+ success: () => uni.navigateBack()
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.message || '提交失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({ title: '提交失败,请重试', icon: 'none' })
|
|
|
+ } finally {
|
|
|
+ this.submitting = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style>
|
|
|
+.page {
|
|
|
+ min-height: 100vh;
|
|
|
+ background: #f5f5f5;
|
|
|
+ padding: 20rpx 30rpx 100rpx;
|
|
|
+}
|
|
|
+.section {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 30rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+.section-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+.required {
|
|
|
+ color: #ff4444;
|
|
|
+}
|
|
|
+.role-grid {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 20rpx;
|
|
|
+}
|
|
|
+.role-card {
|
|
|
+ width: calc(33.33% - 14rpx);
|
|
|
+ background: #f8f8f8;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ padding: 24rpx 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ position: relative;
|
|
|
+ border: 2rpx solid transparent;
|
|
|
+}
|
|
|
+.role-card.selected {
|
|
|
+ background: #fff7ed;
|
|
|
+ border-color: #f97316;
|
|
|
+}
|
|
|
+.role-icon {
|
|
|
+ font-size: 40rpx;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+}
|
|
|
+.role-name {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+.check-mark {
|
|
|
+ position: absolute;
|
|
|
+ top: 8rpx;
|
|
|
+ right: 12rpx;
|
|
|
+ color: #f97316;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+.input {
|
|
|
+ width: 100%;
|
|
|
+ height: 72rpx;
|
|
|
+ border: 2rpx solid #eee;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ padding: 0 20rpx;
|
|
|
+ font-size: 26rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+.upload-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+}
|
|
|
+.upload-item {
|
|
|
+ flex: 1;
|
|
|
+ height: 200rpx;
|
|
|
+ border: 2rpx dashed #ddd;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.upload-placeholder {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.upload-icon {
|
|
|
+ font-size: 48rpx;
|
|
|
+ color: #ccc;
|
|
|
+}
|
|
|
+.upload-label {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999;
|
|
|
+ margin-top: 8rpx;
|
|
|
+}
|
|
|
+.upload-preview {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+.cert-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+.cert-item {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ position: relative;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.cert-preview {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+.cert-del {
|
|
|
+ position: absolute;
|
|
|
+ top: 4rpx;
|
|
|
+ right: 4rpx;
|
|
|
+ width: 32rpx;
|
|
|
+ height: 32rpx;
|
|
|
+ background: rgba(0,0,0,0.5);
|
|
|
+ color: #fff;
|
|
|
+ border-radius: 50%;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 32rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+}
|
|
|
+.cert-add {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ border: 2rpx dashed #ddd;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+.submit-btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 88rpx;
|
|
|
+ background: linear-gradient(135deg, #f97316, #fb923c);
|
|
|
+ color: #fff;
|
|
|
+ font-size: 32rpx;
|
|
|
+ border-radius: 44rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ position: fixed;
|
|
|
+ bottom: 40rpx;
|
|
|
+ left: 30rpx;
|
|
|
+ width: calc(100% - 60rpx);
|
|
|
+}
|
|
|
+.submit-btn[disabled] {
|
|
|
+ opacity: 0.6;
|
|
|
+}
|
|
|
+</style>
|