first commit

This commit is contained in:
2026-04-20 16:42:28 +08:00
commit c77780fa0e
365 changed files with 41599 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
<script setup>
import pcaData from '@/static/pca.json'
const props = defineProps({
ancestor: {
type: String,
required: true,
},
isLoggedIn: {
type: Boolean,
default: false,
},
userMobile: {
type: String,
default: '',
},
isSelf: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['submit', 'close'])
const show = defineModel('show')
const { ancestor, isLoggedIn, userMobile, isSelf } = toRefs(props)
const form = ref({
region: '',
mobile: '',
code: '',
})
const region = ref([])
const loadingSms = ref(false)
const isCountingDown = ref(false)
const isAgreed = ref(false)
const countdown = ref(60)
const mobileReadonly = computed(() => Boolean(isLoggedIn.value && userMobile.value))
function buildPcaColumns() {
return Object.entries(pcaData).map(([provinceName, cityMap]) => ({
label: provinceName,
value: provinceName,
children: Object.entries(cityMap).map(([cityName, districtList]) => ({
label: cityName,
value: cityName,
children: districtList.map(districtName => ({
label: districtName,
value: districtName,
})),
})),
}))
}
const provinceOptions = buildPcaColumns()
const columns = ref([provinceOptions])
function handleColumnChange({ selectedItem, resolve, finish }) {
const children = selectedItem?.children
if (children?.length) {
resolve(children)
return
}
finish()
}
function displayFormat(selectedItems) {
if (!selectedItems?.length)
return ''
return selectedItems.map(item => item.label).join('/')
}
function handleRegionConfirm({ value, selectedItems }) {
region.value = value || []
form.value.region = selectedItems?.map(item => item.label).join('/') || ''
}
function showToast(options) {
const message = typeof options === 'string' ? options : (options?.message || options?.title || '')
if (!message)
return
uni.showToast({
title: message,
icon: options?.type === 'success' ? 'success' : 'none',
})
}
const isPhoneNumberValid = computed(() => {
return /^1[3-9]\d{9}$/.test(form.value.mobile)
})
async function getSmsCode() {
if (!form.value.mobile) {
showToast({ message: '请输入手机号' })
return
}
if (!isPhoneNumberValid.value) {
showToast({ message: '手机号格式不正确' })
return
}
loadingSms.value = true
const { data, error } = await useApiFetch('auth/sendSms')
.post({ mobile: form.value.mobile, actionType: 'agentApply', captchaVerifyParam: '' })
.json()
loadingSms.value = false
if (!error.value && data.value?.code === 200) {
showToast({ message: '获取成功' })
startCountdown()
}
else {
showToast(data.value?.msg || '发送失败')
}
}
let timer = null
function startCountdown() {
isCountingDown.value = true
countdown.value = 60
timer = setInterval(() => {
if (countdown.value > 0) {
countdown.value--
}
else {
clearInterval(timer)
isCountingDown.value = false
}
}, 1000)
}
onUnmounted(() => {
if (timer) {
clearInterval(timer)
}
})
function submit() {
// 校验表单字段
if (!form.value.region) {
showToast({ message: '请选择地区' })
return
}
if (!form.value.mobile) {
showToast({ message: '请输入手机号' })
return
}
if (!isPhoneNumberValid.value) {
showToast({ message: '手机号格式不正确' })
return
}
// 如果不是自己申请,则需要验证码
if (!isSelf.value && !form.value.code) {
showToast({ message: '请输入验证码' })
return
}
if (!isAgreed.value) {
showToast({ message: '请先阅读并同意用户协议及相关条款' })
return
}
// 触发父组件提交申请
emit('submit', form.value)
}
const maskName = computed(() => {
return (name) => {
return `${name.substring(0, 3)}****${name.substring(7)}`
}
})
function closePopup() {
emit('close')
}
function toUserAgreement() {
uni.navigateTo({ url: '/pages/user-agreement' })
}
function toAgentManageAgreement() {
uni.navigateTo({ url: '/pages/agent-manage-agreement' })
}
watch(
() => [isLoggedIn.value, userMobile.value],
([loggedIn, mobile]) => {
if (loggedIn && mobile) {
form.value.mobile = mobile
}
},
{ immediate: true },
)
</script>
<template>
<wd-popup v-model="show" destroy-on-close round position="bottom">
<view class="h-12 flex items-center justify-center font-semibold"
style="background-color: var(--van-theme-primary-light); color: var(--van-theme-primary);">
成为代理
</view>
<view v-if="ancestor" class="my-2 text-center text-xs" style="color: var(--van-text-color-2);">
{{ maskName(ancestor) }}邀您成为赤眉代理方
</view>
<view class="p-4">
<wd-col-picker v-model="region" class="agent-form-field" label-width="42px" label="地区" placeholder="请选择地区"
:columns="columns" :column-change="handleColumnChange" :display-format="displayFormat" :align-right="false"
custom-value-class="agent-col-picker-value" @confirm="handleRegionConfirm" />
<wd-input v-model="form.mobile" class="agent-form-field" label-width="42px" label="手机号" name="mobile"
placeholder="请输入手机号" :align-right="false" :readonly="mobileReadonly" :disabled="mobileReadonly" />
<!-- 获取验证码按钮 -->
<wd-input v-model="form.code" class="agent-form-field" label-width="42px" label="验证码" name="code"
placeholder="请输入验证码" :align-right="false" use-suffix-slot>
<template #suffix>
<button class="ml-2 flex-shrink-0 rounded-lg px-2 py-1 text-sm font-bold transition duration-300" :class="isCountingDown || !isPhoneNumberValid
? 'cursor-not-allowed bg-gray-300 text-gray-500'
: 'text-white hover:opacity-90'" :style="isCountingDown || !isPhoneNumberValid
? ''
: 'background-color: var(--van-theme-primary);'" :disabled="isCountingDown || !isPhoneNumberValid"
@click.stop="getSmsCode">
{{
isCountingDown ? `${countdown}s重新获取` : '获取验证码'
}}
</button>
</template>
</wd-input>
<!-- 同意条款的复选框 -->
<view class="p-4">
<view class="flex items-start">
<wd-checkbox v-model="isAgreed" name="agree" icon-size="16px" class="mr-2 flex-shrink-0" />
<view class="text-xs leading-tight" style="color: var(--van-text-color-2);">
我已阅读并同意
<a class="cursor-pointer hover:underline" style="color: var(--van-theme-primary);"
@click="toUserAgreement">用户协议</a>
<a class="cursor-pointer hover:underline" style="color: var(--van-theme-primary);"
@click="toAgentManageAgreement">推广方管理制度协议</a>
<view class="mt-1 text-xs" style="color: var(--van-text-color-2);">
点击勾选即代表您同意上述法律文书的相关条款并签署上述法律文书
</view>
<view class="mt-1 text-xs" style="color: var(--van-text-color-2);">
手机号未在本平台注册账号则申请后将自动生成账号
</view>
</view>
</view>
</view>
<view class="mt-4">
<wd-button type="primary" round block @click="submit">
提交申请
</wd-button>
</view>
<view class="mt-2">
<wd-button type="default" round block @click="closePopup">
取消
</wd-button>
</view>
</view>
</wd-popup>
</template>
<style scoped>
:deep(.agent-form-field .wd-cell__title) {
flex: 0 0 42px !important;
max-width: 42px !important;
}
:deep(.agent-col-picker-value) {
display: flex !important;
justify-content: flex-start !important;
width: 100% !important;
text-align: left !important;
}
:deep(.agent-form-field .wd-cell__value) {
flex: 1;
min-width: 0;
justify-content: flex-start !important;
text-align: left !important;
}
:deep(.agent-form-field .wd-input__inner),
:deep(.agent-form-field .wd-col-picker__cell),
:deep(.agent-form-field .wd-col-picker__value),
:deep(.agent-form-field .wd-col-picker__text),
:deep(.agent-form-field .is-placeholder) {
text-align: left !important;
}
:deep(.agent-form-field .wd-col-picker__value) {
width: 100%;
}
</style>