对接uniapp端登录[C
This commit is contained in:
3
Cunkebao/.env.production
Normal file
3
Cunkebao/.env.production
Normal file
@@ -0,0 +1,3 @@
|
||||
# 生产环境配置
|
||||
VUE_APP_BASE_API = 'https://api.cunkebao.com'
|
||||
VUE_APP_ENV = 'production'
|
||||
3
Cunkebao/.gitignore
vendored
3
Cunkebao/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
node_modules
|
||||
node_modules
|
||||
.env
|
||||
@@ -1,6 +1,6 @@
|
||||
# 村客宝 UniApp
|
||||
# 存客宝 UniApp
|
||||
|
||||
基于uni-app框架开发的村客宝移动端应用,支持H5、微信小程序、App等多端部署。
|
||||
基于uni-app框架开发的存客宝移动端应用,支持H5、微信小程序、App等多端部署。
|
||||
|
||||
## 项目结构
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@ import request from '@/utils/request'
|
||||
/**
|
||||
* 用户登录
|
||||
* @param {Object} data 登录数据
|
||||
* @param {string} data.username 用户名
|
||||
* @param {string} data.account 账号(手机号)
|
||||
* @param {string} data.password 密码
|
||||
* @param {boolean} data.is_encrypted 密码是否已加密
|
||||
* @param {number} data.typeId 用户类型
|
||||
* @returns {Promise} 登录结果
|
||||
*/
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: '/api/auth/login',
|
||||
url: '/v1/auth/login',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
@@ -19,13 +19,14 @@ export function login(data) {
|
||||
/**
|
||||
* 手机号验证码登录
|
||||
* @param {Object} data 登录数据
|
||||
* @param {string} data.mobile 手机号
|
||||
* @param {string} data.account 手机号
|
||||
* @param {string} data.code 验证码
|
||||
* @param {number} data.typeId 用户类型
|
||||
* @returns {Promise} 登录结果
|
||||
*/
|
||||
export function mobileLogin(data) {
|
||||
return request({
|
||||
url: '/api/auth/mobile-login',
|
||||
url: '/v1/auth/mobile-login',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
@@ -34,13 +35,13 @@ export function mobileLogin(data) {
|
||||
/**
|
||||
* 发送验证码
|
||||
* @param {Object} data 数据
|
||||
* @param {string} data.mobile 手机号
|
||||
* @param {string} data.account 手机号
|
||||
* @param {string} data.type 验证码类型(login:登录,register:注册)
|
||||
* @returns {Promise} 发送结果
|
||||
*/
|
||||
export function sendCode(data) {
|
||||
return request({
|
||||
url: '/api/auth/code',
|
||||
url: '/v1/auth/code',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
@@ -52,7 +53,7 @@ export function sendCode(data) {
|
||||
*/
|
||||
export function getUserInfo() {
|
||||
return request({
|
||||
url: '/api/auth/info',
|
||||
url: '/v1/auth/info',
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
@@ -63,7 +64,7 @@ export function getUserInfo() {
|
||||
*/
|
||||
export function refreshToken() {
|
||||
return request({
|
||||
url: '/api/auth/refresh',
|
||||
url: '/v1/auth/refresh',
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
||||
@@ -86,7 +87,7 @@ export function logout() {
|
||||
*/
|
||||
export function wechatLogin(data) {
|
||||
return request({
|
||||
url: '/api/auth/wechat-login',
|
||||
url: '/v1/auth/wechat-login',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
@@ -100,7 +101,7 @@ export function wechatLogin(data) {
|
||||
*/
|
||||
export function appleLogin(data) {
|
||||
return request({
|
||||
url: '/api/auth/apple-login',
|
||||
url: '/v1/auth/apple-login',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name" : "村客宝",
|
||||
"name" : "存客宝",
|
||||
"appid" : "",
|
||||
"description" : "村客宝应用",
|
||||
"description" : "存客宝应用",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
@@ -69,6 +69,6 @@
|
||||
"enable" : true
|
||||
}
|
||||
},
|
||||
"title" : "村客宝"
|
||||
"title" : "存客宝"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cunkebao",
|
||||
"version": "1.0.0",
|
||||
"description": "村客宝 - 基于 uni-app 的跨平台应用",
|
||||
"description": "存客宝 - 基于 uni-app 的跨平台应用",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "村客宝",
|
||||
"navigationBarTitleText": "存客宝",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
},
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
></u-navbar>
|
||||
|
||||
<view class="content">
|
||||
<view class="title">村客宝隐私政策</view>
|
||||
<view class="title">存客宝隐私政策</view>
|
||||
<view class="date">生效日期:2023年1月1日</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">一、引言</view>
|
||||
<view class="paragraph">
|
||||
村客宝(以下简称"我们")非常重视您的隐私和个人信息保护。本隐私政策旨在向您说明我们如何收集、使用、存储、共享和保护您的个人信息,以及您享有的相关权利。
|
||||
存客宝(以下简称"我们")非常重视您的隐私和个人信息保护。本隐私政策旨在向您说明我们如何收集、使用、存储、共享和保护您的个人信息,以及您享有的相关权利。
|
||||
</view>
|
||||
<view class="paragraph">
|
||||
请您在使用我们的服务前,仔细阅读并了解本隐私政策的全部内容。如您对本隐私政策有任何疑问,可随时联系我们的客服。
|
||||
|
||||
@@ -6,26 +6,26 @@
|
||||
></u-navbar>
|
||||
|
||||
<view class="content">
|
||||
<view class="title">村客宝用户协议</view>
|
||||
<view class="title">存客宝用户协议</view>
|
||||
<view class="date">生效日期:2023年1月1日</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">一、总则</view>
|
||||
<view class="section-title">一、协议的接受与变更</view>
|
||||
<view class="paragraph">
|
||||
1.1 村客宝用户协议(以下简称"本协议")是您与村客宝平台(以下简称"我们")之间就村客宝平台服务等相关事宜所订立的契约。
|
||||
1.1 存客宝用户协议(以下简称"本协议")是您与存客宝平台(以下简称"我们")之间就存客宝平台服务等相关事宜所订立的契约。
|
||||
</view>
|
||||
<view class="paragraph">
|
||||
1.2 您应当在使用村客宝平台服务之前认真阅读本协议全部内容。如您对本协议有任何疑问,可随时咨询我们的客服。
|
||||
1.2 您应当在使用存客宝平台服务之前认真阅读本协议全部内容。如您对本协议有任何疑问,可随时咨询我们的客服。
|
||||
</view>
|
||||
<view class="paragraph">
|
||||
1.3 您点击"同意"或"下一步",或您使用村客宝平台服务,即视为您已阅读并同意签署本协议。本协议自您确认同意之时起生效。
|
||||
1.3 您点击"同意"或"下一步",或您使用存客宝平台服务,即视为您已阅读并同意签署本协议。本协议自您确认同意之时起生效。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">二、账号注册与使用</view>
|
||||
<view class="paragraph">
|
||||
2.1 您应当保证您具有完全民事行为能力,能够独立承担民事责任,并独立承担使用村客宝平台服务的一切法律责任。
|
||||
2.1 您应当保证您具有完全民事行为能力,能够独立承担民事责任,并独立承担使用存客宝平台服务的一切法律责任。
|
||||
</view>
|
||||
<view class="paragraph">
|
||||
2.2 您注册成功后,我们将给予您一个用户账号及相应的密码,该用户账号和密码由您负责保管。
|
||||
@@ -38,7 +38,7 @@
|
||||
<view class="section">
|
||||
<view class="section-title">三、服务内容</view>
|
||||
<view class="paragraph">
|
||||
3.1 村客宝平台服务的具体内容由我们根据实际情况提供,包括但不限于信息发布、交易撮合、数据统计等。
|
||||
3.1 存客宝平台服务的具体内容由我们根据实际情况提供,包括但不限于信息发布、交易撮合、数据统计等。
|
||||
</view>
|
||||
<view class="paragraph">
|
||||
3.2 我们有权不经事先通知,随时变更、中断或终止部分或全部的服务。
|
||||
@@ -46,19 +46,19 @@
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">四、用户义务</view>
|
||||
<view class="section-title">四、用户行为规范</view>
|
||||
<view class="paragraph">
|
||||
4.1 您在使用村客宝平台服务时,必须遵守中华人民共和国相关法律法规。
|
||||
4.1 您在使用存客宝平台服务时,必须遵守中华人民共和国相关法律法规。
|
||||
</view>
|
||||
<view class="paragraph">
|
||||
4.2 您不得利用村客宝平台服务从事违法违规行为,包括但不限于发布违法信息、侵犯他人知识产权等。
|
||||
4.2 您不得利用存客宝平台服务从事违法违规行为,包括但不限于发布违法信息、侵犯他人知识产权等。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">五、知识产权</view>
|
||||
<view class="paragraph">
|
||||
5.1 村客宝平台所包含的全部智力成果,包括但不限于程序、源代码、图标、图饰、图像、图表、文字等,均受著作权法、商标法、专利法及其他知识产权法律法规的保护。
|
||||
5.1 存客宝平台所包含的全部智力成果,包括但不限于程序、源代码、图标、图饰、图像、图表、文字等,均受著作权法、商标法、专利法及其他知识产权法律法规的保护。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
7.1 我们有权随时修改本协议,并在修改后的协议生效前通过适当方式通知您。
|
||||
</view>
|
||||
<view class="paragraph">
|
||||
7.2 如您不同意修改后的协议,可以选择停止使用村客宝平台服务;如您继续使用村客宝平台服务,则视为您已同意修改后的协议。
|
||||
7.2 如您不同意修改后的协议,可以选择停止使用存客宝平台服务;如您继续使用存客宝平台服务,则视为您已同意修改后的协议。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
<script>
|
||||
import LineChart from '@/components/LineChart.vue'
|
||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||
import Auth from '@/utils/auth'
|
||||
import { getUserInfo, logout } from '@/api/user'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -119,14 +121,42 @@ export default {
|
||||
{ icon: 'coupon', color: 'yellow', count: 167, label: '海报获客' },
|
||||
{ icon: 'play-right', color: 'black', count: 156, label: '抖音获客' },
|
||||
{ icon: 'heart', color: 'red', count: 89, label: '小红书获客' }
|
||||
]
|
||||
],
|
||||
userInfo: null
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 检查登录状态
|
||||
if (!Auth.isLogin()) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
this.fetchUserInfo();
|
||||
|
||||
// 加载数据
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
// 获取用户信息
|
||||
fetchUserInfo() {
|
||||
// 先尝试从缓存获取
|
||||
this.userInfo = Auth.getUserInfo();
|
||||
|
||||
// 然后从服务器获取最新信息
|
||||
getUserInfo().then(res => {
|
||||
if (res.code === 200) {
|
||||
this.userInfo = res.data;
|
||||
Auth.setUserInfo(res.data);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取用户信息失败:', err);
|
||||
});
|
||||
},
|
||||
|
||||
// 加载数据
|
||||
loadData() {
|
||||
// 这里可以添加API调用获取实际数据
|
||||
@@ -139,6 +169,34 @@ export default {
|
||||
uni.navigateTo({
|
||||
url: '/pages/notification/index'
|
||||
});
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
handleLogout() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确认退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 直接清除本地保存的登录信息
|
||||
Auth.removeAll();
|
||||
|
||||
// 显示退出成功提示
|
||||
uni.showToast({
|
||||
title: '退出成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
|
||||
// 跳转到登录页面
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +232,25 @@ export default {
|
||||
display: flex;
|
||||
color: black;
|
||||
align-items: center;
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 30rpx;
|
||||
|
||||
.user-name {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-bell {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
<!-- 手机号输入 -->
|
||||
<view class="input-box">
|
||||
<u--input
|
||||
v-model="form.mobile"
|
||||
v-model="form.account"
|
||||
placeholder="+86手机号"
|
||||
prefixIcon="phone"
|
||||
prefixIconStyle="font-size: 52rpx;color: #909399;padding-right: 16rpx;"
|
||||
prefixIconStyle="font-size: 40rpx; color: #909399; padding-right: 16rpx;"
|
||||
clearable
|
||||
type="number"
|
||||
maxlength="11"
|
||||
@@ -71,7 +71,7 @@
|
||||
fontSize="30rpx"
|
||||
suffixIcon="eye"
|
||||
@clickSuffixIcon="showPassword = !showPassword"
|
||||
suffixIconStyle="font-size: 45rpx;"
|
||||
suffixIconStyle="font-size: 40rpx;"
|
||||
></u--input>
|
||||
</view>
|
||||
|
||||
@@ -101,9 +101,10 @@
|
||||
<!-- 登录按钮 -->
|
||||
<u-button
|
||||
text="登录"
|
||||
type="primary"
|
||||
type="info"
|
||||
:disabled="!canLogin"
|
||||
@click="handleLogin"
|
||||
customStyle="width: 100%; margin-top: 40rpx; height: 96rpx; border-radius: 24rpx; font-size: 32rpx; font-weight: 500;"
|
||||
customStyle="width: 100%; margin-top: 40rpx; height: 96rpx; border-radius: 24rpx; font-size: 40rpx; font-weight: bold; background-color: #2563eb; color: #fff;"
|
||||
></u-button>
|
||||
|
||||
<!-- 分割线 -->
|
||||
@@ -117,13 +118,13 @@
|
||||
<view class="other-login">
|
||||
<!-- 微信登录 -->
|
||||
<button class="wechat-btn" @click="handleWechatLogin">
|
||||
<u-icon name="weixin-fill" size="56" color="#07c160" class="wechat-icon"></u-icon>
|
||||
<u-icon name="weixin-fill" size="44" color="#07c160" class="wechat-icon"></u-icon>
|
||||
<text>使用微信登录</text>
|
||||
</button>
|
||||
|
||||
<!-- Apple登录 -->
|
||||
<button class="apple-btn" @click="handleAppleLogin">
|
||||
<u-icon name="apple-fill" size="56" color="#333333" class="apple-icon"></u-icon>
|
||||
<u-icon name="apple-fill" size="44" color="#333333" class="apple-icon"></u-icon>
|
||||
<text>使用 Apple 登录</text>
|
||||
</button>
|
||||
</view>
|
||||
@@ -135,6 +136,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { login, mobileLogin, sendCode } from '@/api/user'
|
||||
import Auth from '@/utils/auth'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -144,9 +148,10 @@ export default {
|
||||
],
|
||||
current: 0,
|
||||
form: {
|
||||
mobile: '',
|
||||
account: '',
|
||||
code: '',
|
||||
password: ''
|
||||
password: '',
|
||||
typeId: 1 // 默认账号类型为运营后台/操盘手
|
||||
},
|
||||
showPassword: false,
|
||||
isAgree: false,
|
||||
@@ -161,7 +166,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
isValidMobile() {
|
||||
return /^1\d{10}$/.test(this.form.mobile)
|
||||
return /^1\d{10}$/.test(this.form.account)
|
||||
},
|
||||
canLogin() {
|
||||
if (!this.isAgree || !this.isValidMobile) return false
|
||||
@@ -185,18 +190,48 @@ export default {
|
||||
},
|
||||
getCode() {
|
||||
if (this.sending || !this.isValidMobile) return
|
||||
this.sending = true
|
||||
this.codeTips = '60s'
|
||||
let seconds = 60
|
||||
const timer = setInterval(() => {
|
||||
seconds--
|
||||
this.codeTips = `${seconds}s`
|
||||
if (seconds <= 0) {
|
||||
clearInterval(timer)
|
||||
|
||||
// 发送验证码接口调用
|
||||
sendCode({
|
||||
account: this.form.account,
|
||||
type: 'login'
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
// 发送成功,开始倒计时
|
||||
this.sending = true
|
||||
this.codeTips = '60s'
|
||||
let seconds = 60
|
||||
const timer = setInterval(() => {
|
||||
seconds--
|
||||
this.codeTips = `${seconds}s`
|
||||
if (seconds <= 0) {
|
||||
clearInterval(timer)
|
||||
this.sending = false
|
||||
this.codeTips = '发送验证码'
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
// 提示用户
|
||||
uni.showToast({
|
||||
title: '验证码已发送',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
// 发送失败
|
||||
uni.showToast({
|
||||
title: res.msg || '验证码发送失败',
|
||||
icon: 'none'
|
||||
})
|
||||
this.sending = false
|
||||
this.codeTips = '发送验证码'
|
||||
}
|
||||
}, 1000)
|
||||
}).catch(err => {
|
||||
console.error('发送验证码失败:', err)
|
||||
uni.showToast({
|
||||
title: '验证码发送失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
this.sending = false
|
||||
})
|
||||
},
|
||||
handleLogin() {
|
||||
if (!this.canLogin) {
|
||||
@@ -237,42 +272,69 @@ export default {
|
||||
mask: true
|
||||
})
|
||||
|
||||
// 模拟登录成功
|
||||
setTimeout(() => {
|
||||
// 根据当前登录方式选择不同的登录API
|
||||
const loginAction = this.current === 0 ?
|
||||
mobileLogin({
|
||||
account: this.form.account,
|
||||
code: this.form.code,
|
||||
typeId: this.form.typeId
|
||||
}) :
|
||||
login({
|
||||
account: this.form.account,
|
||||
password: this.form.password,
|
||||
typeId: this.form.typeId
|
||||
});
|
||||
|
||||
// 调用登录接口
|
||||
loginAction.then(res => {
|
||||
// 隐藏加载提示
|
||||
uni.hideLoading()
|
||||
|
||||
// 保存登录状态和用户信息
|
||||
uni.setStorageSync('token', 'mock_token_' + Date.now())
|
||||
uni.setStorageSync('userInfo', {
|
||||
mobile: this.form.mobile,
|
||||
loginTime: Date.now()
|
||||
})
|
||||
|
||||
// 显示登录成功提示
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
// 延迟跳转到首页
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
success: () => {
|
||||
console.log('跳转到首页成功')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转失败:', err)
|
||||
uni.showToast({
|
||||
title: '跳转失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
if (res.code === 200) {
|
||||
// 登录成功,保存token和用户信息
|
||||
Auth.setToken(res.data.token, res.data.token_expired - Math.floor(Date.now() / 1000));
|
||||
Auth.setUserInfo(res.data.member);
|
||||
|
||||
// 显示登录成功提示
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
}, 1500)
|
||||
}, 1000)
|
||||
|
||||
// 延迟跳转到首页
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
success: () => {
|
||||
console.log('跳转到首页成功')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转失败:', err)
|
||||
uni.showToast({
|
||||
title: '跳转失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}, 1500)
|
||||
} else {
|
||||
// 登录失败
|
||||
uni.showToast({
|
||||
title: res.msg || '登录失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}).catch(err => {
|
||||
// 隐藏加载提示
|
||||
uni.hideLoading()
|
||||
|
||||
console.error('登录失败:', err)
|
||||
uni.showToast({
|
||||
title: '登录失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
},
|
||||
handleWechatLogin() {
|
||||
console.log('微信登录')
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-card">
|
||||
<view class="avatar-wrap">
|
||||
<template v-if="userInfo.avatar">
|
||||
<template v-if="userInfo && userInfo.avatar">
|
||||
<image class="avatar" :src="userInfo.avatar"></image>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -22,8 +22,8 @@
|
||||
</template>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<view class="username">卡若</view>
|
||||
<view class="account">账号: 84675209</view>
|
||||
<view class="username">{{ userInfo && userInfo.username ? userInfo.username : '未设置昵称' }}</view>
|
||||
<view class="account">账号: {{ userInfo && userInfo.account ? userInfo.account : '未登录' }}</view>
|
||||
<view class="edit-profile-btn" @click="editProfile">
|
||||
编辑资料
|
||||
</view>
|
||||
@@ -74,6 +74,8 @@
|
||||
|
||||
<script>
|
||||
import CustomTabBar from '@/components/CustomTabBar.vue'
|
||||
import Auth from '@/utils/auth'
|
||||
import { getUserInfo, logout } from '@/api/user'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -81,28 +83,48 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userInfo: {
|
||||
avatar: null,
|
||||
username: '卡若',
|
||||
account: '84675209'
|
||||
}
|
||||
userInfo: null
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
// 每次显示页面时获取最新的用户信息
|
||||
this.getUserInfo();
|
||||
},
|
||||
onLoad() {
|
||||
// 检查登录状态
|
||||
if (!Auth.isLogin()) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
this.getUserInfo();
|
||||
},
|
||||
methods: {
|
||||
// 获取用户信息
|
||||
getUserInfo() {
|
||||
// 这里可以添加获取用户信息的API调用
|
||||
console.log('获取用户信息');
|
||||
// 示例数据,实际应从API获取
|
||||
this.userInfo = {
|
||||
avatar: 'https://images.unsplash.com/photo-1568602471122-7832951cc4c5?w=400&h=400&auto=format&fit=crop',
|
||||
username: '卡若',
|
||||
account: '84675209'
|
||||
};
|
||||
// 先从本地缓存获取
|
||||
const cachedUserInfo = Auth.getUserInfo();
|
||||
if (cachedUserInfo) {
|
||||
this.userInfo = cachedUserInfo;
|
||||
}
|
||||
|
||||
// 同时从服务器获取最新信息
|
||||
getUserInfo().then(res => {
|
||||
if (res.code === 200) {
|
||||
this.userInfo = res.data;
|
||||
// 更新本地缓存
|
||||
Auth.setUserInfo(res.data);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取用户信息失败:', err);
|
||||
// 如果获取失败但有缓存,使用缓存数据
|
||||
if (!this.userInfo) {
|
||||
this.userInfo = Auth.getUserInfo();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到设置页面
|
||||
@@ -140,14 +162,22 @@ export default {
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 清除登录状态
|
||||
// uni.removeStorageSync('token');
|
||||
// uni.removeStorageSync('userInfo');
|
||||
// 直接清除本地保存的登录信息
|
||||
Auth.removeAll();
|
||||
|
||||
// 显示退出成功提示
|
||||
uni.showToast({
|
||||
title: '退出成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
|
||||
// 跳转到登录页面
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -178,7 +208,9 @@ export default {
|
||||
z-index: 999;
|
||||
|
||||
.title {
|
||||
font-size: 40rpx;
|
||||
font-size: 45rpx;
|
||||
font-weight: bold;
|
||||
color: #2664ec;
|
||||
}
|
||||
|
||||
.header-icons {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* 认证相关工具函数
|
||||
*/
|
||||
import { refreshToken } from '@/api/user';
|
||||
|
||||
const TOKEN_KEY = 'token';
|
||||
const TOKEN_EXPIRES_KEY = 'token_expires';
|
||||
@@ -67,6 +68,28 @@ function removeAll() {
|
||||
removeUserInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新Token
|
||||
* @returns {Promise} 刷新结果
|
||||
*/
|
||||
function refreshTokenAsync() {
|
||||
return new Promise((resolve, reject) => {
|
||||
refreshToken()
|
||||
.then(res => {
|
||||
if (res.code === 200) {
|
||||
// 更新Token
|
||||
setToken(res.data.token, res.data.token_expired - Math.floor(Date.now() / 1000));
|
||||
resolve(res);
|
||||
} else {
|
||||
reject(res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否已登录
|
||||
* @returns {boolean} 是否已登录
|
||||
@@ -84,6 +107,24 @@ function isLogin() {
|
||||
return nowTime < expiresTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户类型
|
||||
* @returns {number} 用户类型ID
|
||||
*/
|
||||
function getUserType() {
|
||||
const userInfo = getUserInfo();
|
||||
return userInfo ? userInfo.typeId || 0 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为管理员
|
||||
* @returns {boolean} 是否为管理员
|
||||
*/
|
||||
function isAdmin() {
|
||||
const userInfo = getUserInfo();
|
||||
return userInfo ? !!userInfo.isAdmin : false;
|
||||
}
|
||||
|
||||
export default {
|
||||
setToken,
|
||||
getToken,
|
||||
@@ -92,5 +133,8 @@ export default {
|
||||
getUserInfo,
|
||||
removeUserInfo,
|
||||
removeAll,
|
||||
isLogin
|
||||
isLogin,
|
||||
refreshToken: refreshTokenAsync,
|
||||
getUserType,
|
||||
isAdmin
|
||||
};
|
||||
@@ -1,9 +1,7 @@
|
||||
import Auth from './auth';
|
||||
|
||||
// 服务器地址
|
||||
const BASE_URL = process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:8080'
|
||||
: 'https://api.example.com';
|
||||
const BASE_URL = process.env.VUE_APP_BASE_API || 'http://yishi.com';
|
||||
|
||||
// 请求超时时间
|
||||
const TIMEOUT = 10000;
|
||||
@@ -17,7 +15,7 @@ function requestInterceptor(config) {
|
||||
// 获取 token
|
||||
const token = uni.getStorageSync('token');
|
||||
|
||||
// 如果有 token,则带上请求头
|
||||
// 如果有 token,则带上请求头 Authorization: Bearer + token
|
||||
if (token) {
|
||||
config.header = {
|
||||
...config.header,
|
||||
@@ -39,11 +37,8 @@ function requestInterceptor(config) {
|
||||
function responseInterceptor(response) {
|
||||
// 未登录或token失效 - 取消登录拦截
|
||||
if (response.data.code === 401) {
|
||||
// 只在控制台打印信息,不进行拦截
|
||||
console.log('登录已过期,但不进行拦截');
|
||||
console.log('登录已过期,需要重新登录');
|
||||
|
||||
/*
|
||||
// 以下代码已注释,取消登录拦截
|
||||
// 清除登录信息
|
||||
Auth.removeToken();
|
||||
Auth.removeUserInfo();
|
||||
@@ -54,29 +49,43 @@ function responseInterceptor(response) {
|
||||
});
|
||||
|
||||
return Promise.reject(new Error('登录已过期,请重新登录'));
|
||||
*/
|
||||
|
||||
// 直接返回响应,不拦截
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// token需要刷新 - 取消登录拦截
|
||||
// token需要刷新 - 410 状态码
|
||||
if (response.data.code === 410) {
|
||||
// 只在控制台打印信息,不进行拦截
|
||||
console.log('Token需要刷新,但不进行拦截');
|
||||
|
||||
/*
|
||||
// 以下代码已注释,取消登录拦截
|
||||
// 处理token刷新逻辑,这里简化处理
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
|
||||
return Promise.reject(new Error('登录已过期,请重新登录'));
|
||||
*/
|
||||
|
||||
// 直接返回响应,不拦截
|
||||
return response.data;
|
||||
// 尝试刷新 token
|
||||
return Auth.refreshToken()
|
||||
.then(res => {
|
||||
if (res.code === 200) {
|
||||
// 更新本地token
|
||||
Auth.setToken(res.data.token, res.data.token_expired - Math.floor(Date.now() / 1000));
|
||||
|
||||
// 使用新token重试原请求
|
||||
const config = response.config;
|
||||
config.header.Authorization = `Bearer ${res.data.token}`;
|
||||
|
||||
// 重新发起请求
|
||||
return request(config);
|
||||
} else {
|
||||
// 刷新失败,跳转到登录页
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
return Promise.reject(new Error('登录已过期,请重新登录'));
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('刷新token失败', err);
|
||||
// 清除登录信息
|
||||
Auth.removeToken();
|
||||
Auth.removeUserInfo();
|
||||
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
return Promise.reject(new Error('登录已过期,请重新登录'));
|
||||
});
|
||||
}
|
||||
|
||||
return response.data;
|
||||
|
||||
@@ -110,9 +110,14 @@ class User extends Model
|
||||
$user->lastLoginTime = time();
|
||||
$user->save();
|
||||
|
||||
// 用手机号当做默认用户名(如果没有设置用户名)
|
||||
$username = $user->username ?: $user->account;
|
||||
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'username' => $username,
|
||||
'account' => $user->account,
|
||||
'avatar' => $user->avatar,
|
||||
'isAdmin' => $user->isAdmin,
|
||||
'companyId' => $user->companyId,
|
||||
'typeId' => $user->typeId,
|
||||
@@ -137,14 +142,21 @@ class User extends Model
|
||||
return null;
|
||||
}
|
||||
|
||||
// 用手机号当做默认用户名(如果没有设置用户名)
|
||||
$username = $user->username ?: $user->account;
|
||||
// 默认头像地址
|
||||
$avatar = $user->avatar ?: '';
|
||||
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'username' => $username,
|
||||
'account' => $user->account,
|
||||
'avatar' => $avatar,
|
||||
'isAdmin' => $user->isAdmin,
|
||||
'companyId' => $user->companyId,
|
||||
'typeId' => $user->typeId,
|
||||
'role' => $user->isAdmin ? 'admin' : 'user',
|
||||
'permissions' => $user->isAdmin ? ['*'] : ['user']
|
||||
'lastLoginIp' => $user->lastLoginIp,
|
||||
'lastLoginTime' => $user->lastLoginTime
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user