hookehuyr

feat: 重构用户认证和个人资料功能

- 更新用户认证流程,启用未授权跳转
- 重构个人资料页面,使用真实API数据
- 修改注册和编辑资料表单,适配新API
- 移除旧订单相关API,添加用户资料API
- 优化验证码发送和手机号绑定逻辑
- 调整样式和代码结构,提高可维护性
/*
* @Date: 2023-12-22 10:29:37
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-06-06 09:31:34
* @FilePath: /meihuaApp/src/api/index.js
* @LastEditTime: 2025-07-08 20:22:08
* @FilePath: /jgdl/src/api/index.js
* @Description: 文件描述
*/
import { fn, fetch } from './fn';
const Api = {
BIND_PHONE: '/srv/?a=room_order&t=bind_phone',
SEND_SMS_CODE: '/srv/?a=room_order&t=send_sms_code',
SHOW_SESSION: '/srv/?a=room_order&t=show_session',
SAVE_CUSTOMER_INFO: '/srv/?a=room_order&t=save_customer_info',
SYS_PARAM: '/srv/?a=room_order&t=sys_param',
GET_LIST: '/srv/?a=room_data&t=get_list',
GET_ROOM: '/srv/?a=room_data&t=get_room',
ADD_ORDER: '/srv/?a=room_data&t=add_order',
MY_ORDER: '/srv/?a=room_data&t=my_order',
ORDER_CANCEL: '/srv/?a=room_data&t=order_cancel',
PAY: '/srv/?a=pay',
PAY_CHECK: '/srv/?a=pay_check',
ORDER_SUCCESS: '/srv/?a=room_data&t=order_success',
TMP_SYS_PARAM: '/srv/?a=get_item',
UPDATE_PROFILE: '/srv/?a=user&t=update_profile',
SEND_SMS_CODE: '/srv/?a=sms_code',
GET_PROFILE: '/srv/?a=user&t=get_profile',
}
/**
* @description: 绑定手机号(手机号登录)
* @param phone 手机号
* @param sms_code 验证码
* @returns
*/
export const bindPhoneAPI = (params) => fn(fetch.post(Api.BIND_PHONE, params));
/**
* @description: 发送验证码
* @param phone 手机号
* @returns
*/
export const sendSmsCodeAPI = (params) => fn(fetch.post(Api.SEND_SMS_CODE, params));
/**
* @description: 获取我的信息
* @returns
*/
export const showMyInfoAPI = (params) => fn(fetch.get(Api.SHOW_SESSION, params));
/**
* @description: 保存我的信息
* @param params
* @returns
*/
export const saveCustomerInfoAPI = (params) => fn(fetch.post(Api.SAVE_CUSTOMER_INFO, params));
/**
* @description: 获取系统参数
* @returns
*/
export const sysParamAPI = (params) => fn(fetch.get(Api.SYS_PARAM, params));
/**
* @description: 获取房间列表
* @param start_date 入住时间
* @param end_date 离店时间
* @param offset 偏移量
* @param limit 条数
* @returns
*/
export const getListAPI = (params) => fn(fetch.get(Api.GET_LIST, params));
/**
* @description: 获取房间详情
* @param start_date 入住时间
* @param end_date 离店时间
* @param room_type floor/room
* @returns
*/
export const getRoomAPI = (params) => fn(fetch.get(Api.GET_ROOM, params));
/**
* @description: 预定房间
* @param id ID
* @param num 预定房间数量
* @param plan_in 入住时间
* @param plan_out 离店时间
* @param contact_name 联系人
* @param contact_phone 联系电话
* @param order_remark 备注
* @param room_type floor/room
* @returns
*/
export const addOrderAPI = (params) => fn(fetch.post(Api.ADD_ORDER, params));
/**
* @description: 支付
* @param order_id 订单ID
......@@ -106,31 +29,26 @@ export const payAPI = (params) => fn(fetch.post(Api.PAY, params));
export const payCheckAPI = (params) => fn(fetch.post(Api.PAY_CHECK, params));
/**
* @description: 获取我的订单列表
* @param pay_type
* @param page
* @param limit
* @returns
*/
export const myOrderAPI = (params) => fn(fetch.get(Api.MY_ORDER, params));
/**
* @description: 取消订单
* @param id
* @description: 注册/编辑用户
* @param nickname 昵称
* @param avatar_url 头像
* @param gender 性别 0=女, 1=男
* @param phone 手机号
* @param sms_code 短信验证码
* @param school_id 学校id
* @returns
*/
export const orderCancelAPI = (params) => fn(fetch.post(Api.ORDER_CANCEL, params));
export const updateProfileAPI = (params) => fn(fetch.post(Api.UPDATE_PROFILE, params));
/**
* @description: 订单成功
* @param id
* @description: 发送验证码
* @param mobile 手机号
* @returns
*/
export const orderSuccessAPI = (params) => fn(fetch.post(Api.ORDER_SUCCESS, params));
export const sendSmsCodeAPI = (params) => fn(fetch.get(Api.SEND_SMS_CODE, params));
/**
* @description:
* @param id
* @returns
* @description: 获取用户资料
* @returns data[{ id,nickname,avatar_url,gender,phone,wechat_id,school_id,real_name_verified,favorite_count,order_count,follower_count }]
*/
export const tmpSysParamAPI = (params) => fn(fetch.get(Api.TMP_SYS_PARAM, params));
export const getProfileAPI = (params) => fn(fetch.get(Api.GET_PROFILE, params));
......
/*
* @Date: 2025-06-28 10:33:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-28 11:04:17
* @FilePath: /myApp/src/app.js
* @LastEditTime: 2025-07-08 17:49:20
* @FilePath: /jgdl/src/app.js
* @Description: 文件描述
*/
import { createApp } from 'vue'
......@@ -23,15 +23,15 @@ const App = createApp({
// if (path !== 'pages/index/index' && !wx.getStorageSync("sessionid")) {
if (!wx.getStorageSync("sessionid")) {
console.warn("没有权限");
// if (path === 'pages/detail/index') {
// Taro.navigateTo({
// url: `./pages/auth/index?url=${path}&id=${query.id}&start_date=${query.start_date}&end_date=${query.end_date}`,
// })
// } else {
// Taro.navigateTo({
// url: './pages/auth/index?url=' + path,
// })
// }
if (path === 'pages/detail/index') {
Taro.navigateTo({
url: `./pages/auth/index?url=${path}&id=${query.id}`,
})
} else {
Taro.navigateTo({
url: './pages/auth/index?url=' + path,
})
}
}
},
onShow(options) {
......
......@@ -56,6 +56,7 @@
import { ref, onMounted } from 'vue'
import Taro from '@tarojs/taro'
import { Home, Category, Comment, My } from '@nutui/icons-vue-taro'
import { getProfileAPI } from '@/api/index';
// 当前激活的tab
const activeTab = ref('')
......@@ -88,24 +89,23 @@ const getCurrentPage = () => {
* @param {string} url - 页面路径
*/
const navigateTo = (url) => {
// TODO: 等待正式接口
// if ((url === '/pages/profile/index' || url === '/pages/sell/index') && !is_auth.value) {
// Taro.showToast({
// title: '请先完善个人信息',
// icon: 'none',
// duration: 2000,
// success: (res) => {
// setTimeout(() => {
// Taro.navigateTo({
// url: '/pages/register/index'
// })
// }, 2000);
// }
// })
// return
// }
Taro.redirectTo({
url: url
if ((url === '/pages/profile/index' || url === '/pages/sell/index') && !is_auth.value) {
Taro.showToast({
title: '请先完善个人信息',
icon: 'none',
duration: 2000,
success: () => {
setTimeout(() => {
Taro.navigateTo({
url: '/pages/register/index'
})
}, 2000);
}
})
return
}
Taro.reLaunch({
url
})
}
......@@ -132,7 +132,7 @@ const getIconColor = (tab) => {
const userInfo = ref({
avatar: '',
nickname: '',
phone: '1',
phone: '',
gender: '',
school: '',
birthday: '',
......@@ -140,13 +140,16 @@ const userInfo = ref({
const is_auth = ref(false);
onMounted(() => {
onMounted(async () => {
getCurrentPage()
// 获取当前用户的信息
// if (userInfo.value && userInfo.value.phone) {
// is_auth.value = true
// }
is_auth.value = false
const user = await getProfileAPI();
if (user.code) {
userInfo.value = user.data
if (userInfo.value && userInfo.value.phone) {
is_auth.value = true
}
}
})
</script>
......
<!--
* @Date: 2023-12-20 14:11:11
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-03 11:43:29
* @LastEditTime: 2025-07-08 20:22:50
* @FilePath: /jgdl/src/components/payCard.vue
* @Description: 文件描述
-->
......@@ -22,7 +22,7 @@
import Taro from '@tarojs/taro'
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { getCurrentPageUrl } from "@/utils/weapp";
import { payAPI, payCheckAPI, orderSuccessAPI } from '@/api/index'
import { payAPI, payCheckAPI } from '@/api/index'
/**
* 格式化时间
......
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-05-26 10:17:04
* @FilePath: /meihuaApp/src/pages/auth/index.vue
* @LastEditTime: 2025-07-08 17:46:08
* @FilePath: /jgdl/src/pages/auth/index.vue
* @Description: 文件描述
-->
<template>
......@@ -35,8 +35,8 @@ export default {
title: '授权中',
})
request.post('/srv/?a=openid', {
code: res.code
// openid: '0002'
code: res.code,
openid: 'h-001'
// openid: 'o5NFZ5cFQtLRy3aVHaZMLkjHFusI'
// openid: 'o5NFZ5TpgG4FwYursGCLjcUJH2ak'
// openid: 'o5NFZ5cqroPYwawCp8FEOxewtgnw'
......@@ -62,7 +62,7 @@ export default {
const params = getCurrentPageParam();
if (getCurrentPageParam().url === 'pages/detail/index') { // 详情页的分享跳转处理
Taro.reLaunch({
url: `../../${params.url}?id=${params.id}&start_date=${params.start_date}&end_date=${params.end_date}`
url: `../../${params.url}?id=${params.id}`
})
} else { // 其他页面分享跳首页
Taro.reLaunch({
......@@ -81,7 +81,7 @@ export default {
Taro.hideLoading();
});
} else {
console.log('登录失败!' + res.errMsg)
console.error('登录失败!' + res.errMsg)
}
}
})
......
......@@ -77,7 +77,7 @@
.nut-input {
text-align: right;
.nut-input__inner {
color: #666;
font-size: 32rpx;
......@@ -94,7 +94,7 @@
.phone-value {
color: #666;
font-size: 32rpx;
// font-size: 32rpx;
margin-right: 16rpx;
}
......@@ -134,7 +134,7 @@
.school-value {
color: #666;
font-size: 32rpx;
// font-size: 32rpx;
margin-right: 16rpx;
}
......@@ -161,7 +161,7 @@
.nut-radio__icon {
color: #f97316;
}
.nut-radio__label {
color: #333;
}
......
......@@ -4,10 +4,10 @@
<view class="avatar-section">
<view class="avatar-container">
<image
:src="formData.avatar || defaultAvatar"
:src="formData.avatar_url || defaultAvatar"
class="avatar-image"
mode="aspectFill"
@tap="previewAvatar(formData.avatar || defaultAvatar)"
@tap="previewAvatar(formData.avatar_url || defaultAvatar)"
/>
</view>
<view class="change-avatar-btn" @click="changeAvatar">
......@@ -39,19 +39,19 @@
<nut-config-provider :theme-vars="themeVars">
<nut-form-item label="性别" prop="gender" body-align="right">
<nut-radio-group v-model="formData.gender" direction="horizontal">
<nut-radio label="男">男</nut-radio>
<nut-radio label="女">女</nut-radio>
<nut-radio :label="0">男</nut-radio>
<nut-radio :label="1">女</nut-radio>
</nut-radio-group>
</nut-form-item>
</nut-config-provider>
<!-- 生日 -->
<nut-form-item label="生日" prop="birthday">
<!-- <nut-form-item label="生日" prop="birthday">
<view class="birthday-item" @click="showDatePicker">
<text class="birthday-value">{{ formData.birthday || '未设置' }}</text>
<Right class="arrow-icon" />
</view>
</nut-form-item>
</nut-form-item> -->
<!-- 所在学校 -->
<nut-form-item label="所在学校" prop="school">
......@@ -64,7 +64,7 @@
<!-- 微信号 -->
<nut-form-item label="微信号" prop="wechat">
<nut-input
v-model="formData.wechat"
v-model="formData.wechat_id"
placeholder="请输入微信号"
input-align="right"
>
......@@ -100,7 +100,7 @@
/>
<view class="code-row">
<nut-input
v-model="verifyCode"
v-model="sms_code"
placeholder="验证码"
class="code-input"
maxlength="6"
......@@ -138,14 +138,14 @@
</nut-popup>
<!-- 日期选择器 -->
<nut-popup v-model:visible="datePickerVisible" position="bottom">
<!-- <nut-popup v-model:visible="datePickerVisible" position="bottom">
<nut-date-picker
v-model="dateValue"
title="选择生日"
@confirm="onDateConfirm"
@cancel="datePickerVisible = false"
/>
</nut-popup>
</nut-popup> -->
<!-- 学校选择器 -->
<nut-popup v-model:visible="schoolPickerVisible" position="bottom">
......@@ -162,20 +162,21 @@
<nut-image-preview v-model:show="previewVisible" :images="previewImages" :init-no="previewIndex" @close="closePreview" />
<!-- 成功提示 -->
<nut-toast
<!-- <nut-toast
v-model:visible="toastVisible"
msg="保存成功"
type="success"
/>
/> -->
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import Taro from '@tarojs/taro'
import Taro, { useDidShow } from '@tarojs/taro'
import './index.less'
import { Right } from '@nutui/icons-vue-taro'
import BASE_URL from '@/utils/config';
import { updateProfileAPI, sendSmsCodeAPI, getProfileAPI } from '@/api/index';
// 主题配置
const themeVars = {
......@@ -187,20 +188,22 @@ const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
// 表单数据
const formData = reactive({
avatar: '',
nickname: '张先生',
phone: '139 2233 8888',
gender: '男',
birthday: '',
school: '上海理工大学',
wechat: ''
avatar_url: '',
nickname: '',
phone: '',
sms_code: '',
gender: '',
// birthday: '',
school: '',
school_id: '',
wechat_id: ''
})
// 弹框控制
const phoneDialogVisible = ref(false)
const datePickerVisible = ref(false)
// const datePickerVisible = ref(false)
const schoolPickerVisible = ref(false)
const toastVisible = ref(false)
// const toastVisible = ref(false)
// 图片预览相关
const previewVisible = ref(false)
......@@ -213,11 +216,11 @@ const closePreview = () => {
// 手机号相关
const newPhone = ref('')
const verifyCode = ref('')
const sms_code = ref('')
const codeCountdown = ref(0)
// 日期选择
const dateValue = ref(new Date())
// const dateValue = ref(new Date())
// 学校选择
const schoolValue = ref([])
......@@ -282,7 +285,7 @@ const uploadImage = (filePath) => {
Taro.hideLoading({
success: () => {
if (res.statusCode === 200) {
formData.avatar = upload_data.data.src;
formData.avatar_url = upload_data.data.src;
Taro.showToast({
title: '上传成功',
icon: 'success'
......@@ -332,7 +335,7 @@ const previewAvatar = (imageUrl) => {
const showPhoneDialog = () => {
phoneDialogVisible.value = true
newPhone.value = ''
verifyCode.value = ''
sms_code.value = ''
}
/**
......@@ -350,7 +353,7 @@ const onPhoneInput = ({ detail }) => {
*/
const onCodeInput = ({ detail }) => {
// 只保留数字
verifyCode.value = detail.value.replace(/\D/g, '')
sms_code.value = detail.value.replace(/\D/g, '')
}
/**
......@@ -364,7 +367,7 @@ const validatePhone = (phone) => {
}
// 发送验证码
const sendCode = () => {
const sendCode = async () => {
if (!newPhone.value) {
Taro.showToast({
title: '请输入手机号',
......@@ -381,23 +384,39 @@ const sendCode = () => {
return
}
codeCountdown.value = 60
const timer = setInterval(() => {
codeCountdown.value--
if (codeCountdown.value <= 0) {
clearInterval(timer)
}
}, 1000)
Taro.showToast({
title: '验证码已发送',
icon: 'success'
})
// 如果正在倒计时,不允许重复发送
if (codeCountdown.value > 0) {
return
}
try {
// 发送验证码API请求
await sendSmsCodeAPI({ mobile: newPhone.value })
Taro.showToast({
title: '验证码已发送',
icon: 'success'
})
// 开始倒计时
codeCountdown.value = 60
const timer = setInterval(() => {
codeCountdown.value--
if (codeCountdown.value <= 0) {
clearInterval(timer)
}
}, 1000)
} catch (error) {
Taro.showToast({
title: error.message || '发送验证码失败,请重试',
icon: 'error'
})
}
}
// 确认手机号更改
const confirmPhoneChange = () => {
if (!newPhone.value || !verifyCode.value) {
const confirmPhoneChange = async () => {
if (!newPhone.value || !sms_code.value) {
Taro.showToast({
title: '请填写完整信息',
icon: 'none'
......@@ -413,7 +432,7 @@ const confirmPhoneChange = () => {
return
}
if (verifyCode.value.length !== 6) {
if (sms_code.value.length !== 6) {
Taro.showToast({
title: '请输入6位验证码',
icon: 'none'
......@@ -421,26 +440,37 @@ const confirmPhoneChange = () => {
return
}
formData.phone = newPhone.value
phoneDialogVisible.value = false
newPhone.value = ''
verifyCode.value = ''
Taro.showToast({
title: '手机号绑定成功',
icon: 'success'
})
try {
// 验证验证码API请求
await updateProfileAPI({ mobile: newPhone.value, sms_code: sms_code.value })
Taro.showToast({
title: '手机号绑定成功',
icon: 'success'
})
// 绑定手机号
formData.phone = newPhone.value
phoneDialogVisible.value = false
newPhone.value = ''
sms_code.value = ''
} catch (error) {
Taro.showToast({
title: error.message || '手机号绑定失败,请重试',
icon: 'error'
})
}
}
// 显示日期选择器
const showDatePicker = () => {
datePickerVisible.value = true
}
// const showDatePicker = () => {
// datePickerVisible.value = true
// }
// 确认日期选择
const onDateConfirm = ({ selectedValue }) => {
formData.birthday = `${selectedValue[0]}-${String(selectedValue[1]).padStart(2, '0')}-${String(selectedValue[2]).padStart(2, '0')}`
datePickerVisible.value = false
}
// const onDateConfirm = ({ selectedValue }) => {
// formData.birthday = `${selectedValue[0]}-${String(selectedValue[1]).padStart(2, '0')}-${String(selectedValue[2]).padStart(2, '0')}`
// datePickerVisible.value = false
// }
// 显示学校选择器
const showSchoolPicker = () => {
......@@ -454,18 +484,44 @@ const onSchoolConfirm = ({ selectedOptions }) => {
}
// 保存
const handleSave = () => {
const handleSave = async () => {
// 这里可以添加表单验证
toastVisible.value = true
// toastVisible.value = true
setTimeout(() => {
toastVisible.value = false
goBack()
}, 1500)
try {
// 保存用户信息API请求
await updateProfileAPI(formData)
Taro.showToast({
title: '保存成功',
icon: 'success',
complete: () => {
goBack()
}
})
// setTimeout(() => {
// toastVisible.value = false
// }, 1500)
// goBack()
} catch (error) {
Taro.showToast({
title: error.message || '保存失败,请重试',
icon: 'error'
})
}
}
// 初始化
onMounted(() => {
useDidShow(async () => {
// 获取用户信息
const user = await getProfileAPI()
if (user.code) {
formData.avatar_url = user.data.avatar_url
formData.nickname = user.data.nickname
formData.phone = user.data.phone
formData.gender = user.data.gender
formData.school = user.data.school
formData.school_id = user.data.school_id
formData.wechat_id = user.data.wechat_id
}
})
</script>
......
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-08 14:15:15
* @LastEditTime: 2025-07-08 15:51:46
* @FilePath: /jgdl/src/pages/productDetail/index.vue
* @Description: 商品详情页
-->
......
......@@ -2,8 +2,8 @@
<view class="profile-page">
<!-- User Profile Section -->
<view class="user-profile-section">
<image :src="userInfo.avatar || defaultAvatar" class="user-avatar" mode="aspectFill" />
<text class="user-name">{{ userInfo.name }}</text>
<image :src="userInfo.avatar_url || defaultAvatar" class="user-avatar" mode="aspectFill" />
<text class="user-name">{{ userInfo.nickname }}</text>
<text class="user-phone">{{ userInfo.phone }}</text>
<nut-button class="edit-profile-btn" @click="onEditProfile">
编辑资料
......@@ -12,15 +12,15 @@
<!-- Stats Row -->
<view class="stats-row">
<view class="stat-item">
<text class="stat-number">{{ userStats.following }}</text>
<text class="stat-number">{{ userInfo.follower_count }}</text>
<text class="stat-label">关注</text>
</view>
<view class="stat-item" @click="onOrderManagement">
<text class="stat-number">{{ userStats.orders }}</text>
<text class="stat-number">{{ userInfo.order_count }}</text>
<text class="stat-label">订单</text>
</view>
<view class="stat-item">
<text class="stat-number">{{ userStats.followers }}</text>
<text class="stat-number">{{ userInfo.favorite_count }}</text>
<text class="stat-label">被关注</text>
</view>
</view>
......@@ -78,10 +78,9 @@
</template>
<script setup>
import { ref } from 'vue'
import {
Heart, Clock, Notice, Cart, Message, Tips, Setting, Right, StarN
} from '@nutui/icons-vue-taro'
import { ref, onMounted } from 'vue'
import { getProfileAPI } from '@/api/index'
import { Heart, Clock, Notice, Cart, Message, Tips, Right, StarN } from '@nutui/icons-vue-taro'
import Taro from '@tarojs/taro'
import TabBar from '@/components/TabBar.vue'
......@@ -90,16 +89,19 @@ const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
// 用户信息
const userInfo = ref({
name: '张同学',
nickname: '张同学',
phone: '138****8888',
avatar: ''
avatar_url: '',
follower_count: 0,
order_count: 0,
favorite_count: 0
})
// 用户统计
const userStats = ref({
following: 12,
orders: 8,
followers: 24
onMounted(async () => {
const user = await getProfileAPI()
if (user.code) {
userInfo.value = user.data
}
})
/**
......
......@@ -4,10 +4,10 @@
<view class="avatar-section">
<view class="avatar-container">
<image
:src="formData.avatar || defaultAvatar"
:src="formData.avatar_url || defaultAvatar"
class="avatar-image"
mode="aspectFill"
@tap="previewAvatar(formData.avatar || defaultAvatar)"
@tap="previewAvatar(formData.avatar_url || defaultAvatar)"
/>
</view>
<view class="change-avatar-btn" @click="changeAvatar">
......@@ -52,9 +52,9 @@
</nut-form-item>
<!-- 验证码 -->
<nut-form-item label="验证码" prop="verifyCode" required :rules="[{ required: true, message: '请输入验证码' }]">
<nut-form-item label="验证码" prop="sms_code" required :rules="[{ required: true, message: '请输入验证码' }]">
<nut-input
v-model="formData.verifyCode"
v-model="formData.sms_code"
placeholder="请输入验证码"
type="number"
maxlength="6"
......@@ -67,19 +67,19 @@
<nut-config-provider :theme-vars="themeVars">
<nut-form-item label="性别" prop="gender" body-align="right" required :rules="[{ required: true, message: '请选择性别' }]">
<nut-radio-group v-model="formData.gender" direction="horizontal">
<nut-radio label="男">男</nut-radio>
<nut-radio label="女">女</nut-radio>
<nut-radio :label="0">男</nut-radio>
<nut-radio :label="1">女</nut-radio>
</nut-radio-group>
</nut-form-item>
</nut-config-provider>
<!-- 生日 -->
<nut-form-item label="生日" prop="birthday" label-position="top">
<!-- <nut-form-item label="生日" prop="birthday" label-position="top">
<view class="birthday-item" @click="showDatePicker">
<text class="birthday-value">{{ formData.birthday || '请选择生日' }}</text>
<Right class="arrow-icon" />
</view>
</nut-form-item>
</nut-form-item> -->
<!-- 所在学校 -->
<nut-form-item label="所在学校" prop="school" required :rules="[{ required: true, message: '请选择学校' }]" label-position="top">
......@@ -88,6 +88,16 @@
<Right class="arrow-icon" />
</view>
</nut-form-item>
<!-- 微信号 -->
<nut-form-item label="微信号" prop="wechat_id" required :rules="[{ required: true, message: '请输入微信号' }]">
<nut-input
v-model="formData.wechat_id"
placeholder="请输入微信号"
input-align="right"
clearable
/>
</nut-form-item>
</view>
</nut-form>
......@@ -143,6 +153,7 @@ import Taro from '@tarojs/taro'
import { Right } from '@nutui/icons-vue-taro'
import './index.less'
import BASE_URL from '@/utils/config';
import { updateProfileAPI, sendSmsCodeAPI } from '@/api/index';
// 主题配置
const themeVars = {
......@@ -154,13 +165,15 @@ const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
// 表单数据
const formData = reactive({
avatar: '',
avatar_url: '',
nickname: '',
phone: '',
verifyCode: '',
sms_code: '',
gender: '',
birthday: '',
school: ''
// birthday: '',
school: '',
school_id: '',
wechat_id: ''
})
// 弹框控制
......@@ -260,7 +273,7 @@ const uploadImage = (filePath) => {
Taro.hideLoading({
success: () => {
if (res.statusCode === 200) {
formData.avatar = upload_data.data.src;
formData.avatar_url = upload_data.data.src;
Taro.showToast({
title: '上传成功',
icon: 'success'
......@@ -308,30 +321,51 @@ const previewAvatar = (imageUrl) => {
/**
* 发送验证码
*/
const sendCode = () => {
const sendCode = async () => {
if (!isPhoneValid.value) {
showToast('请输入正确的手机号', 'error')
Taro.showToast({
title: '请输入正确的手机号',
icon: 'error'
})
return
}
// 模拟发送验证码
codeCountdown.value = 60
const timer = setInterval(() => {
codeCountdown.value--
if (codeCountdown.value <= 0) {
clearInterval(timer)
}
}, 1000)
// 如果正在倒计时,不允许重复发送
if (codeCountdown.value > 0) {
return
}
try {
// 发送验证码API请求
await sendSmsCodeAPI({ mobile: formData.phone })
Taro.showToast({
title: '验证码已发送',
icon: 'success'
})
// 开始倒计时
codeCountdown.value = 60
const timer = setInterval(() => {
codeCountdown.value--
if (codeCountdown.value <= 0) {
clearInterval(timer)
}
}, 1000)
showToast('验证码已发送', 'success')
} catch (error) {
Taro.showToast({
title: error.message || '发送验证码失败,请重试',
icon: 'error'
})
}
}
/**
* 显示日期选择器
*/
const showDatePicker = () => {
datePickerVisible.value = true
}
// const showDatePicker = () => {
// datePickerVisible.value = true
// }
/**
* 确认日期选择
......@@ -353,6 +387,7 @@ const showSchoolPicker = () => {
*/
const onSchoolConfirm = ({ selectedOptions }) => {
formData.school = selectedOptions[0].text
formData.school_id = selectedOptions[0].value
schoolPickerVisible.value = false
}
......@@ -379,7 +414,7 @@ const validateForm = () => {
return false
}
if (!formData.verifyCode.trim()) {
if (!formData.sms_code.trim()) {
showToast('请输入验证码', 'error')
return false
}
......@@ -389,11 +424,16 @@ const validateForm = () => {
return false
}
if (!formData.school) {
if (!formData.school_id) {
showToast('请选择学校', 'error')
return false
}
if (!formData.wechat_id) {
showToast('请输入微信号', 'error')
return false
}
return true
}
......@@ -408,11 +448,13 @@ const handleRegister = async () => {
isRegistering.value = true
try {
// 模拟注册API调用
await new Promise(resolve => setTimeout(resolve, 2000))
// TODO: 这里应该调用实际的注册API
// const result = await registerAPI(formData)
const result = await updateProfileAPI(formData)
if (result.code !== 0) {
showToast(result.msg || '注册失败', 'error')
return
}
showToast('注册成功', 'success')
......
/*
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-01-15 17:07:14
* @FilePath: /meihuaApp/src/utils/config.js
* @LastEditTime: 2025-07-08 17:44:47
* @FilePath: /jgdl/src/utils/config.js
* @Description: 文件描述
*/
// TAG:服务器环境配置
// const BASE_URL = "https://oa-dev.onwall.cn"; // 测试服务器
const BASE_URL = "https://oa.onwall.cn"; // 正式服务器
const BASE_URL = "https://oa-dev.onwall.cn"; // 测试服务器
// const BASE_URL = "https://oa.onwall.cn"; // 正式服务器
export default BASE_URL
......
/*
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-01 11:17:49
* @FilePath: /myApp/src/utils/request.js
* @LastEditTime: 2025-07-08 17:42:15
* @FilePath: /jgdl/src/utils/request.js
* @Description: 简单axios封装,后续按实际处理
*/
// import axios from 'axios'
......@@ -60,8 +60,7 @@ const service = axios.create({
})
service.defaults.params = {
f: 'room',
client_id: '772428',
f: 'jiangedianlv',
};
// request interceptor
......