初始化登录功能,注册功能
This commit is contained in:
1 parent
63726d8200
commit
76ba02d29b
16 files changed
+2090
-1025
No files matched your search
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
# .env.development
|
# .env.development
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VITE_APP_RUN_ENV=development
|
VITE_APP_RUN_ENV=development
|
||||||
VITE_APP_BASE_URL="http://127.0.0.1:8000"
|
VITE_APP_BASE_URL="https://takway-ai.top/test"
|
||||||
+20
-2
@@ -18,7 +18,13 @@ export const editMobileInit = (params) => {
|
|||||||
* @desc 发送验证码
|
* @desc 发送验证码
|
||||||
*/
|
*/
|
||||||
export const sendCode = (params) => {
|
export const sendCode = (params) => {
|
||||||
return get('/sale/login/send-mb-verify-code', params);
|
return post('/app-api/member/auth/send-sms-code', params);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc 发送邮箱验证码
|
||||||
|
*/
|
||||||
|
export const sendCodeToEmail = (params) => {
|
||||||
|
return get('/app-api/member/auth/code', params);
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @desc 发送验证码初始化
|
* @desc 发送验证码初始化
|
||||||
@@ -26,11 +32,23 @@ export const sendCode = (params) => {
|
|||||||
export const loginLRInit = (params) => {
|
export const loginLRInit = (params) => {
|
||||||
return get('/sale/login/send-mb-verify-code-init', params);
|
return get('/sale/login/send-mb-verify-code-init', params);
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @desc 邮箱注册
|
||||||
|
*/
|
||||||
|
export const registerByEmail = (params) => {
|
||||||
|
return post('/app-api/member/auth/email-register', params);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc 邮箱登录
|
||||||
|
*/
|
||||||
|
export const loginByEmail = (params) => {
|
||||||
|
return post('/app-api/member/auth/email-login', params);
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* @desc 登录
|
* @desc 登录
|
||||||
*/
|
*/
|
||||||
export const login = (params) => {
|
export const login = (params) => {
|
||||||
return get('/sale/login/login', params);
|
return post('/app-api/member/auth/weixin-mini-app-login', params);
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @desc 注册
|
* @desc 注册
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
<template>
|
|
||||||
<up-popup :show="showPicker" :closeable="true" round="10" mode="bottom" @close="onClose">
|
|
||||||
<view class="login">
|
|
||||||
<view class="logo mb-[10rpx] mt-[50rpx] flex justify-center text-center">
|
|
||||||
<image class="h-[140rpx] rounded-full" src="/static/common/logo.png" mode="heightFix"></image>
|
|
||||||
</view>
|
|
||||||
<Login @close="onClose"></Login>
|
|
||||||
</view>
|
|
||||||
</up-popup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, watch } from 'vue';
|
|
||||||
import Login from './login.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
show: {
|
|
||||||
// 展示狀態
|
|
||||||
type: Boolean,
|
|
||||||
default: () => {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['close']);
|
|
||||||
const onClose = () => {
|
|
||||||
emit('close');
|
|
||||||
};
|
|
||||||
|
|
||||||
const showPicker = ref(false);
|
|
||||||
watch(
|
|
||||||
() => props.show,
|
|
||||||
(newVal) => {
|
|
||||||
showPicker.value = newVal;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
deep: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
||||||
+797
-818
File diff suppressed because it is too large.
Load diff
+3
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name" : "sweekar-app",
|
"name" : "sweekar-app",
|
||||||
"appid" : "__UNI__AB3EDCE",
|
"appid" : "__UNI__308E2A1",
|
||||||
"description" : "",
|
"description" : "",
|
||||||
"versionName" : "1.1.3",
|
"versionName" : "1.1.3",
|
||||||
"versionCode" : 113,
|
"versionCode" : 113,
|
||||||
@@ -45,7 +45,8 @@
|
|||||||
},
|
},
|
||||||
/* ios打包配置 */
|
/* ios打包配置 */
|
||||||
"ios" : {
|
"ios" : {
|
||||||
"idfa" : false
|
"idfa" : false,
|
||||||
|
"dSYMs" : false
|
||||||
},
|
},
|
||||||
/* SDK配置 */
|
/* SDK配置 */
|
||||||
"sdkConfigs" : {}
|
"sdkConfigs" : {}
|
||||||
|
|||||||
@@ -47,6 +47,12 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/login/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "登录"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|||||||
+15
-2
@@ -3,7 +3,7 @@ import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
|
|||||||
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||||
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
||||||
import LoginPopup from '@/components/login-popup.vue';
|
import LoginPopup from '@/components/login.vue';
|
||||||
import { getProducts } from './api.js';
|
import { getProducts } from './api.js';
|
||||||
import { useUserStore } from '@/store/user.js';
|
import { useUserStore } from '@/store/user.js';
|
||||||
|
|
||||||
@@ -134,7 +134,8 @@ const handleBook = (productId) => {
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 交流栏 -->
|
<!-- 交流栏 -->
|
||||||
<view class="absolute top-[-60px] right-[-30px] w-[120px] flex flex-col justify-center items-center px-[10px] border border-solid border-theme bg-[#fff] rounded-t-lg rounded-br-lg h-[70px] border-[2px] shadow-[4px_4px_1px_0_rgba(0,0,0,1)]" >
|
<view class="absolute top-[-60px] right-[-30px] w-[120px] flex flex-col justify-center items-center px-[10px] border border-solid border-theme bg-[#fff] rounded-t-lg rounded-br-lg h-[70px] border-[2px] shadow-[4px_4px_1px_0_rgba(0,0,0,1)] animate-bounce"
|
||||||
|
style="animation: bounce 1.5s infinite;">
|
||||||
<view class="text-[12px]">
|
<view class="text-[12px]">
|
||||||
Master,I missed you! Let's play together!
|
Master,I missed you! Let's play together!
|
||||||
</view>
|
</view>
|
||||||
@@ -206,5 +207,17 @@ const handleBook = (productId) => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
/* 定义弹跳动画 */
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-bounce {
|
||||||
|
animation: bounce 1.5s infinite;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { get, post, put, dele } from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc 发送邮箱验证码
|
||||||
|
*/
|
||||||
|
export const sendCodeToEmail = (params) => {
|
||||||
|
return get('/app-api/member/auth/code', params);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc 发送验证码初始化
|
||||||
|
*/
|
||||||
|
export const loginLRInit = (params) => {
|
||||||
|
return get('/sale/login/send-mb-verify-code-init', params);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc 邮箱注册
|
||||||
|
*/
|
||||||
|
export const registerByEmail = (params) => {
|
||||||
|
return post('/app-api/member/auth/email-register', params);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc 邮箱登录
|
||||||
|
*/
|
||||||
|
export const loginByEmail = (params) => {
|
||||||
|
return post('/app-api/member/auth/email-login', params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc 登录
|
||||||
|
*/
|
||||||
|
export const login = (params) => {
|
||||||
|
return post('/app-api/member/auth/weixin-mini-app-login', params);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc 注册
|
||||||
|
*/
|
||||||
|
export const register = (params) => {
|
||||||
|
return get('/front/user/login/register', params);
|
||||||
|
};
|
||||||
@@ -0,0 +1,839 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { login, register, loginByEmail, sendCodeToEmail, registerByEmail } from './api';
|
||||||
|
import { useUserStore } from '@/store/user.js';
|
||||||
|
import { showLoadingToast, closeToast } from '@/common/common.js';
|
||||||
|
|
||||||
|
const email = ref(''); // 邮箱
|
||||||
|
const password = ref(''); // 密码
|
||||||
|
const checked = ref(true); // 同意条款,默认勾选
|
||||||
|
const isLoading = ref(false); // 加载状态
|
||||||
|
|
||||||
|
// 注册相关变量
|
||||||
|
const showRegister = ref(false); // 显示注册弹窗
|
||||||
|
const registerEmail = ref(''); // 注册邮箱
|
||||||
|
const registerPassword = ref(''); // 注册密码
|
||||||
|
const confirmPassword = ref(''); // 确认密码
|
||||||
|
const verificationCode = ref(''); // 验证码
|
||||||
|
const codeBtnText = ref('获取验证码');
|
||||||
|
const codeBtnDisabled = ref(false);
|
||||||
|
let countdownTimer = null;
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
// 邮箱格式验证
|
||||||
|
const validateEmail = (email) => {
|
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||||
|
return emailRegex.test(email);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 登录函数
|
||||||
|
const onLogin = async() => {
|
||||||
|
if (!checked.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请先同意用户协议',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!email.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入邮箱',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!password.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入密码',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 邮箱格式验证
|
||||||
|
if (!validateEmail(email.value)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入正确的邮箱',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 密码长度验证
|
||||||
|
if (password.value.length < 6) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '密码至少6位',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防止重复提交
|
||||||
|
if (isLoading.value) return;
|
||||||
|
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '登录中...',
|
||||||
|
mask: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
email: email.value,
|
||||||
|
password: password.value
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await loginByEmail(params);
|
||||||
|
|
||||||
|
if (res && res.code === 0) { // 修改为code===0判断
|
||||||
|
// 存储用户信息到全局状态
|
||||||
|
userStore.setUserInfo(res.data);
|
||||||
|
userStore.setToken(res.data.accessToken);
|
||||||
|
userStore.setLoginStatus(true);
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录成功',
|
||||||
|
icon: 'success',
|
||||||
|
});
|
||||||
|
|
||||||
|
uni.switchTab({
|
||||||
|
url:'/pages/index/index'
|
||||||
|
})
|
||||||
|
// 延迟一点时间再关闭弹窗,让用户看到成功提示
|
||||||
|
setTimeout(() => {
|
||||||
|
// 触发父组件的登录成功事件
|
||||||
|
emit('success');
|
||||||
|
emit('close');
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.msg || '登录失败',
|
||||||
|
icon: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('登录错误:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || '登录失败,请稍后重试',
|
||||||
|
icon: 'error',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading();
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 同意条款切换
|
||||||
|
const onChange = (e) => {
|
||||||
|
checked.value = e.detail.value; // 更新checked值
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示用户协议
|
||||||
|
const showAgreement = () => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '用户协议',
|
||||||
|
content: '欢迎使用我们的服务!\n\n本协议规定了您使用我们服务的条款和条件,请仔细阅读。\n\n1. 服务使用条款\n2. 隐私政策\n3. 账户安全\n4. 免责声明\n\n继续使用即表示您同意遵守这些条款。',
|
||||||
|
showCancel: true,
|
||||||
|
confirmText: '同意',
|
||||||
|
cancelText: '取消',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
checked.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 忘记密码
|
||||||
|
const forgetPassword = () => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/auth/forget-password'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示注册弹窗
|
||||||
|
const showRegisterPopup = () => {
|
||||||
|
showRegister.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 隐藏注册弹窗
|
||||||
|
const hideRegisterPopup = () => {
|
||||||
|
showRegister.value = false;
|
||||||
|
// 清空注册表单
|
||||||
|
registerEmail.value = '';
|
||||||
|
registerPassword.value = '';
|
||||||
|
confirmPassword.value = '';
|
||||||
|
verificationCode.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
const getVerificationCode = async () => {
|
||||||
|
if (!registerEmail.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入邮箱',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEmail(registerEmail.value)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入正确的邮箱',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
try {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '发送中...',
|
||||||
|
mask: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
email: registerEmail.value,
|
||||||
|
register: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await sendCodeToEmail(params);
|
||||||
|
|
||||||
|
if (res && res.code === 0) {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: '验证码已发送',
|
||||||
|
icon: 'success',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
let timeLeft = 60;
|
||||||
|
codeBtnDisabled.value = true;
|
||||||
|
codeBtnText.value = `${timeLeft}秒`;
|
||||||
|
|
||||||
|
countdownTimer = setInterval(() => {
|
||||||
|
timeLeft--;
|
||||||
|
codeBtnText.value = `${timeLeft}秒`;
|
||||||
|
|
||||||
|
if (timeLeft <= 0) {
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
codeBtnText.value = '重新获取';
|
||||||
|
codeBtnDisabled.value = false;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: res.msg || '发送失败',
|
||||||
|
icon: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || '发送失败,请重试',
|
||||||
|
icon: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 注册提交
|
||||||
|
const onRegister = async () => {
|
||||||
|
if (!registerEmail.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入邮箱',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEmail(registerEmail.value)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入正确的邮箱',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verificationCode.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入验证码',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!registerPassword.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入密码',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registerPassword.value !== confirmPassword.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '两次输入密码不一致',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registerPassword.value.length < 6) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '密码至少6位',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '注册中...',
|
||||||
|
mask: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 调用注册API
|
||||||
|
const registerParams = {
|
||||||
|
email: registerEmail.value,
|
||||||
|
verificationCode: verificationCode.value,
|
||||||
|
password: registerPassword.value,
|
||||||
|
confirmPassword: confirmPassword.value
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await registerByEmail(registerParams);
|
||||||
|
|
||||||
|
if (res && res.code === 0) {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: '注册成功',
|
||||||
|
icon: 'success',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 注册成功后直接调用登录接口
|
||||||
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
const loginRes = await loginByEmail({
|
||||||
|
email: registerEmail.value,
|
||||||
|
password: registerPassword.value
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loginRes && loginRes.code === 0) {
|
||||||
|
// 存储用户信息到全局状态
|
||||||
|
userStore.setUserInfo(loginRes.data);
|
||||||
|
userStore.setToken(loginRes.data.accessToken);
|
||||||
|
userStore.setLoginStatus(true);
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录成功',
|
||||||
|
icon: 'success',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 关闭注册弹窗和登录弹窗
|
||||||
|
setTimeout(() => {
|
||||||
|
emit('success');
|
||||||
|
emit('close');
|
||||||
|
hideRegisterPopup();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: loginRes.msg || '自动登录失败',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('自动登录失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '自动登录失败,请手动登录',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: res.msg || '注册失败',
|
||||||
|
icon: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || '注册失败,请稍后重试',
|
||||||
|
icon: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清空输入框
|
||||||
|
const clearInput = (type) => {
|
||||||
|
if (type === 'email') {
|
||||||
|
email.value = '';
|
||||||
|
} else if (type === 'password') {
|
||||||
|
password.value = '';
|
||||||
|
} else if (type === 'registerEmail') {
|
||||||
|
registerEmail.value = '';
|
||||||
|
} else if (type === 'registerPassword') {
|
||||||
|
registerPassword.value = '';
|
||||||
|
} else if (type === 'confirmPassword') {
|
||||||
|
confirmPassword.value = '';
|
||||||
|
} else if (type === 'verificationCode') {
|
||||||
|
verificationCode.value = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听输入变化,清除错误状态
|
||||||
|
const onInputChange = (type) => {
|
||||||
|
if (type === 'email') {
|
||||||
|
// 移除邮箱错误状态
|
||||||
|
} else if (type === 'password') {
|
||||||
|
// 移除密码错误状态
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 暴露事件给父组件
|
||||||
|
const emit = defineEmits(['close', 'success']);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="login-container">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<view class="login-header">
|
||||||
|
<text class="title">欢迎登录</text>
|
||||||
|
<text class="subtitle">请使用您的账号信息登录</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 邮箱输入 -->
|
||||||
|
<view class="input-group">
|
||||||
|
<view class="label">邮箱</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="input-field"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入邮箱"
|
||||||
|
v-model="email"
|
||||||
|
@input="onInputChange('email')"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
v-if="email"
|
||||||
|
class="clear-btn"
|
||||||
|
@tap="clearInput('email')"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 密码输入 -->
|
||||||
|
<view class="input-group">
|
||||||
|
<view class="label">密码</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="input-field"
|
||||||
|
type="password"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
v-model="password"
|
||||||
|
@input="onInputChange('password')"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
v-if="password"
|
||||||
|
class="clear-btn"
|
||||||
|
@tap="clearInput('password')"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 忘记密码链接 -->
|
||||||
|
<view class="links-section">
|
||||||
|
<text class="link" @tap="forgetPassword">忘记密码?</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 登录按钮 -->
|
||||||
|
<button
|
||||||
|
class="login-btn"
|
||||||
|
:class="{ 'btn-loading': isLoading }"
|
||||||
|
@tap="onLogin"
|
||||||
|
:disabled="isLoading"
|
||||||
|
>
|
||||||
|
<text v-if="!isLoading">登录</text>
|
||||||
|
<view v-else class="loading-spinner"></view>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- 注册链接 -->
|
||||||
|
<view class="register-section">
|
||||||
|
<text>还没有账号?</text>
|
||||||
|
<text class="register-link" @tap="showRegisterPopup">立即注册</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 同意条款 -->
|
||||||
|
<view class="agreement-section">
|
||||||
|
<label class="agreement-label">
|
||||||
|
<checkbox
|
||||||
|
class="checkbox"
|
||||||
|
:checked="checked"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
我已阅读并同意
|
||||||
|
<text class="agreement-link" @tap="showAgreement">《用户协议》</text>
|
||||||
|
和
|
||||||
|
<text class="agreement-link" @tap="showAgreement">《隐私政策》</text>
|
||||||
|
</label>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 注册弹窗 -->
|
||||||
|
<u-popup
|
||||||
|
v-model:show="showRegister"
|
||||||
|
mode="center"
|
||||||
|
:border-radius="20"
|
||||||
|
:safe-area-inset-bottom="false"
|
||||||
|
width="80%"
|
||||||
|
:closeable="true"
|
||||||
|
@close="hideRegisterPopup"
|
||||||
|
>
|
||||||
|
<view class="register-popup">
|
||||||
|
<view class="register-header">
|
||||||
|
<text class="register-title">用户注册</text>
|
||||||
|
<text class="register-subtitle">请填写注册信息</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 注册邮箱输入 -->
|
||||||
|
<view class="input-group">
|
||||||
|
<view class="label">邮箱</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="input-field"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入邮箱"
|
||||||
|
v-model="registerEmail"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
v-if="registerEmail"
|
||||||
|
class="clear-btn"
|
||||||
|
@tap="clearInput('registerEmail')"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 验证码输入 -->
|
||||||
|
<view class="input-group">
|
||||||
|
<view class="label">验证码</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="input-field"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
v-model="verificationCode"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
v-if="verificationCode"
|
||||||
|
class="clear-btn"
|
||||||
|
@tap="clearInput('verificationCode')"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button
|
||||||
|
class="code-btn"
|
||||||
|
:disabled="codeBtnDisabled"
|
||||||
|
@tap="getVerificationCode"
|
||||||
|
>
|
||||||
|
{{ codeBtnText }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 注册密码输入 -->
|
||||||
|
<view class="input-group">
|
||||||
|
<view class="label">密码</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="input-field"
|
||||||
|
type="password"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
v-model="registerPassword"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
v-if="registerPassword"
|
||||||
|
class="clear-btn"
|
||||||
|
@tap="clearInput('registerPassword')"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 确认密码输入 -->
|
||||||
|
<view class="input-group">
|
||||||
|
<view class="label">确认密码</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="input-field"
|
||||||
|
type="password"
|
||||||
|
placeholder="请再次输入密码"
|
||||||
|
v-model="confirmPassword"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
v-if="confirmPassword"
|
||||||
|
class="clear-btn"
|
||||||
|
@tap="clearInput('confirmPassword')"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 注册按钮 -->
|
||||||
|
<button
|
||||||
|
class="register-submit-btn"
|
||||||
|
@tap="onRegister"
|
||||||
|
>
|
||||||
|
注册
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- 同意条款 -->
|
||||||
|
<view class="agreement-section">
|
||||||
|
<label class="agreement-label">
|
||||||
|
<checkbox
|
||||||
|
class="checkbox"
|
||||||
|
:checked="checked"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
我已阅读并同意
|
||||||
|
<text class="agreement-link" @tap="showAgreement">《用户协议》</text>
|
||||||
|
和
|
||||||
|
<text class="agreement-link" @tap="showAgreement">《隐私政策》</text>
|
||||||
|
</label>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.login-container {
|
||||||
|
padding: 40rpx;
|
||||||
|
min-height: 600rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header {
|
||||||
|
margin-bottom: 50rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: block;
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
padding-left: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 88rpx;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
padding: 0 30rpx;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-field {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 30rpx;
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #ccc;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #00a88e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 88rpx;
|
||||||
|
background: linear-gradient(90deg, #00a88e, #00c4a2);
|
||||||
|
border-radius: 44rpx;
|
||||||
|
color: white;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
border: none;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
|
||||||
|
&.btn-loading {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 30rpx;
|
||||||
|
height: 30rpx;
|
||||||
|
border: 3rpx solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-top: 3rpx solid white;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 30rpx 0;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-link {
|
||||||
|
color: #00a88e;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-section {
|
||||||
|
margin-top: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
transform: scale(0.7);
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-link {
|
||||||
|
color: #00a88e;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-popup {
|
||||||
|
padding: 40rpx;
|
||||||
|
min-height: 600rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-header {
|
||||||
|
margin-bottom: 50rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-subtitle {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 10rpx;
|
||||||
|
top: 70%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
height: 60rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
background: linear-gradient(90deg, #00a88e, #00c4a2);
|
||||||
|
color: white;
|
||||||
|
font-size: 24rpx;
|
||||||
|
border-radius: 30rpx;
|
||||||
|
border: none;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background: #ccc;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-submit-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 88rpx;
|
||||||
|
background: linear-gradient(90deg, #00a88e, #00c4a2);
|
||||||
|
border-radius: 44rpx;
|
||||||
|
color: white;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
border: none;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,7 +3,7 @@ import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
|
|||||||
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||||
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
||||||
import LoginPopup from '@/components/login-popup.vue';
|
import LoginPopup from '@/components/login.vue';
|
||||||
import { getProducts } from './api.js';
|
import { getProducts } from './api.js';
|
||||||
import { useUserStore } from '@/store/user.js';
|
import { useUserStore } from '@/store/user.js';
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
|
|||||||
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||||
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
||||||
import LoginPopup from '@/components/login-popup.vue';
|
import LoginPopup from '@/components/login.vue';
|
||||||
import { getProducts } from './api.js';
|
import { getProducts } from './api.js';
|
||||||
import { useUserStore } from '@/store/user.js';
|
import { useUserStore } from '@/store/user.js';
|
||||||
|
|
||||||
|
|||||||
+154
-12
@@ -3,7 +3,7 @@ import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
|
|||||||
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||||
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
||||||
import LoginPopup from '@/components/login-popup.vue';
|
import LoginPopup from '@/components/login.vue';
|
||||||
import { getProducts } from './api.js';
|
import { getProducts } from './api.js';
|
||||||
import { useUserStore } from '@/store/user.js';
|
import { useUserStore } from '@/store/user.js';
|
||||||
|
|
||||||
@@ -29,6 +29,27 @@ const productData = ref();
|
|||||||
const scrollHeight = ref(0); //scroll-view滚动高度
|
const scrollHeight = ref(0); //scroll-view滚动高度
|
||||||
|
|
||||||
const pageView = ref({});
|
const pageView = ref({});
|
||||||
|
|
||||||
|
// 控制登录弹窗显示
|
||||||
|
const toggleLoginPopup = () => {
|
||||||
|
showLogin.value = !showLogin.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭登录弹窗
|
||||||
|
const closeLoginPopup = () => {
|
||||||
|
showLogin.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 登录成功回调
|
||||||
|
const onLoginSuccess = () => {
|
||||||
|
closeLoginPopup();
|
||||||
|
// 可以在这里执行登录成功后的操作
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc 获取可视内容高度
|
* @desc 获取可视内容高度
|
||||||
*/
|
*/
|
||||||
@@ -36,11 +57,6 @@ const getContentHeight = (e) => {
|
|||||||
pageView.value = e;
|
pageView.value = e;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc 跳转至详情页面
|
* @desc 跳转至详情页面
|
||||||
*/
|
*/
|
||||||
@@ -49,6 +65,7 @@ const toDetailPage = (productId) => {
|
|||||||
url: '/pages/product/detail',
|
url: '/pages/product/detail',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//获取首页数据
|
//获取首页数据
|
||||||
const getProductList = async()=>{
|
const getProductList = async()=>{
|
||||||
const res = await getProducts();
|
const res = await getProducts();
|
||||||
@@ -57,7 +74,6 @@ const getProductList = async()=>{
|
|||||||
console.log("商品数据",productData.value);
|
console.log("商品数据",productData.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onLoad(()=>{
|
onLoad(()=>{
|
||||||
// getProductList();
|
// getProductList();
|
||||||
|
|
||||||
@@ -65,7 +81,6 @@ onLoad(()=>{
|
|||||||
|
|
||||||
// 模拟数据
|
// 模拟数据
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc 处理预订事件
|
* @desc 处理预订事件
|
||||||
*/
|
*/
|
||||||
@@ -76,14 +91,129 @@ const handleBook = (productId) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc 跳转至登录页面
|
||||||
|
*/
|
||||||
|
const toLoginPage = (productId) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/login/index',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 示例:在页面加载完成后自动显示登录弹窗
|
||||||
|
// setTimeout(() => {
|
||||||
|
// showLogin.value = true;
|
||||||
|
// }, 1000);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="h-[100vh] bg-[#9C032D]">
|
<view class="h-[100vh] bg-[#fff]">
|
||||||
|
<!-- 页面内容区域 -->
|
||||||
<CustomTabBar />
|
<view class="flex flex-col">
|
||||||
|
<!-- 个人页头部区域 -->
|
||||||
|
<view class="profile-header p-4 bg-gradient-to-r from-blue-500 to-purple-600 text-white">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<image
|
||||||
|
src="/static/images/avatar.png"
|
||||||
|
class="w-16 h-16 rounded-full border-2 border-white mr-4"
|
||||||
|
style="background-color: #ddd;"
|
||||||
|
/>
|
||||||
|
<view class="flex-1">
|
||||||
|
<view class="font-bold text-lg">用户昵称</view>
|
||||||
|
<view class="text-sm opacity-80">ID: 123456789</view>
|
||||||
|
</view>
|
||||||
|
<button
|
||||||
|
class="bg-white text-blue-600 px-4 py-2 rounded-full text-sm font-medium"
|
||||||
|
@click="toLoginPage"
|
||||||
|
|
||||||
|
>
|
||||||
|
{{ userStore.isLogin ? '退出登录' : '登录' }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 功能列表 -->
|
||||||
|
<view class="p-4">
|
||||||
|
<view class="bg-white rounded-xl shadow-sm p-4 mb-4">
|
||||||
|
<view class="font-semibold text-lg mb-3">个人中心</view>
|
||||||
|
|
||||||
|
<view class="space-y-3">
|
||||||
|
<view class="flex items-center justify-between p-3 border-b border-gray-100 last:border-0">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center mr-3">
|
||||||
|
<text class="text-blue-600 text-sm">👤</text>
|
||||||
|
</view>
|
||||||
|
<text>个人信息</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-gray-400 text-sm">></text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="flex items-center justify-between p-3 border-b border-gray-100 last:border-0">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center mr-3">
|
||||||
|
<text class="text-green-600 text-sm">🔒</text>
|
||||||
|
</view>
|
||||||
|
<text>账户安全</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-gray-400 text-sm">></text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="flex items-center justify-between p-3 border-b border-gray-100 last:border-0">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="w-8 h-8 bg-yellow-100 rounded-full flex items-center justify-center mr-3">
|
||||||
|
<text class="text-yellow-600 text-sm">💬</text>
|
||||||
|
</view>
|
||||||
|
<text>消息通知</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-gray-400 text-sm">></text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="flex items-center justify-between p-3 border-b border-gray-100 last:border-0">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="w-8 h-8 bg-red-100 rounded-full flex items-center justify-center mr-3">
|
||||||
|
<text class="text-red-600 text-sm">⚙️</text>
|
||||||
|
</view>
|
||||||
|
<text>设置</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-gray-400 text-sm">></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<view class="mt-6">
|
||||||
|
<button
|
||||||
|
class="w-full bg-gradient-to-r from-blue-500 to-purple-600 text-white py-4 rounded-xl font-medium"
|
||||||
|
@tap="toggleLoginPopup"
|
||||||
|
>
|
||||||
|
{{ userStore.isLogin ? '退出登录' : '立即登录' }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 登录弹窗 - 优化版 -->
|
||||||
|
<u-popup
|
||||||
|
v-model:show="showLogin"
|
||||||
|
mode="center"
|
||||||
|
:border-radius="20"
|
||||||
|
:safe-area-inset-bottom="false"
|
||||||
|
width="80%"
|
||||||
|
:closeable="true"
|
||||||
|
@close="closeLoginPopup"
|
||||||
|
>
|
||||||
|
<view class="popup-content">
|
||||||
|
<LoginPopup
|
||||||
|
@close="closeLoginPopup"
|
||||||
|
@success="onLoginSuccess"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
|
||||||
|
<CustomTabBar />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -110,4 +240,16 @@ const handleBook = (productId) => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.profile-header {
|
||||||
|
min-height: 200rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-content {
|
||||||
|
padding: 20rpx;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -3,7 +3,7 @@ import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
|
|||||||
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||||
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
||||||
import LoginPopup from '@/components/login-popup.vue';
|
import LoginPopup from '@/components/login.vue';
|
||||||
import { getProducts } from './api.js';
|
import { getProducts } from './api.js';
|
||||||
import { useUserStore } from '@/store/user.js';
|
import { useUserStore } from '@/store/user.js';
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
|
|||||||
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
import { onLoad, onShow, onReady, onHide, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||||
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
import { getSystemSafeArea, getSystemInfo, isEmpty, showToast, showLoadingToast, closeToast } from '@/common/common.js';
|
||||||
import LoginPopup from '@/components/login-popup.vue';
|
import LoginPopup from '@/components/login.vue';
|
||||||
import { getProducts } from './api.js';
|
import { getProducts } from './api.js';
|
||||||
import { useUserStore } from '@/store/user.js';
|
import { useUserStore } from '@/store/user.js';
|
||||||
|
|
||||||
|
|||||||
+163
-62
@@ -1,27 +1,77 @@
|
|||||||
// 引用pinia商店
|
// 引用pinia商店
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { parse, stringify } from 'zipson';
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
export const useUserStore = defineStore(
|
export const useUserStore = defineStore(
|
||||||
'user',
|
'user',
|
||||||
() => {
|
() => {
|
||||||
const userInfo = ref({});
|
// 用户基础信息
|
||||||
const platform = ref('');
|
const userInfo = ref({
|
||||||
const userToken = ref('');
|
areaCode: '',
|
||||||
|
avatar: '',
|
||||||
|
birthday: null,
|
||||||
|
email: null,
|
||||||
|
gender: null,
|
||||||
|
mobile: '',
|
||||||
|
nickName: '',
|
||||||
|
trueName: null,
|
||||||
|
userId: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 认证相关信息
|
||||||
|
const token = ref('');
|
||||||
const isLogin = ref(false);
|
const isLogin = ref(false);
|
||||||
|
|
||||||
|
// 平台配置信息
|
||||||
|
const platform = ref('');
|
||||||
const currency = ref('HKD');
|
const currency = ref('HKD');
|
||||||
|
const lang = ref('');
|
||||||
|
|
||||||
|
// 客服联系方式
|
||||||
const kfTelCN = ref('');
|
const kfTelCN = ref('');
|
||||||
const kfTelHK = ref('');
|
const kfTelHK = ref('');
|
||||||
const wxLink = ref('');
|
const wxLink = ref('');
|
||||||
const lang = ref('');
|
|
||||||
const setProfile = (val) => {
|
// 计算属性 - 是否已登录
|
||||||
userInfo.value = {
|
const isLoggedIn = computed(() => isLogin.value && token.value !== '');
|
||||||
...val,
|
|
||||||
};
|
// 计算属性 - 用户头像
|
||||||
console.log(userInfo.value);
|
const userAvatar = computed(() => userInfo.value.avatar || '/static/default-avatar.png');
|
||||||
|
|
||||||
|
// 计算属性 - 用户昵称
|
||||||
|
const userName = computed(() => userInfo.value.nickName || userInfo.value.trueName || '游客');
|
||||||
|
|
||||||
|
// 设置用户信息
|
||||||
|
const setUserInfo = (data) => {
|
||||||
|
if (data && typeof data === 'object') {
|
||||||
|
userInfo.value = {
|
||||||
|
...userInfo.value,
|
||||||
|
...data,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
//清理用户信息,退出时使用
|
|
||||||
const clearProfile = () => {
|
// 设置认证令牌
|
||||||
|
const setToken = (tokenValue) => {
|
||||||
|
token.value = tokenValue || '';
|
||||||
|
isLogin.value = !!tokenValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置登录状态
|
||||||
|
const setLoginStatus = (status) => {
|
||||||
|
isLogin.value = Boolean(status);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 用户登录 - 合并设置用户信息和令牌
|
||||||
|
const login = (userData, accessToken) => {
|
||||||
|
setUserInfo(userData);
|
||||||
|
setToken(accessToken);
|
||||||
|
setLoginStatus(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 用户登出 - 清理所有用户相关数据
|
||||||
|
const logout = () => {
|
||||||
userInfo.value = {
|
userInfo.value = {
|
||||||
areaCode: '',
|
areaCode: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
@@ -33,80 +83,131 @@ export const useUserStore = defineStore(
|
|||||||
trueName: null,
|
trueName: null,
|
||||||
userId: null,
|
userId: null,
|
||||||
};
|
};
|
||||||
|
token.value = '';
|
||||||
|
isLogin.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 更新用户特定字段
|
||||||
|
const updateUserInfo = (field, value) => {
|
||||||
|
if (userInfo.value.hasOwnProperty(field)) {
|
||||||
|
userInfo.value[field] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 批量更新用户信息
|
||||||
|
const batchUpdateUserInfo = (updates) => {
|
||||||
|
if (updates && typeof updates === 'object') {
|
||||||
|
Object.keys(updates).forEach(key => {
|
||||||
|
if (userInfo.value.hasOwnProperty(key)) {
|
||||||
|
userInfo.value[key] = updates[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取用户权限列表(如果有的话)
|
||||||
|
const getUserPermissions = computed(() => {
|
||||||
|
// 这里可以根据实际业务逻辑返回用户权限
|
||||||
|
return userInfo.value.permissions || [];
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查用户是否有特定权限
|
||||||
|
const hasPermission = (permission) => {
|
||||||
|
if (!isLoggedIn.value) return false;
|
||||||
|
return getUserPermissions.value.includes(permission);
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isLogin,
|
// 状态
|
||||||
userInfo,
|
userInfo,
|
||||||
userToken,
|
token,
|
||||||
|
isLogin,
|
||||||
platform,
|
platform,
|
||||||
currency,
|
currency,
|
||||||
kfTelCN,
|
kfTelCN,
|
||||||
kfTelHK,
|
kfTelHK,
|
||||||
wxLink,
|
wxLink,
|
||||||
lang,
|
lang,
|
||||||
setProfile,
|
|
||||||
clearProfile,
|
// 计算属性
|
||||||
|
isLoggedIn,
|
||||||
|
userAvatar,
|
||||||
|
userName,
|
||||||
|
getUserPermissions,
|
||||||
|
|
||||||
|
// 动作
|
||||||
|
setUserInfo,
|
||||||
|
setToken,
|
||||||
|
setLoginStatus,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
updateUserInfo,
|
||||||
|
batchUpdateUserInfo,
|
||||||
|
hasPermission,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
persist: {
|
persist: {
|
||||||
|
key: 'user-store', // 自定义存储键名
|
||||||
storage: {
|
storage: {
|
||||||
getItem(key) {
|
getItem(key) {
|
||||||
return uni.getStorageSync(key);
|
try {
|
||||||
|
const storedData = uni.getStorageSync(key);
|
||||||
|
return storedData;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('读取用户存储数据失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setItem(key, value) {
|
setItem(key, value) {
|
||||||
uni.setStorageSync(key, value);
|
try {
|
||||||
|
uni.setStorageSync(key, value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存用户数据失败:', error);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
serializer: {
|
serializer: {
|
||||||
deserialize: parse,
|
deserialize: (data) => {
|
||||||
serialize: stringify,
|
try {
|
||||||
|
return parse(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('反序列化用户数据失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
serialize: (data) => {
|
||||||
|
try {
|
||||||
|
return stringify(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('序列化用户数据失败:', error);
|
||||||
|
return '{}';
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
// 指定需要持久化的状态
|
||||||
|
paths: ['userInfo', 'token', 'isLogin', 'platform', 'currency', 'kfTelCN', 'kfTelHK', 'wxLink', 'lang'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
页面内使用pinia
|
使用示例:
|
||||||
|
1. 在组件中导入
|
||||||
1、引用你定义的store实例
|
import { useUserStore } from '@/store/user.js'
|
||||||
import { useUserStore } from '@/stores/user'
|
|
||||||
|
|
||||||
2、实例化useUserStore
|
2. 使用方式
|
||||||
const user = useUserStore()
|
const userStore = useUserStore();
|
||||||
|
|
||||||
3、引入 storeToRefs 用于 给实例的属性创建refs,即响应式
|
// 获取计算属性
|
||||||
import { storeToRefs } from 'pinia'
|
const { isLoggedIn, userName } = storeToRefs(userStore);
|
||||||
例如:const {count} = storeToRefs(user)
|
|
||||||
count.value 此时为响应式
|
// 调用动作
|
||||||
|
userStore.login(userData, accessToken);
|
||||||
4、修改state 方式共两种 如下
|
userStore.logout();
|
||||||
user.count++
|
|
||||||
4-1、
|
// 检查权限
|
||||||
// 带自动补全 ✨
|
if (userStore.hasPermission('admin')) {
|
||||||
user.$patch({ count: counter.count + 1 })
|
// 执行管理员操作
|
||||||
$patch()可批量修改state的属性值
|
}
|
||||||
例如:
|
*/
|
||||||
批量修改
|
|
||||||
const pathState = () => {
|
|
||||||
store.$patch({
|
|
||||||
user: { name: 'ks', age: 20 },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
其他操作state的方法如下:
|
|
||||||
|
|
||||||
替换State
|
|
||||||
const replaceState = () => {
|
|
||||||
store.$state.user = { age: 20, name: 'eee', sex: 'women' };
|
|
||||||
};
|
|
||||||
重置state的值
|
|
||||||
const reset = () => {
|
|
||||||
store.$reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
4-2、
|
|
||||||
// 或使用 action 代替
|
|
||||||
user.increment()
|
|
||||||
|
|
||||||
*/
|
|
||||||
+49
-78
@@ -1,84 +1,73 @@
|
|||||||
|
// utils/request.js(或你当前文件)
|
||||||
|
|
||||||
import { useUserStore } from '@/store/user';
|
import { useUserStore } from '@/store/user';
|
||||||
|
|
||||||
export const baseUrl = import.meta.env.VITE_APP_BASE_URL;
|
export const baseUrl = import.meta.env.VITE_APP_BASE_URL;
|
||||||
const appVersion = uni.getSystemInfoSync().appVersion;
|
const appVersion = uni.getSystemInfoSync().appVersion;
|
||||||
// 添加拦截器
|
|
||||||
// const httpInterceptor = {
|
|
||||||
// // 拦截前触发
|
|
||||||
// invoke(options) {
|
|
||||||
// // 1. 非 http 开头需拼接地址
|
|
||||||
// if (!options.url.startsWith('http')) {
|
|
||||||
// options.url = baseUrl + options.url;
|
|
||||||
// }
|
|
||||||
// // 2. 请求超时, 默认 10s
|
|
||||||
// options.timeout = 10000;
|
|
||||||
// options.header = {
|
|
||||||
// ...options.header,
|
|
||||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
// };
|
|
||||||
// const userStore = useUserStore();
|
|
||||||
// options.data = {
|
|
||||||
// ...options.data,
|
|
||||||
// __token: userStore.userToken,
|
|
||||||
// __platform: userStore.platform,
|
|
||||||
// };
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// uni.addInterceptor('request', httpInterceptor);
|
|
||||||
// // #ifndef H5
|
|
||||||
// uni.addInterceptor('uploadFile', httpInterceptor);
|
|
||||||
// // #endif
|
|
||||||
|
|
||||||
// 对uni原生的request做的一个封装
|
// 对 uni.request 的封装
|
||||||
export const request = (options = {}) => {
|
export const request = (options = {}) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
// 请求头
|
|
||||||
options.header = {
|
// 👇 关键修改:默认 Content-Type 为 application/json
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
const contentType = options.header?.['Content-Type'] || 'application/json';
|
||||||
// version: appVersion,
|
|
||||||
};
|
// 公共参数
|
||||||
var params = {
|
const commonParams = {
|
||||||
__token: userStore.userToken,
|
__token: userStore.userToken,
|
||||||
__platform: userStore.platform,
|
__platform: userStore.platform,
|
||||||
__language: userStore.lang,
|
__language: userStore.lang,
|
||||||
__channelId: 33,
|
|
||||||
};
|
};
|
||||||
var data = options.data;
|
|
||||||
data = {
|
// 合并 data
|
||||||
...data,
|
let requestData = {
|
||||||
...params,
|
...options.data,
|
||||||
|
...commonParams,
|
||||||
};
|
};
|
||||||
// uni原生request
|
|
||||||
|
// 👇 如果是 JSON,data 保持为对象(uni.request 会自动序列化)
|
||||||
|
// 如果是 x-www-form-urlencoded,需要手动转成字符串(但不推荐)
|
||||||
|
if (contentType === 'application/x-www-form-urlencoded') {
|
||||||
|
// 注意:uni.request 在非 H5 平台可能不支持直接传对象 + x-www-form-urlencoded
|
||||||
|
// 所以这里需要手动拼接
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
for (const key in requestData) {
|
||||||
|
if (requestData[key] !== undefined && requestData[key] !== null) {
|
||||||
|
params.append(key, requestData[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestData = params.toString(); // 转为 a=1&b=2 形式
|
||||||
|
}
|
||||||
|
// 如果是 application/json,requestData 保持为对象即可
|
||||||
|
|
||||||
uni
|
uni
|
||||||
.request({
|
.request({
|
||||||
url: baseUrl + options.url || '',
|
url: baseUrl + (options.url || ''),
|
||||||
method: options.method || 'GET',
|
method: options.method || 'GET',
|
||||||
data: data || {},
|
data: requestData, // 对象 or 字符串
|
||||||
header: options.header || {},
|
header: {
|
||||||
|
'Content-Type': contentType,
|
||||||
|
// version: appVersion, // 如需可加
|
||||||
|
...options.header,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.statusCode === 401) {
|
if (res.statusCode === 401) {
|
||||||
// usetToken无效,移除本地缓存
|
|
||||||
userStore.userToken = '';
|
userStore.userToken = '';
|
||||||
userStore.clearProfile();
|
userStore.clearProfile();
|
||||||
userStore.isLogin = false;
|
userStore.isLogin = false;
|
||||||
resolve({
|
|
||||||
...res.data,
|
|
||||||
statusCode: res.statusCode,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve({
|
|
||||||
...res.data,
|
|
||||||
statusCode: res.statusCode,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
resolve({
|
||||||
|
...res.data,
|
||||||
|
statusCode: res.statusCode,
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.statusCode === 401) {
|
if (error.statusCode === 401) {
|
||||||
// usetToken无效,移除本地缓存
|
|
||||||
userStore.userToken = '';
|
userStore.userToken = '';
|
||||||
userStore.clearProfile();
|
userStore.clearProfile();
|
||||||
|
userStore.isLogin = false;
|
||||||
reject({
|
reject({
|
||||||
...error.data,
|
...error.data,
|
||||||
statusCode: error.statusCode,
|
statusCode: error.statusCode,
|
||||||
@@ -99,37 +88,19 @@ export const request = (options = {}) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 定义get请求
|
// 导出方法(保持不变)
|
||||||
export const get = (url, data = {}, options = {}) => {
|
export const get = (url, data = {}, options = {}) => {
|
||||||
options.url = url;
|
return request({ ...options, url, method: 'GET', data });
|
||||||
options.method = 'GET';
|
|
||||||
options.data = data;
|
|
||||||
|
|
||||||
return request(options);
|
|
||||||
};
|
};
|
||||||
// 定义post请求
|
|
||||||
export const post = (url, data = {}, options = {}) => {
|
export const post = (url, data = {}, options = {}) => {
|
||||||
options.url = url;
|
return request({ ...options, url, method: 'POST', data });
|
||||||
options.method = 'POST';
|
|
||||||
options.data = data;
|
|
||||||
|
|
||||||
return request(options);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 定义put请求
|
|
||||||
export const put = (url, data = {}, options = {}) => {
|
export const put = (url, data = {}, options = {}) => {
|
||||||
options.url = url;
|
return request({ ...options, url, method: 'PUT', data });
|
||||||
options.method = 'PUT';
|
|
||||||
options.data = data;
|
|
||||||
|
|
||||||
return request(options);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 定义delete请求
|
|
||||||
export const dele = (url, data = {}, options = {}) => {
|
export const dele = (url, data = {}, options = {}) => {
|
||||||
options.url = url;
|
return request({ ...options, url, method: 'DELETE', data });
|
||||||
options.method = 'DELETE';
|
};
|
||||||
options.data = data;
|
|
||||||
|
|
||||||
return request(options);
|
|
||||||
};
|
|
||||||
Reference in new issue
Block a user