|
- <template>
- <view class="page">
- <!-- 当前手机号 -->
- <view class="current-phone">
- <view class="label">当前绑定手机号</view>
- <view class="phone">{{ currentPhone ? maskedPhone : '未绑定' }}</view>
- </view>
-
- <!-- 绑定新手机号 -->
- <view class="step-card">
- <view class="card-title">绑定新手机号</view>
- <view class="form-group">
- <text class="form-label"><text class="required">*</text> 新手机号</text>
- <u-input v-model="form.mobile" type="number" placeholder="请输入新手机号" maxlength="11"
- border="surround" />
- </view>
- <view class="form-group">
- <text class="form-label"><text class="required">*</text> 验证码</text>
- <view class="code-row">
- <view class="code-input">
- <u-input v-model="form.code" type="number" placeholder="请输入验证码" maxlength="6"
- border="surround" />
- </view>
- <u-button :disabled="!!countdown" :text="countdownText"
- size="normal" @click="handleSendCode"
- color="#0E63E3"
- :customStyle="{ width: '240rpx', flexShrink: 0 }" />
- </view>
- </view>
- </view>
-
- <view class="btn-wrap">
- <u-button text="确认修改" :loading="submitting" @click="handleSubmit"
- color="#0E63E3" size="large" />
- </view>
-
- <!-- 温馨提示 -->
- <view class="tips">
- <view class="tips-title">温馨提示</view>
- <view class="tips-list">
- <view class="tips-item">修改手机号后,后续相关短信通知将发送到新手机号</view>
- </view>
- </view>
- </view>
- </template>
-
- <script setup>
- import { ref, computed } from 'vue'
- import { onShow } from '@dcloudio/uni-app'
- import { get, post } from '@/utils/request.js'
- import { getUserInfo, setUserInfo } from '@/utils/cache.js'
-
- const currentPhone = ref('')
- const form = ref({ mobile: '', code: '' })
- const countdown = ref(0)
- const submitting = ref(false)
- let timer = null
-
- const maskedPhone = computed(() => {
- if (!currentPhone.value || currentPhone.value.length !== 11) return currentPhone.value || ''
- return currentPhone.value.slice(0, 3) + ' **** ' + currentPhone.value.slice(-4)
- })
-
- const countdownText = computed(() => {
- return countdown.value > 0 ? `${countdown.value}s后重新获取` : '获取验证码'
- })
-
- onShow(() => {
- const info = getUserInfo()
- currentPhone.value = (info && info.patient && info.patient.phone) || ''
- })
-
- const handleSendCode = async () => {
- if (countdown.value > 0) return
- if (!form.value.mobile || !/^1[3-9]\d{9}$/.test(form.value.mobile)) {
- return uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
- }
- if (form.value.mobile === currentPhone.value) {
- return uni.showToast({ title: '新手机号不能与当前手机号相同', icon: 'none' })
- }
- try {
- await post('/api/mp/sendSmsCode', { mobile: form.value.mobile, bizType: 'change_phone' })
- uni.showToast({ title: '验证码已发送', icon: 'success' })
- countdown.value = 60
- timer = setInterval(() => {
- countdown.value--
- if (countdown.value <= 0) {
- clearInterval(timer)
- timer = null
- }
- }, 1000)
- } catch (e) {
- if (e && e.msg) uni.showToast({ title: e.msg, icon: 'none' })
- }
- }
-
- const handleSubmit = async () => {
- if (!form.value.mobile || !/^1[3-9]\d{9}$/.test(form.value.mobile)) {
- return uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
- }
- if (!form.value.code || !/^\d{6}$/.test(form.value.code)) {
- return uni.showToast({ title: '请输入6位验证码', icon: 'none' })
- }
- submitting.value = true
- try {
- await post('/api/mp/changePhone', { mobile: form.value.mobile, code: form.value.code })
- // 刷新用户信息
- const res = await get('/api/mp/userinfo')
- setUserInfo(res.data)
- uni.showToast({ title: '修改成功', icon: 'success' })
- setTimeout(() => uni.navigateBack(), 1500)
- } catch (e) {
- if (e && e.msg) uni.showToast({ title: e.msg, icon: 'none' })
- } finally {
- submitting.value = false
- }
- }
- </script>
-
- <style lang="scss" scoped>
- .page {
- min-height: 100vh;
- background: #f4f4f5;
- padding: 32rpx;
- padding-bottom: 60rpx;
- }
-
- .current-phone {
- background: #fff;
- border-radius: 8rpx;
- padding: 40rpx;
- text-align: center;
- border: 1rpx solid #ebeef5;
- margin-bottom: 32rpx;
-
- .label {
- font-size: 26rpx;
- color: #909399;
- margin-bottom: 16rpx;
- }
-
- .phone {
- font-size: 48rpx;
- font-weight: 600;
- color: #303133;
- letter-spacing: 4rpx;
- }
- }
-
- .step-card {
- background: #fff;
- border-radius: 8rpx;
- padding: 40rpx 32rpx;
- border: 1rpx solid #ebeef5;
- }
-
- .card-title {
- font-size: 32rpx;
- font-weight: 600;
- color: #303133;
- margin-bottom: 32rpx;
- }
-
- .form-group {
- margin-bottom: 32rpx;
-
- &:last-child {
- margin-bottom: 0;
- }
- }
-
- .form-label {
- font-size: 28rpx;
- color: #606266;
- margin-bottom: 16rpx;
- display: block;
- }
-
- .required {
- color: #3a85f0;
- }
-
- .code-row {
- display: flex;
- gap: 20rpx;
- align-items: stretch;
-
- .code-input {
- flex: 1;
- min-width: 0;
- }
- }
-
- .btn-wrap {
- padding-top: 48rpx;
- }
-
- .tips {
- margin-top: 32rpx;
- padding: 32rpx;
- background: #fff;
- border-radius: 8rpx;
- border: 1rpx solid #ebeef5;
-
- .tips-title {
- font-size: 28rpx;
- font-weight: 600;
- color: #303133;
- margin-bottom: 20rpx;
- }
-
- .tips-list {
- padding-left: 8rpx;
- }
-
- .tips-item {
- font-size: 26rpx;
- color: #909399;
- line-height: 1.8;
- padding-left: 20rpx;
- position: relative;
-
- &::before {
- content: '·';
- position: absolute;
- left: 0;
- }
- }
- }
- </style>
|