8.7更新
This commit is contained in:
parent
cd8e267c30
commit
9d430f08ab
@ -1,7 +1,10 @@
|
|||||||
.news-view-page {
|
.news-view-page {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
overflow-x: hidden;
|
overflow-x: clip;
|
||||||
color: #1f2937;
|
color: #1f2937;
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 78% 18%, rgba(236, 72, 153, 0.07) 0%, rgba(236, 72, 153, 0) 32%),
|
radial-gradient(circle at 78% 18%, rgba(236, 72, 153, 0.07) 0%, rgba(236, 72, 153, 0) 32%),
|
||||||
@ -12,13 +15,15 @@
|
|||||||
.news-shell {
|
.news-shell {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
max-width: 1280px;
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1400px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.orb {
|
.orb {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
filter: blur(110px);
|
filter: blur(110px);
|
||||||
@ -196,6 +201,8 @@
|
|||||||
.news-featured,
|
.news-featured,
|
||||||
.news-item {
|
.news-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
@ -253,11 +260,19 @@
|
|||||||
|
|
||||||
.news-featured-inner {
|
.news-featured-inner {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 2fr;
|
grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
|
||||||
min-height: 180px;
|
align-items: stretch;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-featured-img {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.news-featured-img,
|
|
||||||
.news-item-img {
|
.news-item-img {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -280,6 +295,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
padding: 24px 40px;
|
padding: 24px 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,6 +508,15 @@
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.news-featured-inner {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-featured-img {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
.filter-tabs {
|
.filter-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@ -502,15 +528,10 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.news-featured-inner,
|
|
||||||
.news-grid {
|
.news-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.news-featured-img {
|
|
||||||
height: 220px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-featured-body {
|
.news-featured-body {
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -401,5 +401,59 @@ export default {
|
|||||||
openedDecision: 'The Investment Strategy Agent page has been opened.<br>Anything else you would like to know?',
|
openedDecision: 'The Investment Strategy Agent page has been opened.<br>Anything else you would like to know?',
|
||||||
openedPage: 'The related page has been opened. Anything else you would like to know?'
|
openedPage: 'The related page has been opened. Anything else you would like to know?'
|
||||||
},
|
},
|
||||||
|
loginDialog: {
|
||||||
|
welcomeLogin: 'Welcome',
|
||||||
|
createAccount: 'Create Account',
|
||||||
|
signIn: 'Sign In',
|
||||||
|
signUp: 'Sign Up',
|
||||||
|
signInWithPassword: 'Password',
|
||||||
|
signInWithCode: 'Verification Code',
|
||||||
|
enterAccount: 'Enter account',
|
||||||
|
enterPassword: 'Enter password',
|
||||||
|
enterMobile: 'Enter mobile number',
|
||||||
|
enterVerificationCode: 'Enter verification code',
|
||||||
|
enterAccountName: 'Enter account name',
|
||||||
|
forgotPassword: 'Forgot password?',
|
||||||
|
noAccountSignUp: 'No account? Sign Up',
|
||||||
|
signInNow: 'Sign In',
|
||||||
|
getVerificationCode: 'Get Verification Code',
|
||||||
|
agreePrefix: 'I have read and agree to the ',
|
||||||
|
userAgreement: 'User Agreement',
|
||||||
|
agreeAnd: ' and ',
|
||||||
|
privacyPolicy: 'Privacy Policy',
|
||||||
|
signUpNow: 'Sign Up',
|
||||||
|
hasAccountSignIn: 'Already have an account? Sign In',
|
||||||
|
signingIn: 'Signing in...',
|
||||||
|
signingUp: 'Signing up...',
|
||||||
|
resendCode: 'Resend {seconds}s',
|
||||||
|
mobileRequired: 'Enter mobile number',
|
||||||
|
mobileInvalid: 'Please enter a valid mobile number',
|
||||||
|
accountRequired: 'Enter account',
|
||||||
|
passwordRequired: 'Enter password',
|
||||||
|
codeRequired: 'Enter verification code',
|
||||||
|
accountNameRequired: 'Enter account name',
|
||||||
|
agreeRequired: 'Please read and agree to the agreements first',
|
||||||
|
codeSent: 'Verification code sent',
|
||||||
|
codeSendFail: 'Failed to get verification code',
|
||||||
|
loginFail: 'Sign in failed',
|
||||||
|
loginSuccess: 'Signed in successfully',
|
||||||
|
registerSuccess: 'Registration successful. Please sign in.',
|
||||||
|
registerFail: 'Registration failed',
|
||||||
|
registerRetry: 'Registration failed. Please try again.',
|
||||||
|
resetPassword: 'Reset Password',
|
||||||
|
resetPasswordDesc: 'Verify identity via mobile verification code to set a new password',
|
||||||
|
mobileLabel: 'Mobile Number',
|
||||||
|
newPasswordLabel: 'New Password',
|
||||||
|
verificationCodeLabel: 'Verification Code',
|
||||||
|
enterBoundMobile: 'Enter bound mobile number',
|
||||||
|
enterNewPassword: 'Enter new password',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
confirmReset: 'Confirm Reset',
|
||||||
|
newPasswordRequired: 'Enter new password',
|
||||||
|
getCodeFirst: 'Please get the verification code first',
|
||||||
|
resetSuccess: 'Password reset successfully',
|
||||||
|
resetFail: 'Password reset failed',
|
||||||
|
codeSentCheck: 'Verification code sent. Please check your messages.'
|
||||||
|
},
|
||||||
...autoMessages
|
...autoMessages
|
||||||
}
|
}
|
||||||
|
|||||||
@ -401,5 +401,59 @@ export default {
|
|||||||
openedDecision: '已为您打开投策智能体页面 📊<br>还有其他想了解的吗?',
|
openedDecision: '已为您打开投策智能体页面 📊<br>还有其他想了解的吗?',
|
||||||
openedPage: '已为您打开相关页面。还有其他想了解的吗?'
|
openedPage: '已为您打开相关页面。还有其他想了解的吗?'
|
||||||
},
|
},
|
||||||
|
loginDialog: {
|
||||||
|
welcomeLogin: '欢迎登录',
|
||||||
|
createAccount: '创建账号',
|
||||||
|
signIn: '登录',
|
||||||
|
signUp: '注册',
|
||||||
|
signInWithPassword: '密码登录',
|
||||||
|
signInWithCode: '验证码登录',
|
||||||
|
enterAccount: '请输入账户',
|
||||||
|
enterPassword: '请输入密码',
|
||||||
|
enterMobile: '请输入手机号',
|
||||||
|
enterVerificationCode: '请输入验证码',
|
||||||
|
enterAccountName: '请输入账户名',
|
||||||
|
forgotPassword: '忘记密码?',
|
||||||
|
noAccountSignUp: '没有账号?去注册',
|
||||||
|
signInNow: '立即登录',
|
||||||
|
getVerificationCode: '获取验证码',
|
||||||
|
agreePrefix: '我已阅读并同意',
|
||||||
|
userAgreement: '《用户协议》',
|
||||||
|
agreeAnd: '、',
|
||||||
|
privacyPolicy: '《隐私政策》',
|
||||||
|
signUpNow: '立即注册',
|
||||||
|
hasAccountSignIn: '已有账号?前往登录',
|
||||||
|
signingIn: '登录中...',
|
||||||
|
signingUp: '注册中...',
|
||||||
|
resendCode: '重新发送 {seconds}s',
|
||||||
|
mobileRequired: '请输入手机号',
|
||||||
|
mobileInvalid: '请输入正确的手机号',
|
||||||
|
accountRequired: '请输入账户',
|
||||||
|
passwordRequired: '请输入密码',
|
||||||
|
codeRequired: '请输入验证码',
|
||||||
|
accountNameRequired: '请输入账户名',
|
||||||
|
agreeRequired: '请先阅读并同意相关协议',
|
||||||
|
codeSent: '验证码已发送',
|
||||||
|
codeSendFail: '验证码获取失败',
|
||||||
|
loginFail: '登录失败',
|
||||||
|
loginSuccess: '登录成功',
|
||||||
|
registerSuccess: '注册成功,请登录',
|
||||||
|
registerFail: '注册失败',
|
||||||
|
registerRetry: '注册失败,请重试',
|
||||||
|
resetPassword: '重置密码',
|
||||||
|
resetPasswordDesc: '通过手机号验证码验证身份后设置新密码',
|
||||||
|
mobileLabel: '手机号',
|
||||||
|
newPasswordLabel: '新密码',
|
||||||
|
verificationCodeLabel: '验证码',
|
||||||
|
enterBoundMobile: '请输入绑定手机号',
|
||||||
|
enterNewPassword: '请输入新密码',
|
||||||
|
cancel: '取消',
|
||||||
|
confirmReset: '确认重置',
|
||||||
|
newPasswordRequired: '请输入新密码',
|
||||||
|
getCodeFirst: '请先获取验证码',
|
||||||
|
resetSuccess: '密码重置成功',
|
||||||
|
resetFail: '密码重置失败',
|
||||||
|
codeSentCheck: '验证码已发送,请注意查收。'
|
||||||
|
},
|
||||||
...autoMessages
|
...autoMessages
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import 'xterm/css/xterm.css'
|
|||||||
// import 'lib-flexible/flexible'
|
// import 'lib-flexible/flexible'
|
||||||
|
|
||||||
import '@/styles/index.scss' // global css
|
import '@/styles/index.scss' // global css
|
||||||
|
import '@/assets/less/news/news.less'
|
||||||
|
|
||||||
import globalMixin from '@/mixin/globalMixin'; // 替换为实际的文件路径
|
import globalMixin from '@/mixin/globalMixin'; // 替换为实际的文件路径
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Router from 'vue-router'
|
import Router from 'vue-router'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
import { scheduleHomePageLayoutReset, resetHomePageLayout } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
|
const HOME_ROUTE_RE = /^\/(homePage|ncmatchHome)(\/|$)/
|
||||||
/* Layout */
|
/* Layout */
|
||||||
import Layout from '@/layout'
|
import Layout from '@/layout'
|
||||||
import GpuProduct from '@/views/product/productHome/capitalOnline/productItem/GpuProduct/index.vue'
|
import GpuProduct from '@/views/product/productHome/capitalOnline/productItem/GpuProduct/index.vue'
|
||||||
@ -2618,10 +2621,18 @@ const router = createRouter()
|
|||||||
|
|
||||||
// 在beforeRouteLeave导航守卫中清空面包屑状态
|
// 在beforeRouteLeave导航守卫中清空面包屑状态
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
// 清空面包屑状态的代码
|
if (HOME_ROUTE_RE.test(to.path) || HOME_ROUTE_RE.test(from.path)) {
|
||||||
// store.commit('tagsView/resetBreadcrumbState');
|
resetHomePageLayout()
|
||||||
|
}
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.afterEach((to) => {
|
||||||
|
if (!HOME_ROUTE_RE.test(to.path)) return
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
window.setTimeout(() => scheduleHomePageLayoutReset(), 900)
|
||||||
|
})
|
||||||
|
|
||||||
window.addEventListener('beforeunload', function() {
|
window.addEventListener('beforeunload', function() {
|
||||||
// 清空面包屑状态的代码
|
// 清空面包屑状态的代码
|
||||||
store.commit('tagsView/resetBreadcrumbState')
|
store.commit('tagsView/resetBreadcrumbState')
|
||||||
|
|||||||
140
f/web-kboss/src/styles/home-page-shell.scss
Normal file
140
f/web-kboss/src/styles/home-page-shell.scss
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// 官网 shell:html/body 不滚动,仅 #homeOut 内部纵向滚动,彻底避免 SPA 跳转后 scrollLeft 残留
|
||||||
|
|
||||||
|
html.home-page-shell-active,
|
||||||
|
body.home-page-shell-active {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.home-page-shell-active #app,
|
||||||
|
body.home-page-shell-active #app {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
height: 100% !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell > #topBox,
|
||||||
|
.home-page-shell > #topBox.top-nav,
|
||||||
|
#topBox.top-nav {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
min-width: 0 !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell #homeOut {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
min-height: 0 !important;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
overscroll-behavior-x: none;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .home-route-stage,
|
||||||
|
.home-page-shell .home-router-view {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .home-router-view > * {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .train-page,
|
||||||
|
.home-page-shell .agent-store-page,
|
||||||
|
.home-page-shell .jd-homepage,
|
||||||
|
.home-page-shell .product-service-page,
|
||||||
|
.home-page-shell .news-view-page,
|
||||||
|
.home-page-shell .about-page,
|
||||||
|
.home-page-shell .home-main-page {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .about-page,
|
||||||
|
.home-page-shell .about-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .grid-bg {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .product-service-page.single-product-page {
|
||||||
|
height: auto !important;
|
||||||
|
min-height: calc(100vh - 82px);
|
||||||
|
overflow-y: visible !important;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .nav-container {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .news-shell {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .news-featured-inner {
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
|
||||||
|
align-items: stretch;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .news-featured-body {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .news-featured,
|
||||||
|
.home-page-shell .news-item {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-page-shell .footer {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
182
f/web-kboss/src/utils/resetHomePageLayout.js
Normal file
182
f/web-kboss/src/utils/resetHomePageLayout.js
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
const HOME_SHELL_CLASS = 'home-page-shell-active'
|
||||||
|
const RESET_TARGETS = [
|
||||||
|
'.home-page-shell',
|
||||||
|
'#homeOut',
|
||||||
|
'.home-route-stage',
|
||||||
|
'.home-router-view'
|
||||||
|
]
|
||||||
|
|
||||||
|
let scrollLockBound = false
|
||||||
|
let homeOutObserver = null
|
||||||
|
|
||||||
|
function attachHomeOutScrollListener() {
|
||||||
|
const homeOut = getHomeOut()
|
||||||
|
if (!homeOut || homeOut.dataset.scrollLockBound === '1') return
|
||||||
|
homeOut.dataset.scrollLockBound = '1'
|
||||||
|
homeOut.addEventListener('scroll', lockHomeOutHorizontalScroll, { passive: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enableHomePageBodyScroll() {
|
||||||
|
document.documentElement.classList.add(HOME_SHELL_CLASS)
|
||||||
|
document.body.classList.add(HOME_SHELL_CLASS)
|
||||||
|
bindHomeOutScrollLock()
|
||||||
|
bindHomeOutResizeObserver()
|
||||||
|
attachHomeOutScrollListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disableHomePageBodyScroll() {
|
||||||
|
document.documentElement.classList.remove(HOME_SHELL_CLASS)
|
||||||
|
document.body.classList.remove(HOME_SHELL_CLASS)
|
||||||
|
if (homeOutObserver) {
|
||||||
|
homeOutObserver.disconnect()
|
||||||
|
homeOutObserver = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHomeOut() {
|
||||||
|
return document.getElementById('homeOut')
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHomeScroller() {
|
||||||
|
return getHomeOut() || document.documentElement
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearInlineLayoutStyles(element) {
|
||||||
|
if (!element || !element.style) return
|
||||||
|
element.style.removeProperty('width')
|
||||||
|
element.style.removeProperty('max-width')
|
||||||
|
element.style.removeProperty('min-width')
|
||||||
|
element.style.removeProperty('transform')
|
||||||
|
element.style.removeProperty('margin-left')
|
||||||
|
element.style.removeProperty('left')
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetElementScroll(element, resetVertical = true) {
|
||||||
|
if (!element) return
|
||||||
|
element.scrollLeft = 0
|
||||||
|
if (resetVertical) {
|
||||||
|
element.scrollTop = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetScrollableDescendants(root) {
|
||||||
|
if (!root || !root.querySelectorAll) return
|
||||||
|
root.querySelectorAll('*').forEach((element) => {
|
||||||
|
if (element.scrollLeft) {
|
||||||
|
element.scrollLeft = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function lockHomeOutHorizontalScroll() {
|
||||||
|
const homeOut = getHomeOut()
|
||||||
|
if (!homeOut) return
|
||||||
|
|
||||||
|
if (homeOut.scrollLeft !== 0) {
|
||||||
|
homeOut.scrollLeft = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
resetElementScroll(document.documentElement, false)
|
||||||
|
resetElementScroll(document.body, false)
|
||||||
|
|
||||||
|
if (window.scrollX !== 0) {
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetHomePageLayout(resetVertical = true) {
|
||||||
|
const homeOut = getHomeOut()
|
||||||
|
|
||||||
|
RESET_TARGETS.forEach((selector) => {
|
||||||
|
document.querySelectorAll(selector).forEach((element) => {
|
||||||
|
resetElementScroll(element, resetVertical)
|
||||||
|
clearInlineLayoutStyles(element)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (homeOut) {
|
||||||
|
resetElementScroll(homeOut, resetVertical)
|
||||||
|
clearInlineLayoutStyles(homeOut)
|
||||||
|
resetScrollableDescendants(homeOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
resetElementScroll(document.documentElement, resetVertical)
|
||||||
|
resetElementScroll(document.body, resetVertical)
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
lockHomeOutHorizontalScroll()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scheduleHomePageLayoutReset(resetVertical = true) {
|
||||||
|
attachHomeOutScrollListener()
|
||||||
|
resetHomePageLayout(resetVertical)
|
||||||
|
window.requestAnimationFrame(() => resetHomePageLayout(resetVertical))
|
||||||
|
window.setTimeout(() => resetHomePageLayout(resetVertical), 0)
|
||||||
|
window.setTimeout(() => resetHomePageLayout(resetVertical), 80)
|
||||||
|
window.setTimeout(() => resetHomePageLayout(resetVertical), 200)
|
||||||
|
window.setTimeout(() => resetHomePageLayout(resetVertical), 500)
|
||||||
|
window.setTimeout(() => resetHomePageLayout(resetVertical), 900)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scrollHomeSection(id, offset = 82) {
|
||||||
|
const homeOut = getHomeOut()
|
||||||
|
const element = document.getElementById(id)
|
||||||
|
if (!element) return false
|
||||||
|
|
||||||
|
lockHomeOutHorizontalScroll()
|
||||||
|
|
||||||
|
if (homeOut) {
|
||||||
|
const top = element.getBoundingClientRect().top - homeOut.getBoundingClientRect().top + homeOut.scrollTop - offset
|
||||||
|
homeOut.scrollTo({
|
||||||
|
left: 0,
|
||||||
|
top: Math.max(top, 0),
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const top = element.getBoundingClientRect().top + window.pageYOffset - offset
|
||||||
|
window.scrollTo({
|
||||||
|
left: 0,
|
||||||
|
top: Math.max(top, 0),
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bindHomeOutScrollLock() {
|
||||||
|
if (scrollLockBound) return
|
||||||
|
scrollLockBound = true
|
||||||
|
|
||||||
|
document.addEventListener('scroll', (event) => {
|
||||||
|
if (!document.body.classList.contains(HOME_SHELL_CLASS)) return
|
||||||
|
if (event.target === getHomeOut()) {
|
||||||
|
lockHomeOutHorizontalScroll()
|
||||||
|
}
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
window.addEventListener('resize', () => scheduleHomePageLayoutReset(true), { passive: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bindHomeOutResizeObserver() {
|
||||||
|
if (homeOutObserver || typeof ResizeObserver === 'undefined') return
|
||||||
|
|
||||||
|
homeOutObserver = new ResizeObserver(() => {
|
||||||
|
if (!document.body.classList.contains(HOME_SHELL_CLASS)) return
|
||||||
|
lockHomeOutHorizontalScroll()
|
||||||
|
})
|
||||||
|
|
||||||
|
const observe = () => {
|
||||||
|
const homeOut = getHomeOut()
|
||||||
|
if (homeOut) homeOutObserver.observe(homeOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
observe()
|
||||||
|
window.setTimeout(observe, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const bindHomeHorizontalScrollLock = bindHomeOutScrollLock
|
||||||
|
export const bindHomeOutHorizontalScrollLock = bindHomeOutScrollLock
|
||||||
|
|
||||||
|
export function getHomeScrollContainer() {
|
||||||
|
return getHomeScroller()
|
||||||
|
}
|
||||||
@ -13,31 +13,31 @@
|
|||||||
<div class="brand-area">
|
<div class="brand-area">
|
||||||
|
|
||||||
<div class="brand-text">
|
<div class="brand-text">
|
||||||
<h2>{{ activeTab === 'login' ? '欢迎登录' : '创建账号' }}</h2>
|
<h2>{{ activeTab === 'login' ? $t('loginDialog.welcomeLogin') : $t('loginDialog.createAccount') }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-group">
|
<div class="tab-group">
|
||||||
<button type="button" :class="{ active: activeTab === 'login' }" @click="switchTab('login')">登录</button>
|
<button type="button" :class="{ active: activeTab === 'login' }" @click="switchTab('login')">{{ $t('loginDialog.signIn') }}</button>
|
||||||
<button type="button" :class="{ active: activeTab === 'register' }" @click="switchTab('register')">注册</button>
|
<button type="button" :class="{ active: activeTab === 'register' }" @click="switchTab('register')">{{ $t('loginDialog.signUp') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="activeTab === 'login'" class="form-panel">
|
<div v-if="activeTab === 'login'" class="form-panel">
|
||||||
<div class="mode-tabs">
|
<div class="mode-tabs">
|
||||||
<button type="button" :class="{ active: loginMode === 'password' }" @click="switchLoginMode('password')">密码登录</button>
|
<button type="button" :class="{ active: loginMode === 'password' }" @click="switchLoginMode('password')">{{ $t('loginDialog.signInWithPassword') }}</button>
|
||||||
<button type="button" :class="{ active: loginMode === 'mobile' }" @click="switchLoginMode('mobile')">验证码登录</button>
|
<button type="button" :class="{ active: loginMode === 'mobile' }" @click="switchLoginMode('mobile')">{{ $t('loginDialog.signInWithCode') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form ref="loginForm" :model="loginForm" :rules="activeLoginRules" label-position="top">
|
<el-form ref="loginForm" :model="loginForm" :rules="activeLoginRules" label-position="top">
|
||||||
<template v-if="loginMode === 'password'">
|
<template v-if="loginMode === 'password'">
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input v-model.trim="loginForm.username" placeholder="请输入账户" prefix-icon="el-icon-user" @keyup.enter.native="handleLogin" />
|
<el-input v-model.trim="loginForm.username" :placeholder="$t('loginDialog.enterAccount')" prefix-icon="el-icon-user" @keyup.enter.native="handleLogin" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="loginForm.password"
|
v-model="loginForm.password"
|
||||||
:type="loginPwdVisible ? 'text' : 'password'"
|
:type="loginPwdVisible ? 'text' : 'password'"
|
||||||
placeholder="请输入密码"
|
:placeholder="$t('loginDialog.enterPassword')"
|
||||||
prefix-icon="el-icon-lock"
|
prefix-icon="el-icon-lock"
|
||||||
@keyup.enter.native="handleLogin"
|
@keyup.enter.native="handleLogin"
|
||||||
>
|
>
|
||||||
@ -48,11 +48,11 @@
|
|||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-form-item prop="mobile">
|
<el-form-item prop="mobile">
|
||||||
<el-input v-model.trim="loginForm.mobile" placeholder="请输入手机号" prefix-icon="el-icon-mobile-phone" />
|
<el-input v-model.trim="loginForm.mobile" :placeholder="$t('loginDialog.enterMobile')" prefix-icon="el-icon-mobile-phone" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="vcode">
|
<el-form-item prop="vcode">
|
||||||
<div class="code-row">
|
<div class="code-row">
|
||||||
<el-input v-model.trim="loginForm.vcode" placeholder="请输入验证码" prefix-icon="el-icon-key" @keyup.enter.native="handleLogin" />
|
<el-input v-model.trim="loginForm.vcode" :placeholder="$t('loginDialog.enterVerificationCode')" prefix-icon="el-icon-key" @keyup.enter.native="handleLogin" />
|
||||||
<button type="button" class="code-btn" :disabled="loginCodeDisabled" @click="getLoginCode">{{ loginCodeText }}</button>
|
<button type="button" class="code-btn" :disabled="loginCodeDisabled" @click="getLoginCode">{{ loginCodeText }}</button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -60,36 +60,36 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="text-btn" @click="forgotPasswordVisible = true">忘记密码?</button>
|
<button type="button" class="text-btn" @click="forgotPasswordVisible = true">{{ $t('loginDialog.forgotPassword') }}</button>
|
||||||
<button type="button" class="text-btn" @click="switchTab('register')">没有账号?去注册</button>
|
<button type="button" class="text-btn" @click="switchTab('register')">{{ $t('loginDialog.noAccountSignUp') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="main-btn" :disabled="loginLoading" @click="handleLogin">
|
<button type="button" class="main-btn" :disabled="loginLoading" @click="handleLogin">
|
||||||
{{ loginLoading ? '登录中...' : '立即登录' }}
|
{{ loginLoading ? $t('loginDialog.signingIn') : $t('loginDialog.signInNow') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="form-panel">
|
<div v-else class="form-panel">
|
||||||
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" label-position="top">
|
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" label-position="top">
|
||||||
<el-form-item prop="mobile">
|
<el-form-item prop="mobile">
|
||||||
<el-input v-model.trim="registerForm.mobile" class="phone-input" placeholder="请输入手机号">
|
<el-input v-model.trim="registerForm.mobile" class="phone-input" :placeholder="$t('loginDialog.enterMobile')">
|
||||||
<span slot="prefix" class="country-prefix">+86</span>
|
<span slot="prefix" class="country-prefix">+86</span>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="vcode">
|
<el-form-item prop="vcode">
|
||||||
<div class="code-row">
|
<div class="code-row">
|
||||||
<el-input v-model.trim="registerForm.vcode" placeholder="请输入验证码" prefix-icon="el-icon-key" />
|
<el-input v-model.trim="registerForm.vcode" :placeholder="$t('loginDialog.enterVerificationCode')" prefix-icon="el-icon-key" />
|
||||||
<button type="button" class="code-btn" :disabled="regCodeDisabled" @click="getRegisterCode">{{ regCodeText }}</button>
|
<button type="button" class="code-btn" :disabled="regCodeDisabled" @click="getRegisterCode">{{ regCodeText }}</button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input v-model.trim="registerForm.username" placeholder="请输入账户名" prefix-icon="el-icon-user" />
|
<el-input v-model.trim="registerForm.username" :placeholder="$t('loginDialog.enterAccountName')" prefix-icon="el-icon-user" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="registerForm.password"
|
v-model="registerForm.password"
|
||||||
:type="regPwdVisible ? 'text' : 'password'"
|
:type="regPwdVisible ? 'text' : 'password'"
|
||||||
placeholder="请输入密码"
|
:placeholder="$t('loginDialog.enterPassword')"
|
||||||
prefix-icon="el-icon-lock"
|
prefix-icon="el-icon-lock"
|
||||||
@keyup.enter.native="handleRegister"
|
@keyup.enter.native="handleRegister"
|
||||||
>
|
>
|
||||||
@ -100,19 +100,18 @@
|
|||||||
|
|
||||||
<div class="agreement-wrap">
|
<div class="agreement-wrap">
|
||||||
<el-checkbox v-model="registerForm.agree">
|
<el-checkbox v-model="registerForm.agree">
|
||||||
我已阅读并同意
|
{{ $t('loginDialog.agreePrefix') }}
|
||||||
<a class="agreement-link" :href="getAgreementUrl('user')" target="_blank" rel="noopener noreferrer" @click.stop>《用户协议》</a>
|
<a class="agreement-link" :href="getAgreementUrl('user')" target="_blank" rel="noopener noreferrer" @click.stop>{{ $t('loginDialog.userAgreement') }}</a>
|
||||||
、
|
{{ $t('loginDialog.agreeAnd') }}
|
||||||
<a class="agreement-link" :href="getAgreementUrl('privacy')" target="_blank" rel="noopener noreferrer" @click.stop>《隐私政策》</a>
|
<a class="agreement-link" :href="getAgreementUrl('privacy')" target="_blank" rel="noopener noreferrer" @click.stop>{{ $t('loginDialog.privacyPolicy') }}</a>
|
||||||
|
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="main-btn" :disabled="registerLoading" @click="handleRegister">
|
<button type="button" class="main-btn" :disabled="registerLoading" @click="handleRegister">
|
||||||
{{ registerLoading ? '注册中...' : '立即注册' }}
|
{{ registerLoading ? $t('loginDialog.signingUp') : $t('loginDialog.signUpNow') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="bottom-link" @click="switchTab('login')">已有账号?前往登录</button>
|
<button type="button" class="bottom-link" @click="switchTab('login')">{{ $t('loginDialog.hasAccountSignIn') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -139,12 +138,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
const validatePhone = (rule, value, callback) => {
|
|
||||||
if (!value) callback(new Error('请输入手机号'))
|
|
||||||
else if (!/^1[3-9]\d{9}$/.test(value)) callback(new Error('请输入正确的手机号'))
|
|
||||||
else callback()
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeTab: 'login',
|
activeTab: 'login',
|
||||||
loginMode: 'password',
|
loginMode: 'password',
|
||||||
@ -155,8 +148,8 @@ export default {
|
|||||||
regPwdVisible: false,
|
regPwdVisible: false,
|
||||||
loginCodeDisabled: false,
|
loginCodeDisabled: false,
|
||||||
regCodeDisabled: false,
|
regCodeDisabled: false,
|
||||||
loginCodeText: '获取验证码',
|
loginCodeText: '',
|
||||||
regCodeText: '获取验证码',
|
regCodeText: '',
|
||||||
loginTimer: null,
|
loginTimer: null,
|
||||||
regTimer: null,
|
regTimer: null,
|
||||||
loginCount: 60,
|
loginCount: 60,
|
||||||
@ -178,18 +171,6 @@ export default {
|
|||||||
agree: false,
|
agree: false,
|
||||||
wechat_openid: localStorage.getItem('wechat_openid') || '',
|
wechat_openid: localStorage.getItem('wechat_openid') || '',
|
||||||
domain_name: window.location.hostname
|
domain_name: window.location.hostname
|
||||||
},
|
|
||||||
loginRules: {
|
|
||||||
username: [{ required: true, message: '请输入账户', trigger: 'blur' }],
|
|
||||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
|
||||||
mobile: [{ required: true, validator: validatePhone, trigger: 'blur' }],
|
|
||||||
vcode: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
|
||||||
},
|
|
||||||
registerRules: {
|
|
||||||
mobile: [{ required: true, validator: validatePhone, trigger: 'blur' }],
|
|
||||||
vcode: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
|
||||||
username: [{ required: true, message: '请输入账户名', trigger: 'blur' }],
|
|
||||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -213,13 +194,50 @@ export default {
|
|||||||
username: this.loginRules.username,
|
username: this.loginRules.username,
|
||||||
password: this.loginRules.password
|
password: this.loginRules.password
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
loginRules() {
|
||||||
|
return {
|
||||||
|
username: [{ required: true, message: this.$t('loginDialog.accountRequired'), trigger: 'blur' }],
|
||||||
|
password: [{ required: true, message: this.$t('loginDialog.passwordRequired'), trigger: 'blur' }],
|
||||||
|
mobile: [{ required: true, validator: this.validatePhone, trigger: 'blur' }],
|
||||||
|
vcode: [{ required: true, message: this.$t('loginDialog.codeRequired'), trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
registerRules() {
|
||||||
|
return {
|
||||||
|
mobile: [{ required: true, validator: this.validatePhone, trigger: 'blur' }],
|
||||||
|
vcode: [{ required: true, message: this.$t('loginDialog.codeRequired'), trigger: 'blur' }],
|
||||||
|
username: [{ required: true, message: this.$t('loginDialog.accountNameRequired'), trigger: 'blur' }],
|
||||||
|
password: [{ required: true, message: this.$t('loginDialog.passwordRequired'), trigger: 'blur' }]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
'$i18n.locale'() {
|
||||||
|
this.resetCodeButtonText()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.resetCodeButtonText()
|
||||||
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
clearInterval(this.loginTimer)
|
clearInterval(this.loginTimer)
|
||||||
clearInterval(this.regTimer)
|
clearInterval(this.regTimer)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
validatePhone(rule, value, callback) {
|
||||||
|
if (!value) callback(new Error(this.$t('loginDialog.mobileRequired')))
|
||||||
|
else if (!/^1[3-9]\d{9}$/.test(value)) callback(new Error(this.$t('loginDialog.mobileInvalid')))
|
||||||
|
else callback()
|
||||||
|
},
|
||||||
|
resetCodeButtonText() {
|
||||||
|
if (!this.loginCodeDisabled) {
|
||||||
|
this.loginCodeText = this.$t('loginDialog.getVerificationCode')
|
||||||
|
}
|
||||||
|
if (!this.regCodeDisabled) {
|
||||||
|
this.regCodeText = this.$t('loginDialog.getVerificationCode')
|
||||||
|
}
|
||||||
|
},
|
||||||
handleClose() {
|
handleClose() {
|
||||||
this.loginLoading = false
|
this.loginLoading = false
|
||||||
this.registerLoading = false
|
this.registerLoading = false
|
||||||
@ -284,18 +302,18 @@ export default {
|
|||||||
clearInterval(this[timerKey])
|
clearInterval(this[timerKey])
|
||||||
this[countKey] = 59
|
this[countKey] = 59
|
||||||
this[disabledKey] = true
|
this[disabledKey] = true
|
||||||
this[textKey] = `重新发送 ${this[countKey]}s`
|
this[textKey] = this.$t('loginDialog.resendCode', { seconds: this[countKey] })
|
||||||
this[timerKey] = setInterval(() => {
|
this[timerKey] = setInterval(() => {
|
||||||
if (this[countKey] > 0) {
|
if (this[countKey] > 0) {
|
||||||
this[countKey] -= 1
|
this[countKey] -= 1
|
||||||
this[textKey] = `重新发送 ${this[countKey]}s`
|
this[textKey] = this.$t('loginDialog.resendCode', { seconds: this[countKey] })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clearInterval(this[timerKey])
|
clearInterval(this[timerKey])
|
||||||
this[timerKey] = null
|
this[timerKey] = null
|
||||||
this[countKey] = 60
|
this[countKey] = 60
|
||||||
this[disabledKey] = false
|
this[disabledKey] = false
|
||||||
this[textKey] = '获取验证码'
|
this[textKey] = this.$t('loginDialog.getVerificationCode')
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
getLoginCode() {
|
getLoginCode() {
|
||||||
@ -306,12 +324,12 @@ export default {
|
|||||||
if (res.status) {
|
if (res.status) {
|
||||||
this.loginForm.codeid = res.codeid || (res.data && res.data.codeid) || ''
|
this.loginForm.codeid = res.codeid || (res.data && res.data.codeid) || ''
|
||||||
this.startCountdown('login')
|
this.startCountdown('login')
|
||||||
this.$message.success('验证码已发送')
|
this.$message.success(this.$t('loginDialog.codeSent'))
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg || '验证码获取失败')
|
this.$message.error(res.msg || this.$t('loginDialog.codeSendFail'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error('验证码获取失败')
|
this.$message.error(this.$t('loginDialog.codeSendFail'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -323,12 +341,12 @@ export default {
|
|||||||
if (res.status) {
|
if (res.status) {
|
||||||
this.registerForm.codeid = res.codeid || (res.data && res.data.codeid) || res.data || ''
|
this.registerForm.codeid = res.codeid || (res.data && res.data.codeid) || res.data || ''
|
||||||
this.startCountdown('register')
|
this.startCountdown('register')
|
||||||
this.$message.success('验证码已发送')
|
this.$message.success(this.$t('loginDialog.codeSent'))
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg || '验证码获取失败')
|
this.$message.error(res.msg || this.$t('loginDialog.codeSendFail'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error('验证码获取失败')
|
this.$message.error(this.$t('loginDialog.codeSendFail'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -340,12 +358,12 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const check = await logintypeAPI(loginParams)
|
const check = await logintypeAPI(loginParams)
|
||||||
if (!check.status) {
|
if (!check.status) {
|
||||||
this.$message.error(check.msg || '登录失败')
|
this.$message.error(check.msg || this.$t('loginDialog.loginFail'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const res = await this.$store.dispatch('user/login', loginParams)
|
const res = await this.$store.dispatch('user/login', loginParams)
|
||||||
if (!res.status) {
|
if (!res.status) {
|
||||||
this.$message.error(res.msg || '登录失败')
|
this.$message.error(res.msg || this.$t('loginDialog.loginFail'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,12 +395,12 @@ export default {
|
|||||||
})
|
})
|
||||||
router.addRoutes(accessRoutes)
|
router.addRoutes(accessRoutes)
|
||||||
|
|
||||||
this.$message.success(res.msg || '登录成功')
|
this.$message.success(res.msg || this.$t('loginDialog.loginSuccess'))
|
||||||
this.dialogVisible = false
|
this.dialogVisible = false
|
||||||
this.$emit('success', res)
|
this.$emit('success', res)
|
||||||
this.redirectAfterLogin(res)
|
this.redirectAfterLogin(res)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error((error && error.msg) || '登录失败')
|
this.$message.error((error && error.msg) || this.$t('loginDialog.loginFail'))
|
||||||
} finally {
|
} finally {
|
||||||
this.loginLoading = false
|
this.loginLoading = false
|
||||||
}
|
}
|
||||||
@ -434,7 +452,7 @@ export default {
|
|||||||
},
|
},
|
||||||
handleRegister() {
|
handleRegister() {
|
||||||
if (!this.registerForm.agree) {
|
if (!this.registerForm.agree) {
|
||||||
this.$message.warning('请先阅读并同意相关协议')
|
this.$message.warning(this.$t('loginDialog.agreeRequired'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$refs.registerForm.validate(async valid => {
|
this.$refs.registerForm.validate(async valid => {
|
||||||
@ -454,17 +472,17 @@ export default {
|
|||||||
}
|
}
|
||||||
const res = await register(registerData)
|
const res = await register(registerData)
|
||||||
if (res.status) {
|
if (res.status) {
|
||||||
this.$message.success('注册成功,请登录')
|
this.$message.success(this.$t('loginDialog.registerSuccess'))
|
||||||
this.loginForm.mobile = this.registerForm.mobile
|
this.loginForm.mobile = this.registerForm.mobile
|
||||||
this.switchTab('login')
|
this.switchTab('login')
|
||||||
this.loginMode = 'mobile'
|
this.loginMode = 'mobile'
|
||||||
this.$refs.registerForm.resetFields()
|
this.$refs.registerForm.resetFields()
|
||||||
this.registerForm.agree = false
|
this.registerForm.agree = false
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.message || res.msg || '注册失败')
|
this.$message.error(res.message || res.msg || this.$t('loginDialog.registerFail'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error('注册失败,请重试')
|
this.$message.error(this.$t('loginDialog.registerRetry'))
|
||||||
} finally {
|
} finally {
|
||||||
this.registerLoading = false
|
this.registerLoading = false
|
||||||
}
|
}
|
||||||
@ -628,7 +646,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.form-panel ::v-deep .el-form-item {
|
.form-panel ::v-deep .el-form-item {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-panel ::v-deep .el-form-item__error {
|
.form-panel ::v-deep .el-form-item__error {
|
||||||
|
|||||||
@ -205,8 +205,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { scheduleHomePageLayoutReset } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HomeAbout',
|
name: 'HomeAbout',
|
||||||
|
mounted() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
moveCardGlow(event) {
|
moveCardGlow(event) {
|
||||||
const card = event.currentTarget
|
const card = event.currentTarget
|
||||||
|
|||||||
@ -10,10 +10,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.grid-bg {
|
.grid-bg {
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
margin-left: calc(50% - 50vw);
|
|
||||||
margin-right: calc(50% - 50vw);
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background:
|
background:
|
||||||
linear-gradient(rgba(37, 99, 235, 0.05) 1px, transparent 1px),
|
linear-gradient(rgba(37, 99, 235, 0.05) 1px, transparent 1px),
|
||||||
|
|||||||
@ -87,6 +87,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Talk from '@/views/homePage/dialog/talk/index.vue'
|
import Talk from '@/views/homePage/dialog/talk/index.vue'
|
||||||
|
import { scheduleHomePageLayoutReset } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AgentStore',
|
name: 'AgentStore',
|
||||||
@ -136,6 +137,9 @@ export default {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setMainTab(tab) {
|
setMainTab(tab) {
|
||||||
this.activeMainTab = tab
|
this.activeMainTab = tab
|
||||||
|
|||||||
@ -54,7 +54,13 @@
|
|||||||
<button v-if="!isNcmatchDomain" type="button" class="nav-item" @click.stop="goHomeAnchor('cases-section')">
|
<button v-if="!isNcmatchDomain" type="button" class="nav-item" @click.stop="goHomeAnchor('cases-section')">
|
||||||
{{ $t('topbar.cases') }}
|
{{ $t('topbar.cases') }}
|
||||||
</button>
|
</button>
|
||||||
<button v-if="!isNcmatchDomain" type="button" class="nav-item" @click.stop="goHomeAnchor('news')">
|
<button
|
||||||
|
v-if="!isNcmatchDomain"
|
||||||
|
type="button"
|
||||||
|
class="nav-item"
|
||||||
|
:class="{ active: isActiveNews }"
|
||||||
|
@click.stop="navigateTo('/homePage/news')"
|
||||||
|
>
|
||||||
{{ $t('topbar.news') }}
|
{{ $t('topbar.news') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@ -253,6 +259,7 @@ import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
|
|||||||
import { setLocale } from '@/i18n'
|
import { setLocale } from '@/i18n'
|
||||||
import MessageCenter from '@/components/MessageCenter/MessageCenter.vue'
|
import MessageCenter from '@/components/MessageCenter/MessageCenter.vue'
|
||||||
import LoginDialog from '@/views/LoginDialog/LoginDialog.vue'
|
import LoginDialog from '@/views/LoginDialog/LoginDialog.vue'
|
||||||
|
import { scheduleHomePageLayoutReset, scrollHomeSection } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
const LOCALE_KEY = 'kboss-locale'
|
const LOCALE_KEY = 'kboss-locale'
|
||||||
const SUPPORTED_LOCALES = ['zh-CN', 'en-US']
|
const SUPPORTED_LOCALES = ['zh-CN', 'en-US']
|
||||||
@ -329,6 +336,9 @@ export default Vue.extend({
|
|||||||
? this.$route.path.includes('/ncmatchHome/index')
|
? this.$route.path.includes('/ncmatchHome/index')
|
||||||
: this.$route.path.includes('/homePage/index')
|
: this.$route.path.includes('/homePage/index')
|
||||||
},
|
},
|
||||||
|
isActiveNews() {
|
||||||
|
return this.$route.path.includes('/homePage/news')
|
||||||
|
},
|
||||||
langToggleText() {
|
langToggleText() {
|
||||||
return this.activeLocale === 'en-US' ? 'EN/中' : '中/EN'
|
return this.activeLocale === 'en-US' ? 'EN/中' : '中/EN'
|
||||||
},
|
},
|
||||||
@ -452,8 +462,18 @@ export default Vue.extend({
|
|||||||
// =========================
|
// =========================
|
||||||
navigateTo(path) {
|
navigateTo(path) {
|
||||||
this.closeProductPanelImmediate()
|
this.closeProductPanelImmediate()
|
||||||
if (this.$route.path === path) return
|
this.blurActiveElement()
|
||||||
this.$router.push(path).catch(() => {})
|
if (this.$route.path === path) {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$router.push(path).then(() => {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
blurActiveElement() {
|
||||||
|
const active = document.activeElement
|
||||||
|
if (active && typeof active.blur === 'function') active.blur()
|
||||||
},
|
},
|
||||||
goHome() {
|
goHome() {
|
||||||
this.closeProductPanelImmediate()
|
this.closeProductPanelImmediate()
|
||||||
@ -462,21 +482,27 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
goHomeAnchor(id) {
|
goHomeAnchor(id) {
|
||||||
this.closeProductPanelImmediate()
|
this.closeProductPanelImmediate()
|
||||||
const scrollToTarget = () => {
|
this.blurActiveElement()
|
||||||
const target = document.getElementById(id)
|
const scrollToTarget = (attempt = 0) => {
|
||||||
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
if (scrollHomeSection(id)) return
|
||||||
|
if (attempt < 30) {
|
||||||
|
window.setTimeout(() => scrollToTarget(attempt + 1), 100)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const startScroll = () => window.setTimeout(() => scrollToTarget(), 120)
|
||||||
if (this.$route.path.includes('/homePage/index')) {
|
if (this.$route.path.includes('/homePage/index')) {
|
||||||
this.$nextTick(scrollToTarget)
|
this.$nextTick(startScroll)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$router.push('/homePage/index').then(() => this.$nextTick(scrollToTarget)).catch(() => {})
|
this.$router.push({ path: '/homePage/index', query: { anchor: id } }).catch(() => {})
|
||||||
},
|
},
|
||||||
handleModelSquareClick() {
|
handleModelSquareClick() {
|
||||||
this.closeProductPanelImmediate()
|
this.closeProductPanelImmediate()
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: '/homePage/tokenMarket',
|
path: '/homePage/tokenMarket',
|
||||||
query: { category: 'TOKEN市集', single: '1' }
|
query: { category: 'TOKEN市集', single: '1' }
|
||||||
|
}).then(() => {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
async goYuanjing() {
|
async goYuanjing() {
|
||||||
@ -903,8 +929,19 @@ export default Vue.extend({
|
|||||||
line-height: 82px;
|
line-height: 82px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
outline: none;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
color: #1e6fff;
|
||||||
|
box-shadow: inset 0 -2px 0 #1e6fff;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&.active {
|
&.active {
|
||||||
color: #1e6fff;
|
color: #1e6fff;
|
||||||
|
|||||||
@ -1,12 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="homeOut" class="homeOut">
|
<div class="home-page-shell">
|
||||||
<TopBox id="topBox"></TopBox>
|
<TopBox id="topBox"></TopBox>
|
||||||
|
|
||||||
<div class="home-router-view">
|
<div id="homeOut" class="homeOut">
|
||||||
<router-view></router-view>
|
<div class="home-route-stage">
|
||||||
</div>
|
<div class="home-router-view">
|
||||||
<!-- footer-->
|
<router-view
|
||||||
<div class="footer">
|
:key="$route.fullPath"
|
||||||
|
@hook:mounted="handleChildRouteMounted"
|
||||||
|
@hook:updated="handleChildRouteMounted"
|
||||||
|
></router-view>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- footer-->
|
||||||
|
<div class="footer">
|
||||||
<div class="footer-main">
|
<div class="footer-main">
|
||||||
<div class="footer-brand-col">
|
<div class="footer-brand-col">
|
||||||
<img
|
<img
|
||||||
@ -96,12 +103,20 @@
|
|||||||
<!-- </span>-->
|
<!-- </span>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import TopBox from "@/views/homePage/components/topBox/index.vue";
|
import TopBox from "@/views/homePage/components/topBox/index.vue";
|
||||||
import {mapGetters, mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
|
import '@/styles/home-page-shell.scss'
|
||||||
|
import {
|
||||||
|
disableHomePageBodyScroll,
|
||||||
|
enableHomePageBodyScroll,
|
||||||
|
scheduleHomePageLayoutReset,
|
||||||
|
scrollHomeSection
|
||||||
|
} from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: "indexLast",
|
name: "indexLast",
|
||||||
@ -247,21 +262,40 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
enableHomePageBodyScroll()
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
disableHomePageBodyScroll()
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route.fullPath'() {
|
'$route.fullPath'() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.scrollHomeToTop()
|
const anchor = this.$route.query.anchor
|
||||||
window.setTimeout(this.scrollHomeToTop, 0)
|
if (anchor && this.$route.path.includes('/homePage/index')) {
|
||||||
|
window.setTimeout(() => {
|
||||||
|
scrollHomeSection(anchor)
|
||||||
|
}, 120)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleChildRouteMounted() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetHomeLayout() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
scrollHomeToTop() {
|
scrollHomeToTop() {
|
||||||
const container = this.$el
|
scheduleHomePageLayoutReset()
|
||||||
if (container) container.scrollTop = 0
|
|
||||||
window.scrollTo(0, 0)
|
|
||||||
document.documentElement.scrollTop = 0
|
|
||||||
document.body.scrollTop = 0
|
|
||||||
},
|
},
|
||||||
goOut(url){
|
goOut(url){
|
||||||
window.open(url)
|
window.open(url)
|
||||||
@ -271,13 +305,7 @@ export default Vue.extend({
|
|||||||
this.$router.push(path)
|
this.$router.push(path)
|
||||||
},
|
},
|
||||||
scrollToElement(id) {
|
scrollToElement(id) {
|
||||||
const element = document.getElementById(id);
|
scrollHomeSection(id)
|
||||||
if (element) {
|
|
||||||
element.scrollIntoView({
|
|
||||||
behavior: 'smooth', // 平滑滚动
|
|
||||||
block: 'start', // 滚动到顶部对齐(可选:'start', 'center', 'end', 'nearest')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
clickBaseMenu(menu) {
|
clickBaseMenu(menu) {
|
||||||
console.log("emnu", menu)
|
console.log("emnu", menu)
|
||||||
@ -333,43 +361,67 @@ export default Vue.extend({
|
|||||||
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.homeOut {
|
.home-page-shell {
|
||||||
//padding-top: 60px;
|
display: flex;
|
||||||
height: 100%;
|
flex-direction: column;
|
||||||
overflow: auto !important;
|
width: 100%;
|
||||||
min-width: 1500px;
|
height: 100vh;
|
||||||
// background: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%);
|
height: 100dvh;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#topBox{
|
|
||||||
// height: 82px;
|
.homeOut {
|
||||||
background: transparent!important;
|
flex: 1 1 auto;
|
||||||
background-color: transparent!important;
|
width: 100%;
|
||||||
box-shadow: none!important;
|
min-width: 0;
|
||||||
border: 0!important;
|
min-height: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-route-stage {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#topBox {
|
||||||
|
background: transparent !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-router-view {
|
.home-router-view {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 38px 0 22px;
|
padding: 38px 0 22px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
background: #f1f3f7;
|
background: #f1f3f7;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-main {
|
.footer-main {
|
||||||
width: 1400px;
|
width: 100%;
|
||||||
|
max-width: 1400px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 38px;
|
gap: 38px;
|
||||||
padding: 0 0 32px;
|
padding: 0 24px 32px;
|
||||||
border-bottom: 1px solid rgba(122, 130, 160, 0.22);
|
border-bottom: 1px solid rgba(122, 130, 160, 0.22);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@ -508,7 +560,8 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer-record__text {
|
.footer-record__text {
|
||||||
width: 1400px;
|
width: 100%;
|
||||||
|
max-width: 1400px;
|
||||||
margin: 18px 0 0;
|
margin: 18px 0 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@ -174,6 +174,7 @@ import Vue from 'vue'
|
|||||||
import { reqPublishProductSearchFirstPage, reqEnterpriseAuditInfoSearch, reqHomepageProductCategory, reqGetSupplyAndDemandSquareList } from '@/api/ncmatch'
|
import { reqPublishProductSearchFirstPage, reqEnterpriseAuditInfoSearch, reqHomepageProductCategory, reqGetSupplyAndDemandSquareList } from '@/api/ncmatch'
|
||||||
import { mapGetters, mapState } from "vuex";
|
import { mapGetters, mapState } from "vuex";
|
||||||
import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
|
import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
|
||||||
|
import { scheduleHomePageLayoutReset } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: "mainPage",
|
name: "mainPage",
|
||||||
@ -186,6 +187,9 @@ export default Vue.extend({
|
|||||||
created() {
|
created() {
|
||||||
this.getHomepageProductCategory()
|
this.getHomepageProductCategory()
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
boxLoading: false,
|
boxLoading: false,
|
||||||
|
|||||||
@ -571,6 +571,8 @@ export default {
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.home-main-page {
|
.home-main-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
background-color: #f0f7ff !important;
|
background-color: #f0f7ff !important;
|
||||||
background-image: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%) !important;
|
background-image: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%) !important;
|
||||||
color: #111827;
|
color: #111827;
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reqNewsDetail } from '@/api/newsapi/newsapi'
|
import { reqNewsDetail } from '@/api/newsapi/newsapi'
|
||||||
|
import { scheduleHomePageLayoutReset } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NewsDetail',
|
name: 'NewsDetail',
|
||||||
@ -72,19 +73,12 @@ export default {
|
|||||||
window.setTimeout(this.scrollToTop, 0)
|
window.setTimeout(this.scrollToTop, 0)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
scrollToTop() {
|
scrollToTop() {
|
||||||
window.scrollTo(0, 0)
|
scheduleHomePageLayoutReset()
|
||||||
document.documentElement.scrollTop = 0
|
|
||||||
document.body.scrollTop = 0
|
|
||||||
const scrollContainers = [
|
|
||||||
document.querySelector('.homeOut'),
|
|
||||||
document.querySelector('.home-router-view'),
|
|
||||||
document.querySelector('#app')
|
|
||||||
].filter(Boolean)
|
|
||||||
scrollContainers.forEach((container) => {
|
|
||||||
container.scrollTop = 0
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
goBack() {
|
goBack() {
|
||||||
this.$router.push('/homePage/news')
|
this.$router.push('/homePage/news')
|
||||||
|
|||||||
@ -107,6 +107,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reqNewsList } from '@/api/newsapi/newsapi'
|
import { reqNewsList } from '@/api/newsapi/newsapi'
|
||||||
|
import { scheduleHomePageLayoutReset } from '@/utils/resetHomePageLayout'
|
||||||
export default {
|
export default {
|
||||||
name: 'NewsView',
|
name: 'NewsView',
|
||||||
data() {
|
data() {
|
||||||
@ -157,6 +158,12 @@ export default {
|
|||||||
created() {
|
created() {
|
||||||
this.getNewsList()
|
this.getNewsList()
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goAbout() {
|
goAbout() {
|
||||||
this.$router.push('/homePage/about')
|
this.$router.push('/homePage/about')
|
||||||
@ -274,12 +281,12 @@ export default {
|
|||||||
this.newsList = []
|
this.newsList = []
|
||||||
this.total = 0
|
this.total = 0
|
||||||
this.$message.error(this.$t('newsView.loadFail'))
|
this.$message.error(this.$t('newsView.loadFail'))
|
||||||
|
} finally {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
@import url('../../../assets/less/news/news.less');
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -102,6 +102,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { scheduleHomePageLayoutReset } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TrainPlatform',
|
name: 'TrainPlatform',
|
||||||
data() {
|
data() {
|
||||||
@ -129,6 +131,9 @@ export default {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleStart() {
|
handleStart() {
|
||||||
this.$message.info('开始使用训推平台')
|
this.$message.info('开始使用训推平台')
|
||||||
|
|||||||
@ -11,10 +11,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.grid-bg {
|
.grid-bg {
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
margin-left: calc(50% - 50vw);
|
|
||||||
margin-right: calc(50% - 50vw);
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background:
|
background:
|
||||||
linear-gradient(rgba(37, 99, 235, 0.05) 1px, transparent 1px),
|
linear-gradient(rgba(37, 99, 235, 0.05) 1px, transparent 1px),
|
||||||
|
|||||||
@ -6,24 +6,24 @@
|
|||||||
<i class="el-icon-lock"></i>
|
<i class="el-icon-lock"></i>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3>重置密码</h3>
|
<h3>{{ $t('loginDialog.resetPassword') }}</h3>
|
||||||
<p>通过手机号验证码验证身份后设置新密码</p>
|
<p>{{ $t('loginDialog.resetPasswordDesc') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="forgot-form" autocomplete="off">
|
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="forgot-form" autocomplete="off">
|
||||||
<el-form-item label="手机号" prop="username">
|
<el-form-item :label="`* ${$t('loginDialog.mobileLabel')}`" prop="username">
|
||||||
<el-input v-model="form.username" clearable autocomplete="off" placeholder="请输入绑定手机号"></el-input>
|
<el-input v-model="form.username" clearable autocomplete="off" :placeholder="$t('loginDialog.enterBoundMobile')"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="新密码" prop="password">
|
<el-form-item :label="`* ${$t('loginDialog.newPasswordLabel')}`" prop="password">
|
||||||
<el-input v-model="form.password" clearable show-password autocomplete="new-password"
|
<el-input v-model="form.password" clearable show-password autocomplete="new-password"
|
||||||
placeholder="请输入新密码"></el-input>
|
:placeholder="$t('loginDialog.enterNewPassword')"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="验证码" prop="vcode">
|
<el-form-item :label="`* ${$t('loginDialog.verificationCodeLabel')}`" prop="vcode">
|
||||||
<div class="code-row">
|
<div class="code-row">
|
||||||
<el-input v-model="form.vcode" clearable autocomplete="off" placeholder="请输入验证码"></el-input>
|
<el-input v-model="form.vcode" clearable autocomplete="off" :placeholder="$t('loginDialog.enterVerificationCode')"></el-input>
|
||||||
<el-button class="code-btn" :disabled="isDisabled || isGettingCode" :loading="isGettingCode"
|
<el-button class="code-btn" :disabled="isDisabled || isGettingCode" :loading="isGettingCode"
|
||||||
@click="debouncedGetCode">
|
@click="debouncedGetCode">
|
||||||
{{ sendCodeText }}
|
{{ sendCodeText }}
|
||||||
@ -33,8 +33,8 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<div slot="footer" class="forgot-footer">
|
<div slot="footer" class="forgot-footer">
|
||||||
<el-button @click="handleClose">取消</el-button>
|
<el-button @click="handleClose">{{ $t('loginDialog.cancel') }}</el-button>
|
||||||
<el-button class="confirm-btn" type="primary" :loading="submitting" @click="handleSubmit">确认重置</el-button>
|
<el-button class="confirm-btn" type="primary" :loading="submitting" @click="handleSubmit">{{ $t('loginDialog.confirmReset') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
@ -53,15 +53,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: this.createEmptyForm(),
|
form: this.createEmptyForm(),
|
||||||
rules: {
|
sendCodeText: '',
|
||||||
username: [
|
|
||||||
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
|
||||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
password: [{ required: true, message: '请输入新密码', trigger: 'blur' }],
|
|
||||||
vcode: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
|
||||||
},
|
|
||||||
sendCodeText: '获取验证码',
|
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
isGettingCode: false,
|
isGettingCode: false,
|
||||||
submitting: false,
|
submitting: false,
|
||||||
@ -70,11 +62,36 @@ export default {
|
|||||||
debounceTimer: null
|
debounceTimer: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
rules() {
|
||||||
|
return {
|
||||||
|
username: [
|
||||||
|
{ required: true, message: this.$t('loginDialog.mobileRequired'), trigger: 'blur' },
|
||||||
|
{ pattern: /^1[3-9]\d{9}$/, message: this.$t('loginDialog.mobileInvalid'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
password: [{ required: true, message: this.$t('loginDialog.newPasswordRequired'), trigger: 'blur' }],
|
||||||
|
vcode: [{ required: true, message: this.$t('loginDialog.codeRequired'), trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$i18n.locale'() {
|
||||||
|
this.resetCodeButtonText()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.resetCodeButtonText()
|
||||||
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.resetCodeState()
|
this.resetCodeState()
|
||||||
clearTimeout(this.debounceTimer)
|
clearTimeout(this.debounceTimer)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
resetCodeButtonText() {
|
||||||
|
if (!this.isDisabled) {
|
||||||
|
this.sendCodeText = this.$t('loginDialog.getVerificationCode')
|
||||||
|
}
|
||||||
|
},
|
||||||
handleOpen() {
|
handleOpen() {
|
||||||
this.resetForm()
|
this.resetForm()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@ -110,7 +127,7 @@ export default {
|
|||||||
async getCode() {
|
async getCode() {
|
||||||
if (!this.form.username || !/^1[3-9]\d{9}$/.test(this.form.username)) {
|
if (!this.form.username || !/^1[3-9]\d{9}$/.test(this.form.username)) {
|
||||||
this.isGettingCode = false
|
this.isGettingCode = false
|
||||||
this.$message.error('请输入正确的手机号')
|
this.$message.error(this.$t('loginDialog.mobileInvalid'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,13 +140,13 @@ export default {
|
|||||||
if (res.status === true) {
|
if (res.status === true) {
|
||||||
this.form.codeid = res.codeid
|
this.form.codeid = res.codeid
|
||||||
this.startCountdown()
|
this.startCountdown()
|
||||||
this.$message.success('验证码已发送,请注意查收。')
|
this.$message.success(this.$t('loginDialog.codeSentCheck'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$message.error(res.msg || '验证码获取失败')
|
this.$message.error(res.msg || this.$t('loginDialog.codeSendFail'))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error('验证码获取失败')
|
this.$message.error(this.$t('loginDialog.codeSendFail'))
|
||||||
} finally {
|
} finally {
|
||||||
this.isGettingCode = false
|
this.isGettingCode = false
|
||||||
}
|
}
|
||||||
@ -137,20 +154,20 @@ export default {
|
|||||||
startCountdown() {
|
startCountdown() {
|
||||||
this.timeCount = 59
|
this.timeCount = 59
|
||||||
this.isDisabled = true
|
this.isDisabled = true
|
||||||
this.sendCodeText = `重新发送${this.timeCount}s`
|
this.sendCodeText = this.$t('loginDialog.resendCode', { seconds: this.timeCount })
|
||||||
|
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer)
|
||||||
this.timer = setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
if (this.timeCount > 0) {
|
if (this.timeCount > 0) {
|
||||||
this.timeCount--
|
this.timeCount--
|
||||||
this.sendCodeText = `重新发送${this.timeCount}s`
|
this.sendCodeText = this.$t('loginDialog.resendCode', { seconds: this.timeCount })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.resetCodeState()
|
this.resetCodeState()
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
resetCodeState() {
|
resetCodeState() {
|
||||||
this.sendCodeText = '获取验证码'
|
this.sendCodeText = this.$t('loginDialog.getVerificationCode')
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer)
|
||||||
this.timer = null
|
this.timer = null
|
||||||
this.isDisabled = false
|
this.isDisabled = false
|
||||||
@ -160,7 +177,7 @@ export default {
|
|||||||
this.$refs.formRef.validate(async valid => {
|
this.$refs.formRef.validate(async valid => {
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
if (!this.form.codeid) {
|
if (!this.form.codeid) {
|
||||||
this.$message.error('请先获取验证码')
|
this.$message.error(this.$t('loginDialog.getCodeFirst'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,14 +192,14 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (res.status === true) {
|
if (res.status === true) {
|
||||||
this.$message.success('密码重置成功')
|
this.$message.success(this.$t('loginDialog.resetSuccess'))
|
||||||
this.handleClose()
|
this.handleClose()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$message.error(res.msg || '密码重置失败')
|
this.$message.error(res.msg || this.$t('loginDialog.resetFail'))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error('密码重置失败')
|
this.$message.error(this.$t('loginDialog.resetFail'))
|
||||||
} finally {
|
} finally {
|
||||||
this.submitting = false
|
this.submitting = false
|
||||||
}
|
}
|
||||||
@ -250,7 +267,14 @@ export default {
|
|||||||
|
|
||||||
.forgot-form {
|
.forgot-form {
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
margin-bottom: 22px;
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__error {
|
||||||
|
position: static;
|
||||||
|
margin-top: 6px;
|
||||||
|
padding-top: 0;
|
||||||
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-form-item__label {
|
.el-form-item__label {
|
||||||
|
|||||||
@ -223,6 +223,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { reqNavList, reqNewHomeSync, reqNewHomeFestival } from "@/api/newHome";
|
import { reqNavList, reqNewHomeSync, reqNewHomeFestival } from "@/api/newHome";
|
||||||
import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
|
import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
|
||||||
|
import { scheduleHomePageLayoutReset } from '@/utils/resetHomePageLayout'
|
||||||
|
|
||||||
const getImageUrlPrefix = () => {
|
const getImageUrlPrefix = () => {
|
||||||
const origin = window.location.origin
|
const origin = window.location.origin
|
||||||
@ -354,8 +355,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.loadNavData();
|
scheduleHomePageLayoutReset()
|
||||||
this.initializeDefaultData();
|
await this.loadNavData()
|
||||||
|
this.initializeDefaultData()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
scheduleHomePageLayoutReset()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 判断当前一级分类是否为 TOKEN 市集,后续用于切换独立渲染逻辑。
|
// 判断当前一级分类是否为 TOKEN 市集,后续用于切换独立渲染逻辑。
|
||||||
@ -912,11 +917,9 @@ export default {
|
|||||||
min-height: calc(100vh - 100px);
|
min-height: calc(100vh - 100px);
|
||||||
|
|
||||||
&.single-product-page {
|
&.single-product-page {
|
||||||
height: 100vh;
|
min-height: calc(100vh - 82px);
|
||||||
min-height: 100vh;
|
|
||||||
padding: 82px 0 0;
|
padding: 82px 0 0;
|
||||||
background: linear-gradient(180deg, #f3f7ff 0%, #ffffff 100%);
|
background: linear-gradient(180deg, #f3f7ff 0%, #ffffff 100%);
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
.product-content {
|
.product-content {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user