| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- <template>
- <CustomNav title="完善信息" leftType="back" />
- <view class="complete-container">
- <view class="form-section">
- <view class="avatar-section">
- <view class="avatar">
- <button
- class="avatar-wrapper"
- :class="{ disabled: isChoosing }"
- :disabled="isChoosing"
- open-type="chooseAvatar"
- @tap="startChooseAvatar"
- @chooseavatar="onChooseAvatar"
- >
- <view class="avatar-frame">
- <image v-if="form.avatar" class="avatar-img" :src="form.avatar" mode="aspectFill" />
- <text v-else class="avatar-placeholder">点击选择头像</text>
- </view>
- </button>
- </view>
- </view>
- <view class="form-item">
- <text class="label">姓名</text>
- <input class="input" type="nickname" v-model="form.nickname" placeholder="请输入姓名" />
- </view>
- <view class="form-item">
- <text class="label">手机号</text>
- <input class="input" v-model="form.phone" placeholder="请输入手机号" type="number" />
- </view>
- <view class="form-item">
- <text class="label">年龄</text>
- <input class="input" v-model="form.age" placeholder="请输入年龄" type="number" />
- </view>
- <view class="form-item">
- <text class="label">性别</text>
- <view class="radio-group">
- <label class="radio-item" @click="form.sex = 1">
- <radio :checked="form.sex === 1" color="#07C160" />
- <text>男</text>
- </label>
- <label class="radio-item" @click="form.sex = 2">
- <radio :checked="form.sex === 2" color="#07C160" />
- <text>女</text>
- </label>
- </view>
- </view>
- <view class="form-item">
- <text class="label">省/市</text>
- <view class="location-section">
- <picker mode="region" :value="region" @change="onRegionChange">
- <view class="picker">{{ region.join(' ') || '请选择省/市' }}</view>
- </picker>
- <button class="get-location-btn" @click="getCurrentLocation" :disabled="gettingLocation">
- {{ gettingLocation ? '获取中...' : '自动获取' }}
- </button>
- </view>
- </view>
- <view class="submit-section">
- <button class="submit-btn" @click="onSubmit" :disabled="submitting">{{ submitting ? '提交中...' : '提交' }}</button>
- </view>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import { ref } from 'vue'
- import CustomNav from '@/components/CustomNav.vue'
- const form = ref({
- avatar: '',
- nickname: '',
- phone: '',
- age: '',
- sex: 0,
- address: ''
- })
- const region = ref<string[]>([])
- const submitting = ref(false)
- const isChoosing = ref(false)
- const gettingLocation = ref(false)
- const onChooseAvatar = (e: any) => {
- console.log('onChooseAvatar called with event:', e)
- try {
- const detail = e?.detail
- console.log('Event detail:', detail)
- let url = ''
- if (!detail) {
- url = typeof e === 'string' ? e : ''
- console.log('No detail, using event as string:', url)
- } else if (typeof detail === 'string') {
- url = detail
- console.log('Detail is string:', url)
- } else if (detail.avatarUrl) {
- url = detail.avatarUrl
- console.log('Using detail.avatarUrl:', url)
- } else if (Array.isArray(detail) && detail[0]) {
- url = detail[0]
- console.log('Using first element of array:', url)
- }
- if (url) {
- form.value.avatar = url
- console.log('Avatar URL updated to:', form.value.avatar)
- }
- if (detail && detail.nickName && !form.value.nickname) {
- form.value.nickname = detail.nickName
- console.log('Nickname updated from detail:', form.value.nickname)
- }
- } catch (err) {
- console.error('Error in onChooseAvatar:', err)
- } finally {
- isChoosing.value = false
- console.log('isChoosing reset to false')
- }
- }
- const startChooseAvatar = () => {
- console.log('startChooseAvatar called, current isChoosing:', isChoosing.value)
- if (isChoosing.value) {
- console.log('Already choosing, ignoring')
- return
- }
- isChoosing.value = true
- console.log('isChoosing set to true')
- setTimeout(() => {
- isChoosing.value = false
- console.log('Timeout: isChoosing reset to false')
- }, 3000)
- }
- const onRegionChange = (e: any) => {
- region.value = e.detail.value
- form.value.address = region.value.join(' ')
- }
- const getCurrentLocation = async () => {
- if (gettingLocation.value) return
- gettingLocation.value = true
- try {
- // 获取经纬度
- const locationRes = await uni.getLocation({ type: 'wgs84' })
- const { latitude, longitude } = locationRes
- console.log('getLocation success:', locationRes)
- // 调用用户自己的地理编码接口
- const geocodeRes = await uni.request({
- url: `http://45.207.222.6/geo/nearest.php?latitude=${latitude}&longitude=${longitude}`,
- method: 'GET'
- })
- const data = geocodeRes.data as any
- if (data && data.province && data.city) {
- region.value = [data.province, data.city,data.district]
- form.value.address = region.value.join(' ')
- uni.showToast({ title: '位置获取成功', icon: 'success' })
- } else {
- throw new Error('Geocode failed')
- }
- } catch (err) {
- console.error('Get location error:', err)
- uni.showToast({ title: '获取位置失败,请检查定位权限和网络', icon: 'none' })
- } finally {
- gettingLocation.value = false
- }
- }
- const onSubmit = async () => {
- if (submitting.value) return
- // 检查所有必需字段
- if (!form.value.avatar) {
- uni.showToast({ title: '请选择头像', icon: 'none' })
- return
- }
- if (!form.value.nickname) {
- uni.showToast({ title: '请输入姓名', icon: 'none' })
- return
- }
- if (!form.value.phone) {
- uni.showToast({ title: '请输入手机号', icon: 'none' })
- return
- }
- if (!form.value.age) {
- uni.showToast({ title: '请输入年龄', icon: 'none' })
- return
- }
- if (!form.value.sex) {
- uni.showToast({ title: '请选择性别', icon: 'none' })
- return
- }
- if (!form.value.address) {
- uni.showToast({ title: '请选择或自动获取省/市', icon: 'none' })
- return
- }
- submitting.value = true
- try {
- const token = uni.getStorageSync('token')
- const response = await uni.request({
- url: 'http://10.20.30.111:8080/update_user_info',
- method: 'POST',
- header: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${token}`
- },
- data: form.value
- })
- console.log('Update response:', response)
- const resp = response.data as any
- if (resp && resp.code === 200) {
- uni.showToast({ title: '信息更新成功', icon: 'success' })
- setTimeout(() => {
- uni.navigateBack()
- }, 1500)
- } else {
- throw new Error('Update failed')
- }
- } catch (err) {
- console.error('Update error:', err)
- uni.showToast({ title: '更新失败', icon: 'error' })
- } finally {
- submitting.value = false
- }
- }
- </script>
- <style>
- .complete-container {
- min-height: 100vh;
- background-color: #f5f5f5;
- padding-top: calc(var(--status-bar-height) + 44px);
- padding-left: 40rpx;
- padding-right: 40rpx;
- padding-bottom: 40rpx;
- }
- .form-section {
- background-color: #fff;
- border-radius: 20rpx;
- padding: 40rpx;
- }
- .avatar-section {
- display: flex;
- justify-content: center;
- margin-bottom: 40rpx;
- }
- .avatar {
- width: 120rpx;
- height: 120rpx;
- border-radius: 60rpx;
- background-color: #eee;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .avatar-wrapper {
- width: 120rpx;
- height: 120rpx;
- border-radius: 60rpx;
- overflow: hidden;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 0;
- border: 2rpx solid #07C160;
- background: #fff;
- }
- .avatar-wrapper.disabled {
- opacity: 0.5;
- }
- .avatar-frame {
- width: 100%;
- height: 100%;
- border-radius: 60rpx;
- overflow: hidden;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .avatar-img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- .avatar-placeholder {
- color: #999;
- font-size: 24rpx;
- }
- .form-item {
- margin-bottom: 30rpx;
- }
- .label {
- display: block;
- font-size: 32rpx;
- color: #333;
- margin-bottom: 10rpx;
- }
- .input {
- width: 100%;
- height: 80rpx;
- border: 1rpx solid #ddd;
- border-radius: 8rpx;
- padding: 0 20rpx;
- font-size: 32rpx;
- }
- .phone-section {
- display: flex;
- align-items: center;
- }
- .get-phone-btn {
- flex: 1;
- height: 80rpx;
- background: linear-gradient(135deg, #07C160 0%, #00A854 100%);
- color: #fff;
- border-radius: 8rpx;
- font-size: 32rpx;
- border: none;
- }
- .get-phone-btn:disabled {
- opacity: 0.5;
- }
- .radio-group {
- display: flex;
- gap: 40rpx;
- }
- .radio-item {
- display: flex;
- align-items: center;
- font-size: 32rpx;
- color: #333;
- }
- .picker {
- width: 100%;
- height: 80rpx;
- border: 1rpx solid #ddd;
- border-radius: 8rpx;
- padding: 0 20rpx;
- display: flex;
- align-items: center;
- font-size: 32rpx;
- color: #333;
- }
- .location-section {
- display: flex;
- align-items: center;
- gap: 20rpx;
- }
- .get-location-btn {
- flex-shrink: 0;
- height: 80rpx;
- background: linear-gradient(135deg, #07C160 0%, #00A854 100%);
- color: #fff;
- border-radius: 8rpx;
- font-size: 28rpx;
- padding: 0 30rpx;
- border: none;
- }
- .get-location-btn:disabled {
- opacity: 0.5;
- }
- .submit-section {
- margin-top: 60rpx;
- }
- .submit-btn {
- width: 100%;
- background: linear-gradient(135deg, #07C160 0%, #00A854 100%);
- color: #fff;
- border-radius: 12rpx;
- font-size: 32rpx;
- line-height: 80rpx;
- border: none;
- }
- .submit-btn:disabled {
- opacity: 0.5;
- }
- </style>
|