添加登录、注册、重置密码、谷歌验证码处理中
This commit is contained in:
69
power_leasing/src/api/verification.js
Normal file
69
power_leasing/src/api/verification.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import request from '../utils/request'
|
||||
|
||||
//获取谷歌验证器二维码和密钥
|
||||
export function getBindInfo(data) {
|
||||
return request({
|
||||
url: `/lease/auth/getBindInfo`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//绑定谷歌验证码
|
||||
export function bindGoogle(data) {
|
||||
return request({
|
||||
url: `/lease/auth/bindGoogle`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//开启谷歌验证器 发送邮箱验证码
|
||||
export function sendOpenGoogleCode(data) {
|
||||
return request({
|
||||
url: `/lease/auth/sendOpenGoogleCode`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//关闭双重验证
|
||||
export function closeStepTwo(data) {
|
||||
return request({
|
||||
url: `/lease/auth/closeStepTwo`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//关闭谷歌验证器 发送邮箱验证码
|
||||
export function sendCloseGoogleCode(data) {
|
||||
return request({
|
||||
url: `/lease/auth/sendCloseGoogleCode`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
//谷歌验证开启状态
|
||||
export function getGoogleStatus(data) {
|
||||
return request({
|
||||
url: `/lease/auth/getGoogleStatus`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//开启谷歌验证
|
||||
export function openStepTwo(data) {
|
||||
return request({
|
||||
url: `/lease/auth/openStepTwo`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -75,7 +75,9 @@ export default {
|
||||
cartServerCount: 0,
|
||||
navigation: mainNavigation,
|
||||
// 用户邮箱
|
||||
userEmail: ''
|
||||
userEmail: '',
|
||||
// 登录状态(改为 data 属性,支持响应式更新)
|
||||
isLoggedIn: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -87,15 +89,12 @@ export default {
|
||||
// 计算面包屑导航
|
||||
breadcrumbs() {
|
||||
return getBreadcrumb(this.$route.path)
|
||||
},
|
||||
// 判断是否已登录(检查localStorage中是否有token)
|
||||
isLoggedIn() {
|
||||
const token = JSON.parse(localStorage.getItem('leasToken'))
|
||||
return !!token // 有token就是已登录,没有就是未登录
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
mounted() {
|
||||
// 初始化登录状态
|
||||
this.updateLoginStatus()
|
||||
this.loadCart()
|
||||
// 监听购物车变化
|
||||
window.addEventListener('storage', this.handleStorageChange)
|
||||
@@ -103,12 +102,15 @@ export default {
|
||||
this.loadServerCartCount()
|
||||
// 监听应用内购物车更新事件
|
||||
window.addEventListener('cart-updated', this.handleCartUpdated)
|
||||
// 监听登录状态变化事件(当 token 被清除时触发)
|
||||
window.addEventListener('login-status-changed', this.handleLoginStatusChanged)
|
||||
// 加载用户信息(邮箱)
|
||||
this.loadUserEmail()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('storage', this.handleStorageChange)
|
||||
window.removeEventListener('cart-updated', this.handleCartUpdated)
|
||||
window.removeEventListener('login-status-changed', this.handleLoginStatusChanged)
|
||||
},
|
||||
methods: {
|
||||
loadCart() {
|
||||
@@ -151,6 +153,38 @@ export default {
|
||||
if (event.key === 'power_leasing_cart_v1') {
|
||||
this.loadCart()
|
||||
this.loadServerCartCount()
|
||||
} else if (event.key === 'leasToken') {
|
||||
// 当 token 变化时,更新登录状态
|
||||
this.updateLoginStatus()
|
||||
// 如果 token 被清除,同时清除用户信息
|
||||
if (!event.newValue) {
|
||||
this.userEmail = ''
|
||||
} else {
|
||||
this.loadUserEmail()
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 处理登录状态变化事件
|
||||
*/
|
||||
handleLoginStatusChanged() {
|
||||
this.updateLoginStatus()
|
||||
// 如果未登录,清除用户信息
|
||||
if (!this.isLoggedIn) {
|
||||
this.userEmail = ''
|
||||
} else {
|
||||
this.loadUserEmail()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 更新登录状态
|
||||
*/
|
||||
updateLoginStatus() {
|
||||
try {
|
||||
const token = localStorage.getItem('leasToken')
|
||||
this.isLoggedIn = !!token && token !== 'null' && token !== 'undefined'
|
||||
} catch (e) {
|
||||
this.isLoggedIn = false
|
||||
}
|
||||
},
|
||||
handleCartUpdated(event) {
|
||||
@@ -207,11 +241,17 @@ export default {
|
||||
localStorage.removeItem('userId')
|
||||
localStorage.removeItem('username')
|
||||
|
||||
// 更新登录状态
|
||||
this.updateLoginStatus()
|
||||
|
||||
// 清空购物车
|
||||
this.user = null
|
||||
this.cart = []
|
||||
this.userEmail = ''
|
||||
|
||||
// 触发登录状态变化事件
|
||||
window.dispatchEvent(new CustomEvent('login-status-changed'))
|
||||
|
||||
// 提示用户
|
||||
this.$message.success('退出登录成功')
|
||||
|
||||
|
||||
@@ -16,8 +16,11 @@ Vue.config.productionTip = false
|
||||
Vue.use(ElementUI);
|
||||
// 初始化全局防表情拦截器
|
||||
initNoEmojiGuard();
|
||||
new Vue({
|
||||
const vm = new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
|
||||
// 将 Vue 实例挂载到 window 上,供 request.js 等工具使用
|
||||
window.vm = vm
|
||||
|
||||
@@ -213,6 +213,16 @@ export const accountRoutes = [
|
||||
allAuthority: ['all']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'purchased-machine-detail/:id',
|
||||
name: 'purchasedMachineDetail',
|
||||
component: () => import('../views/account/purchasedMachineDetail.vue'),
|
||||
meta: {
|
||||
title: '已购商品详情',
|
||||
description: '查看已购买商品的详细信息',
|
||||
allAuthority: ['all']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'funds-flow',
|
||||
name: 'accountFundsFlow',
|
||||
@@ -282,6 +292,16 @@ export const accountRoutes = [
|
||||
description: '为商品添加出售机器',
|
||||
allAuthority: ['all']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'security-settings',
|
||||
name: 'accountSecuritySettings',
|
||||
component: () => import('../views/account/securitySettings.vue'),
|
||||
meta: {
|
||||
title: '安全设置',
|
||||
description: '管理账户安全选项',
|
||||
allAuthority: ['all']
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -276,28 +276,67 @@ service.interceptors.response.use(res => {
|
||||
if (code === 421) {
|
||||
localStorage.setItem('cs_disconnect_all', Date.now().toString()); //告知客服页面断开连接
|
||||
localStorage.removeItem('leasToken')
|
||||
// 触发登录状态变化事件,通知头部组件更新
|
||||
window.dispatchEvent(new CustomEvent('login-status-changed'))
|
||||
// 系统状态已过期,请重新点击SUPPORT按钮进入
|
||||
superReportError = localStorage.getItem('superReportError')
|
||||
if (!superReportError) {
|
||||
superReportError = 421
|
||||
localStorage.setItem('superReportError', superReportError)
|
||||
MessageBox.confirm(window.vm.$i18n.t(`user.loginExpired`), window.vm.$i18n.t(`user.overduePrompt`), {
|
||||
|
||||
// 获取 i18n 文本,如果 window.vm 不存在则使用默认中文
|
||||
const getText = (key, defaultValue) => {
|
||||
if (window.vm && window.vm.$i18n) {
|
||||
return window.vm.$i18n.t(key) || defaultValue
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// 获取路由跳转路径
|
||||
const getLoginPath = () => {
|
||||
if (window.vm && window.vm.$i18n && window.vm.$i18n.locale) {
|
||||
return `/${window.vm.$i18n.locale}/login`
|
||||
}
|
||||
return '/login'
|
||||
}
|
||||
|
||||
const getHomePath = () => {
|
||||
if (window.vm && window.vm.$i18n && window.vm.$i18n.locale) {
|
||||
return `/${window.vm.$i18n.locale}/`
|
||||
}
|
||||
return '/'
|
||||
}
|
||||
|
||||
MessageBox.confirm(
|
||||
getText('user.loginExpired', '登录状态已过期'),
|
||||
getText('user.overduePrompt', '您的登录状态已过期,请重新登录'),
|
||||
{
|
||||
distinguishCancelAndClose: true,
|
||||
confirmButtonText: window.vm.$i18n.t(`user.login`),
|
||||
cancelButtonText: window.vm.$i18n.t(`user.Home`),
|
||||
// showCancelButton: false, // 隐藏取消按钮
|
||||
confirmButtonText: getText('user.login', '登录'),
|
||||
cancelButtonText: getText('user.Home', '返回首页'),
|
||||
closeOnClickModal: false, // 点击空白处不关闭对话框
|
||||
showClose: false, // 隐藏关闭按钮
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
window.vm.$router.push(`/${window.vm.$i18n.locale}/login`)
|
||||
// 跳转到登录页
|
||||
if (window.vm && window.vm.$router) {
|
||||
window.vm.$router.push(getLoginPath())
|
||||
} else {
|
||||
window.location.href = getLoginPath()
|
||||
}
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('superReportError')
|
||||
}).catch(() => {
|
||||
window.vm.$router.push(`/${window.vm.$i18n.locale}/`)
|
||||
// 跳转到首页
|
||||
if (window.vm && window.vm.$router) {
|
||||
window.vm.$router.push(getHomePath())
|
||||
} else {
|
||||
window.location.href = getHomePath()
|
||||
}
|
||||
localStorage.removeItem('leasToken')
|
||||
localStorage.removeItem('superReportError')
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -208,7 +208,8 @@ export default {
|
||||
items: { type: Array, default: () => [] },
|
||||
emptyText: { type: String, default: '暂无数据' },
|
||||
showCheckout: { type: Boolean, default: false },
|
||||
onCancel: { type: Function, default: null }
|
||||
onCancel: { type: Function, default: null },
|
||||
isSeller: { type: Boolean, default: false } // 标识是否是卖家订单
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -310,7 +311,20 @@ export default {
|
||||
});
|
||||
return
|
||||
}
|
||||
try { this.$router.push(`/account/order-detail/${id}`) } catch (e) {
|
||||
try {
|
||||
// 判断是买家还是卖家订单,传递 from 参数
|
||||
const from = this.isSeller ? 'seller' : 'buyer'
|
||||
// 保存到 sessionStorage,以便详情页可以读取
|
||||
try {
|
||||
sessionStorage.setItem('orderDetailFrom', from)
|
||||
} catch (e) {
|
||||
console.warn('保存订单来源失败', e)
|
||||
}
|
||||
this.$router.push({
|
||||
path: `/account/order-detail/${id}`,
|
||||
query: { from: from }
|
||||
})
|
||||
} catch (e) {
|
||||
this.$message({
|
||||
message: '无法跳转到详情页',
|
||||
type: 'error',
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<h2 class="title">已售出订单</h2>
|
||||
<el-tabs v-model="active" @tab-click="handleTabClick">
|
||||
<el-tab-pane label="订单进行中" name="7">
|
||||
<order-list :items="orders[7]" :show-checkout="false" empty-text="暂无进行中的订单" />
|
||||
<order-list :items="orders[7]" :show-checkout="false" :is-seller="true" empty-text="暂无进行中的订单" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="订单已完成" name="8">
|
||||
<order-list :items="orders[8]" :show-checkout="false" empty-text="暂无已完成的订单" />
|
||||
<order-list :items="orders[8]" :show-checkout="false" :is-seller="true" empty-text="暂无已完成的订单" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
@@ -68,6 +68,7 @@ export default {
|
||||
// { label: '充值记录', to: '/account/rechargeRecord' },
|
||||
// { label: '提现记录', to: '/account/withdrawalHistory' },
|
||||
{ label: '资金流水', to: '/account/funds-flow' },
|
||||
{ label: '安全设置', to: '/account/security-settings' },
|
||||
],
|
||||
// 卖家侧导航
|
||||
sellerLinks: [
|
||||
@@ -76,7 +77,7 @@ export default {
|
||||
{ label: '商品列表', to: '/account/products' },
|
||||
{ label: '已售出订单', to: '/account/seller-orders' },
|
||||
{ label: '资金流水', to: '/account/seller-funds-flow' },
|
||||
|
||||
{ label: '安全设置', to: '/account/security-settings' },
|
||||
],
|
||||
}
|
||||
},
|
||||
@@ -140,13 +141,15 @@ export default {
|
||||
setActiveRoleByRoute() {
|
||||
const path = (this.$route && this.$route.path) || ''
|
||||
// 详情页:根据来源 from=buyer/seller 判定(优先 query,其次 sessionStorage)
|
||||
// 如果未指定 from,默认使用买家分组(因为订单详情页默认高亮订单列表)
|
||||
if (path.indexOf('/account/order-detail') === 0) {
|
||||
const qFrom = (this.$route && this.$route.query && this.$route.query.from) || ''
|
||||
let from = qFrom
|
||||
if (!from) {
|
||||
try { from = sessionStorage.getItem('orderDetailFrom') || '' } catch (e) { from = '' }
|
||||
}
|
||||
const role = from === 'buyer' ? 'buyer' : (from === 'seller' ? 'seller' : this.activeRole)
|
||||
// 如果明确指定了 from=seller,使用卖家分组;否则默认使用买家分组
|
||||
const role = from === 'seller' ? 'seller' : 'buyer'
|
||||
if (this.activeRole !== role) {
|
||||
this.activeRole = role
|
||||
try { localStorage.setItem('accountActiveRole', JSON.stringify(role)) } catch (e) {}
|
||||
@@ -175,6 +178,10 @@ export default {
|
||||
'/account/withdraw-record',
|
||||
'/account/shop-config'
|
||||
]
|
||||
// 安全设置页面买家和卖家都可见,不参与分组判断
|
||||
if (path === '/account/security-settings') {
|
||||
return
|
||||
}
|
||||
const shouldBuyer = buyerPrefixes.some(p => path.indexOf(p) === 0)
|
||||
const shouldSeller = sellerPrefixes.some(p => path.indexOf(p) === 0)
|
||||
const role = shouldBuyer ? 'buyer' : (shouldSeller ? 'seller' : this.activeRole)
|
||||
@@ -186,7 +193,7 @@ export default {
|
||||
/**
|
||||
* 判断左侧导航项是否高亮
|
||||
* - 普通路径完全匹配
|
||||
* - “已售出订单”需同时匹配详情页 /account/order-detail/:id
|
||||
* - "已售出订单"需同时匹配详情页 /account/order-detail/:id
|
||||
*/
|
||||
isActiveLink(pathLike) {
|
||||
const current = (this.$route && this.$route.path) || ''
|
||||
@@ -198,9 +205,10 @@ export default {
|
||||
if (!from) {
|
||||
try { from = sessionStorage.getItem('orderDetailFrom') || '' } catch (e) { from = '' }
|
||||
}
|
||||
if (from === 'buyer' && pathLike === '/account/orders') return true
|
||||
// 如果明确指定了 from=seller,高亮卖家订单列表
|
||||
if (from === 'seller' && pathLike === '/account/seller-orders') return true
|
||||
// 兜底:不匹配
|
||||
// 默认高亮买家订单列表(包括 from=buyer 或未指定 from 的情况)
|
||||
if (pathLike === '/account/orders') return true
|
||||
return false
|
||||
}
|
||||
// 列表-详情联动高亮映射
|
||||
|
||||
@@ -772,7 +772,7 @@ export default {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('修改配置失败', e)
|
||||
this.$message.error('修改配置失败,请重试')
|
||||
|
||||
}
|
||||
},
|
||||
removeSelectedCoin(labelUpper) {
|
||||
|
||||
@@ -675,7 +675,7 @@ export default {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("加载币种列表失败", e);
|
||||
this.$message.error("加载币种列表失败,请稍后重试");
|
||||
|
||||
} finally {
|
||||
this.loadingCoins = false;
|
||||
}
|
||||
@@ -734,7 +734,7 @@ export default {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`加载币种 ${coin} 的算法列表失败`, e);
|
||||
this.$message.error(`加载算法列表失败,请稍后重试`);
|
||||
|
||||
// 设置空数组,避免重复请求
|
||||
this.$set(this.algoOptionsMap, coin, []);
|
||||
} finally {
|
||||
|
||||
@@ -1319,7 +1319,7 @@ export default {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新失败', error)
|
||||
this.$message.error('修改失败')
|
||||
|
||||
} finally {
|
||||
this.editDialog.saving = false
|
||||
}
|
||||
|
||||
@@ -249,14 +249,22 @@ export default {
|
||||
* @param {Object} row - 行数据
|
||||
*/
|
||||
handleViewDetail(row) {
|
||||
console.log('查看详情,行数据:', row) // 调试用
|
||||
// 跳转到详情页面,传递行数据的ID
|
||||
const id = row.id || row.productMachineId || row.machineId
|
||||
console.log('提取的ID:', id) // 调试用
|
||||
if (id) {
|
||||
try {
|
||||
this.$router.push({
|
||||
name: 'purchasedMachineDetail',
|
||||
params: { id: id }
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('路由跳转失败:', e)
|
||||
this.$message.error('跳转失败,请稍后重试')
|
||||
}
|
||||
} else {
|
||||
console.warn('行数据中缺少ID字段:', row) // 调试用
|
||||
this.$message.warning('无法获取详情,缺少ID信息')
|
||||
}
|
||||
},
|
||||
|
||||
1165
power_leasing/src/views/account/securitySettings.vue
Normal file
1165
power_leasing/src/views/account/securitySettings.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -278,7 +278,7 @@
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送验证码失败:', error)
|
||||
this.$message.error('发送验证码失败,请重试')
|
||||
this.$message.error(error.message || '发送验证码失败,请重试')
|
||||
} finally {
|
||||
this.sendingCode = false
|
||||
}
|
||||
@@ -353,7 +353,17 @@
|
||||
}
|
||||
localStorage.setItem('userInfo', JSON.stringify(userInfo))
|
||||
localStorage.setItem('leasEmail', this.loginForm.email)
|
||||
this.$message.success('登录成功')
|
||||
|
||||
// 触发登录状态变化事件,通知头部组件更新
|
||||
window.dispatchEvent(new CustomEvent('login-status-changed'))
|
||||
|
||||
|
||||
this.$message({
|
||||
message: '登录成功',
|
||||
type: 'success',
|
||||
duration: 3000,
|
||||
showClose: true
|
||||
})
|
||||
|
||||
// 跳转到首页或者来源页面
|
||||
const redirect = this.$route.query.redirect || '/productList'
|
||||
|
||||
@@ -371,7 +371,7 @@ export default {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送验证码失败:', error)
|
||||
this.$message.error('发送验证码失败,请重试')
|
||||
this.$message.error(error.message || '发送验证码失败,请重试')
|
||||
} finally {
|
||||
this.sendingCode = false
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ export default {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送验证码失败:', error)
|
||||
this.$message.error('发送验证码失败,请重试')
|
||||
this.$message.error(error.message || '发送验证码失败,请重试')
|
||||
} finally {
|
||||
this.sendingCode = false
|
||||
}
|
||||
|
||||
Binary file not shown.
1
power_leasing/test/css/app.395f1e08.css
Normal file
1
power_leasing/test/css/app.395f1e08.css
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>power_leasing</title><script defer="defer" src="/js/chunk-vendors.d698a8ca.js"></script><script defer="defer" src="/js/app.58e678d6.js"></script><link href="/css/chunk-vendors.10dd4e95.css" rel="stylesheet"><link href="/css/app.262a57c7.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but power_leasing doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>power_leasing</title><script defer="defer" src="/js/chunk-vendors.4369320b.js"></script><script defer="defer" src="/js/app.cc5f454d.js"></script><link href="/css/chunk-vendors.10dd4e95.css" rel="stylesheet"><link href="/css/app.395f1e08.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but power_leasing doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
2
power_leasing/test/js/app.cc5f454d.js
Normal file
2
power_leasing/test/js/app.cc5f454d.js
Normal file
File diff suppressed because one or more lines are too long
1
power_leasing/test/js/app.cc5f454d.js.map
Normal file
1
power_leasing/test/js/app.cc5f454d.js.map
Normal file
File diff suppressed because one or more lines are too long
43
power_leasing/test/js/chunk-vendors.4369320b.js
Normal file
43
power_leasing/test/js/chunk-vendors.4369320b.js
Normal file
File diff suppressed because one or more lines are too long
1
power_leasing/test/js/chunk-vendors.4369320b.js.map
Normal file
1
power_leasing/test/js/chunk-vendors.4369320b.js.map
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user