Commit d081497d by wusiyi

feat: 官网2.0样式优化

parent d5494f62
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<p class="footer-title">{{ bannerContent.title }}</p> <p class="footer-title">{{ bannerContent.title }}</p>
<p class="footer-description">{{ bannerContent.description }}</p> <p class="footer-description">{{ bannerContent.description }}</p>
<button class="footer-register-btn" @click="goToLogin">立即使用</button> <button class="footer-register-btn" @click="goToLogin">立即使用</button>
<Register v-if="registerDialog" @close="registerDialog = false" /> <Register :visible="registerDialog" @close="registerDialog = false" />
</div> </div>
<div class="bg-right"></div> <div class="bg-right"></div>
</div> </div>
......
...@@ -98,6 +98,12 @@ ...@@ -98,6 +98,12 @@
</template> </template>
<script> <script>
import { mapMutations } from 'vuex' import { mapMutations } from 'vuex'
import productionSvg from '../assets/images/home/production.svg'
import customSvg from '../assets/images/home/custom.svg'
import supplyChainSvg from '../assets/images/home/earth.svg'
import logisticsSvg from '../assets/images/home/logistics.svg'
import usSvg from '../assets/images/product/us.svg'
export default { export default {
name: 'headerNavMobile', name: 'headerNavMobile',
data() { data() {
...@@ -111,71 +117,34 @@ export default { ...@@ -111,71 +117,34 @@ export default {
expanding: false, expanding: false,
children: [ children: [
{ {
name: '生产管理', name: '九猫ERP',
path: '/product/production', subTitle: '精细化运营和供应链一体化解决方案',
path: '/product/production?tab=product',
icon: productionSvg,
}, },
{ {
name: '一件定制', name: 'POD和满印供应链',
path: '/product/custom-chain', subTitle: '⼏⼗万件底胚库存,多种⼯艺,五千多款模型,品类⻬全',
path: '/product/production?tab=custom-chain',
icon: customSvg,
}, },
{ {
name: '海外仓物流', name: '九猫美国供应链 [LA POD]',
path: '/product/logistics', subTitle: '美国本⼟海外⽣产线,平台客户⾸选',
path: '/product/production?tab=supply-chain',
icon: supplyChainSvg,
}, },
{ {
name: '自建站平台', name: '九猫物流',
path: '/product/platform', subTitle: '集成国内主流物流,价格优惠时效快',
path: '/product/production?tab=logistics',
icon: logisticsSvg,
}, },
], ],
}, },
{ name: '价格', path: '/price' }, { name: '价格', path: '/price' },
{ name: '一件定制', path: 'https://jomalls.com/custom/' }, { name: '一件定制', path: 'https://jomalls.com/custom/' },
{ name: '案例', path: '/case' }, // { name: '案例', path: '/case' },
{
name: '资源与支持',
path: '/support',
expanding: false,
children: [
{
name: '资源',
expanding: false,
children: [
{
name: '活动信息',
path: '',
},
{
name: '入住流程平台',
path: '',
},
{
name: '资讯',
path: '',
},
],
},
{
name: '支持',
expanding: false,
children: [
{
name: '帮助中心',
path: '',
},
],
},
{
name: '了解SaaS ERP',
expanding: false,
// children: [
// {
// name: '如何通过财务管控向内部要效益',
// path: '/financial',
// },
// ],
},
],
},
{ {
name: '关于', name: '关于',
path: '/about', path: '/about',
...@@ -183,14 +152,19 @@ export default { ...@@ -183,14 +152,19 @@ export default {
children: [ children: [
{ {
name: '关于我们', name: '关于我们',
subTitle: '九猫ERP以精细化管理方案,帮助卖家实现业务增长',
path: '/about', path: '/about',
icon: usSvg,
}, },
{ // {
name: '加入我们', // name: '加入我们',
path: '/join', // subTitle: '加入九猫,一切皆有可能',
}, // path: '/join',
// icon: joinSvg,
// },
], ],
}, },
{ name: '帮助', path: '/help' },
], ],
} }
}, },
......
...@@ -20,12 +20,18 @@ import './assets/css/index.css' ...@@ -20,12 +20,18 @@ import './assets/css/index.css'
import './styles/index.scss' import './styles/index.scss'
const isMobile = () => window.innerWidth <= 1100 const isMobile = () => window.innerWidth <= 1100
Vue.util.defineReactive(Vue.prototype, '$isMobile', isMobile()) // 响应式更新 $isMobile 状态
// document.querySelector('html').style.fontSize = window.innerWidth / 100 + 'px' const mobileData = Vue.observable({ value: isMobile() })
// window.addEventListener('resize', () => { Object.defineProperty(Vue.prototype, '$isMobile', {
// Vue.prototype.$isMobile = isMobile() get() {
// document.querySelector('html').style.fontSize = window.innerWidth / 100 + 'px' return mobileData.value
// }) },
enumerable: true,
configurable: true
})
window.addEventListener('resize', () => {
mobileData.value = isMobile()
})
new Vue({ new Vue({
store, store,
......
...@@ -20,7 +20,7 @@ const zImgPath = window.apiHostSetting.VUE_APP_ZIMG_URL ...@@ -20,7 +20,7 @@ const zImgPath = window.apiHostSetting.VUE_APP_ZIMG_URL
// 文件存储路径地址 // 文件存储路径地址
const filePath = getStaticPath() + 'upload/erp' const filePath = getStaticPath() + 'upload/erp'
const instance = axios.create({ const instance = axios.create({
baseURL: baseURL+'api/', baseURL: baseURL + 'api/',
timeout: 5 * 60 * 1000, timeout: 5 * 60 * 1000,
// headers: { // headers: {
// "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", // "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
...@@ -43,12 +43,15 @@ instance.interceptors.request.use( ...@@ -43,12 +43,15 @@ instance.interceptors.request.use(
} }
config.data = data config.data = data
} }
if (HTTPNUM === 0) { // 如果配置了 skipLoading,跳过全局 loading
loading = Vue.prototype.$loading({ if (!config.skipLoading) {
background: 'rgba(0, 0, 0, 0.3)', if (HTTPNUM === 0) {
}) loading = Vue.prototype.$loading({
background: 'rgba(0, 0, 0, 0.3)',
})
}
HTTPNUM++
} }
HTTPNUM++
cancelToken.add(config) cancelToken.add(config)
return config return config
}, },
...@@ -62,9 +65,12 @@ instance.interceptors.request.use( ...@@ -62,9 +65,12 @@ instance.interceptors.request.use(
instance.interceptors.response.use( instance.interceptors.response.use(
(res) => { (res) => {
cancelToken.remove(res.config) cancelToken.remove(res.config)
HTTPNUM-- // 如果配置了 skipLoading,跳过全局 loading 的关闭
if (HTTPNUM === 0) { if (!res.config.skipLoading) {
loading.close() HTTPNUM--
if (HTTPNUM === 0) {
loading.close()
}
} }
if (res.status === 200) { if (res.status === 200) {
if (res.data.code === 401) { if (res.data.code === 401) {
...@@ -144,22 +150,25 @@ instance.interceptors.response.use( ...@@ -144,22 +150,25 @@ instance.interceptors.response.use(
// 服务器状态码不是200的情况 // 服务器状态码不是200的情况
(error) => { (error) => {
cancelToken.clear() cancelToken.clear()
HTTPNUM-- // 如果配置了 skipLoading,跳过全局 loading 的关闭和错误提示
if (HTTPNUM == 0) { if (!error.config || !error.config.skipLoading) {
Vue.prototype.$alert(error.message, 'Error', { HTTPNUM--
confirmButtonText: '确定', if (HTTPNUM == 0) {
callback: () => {}, Vue.prototype.$alert(error.message, 'Error', {
}) confirmButtonText: '确定',
loading.close() callback: () => {},
})
loading.close()
}
} }
return Promise.reject(error) return Promise.reject(error)
} }
) )
function get(url, params) { function get(url, params, config = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
instance instance
.get(url, { params }) .get(url, { params, ...config })
.then((res) => { .then((res) => {
if (res.status === 200 && res.data) { if (res.status === 200 && res.data) {
resolve(res.data) resolve(res.data)
......
<template> <template>
<div class="modal" :style="visible ? 'display: block' : 'display: none'"> <el-dialog
<div class="forget-form"> :visible.sync="dialogVisible"
<div class="forget-title">忘记密码</div> title="忘记密码"
<el-form size="medium" :model="forgetForm" ref="forgetForm"> :width="$isMobile ? '100%' : '36%'"
<el-form-item :center="true"
v-if="labelPosition === 'passwordLogin'" :close-on-click-modal="false"
prop="email" :close-on-press-escape="true"
label="" @close="handleClose"
:rules="[ @opened="handleOpened"
{ required: true, message: '请输入邮箱地址', type: 'email' }, class="forget-dialog">
]"> <el-radio-group
<el-input v-model="labelPosition"
v-model="forgetForm.email" class="radioGroup flex justify-center items-center mb-5"
prefix-icon="el-icon-postcard" size="small">
style="background: #fff" <el-radio-button label="passwordLogin">邮箱找回</el-radio-button>
placeholder="请输入邮箱"></el-input> <el-radio-button label="verificationLogin">验证码找回</el-radio-button>
</el-form-item> </el-radio-group>
<el-form
size="medium"
:model="forgetForm"
ref="forgetForm"
class="forget-form flex flex-col flex-1">
<el-form-item
v-if="labelPosition === 'passwordLogin'"
prop="email"
label=""
:rules="[{ required: true, message: '请输入邮箱地址', type: 'email' }]">
<el-input
v-model="forgetForm.email"
prefix-icon="el-icon-message"
placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item <el-form-item
v-if="labelPosition === 'passwordLogin'" v-if="labelPosition === 'passwordLogin'"
prop="code" prop="code"
label="" label=""
:rules="[{ required: true, message: '请输入验证码' }]"> :rules="[{ required: true, message: '请输入邮箱验证码' }]">
<div style="display: flex; gap: 20px"> <div class="flex gap-5">
<div style="flex: 1"> <div class="flex-1">
<el-input <el-input
v-model="forgetForm.code" v-model="forgetForm.code"
style="background: #fff" prefix-icon="el-icon-chat-line-square"
prefix-icon="el-icon-message" placeholder="请输入邮箱验证码"></el-input>
placeholder="请输入验证码"></el-input>
</div>
<div>
<el-button
class="get-code-button"
:disabled="getCodeDisabled"
:class="getCodeDisabled ? 'disabled' : 'code-btn'"
@click="verCode">
{{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
</el-button>
</div>
</div> </div>
</el-form-item> <div>
<el-button
class="get-code-button"
:disabled="getCodeDisabled"
:class="getCodeDisabled ? 'disabled' : 'code-btn'"
@click="verCode">
{{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
</el-button>
</div>
</div>
</el-form-item>
<el-form-item <el-form-item
v-if="labelPosition === 'verificationLogin'" v-if="labelPosition === 'verificationLogin'"
prop="phone" prop="phone"
:rules="[{ required: true, message: '请输入手机号' }]"> :rules="[{ required: true, message: '请输入手机号' }]">
<el-input <el-input
prefix-icon="el-icon-phone" prefix-icon="el-icon-phone"
style="background: #fff" v-model="forgetForm.phone"
v-model="forgetForm.phone" placeholder="请输入手机号"></el-input>
placeholder="请输入手机号"></el-input> </el-form-item>
</el-form-item>
<el-form-item <el-form-item
v-if="labelPosition === 'verificationLogin'" v-if="labelPosition === 'verificationLogin'"
prop="verifyKey" prop="verifyKey"
label="" label=""
:rules="[{ required: true, message: '请输入验证码' }]"> :rules="[{ required: true, message: '请输入验证码' }]">
<div style="display: flex; gap: 20px; margin-bottom: -10px"> <div class="flex gap-5 mb-0">
<div style="flex: 1"> <div class="flex-1">
<el-input <el-input
v-model="forgetForm.verifyKey" v-model="forgetForm.verifyKey"
prefix-icon="el-icon-postcard" prefix-icon="el-icon-postcard"
placeholder="请输入验证码,区分大小写"></el-input> placeholder="请输入验证码,区分大小写"></el-input>
</div>
<div @click="getVerifycode">
<img style="width: 100px; height: 80%" :src="VerifyUrl" />
</div>
</div> </div>
</el-form-item> <div class="cursor-pointer" @click="getVerifycode">
<img class="w-20 lg:w-28 h-full" :src="VerifyUrl" />
<el-form-item
v-if="labelPosition === 'verificationLogin'"
prop="code"
label=""
:rules="[{ required: true, message: '请输入短信验证码' }]">
<div style="display: flex; gap: 20px">
<div style="flex: 1">
<el-input
v-model="forgetForm.code"
prefix-icon="el-icon-message"
placeholder="请输入短信验证码"></el-input>
</div>
<div>
<el-button
class="get-code-button"
style="width: 112px"
:disabled="getCodeDisabled"
:class="getCodeDisabled ? 'disabled' : 'code-btn'"
@click="forgetPhonecode">
{{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
</el-button>
</div>
</div> </div>
</el-form-item> </div>
</el-form-item>
<el-form-item
prop="password"
:rules="[{ required: true, message: '请输入新密码' }]">
<el-input
v-model="forgetForm.password"
placeholder="请输入新密码"
:type="showNewPwd ? 'text' : 'password'"
prefix-icon="el-icon-lock"
style="background-color: #fff">
<i
@click="showNewPwd = !showNewPwd"
slot="suffix"
:class="{ eyes: true, open: !showNewPwd, close: showNewPwd }"></i>
</el-input>
</el-form-item>
<el-form-item <el-form-item
prop="confirmNewPassword" v-if="labelPosition === 'verificationLogin'"
:rules="[{ validator: validatePass, trigger: 'blur' }]"> prop="code"
<el-input label=""
v-model="forgetForm.confirmNewPassword" :rules="[{ required: true, message: '请输入短信验证码' }]">
placeholder="请再次输入新密码" <div class="flex gap-5">
:type="showAgNewPwd ? 'text' : 'password'" <div class="flex-1">
prefix-icon="el-icon-lock" <el-input
style="background-color: #fff"> v-model="forgetForm.code"
<i prefix-icon="el-icon-chat-line-square"
@click="showAgNewPwd = !showAgNewPwd" placeholder="请输入短信验证码"></el-input>
slot="suffix" </div>
:class="{ <div>
eyes: true, <el-button
open: !showAgNewPwd, class="get-code-button"
close: showAgNewPwd, :disabled="getCodeDisabled"
}"></i> :class="getCodeDisabled ? 'disabled' : 'code-btn'"
</el-input> @click="forgetPhonecode">
</el-form-item> {{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
</el-button>
</div>
</div>
</el-form-item>
<el-form-item style="margin-bottom: 10px"> <el-form-item
<el-button class="reset-password" round @click="resetPassword"> prop="password"
:rules="[{ required: true, message: '请输入新密码' }]">
<el-input
v-model="forgetForm.password"
placeholder="请输入新密码"
:type="showNewPwd ? 'text' : 'password'"
prefix-icon="el-icon-lock">
<i
@click="showNewPwd = !showNewPwd"
slot="suffix"
:class="{ eyes: true, open: !showNewPwd, close: showNewPwd }"></i>
</el-input>
</el-form-item>
<el-form-item
prop="confirmNewPassword"
:rules="[{ validator: validatePass, trigger: 'blur' }]">
<el-input
v-model="forgetForm.confirmNewPassword"
placeholder="请再次输入新密码"
:type="showAgNewPwd ? 'text' : 'password'"
prefix-icon="el-icon-lock">
<i
@click="showAgNewPwd = !showAgNewPwd"
slot="suffix"
:class="{
eyes: true,
open: !showAgNewPwd,
close: showAgNewPwd,
}"></i>
</el-input>
</el-form-item>
<slot name="footer">
<div class="footer-buttons flex flex-col gap-2 w-full mt-auto">
<el-button
class="reset-password w-full lg:h-10 lg:text-base text-white"
round
@click="resetPassword">
重置密码 重置密码
</el-button> </el-button>
</el-form-item> <el-button
<div style="font-size: 14px"> class="login-btn w-full lg:h-10 lg:text-base text-white"
<span>无需重置</span> round
<span @click="handleClose">
style=" 无需重置,直接登录
margin-left: 20px; </el-button>
color: var(--primary-color);
cursor: pointer;
"
@click="$emit('close')">
登录
</span>
</div> </div>
</el-form> </slot>
<i class="el-icon-circle-close close-icon" @click="$emit('close')"></i> </el-form>
</div> </el-dialog>
</div>
</template> </template>
<script> <script>
...@@ -163,10 +168,10 @@ export default { ...@@ -163,10 +168,10 @@ export default {
name: 'ForgetPassword', name: 'ForgetPassword',
props: { props: {
visible: { type: Boolean, default: false }, visible: { type: Boolean, default: false },
labelPosition: { type: String, default: 'passwordLogin' },
}, },
data() { data() {
return { return {
labelPosition: 'passwordLogin',
validatePass: (rule, value, callback) => { validatePass: (rule, value, callback) => {
if (!value) { if (!value) {
callback(new Error('请再次输入密码')) callback(new Error('请再次输入密码'))
...@@ -189,24 +194,38 @@ export default { ...@@ -189,24 +194,38 @@ export default {
getCodeDisabled() { getCodeDisabled() {
return this.codeCountDown > 0 return this.codeCountDown > 0
}, },
dialogVisible: {
get() {
return this.visible
},
set(val) {
if (!val) {
this.$emit('close')
}
},
},
}, },
watch: { watch: {
visible(val) { visible(val) {
if (val) { if (val) {
this.initForm() if (this.labelPosition === 'verificationLogin') {
this.getVerifycode()
}
} else { } else {
this.clearTimer() this.clearTimer()
} }
}, },
}, labelPosition() {
mounted() { this.initForm()
if (this.visible) this.initForm() },
}, },
methods: { methods: {
initForm() { initForm() {
this.forgetForm = {} this.forgetForm = {}
this.codeCountDown = 0 this.codeCountDown = 0
this.getVerifycode() if (this.labelPosition === 'verificationLogin') {
this.getVerifycode()
}
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.forgetForm && this.$refs.forgetForm.clearValidate() this.$refs.forgetForm && this.$refs.forgetForm.clearValidate()
}) })
...@@ -299,13 +318,29 @@ export default { ...@@ -299,13 +318,29 @@ export default {
}, },
getVerifycode() { getVerifycode() {
this.verifyKeyTime = new Date().getTime() this.verifyKeyTime = new Date().getTime()
get('business/user/verifycode', { get(
verifyKey: this.verifyKeyTime, 'business/user/verifycode',
}).then((res) => { {
if (res.code === 200) { verifyKey: this.verifyKeyTime,
this.VerifyUrl = res.message },
} { skipLoading: true }
}) )
.then((res) => {
if (res.code === 200) {
this.VerifyUrl = res.message
} else {
this.VerifyUrl = ''
}
})
.catch(() => {
this.VerifyUrl = ''
})
},
handleClose() {
this.$emit('close')
},
handleOpened() {
this.initForm()
}, },
}, },
beforeDestroy() { beforeDestroy() {
...@@ -314,56 +349,83 @@ export default { ...@@ -314,56 +349,83 @@ export default {
} }
</script> </script>
<style scoped> <style scoped lang="scss">
.modal { .forget-dialog ::v-deep .el-dialog__header {
position: fixed; padding: 40px 0 20px 0;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
transition: all 0.3s;
}
.forget-form {
position: fixed;
width: 36%;
padding: 50px 60px;
box-sizing: border-box;
border-radius: 6px;
top: 50%;
left: 50%;
background-color: #fff;
transform: translate(-50%, -50%);
} }
.forget-title { .forget-dialog ::v-deep .el-dialog__title {
text-align: center;
margin-bottom: 26px;
font-size: 26px; font-size: 26px;
font-weight: 400; font-weight: 500;
letter-spacing: 2px; letter-spacing: 2px;
} }
.forget-form .close-icon { .forget-dialog ::v-deep .el-dialog__body {
position: fixed; padding: 0 60px 20px;
top: -30px; height: 460px;
right: -28px; display: flex;
font-size: 30px; flex-direction: column;
color: #fff; }
cursor: pointer;
@media (max-width: 1100px) {
.forget-dialog ::v-deep .el-dialog {
margin-top: 10vh;
min-height: 200px;
}
.forget-dialog ::v-deep .el-dialog__title {
font-size: 20px;
display: flex;
flex-direction: column;
}
.forget-dialog ::v-deep .el-dialog__body {
padding: 0 30px 20px;
display: flex;
flex-direction: column;
}
} }
.reset-password { .reset-password {
width: 100%;
background-image: linear-gradient( background-image: linear-gradient(
to right, to right,
var(--primary-color) 0%, var(--primary-color) 0%,
#d59723 51%, #d59723 51%,
#f0cb66 100% #f0cb66 100%
); );
color: #fff; &:hover {
background-image: linear-gradient(
to right,
var(--hover-color) 0%,
#cf9e42 51%,
#eed183 100%
);
color: #fff;
}
&:focus {
background-image: linear-gradient(
to right,
var(--hover-color) 0%,
#cf9e42 51%,
#eed183 100%
);
color: #fff;
border: 1px solid var(--hover-color);
}
}
.login-btn {
background: #ffffff;
color: #838383;
border: 1px solid #a8a8a8;
&:hover {
background: #ffffff;
color: #949494;
border: 1px solid #c7c7c7;
}
&:focus {
background: #ffffff;
color: #838383;
border: 1px solid #a8a8a8;
}
} }
.get-code-button:disabled:hover { .get-code-button:disabled:hover {
...@@ -401,4 +463,8 @@ export default { ...@@ -401,4 +463,8 @@ export default {
.eyes.close { .eyes.close {
background: url('../../assets/eyes-closed.png') no-repeat center / cover; background: url('../../assets/eyes-closed.png') no-repeat center / cover;
} }
.forget-dialog ::v-deep .el-button + .el-button {
margin-left: 0;
}
</style> </style>
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<platform /> <platform />
<product-intro /> <product-intro />
<Register v-if="registerDialog" @close="registerDialog = false" /> <Register :visible="registerDialog" @close="registerDialog = false" />
</div> </div>
</template> </template>
<script> <script>
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
<el-radio-group <el-radio-group
v-model="labelPosition" v-model="labelPosition"
class="radioGroup mt-5 flex justify-center items-center mb-5" class="radioGroup mt-5 flex justify-center items-center mb-5"
size="small"> size="small"
@change="clickChange">
<el-radio-button label="passwordLogin">密码登录</el-radio-button> <el-radio-button label="passwordLogin">密码登录</el-radio-button>
<el-radio-button label="verificationLogin">验证码登录</el-radio-button> <el-radio-button label="verificationLogin">验证码登录</el-radio-button>
</el-radio-group> </el-radio-group>
...@@ -75,7 +76,7 @@ ...@@ -75,7 +76,7 @@
prefix-icon="el-icon-postcard" prefix-icon="el-icon-postcard"
placeholder="请输入验证码(区分大小写)"></el-input> placeholder="请输入验证码(区分大小写)"></el-input>
</div> </div>
<div @click="getVerifycode"> <div class="cursor-pointer" @click="getVerifycode">
<img class="w-20 lg:w-32 h-full" :src="VerifyUrl" /> <img class="w-20 lg:w-32 h-full" :src="VerifyUrl" />
</div> </div>
</div> </div>
...@@ -88,11 +89,11 @@ ...@@ -88,11 +89,11 @@
<div class="flex-1"> <div class="flex-1">
<el-input <el-input
v-model="ruleForm.code" v-model="ruleForm.code"
prefix-icon="el-icon-message" prefix-icon="el-icon-chat-line-square"
placeholder="请输入短信验证码"></el-input> placeholder="请输入短信验证码"></el-input>
</div> </div>
<el-button <el-button
class="w-22 text-white border-0" class="w-22 text-white text-xs lg:text-base border-0"
:disabled="getCodeDisabled" :disabled="getCodeDisabled"
:class="getCodeDisabled ? 'disabled' : 'get-code-button'" :class="getCodeDisabled ? 'disabled' : 'get-code-button'"
@click="verPhonecode"> @click="verPhonecode">
...@@ -119,8 +120,7 @@ ...@@ -119,8 +120,7 @@
<el-divider direction="vertical" class="bottom-line"></el-divider> <el-divider direction="vertical" class="bottom-line"></el-divider>
<div <div
class="register-btn-text cursor-pointer" class="register-btn-text cursor-pointer"
@click="registerDialog = true" @click="registerDialog = true">
style="color: var(--primary-color)">
马上注册 马上注册
</div> </div>
</div> </div>
...@@ -131,9 +131,8 @@ ...@@ -131,9 +131,8 @@
<ForgetPassword <ForgetPassword
v-if="isShowModal" v-if="isShowModal"
:visible="isShowModal" :visible="isShowModal"
:label-position="labelPosition"
@close="isShowModal = false" /> @close="isShowModal = false" />
<Register v-if="registerDialog" @close="registerDialog = false" /> <Register :visible="registerDialog" @close="registerDialog = false" />
</div> </div>
</template> </template>
...@@ -175,7 +174,9 @@ export default { ...@@ -175,7 +174,9 @@ export default {
trigger: ['blur', 'change'], trigger: ['blur', 'change'],
}, },
], ],
code: [{ required: true, message: '请输入验证码', trigger: 'blur' }], code: [
{ required: true, message: '请输入短信验证码', trigger: 'blur' },
],
verifyKey: [ verifyKey: [
{ required: true, message: '请输入验证码', trigger: 'blur' }, { required: true, message: '请输入验证码', trigger: 'blur' },
], ],
...@@ -188,11 +189,23 @@ export default { ...@@ -188,11 +189,23 @@ export default {
return this.codeCountDown > 0 return this.codeCountDown > 0
}, },
}, },
mounted() {
this.getVerifycode()
},
methods: { methods: {
...mapMutations(['setUserInfo']), ...mapMutations(['setUserInfo']),
initForm() {
this.ruleForm = {}
this.codeCountDown = 0
if (this.labelPosition === 'verificationLogin') {
this.getVerifycode()
}
this.$nextTick(() => {
this.$refs.ruleForm && this.$refs.ruleForm.clearValidate()
})
},
clearTimer() {
if (this.timer) clearInterval(this.timer)
this.timer = null
},
async verPhonecode() { async verPhonecode() {
try { try {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
...@@ -263,13 +276,26 @@ export default { ...@@ -263,13 +276,26 @@ export default {
}, },
getVerifycode() { getVerifycode() {
this.verifyKeyTime = new Date().getTime() this.verifyKeyTime = new Date().getTime()
get('business/user/verifycode', { get(
verifyKey: this.verifyKeyTime, 'business/user/verifycode',
}).then((res) => { {
if (res.code === 200) { verifyKey: this.verifyKeyTime,
this.VerifyUrl = res.message },
} { skipLoading: true }
}) )
.then((res) => {
if (res.code === 200) {
this.VerifyUrl = res.message
} else {
this.VerifyUrl = ''
}
})
.catch(() => {
this.VerifyUrl = ''
})
},
clickChange() {
this.initForm()
}, },
}, },
} }
...@@ -315,9 +341,10 @@ export default { ...@@ -315,9 +341,10 @@ export default {
} }
.disabled { .disabled {
background-color: #d0d2d8; background-color: #f0f0f0;
color: #666; color: #666;
margin-left: 10px; border: 1px solid #cccccc;
cursor: not-allowed;
} }
.code-btn { .code-btn {
...@@ -348,6 +375,7 @@ export default { ...@@ -348,6 +375,7 @@ export default {
} }
.register-btn-text { .register-btn-text {
color: var(--primary-color);
&:hover { &:hover {
color: var(--hover-color); color: var(--hover-color);
} }
......
<template> <template>
<div class="docking-platform flex justify-center"> <div class="docking-platform flex justify-center py-8">
<div> <vue-seamless-scroll
<div class="flex justify-center flex-col items-center mb-5 gap-2"> :data="platforms"
<div class="mt-30 platforms-marquee flex justify-center"> :class-option="classOption"
<vue-seamless-scroll class="warp flex justify-center items-center">
:data="platforms" <ul class="flex flex-wrap">
:class-option="classOption" <li
class="warp"> class="platform-item flex justify-center items-center w-20"
<ul class="flex flex-wrap"> v-for="platform in platforms"
<li :key="platform.name">
class="platform-item" <a
v-for="platform in platforms" v-if="platform.link"
:key="platform.name"> :href="platform.link"
<a v-if="platform.link" :href="platform.link" target="_blank"> target="_blank"
<img class="flex justify-center items-center w-full h-full">
class="platform-image" <img
:src=" class="platform-image"
require(`../../assets/platforms/${platform.name}.${platform.type}`) :src="
" require(`../../assets/platforms/${platform.name}.${platform.type}`)
:alt="platform.name" /> "
</a> :alt="platform.name" />
<img </a>
v-else <img
class="platform-image" v-else
:src=" class="platform-image"
require(`../../assets/platforms/${platform.name}.${platform.type}`) :src="
" require(`../../assets/platforms/${platform.name}.${platform.type}`)
:alt="platform.name" /> "
</li> :alt="platform.name" />
</ul> </li>
</vue-seamless-scroll> </ul>
</div> </vue-seamless-scroll>
</div>
</div>
</div> </div>
</template> </template>
...@@ -68,7 +66,7 @@ export default { ...@@ -68,7 +66,7 @@ export default {
], ],
classOption: { classOption: {
step: 0.6, // 数值越大速度滚动越快 step: 0.6, // 数值越大速度滚动越快
limitMoveNum: 5, // 开始无缝滚动的数据量 this.dataList.length limitMoveNum: 18, // 开始无缝滚动的数据量 this.dataList.length
hoverStop: true, // 是否开启鼠标悬停stop hoverStop: true, // 是否开启鼠标悬停stop
direction: 1, // 0向下 1向上 2向左 3向右 direction: 1, // 0向下 1向上 2向左 3向右
autoPlay: true, // 是否自动滚动 autoPlay: true, // 是否自动滚动
...@@ -82,12 +80,6 @@ export default { ...@@ -82,12 +80,6 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.docking-platform { .docking-platform {
background: var(--light-color); background: var(--light-color);
padding: 30px 0 10px 0;
}
.docking-platform h2 {
color: #000;
font-weight: 500;
} }
.warp { .warp {
...@@ -95,42 +87,24 @@ export default { ...@@ -95,42 +87,24 @@ export default {
height: 100px; height: 100px;
overflow: hidden; overflow: hidden;
} }
.lx-title {
font-size: 2.25rem;
color: #ffffff;
font-weight: 500;
line-height: 1.75rem;
margin-bottom: 0.25rem;
max-width: 840px;
text-align: center;
--tw-text-opacity: 1;
letter-spacing: 1px;
}
.platforms-marquee .platform-item { .platform-item {
flex: 0 0 auto; flex: 0 0 auto;
width: 140px; width: 140px;
height: 60px; height: 60px;
display: flex;
align-items: center;
justify-content: center;
} }
.platforms-marquee .platform-item a { @media (max-width: 1100px) {
display: flex; .warp {
align-items: center; width: 90%;
justify-content: center; }
width: 100%; .platform-item {
height: 100%; width: 33%;
text-decoration: none; }
transition: opacity 0.3s ease;
} }
.platform-image { .platform-image {
width: 120px; width: 80%;
height: auto;
max-height: 80px;
object-fit: contain;
transition: filter 0.3s ease; transition: filter 0.3s ease;
filter: brightness(0) invert(1); filter: brightness(0) invert(1);
} }
......
<template> <template>
<div class="login_bg"> <el-dialog
<div class="login_content"> :visible.sync="dialogVisible"
<h2 title="用户注册"
style=" :width="$isMobile ? '100%' : '36%'"
font-size: 24px; :center="true"
text-align: center; :close-on-click-modal="false"
font-weight: 400; :close-on-press-escape="true"
color: #4a4c6d; @close="closeDialog"
"> @opened="handleOpened"
用户注册 class="register-dialog">
</h2> <el-radio-group
<el-radio-group v-model="labelPosition"
v-model="labelPosition" class="radioGroup flex justify-center items-center mb-5"
class="radioGroup" size="small">
size="small" <el-radio-button label="phone">手机号注册</el-radio-button>
@change="clickChange"> <el-radio-button label="mailbox">邮箱注册</el-radio-button>
<el-radio-button label="phone">手机号注册</el-radio-button> </el-radio-group>
<el-radio-button label="mailbox">邮箱注册</el-radio-button> <el-form
</el-radio-group> size="medium"
<el-form :model="registerForm"
size="medium" :rules="rules"
:model="registerForm" ref="registerForm"
:rules="rules" class="login_form flex flex-col flex-1">
ref="registerForm" <el-form-item v-if="labelPosition === 'mailbox'" prop="email" label="">
class="login_form"> <el-input
<el-form-item v-if="labelPosition === 'mailbox'" prop="email" label=""> v-model="registerForm.email"
<el-input prefix-icon="el-icon-message"
v-model="registerForm.email" placeholder="请输入邮箱"></el-input>
prefix-icon="el-icon-postcard" </el-form-item>
placeholder="请输入邮箱"></el-input> <el-form-item v-if="labelPosition === 'mailbox'" prop="code" label="">
</el-form-item> <div class="flex gap-5">
<el-form-item v-if="labelPosition === 'mailbox'" prop="code" label=""> <div class="flex-1">
<div style="display: flex; gap: 20px"> <el-input
<div style="flex: 1"> v-model="registerForm.code"
<el-input prefix-icon="el-icon-postcard"
v-model="registerForm.code" placeholder="请输入邮箱验证码"></el-input>
prefix-icon="el-icon-message"
placeholder="请输入邮箱验证码"></el-input>
</div>
<div>
<el-button
class="get-code-button"
style="width: 112px"
:disabled="getCodeDisabled"
:class="getCodeDisabled ? 'disabled' : 'code-btn'"
@click="verCode">
{{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
</el-button>
</div>
</div> </div>
</el-form-item> <div>
<el-form-item v-if="labelPosition === 'phone'" prop="phone"> <el-button
<el-input class="get-code-button"
v-model="registerForm.phone" style="width: 112px"
prefix-icon="el-icon-phone" :disabled="getCodeDisabled"
placeholder="请输入手机号"></el-input> :class="getCodeDisabled ? 'disabled' : 'code-btn'"
</el-form-item> @click="verCode">
<el-form-item v-if="labelPosition === 'phone'" prop="verifyKey"> {{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
<div style="display: flex; gap: 20px"> </el-button>
<div style="flex: 1">
<el-input
v-model="registerForm.verifyKey"
prefix-icon="el-icon-postcard"
placeholder="请输入验证码,区分大小写"></el-input>
</div>
<div @click="getVerifycode">
<img style="width: 120px; height: 100%" :src="VerifyUrl" />
</div>
</div> </div>
</el-form-item>
<el-form-item v-if="labelPosition === 'phone'" prop="code">
<div style="display: flex; gap: 20px">
<div style="flex: 1">
<el-input
v-model="registerForm.code"
prefix-icon="el-icon-message"
placeholder="请输入短信验证码"></el-input>
</div>
<div>
<el-button
class="get-code-button"
style="width: 112px"
:disabled="getCodeDisabled"
:class="getCodeDisabled ? 'disabled' : 'code-btn'"
@click="verPhonecode">
{{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
</el-button>
</div>
</div>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
v-model="registerForm.password"
prefix-icon="el-icon-lock"
placeholder="请输入密码"
autocomplete="off"></el-input>
</el-form-item>
<el-form-item prop="checkPass">
<el-input
type="password"
prefix-icon="el-icon-lock"
v-model="registerForm.checkPass"
placeholder="请再次输入密码"
autocomplete="off"></el-input>
</el-form-item>
<el-form-item prop="companyName">
<el-input
v-model="registerForm.companyName"
prefix-icon="el-icon-s-home"
placeholder="请输入公司名称"></el-input>
</el-form-item>
<el-form-item prop="job">
<el-input
v-model="registerForm.job"
prefix-icon="el-icon-s-order"
placeholder="请输入职务"></el-input>
</el-form-item>
</el-form>
<div class="bottom-section">
<div class="agree-terms" :class="agreeAnimate ? 'agree-animate' : ''">
<el-checkbox v-model="isRead" label="" :indeterminate="false" />
<span class="tos-link">
阅读并同意
<a class="link" href="/protocol/term" target="_blank">
《九猫ERP条款与协议》
</a>
<span></span>
<a class="link" href="/protocol/privacy" target="_blank">
《隐私协议》
</a>
</span>
</div> </div>
<div class="register-btn-container"> </el-form-item>
<button class="register-btn" @click="onRegister">立即注册</button> <el-form-item v-if="labelPosition === 'phone'" prop="phone">
<el-input
v-model="registerForm.phone"
prefix-icon="el-icon-phone"
placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item v-if="labelPosition === 'phone'" prop="verifyKey">
<div class="flex gap-5">
<div class="flex-1">
<el-input
v-model="registerForm.verifyKey"
prefix-icon="el-icon-postcard"
placeholder="请输入验证码,区分大小写"></el-input>
</div>
<div class="cursor-pointer" @click="getVerifycode">
<img class="w-20 lg:w-28 h-full" :src="VerifyUrl" />
</div>
</div> </div>
<div class="bottom-login-link"> </el-form-item>
已有账号? <el-form-item v-if="labelPosition === 'phone'" prop="code">
<span <div class="flex gap-5">
style="cursor: pointer; color: var(--primary-color)" <div class="flex-1">
@click="goToLogin"> <el-input
马上登录 v-model="registerForm.code"
</span> prefix-icon="el-icon-chat-line-square"
placeholder="请输入短信验证码"></el-input>
</div>
<div>
<el-button
class="get-code-button ml-2 w-28 border-none text-sm text-white"
:disabled="getCodeDisabled"
:class="getCodeDisabled ? 'disabled' : 'code-btn'"
@click="verPhonecode">
{{ codeCountDown === 0 ? '获取验证码' : `${codeCountDown}秒` }}
</el-button>
</div>
</div> </div>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
v-model="registerForm.password"
prefix-icon="el-icon-lock"
placeholder="请输入密码"
autocomplete="off"></el-input>
</el-form-item>
<el-form-item prop="checkPass">
<el-input
type="password"
prefix-icon="el-icon-lock"
v-model="registerForm.checkPass"
placeholder="请再次输入密码"
autocomplete="off"></el-input>
</el-form-item>
<el-form-item prop="companyName">
<el-input
v-model="registerForm.companyName"
prefix-icon="el-icon-s-home"
placeholder="请输入公司名称"></el-input>
</el-form-item>
<el-form-item prop="job">
<el-input
v-model="registerForm.job"
prefix-icon="el-icon-s-order"
placeholder="请输入职务"></el-input>
</el-form-item>
</el-form>
<div class="bottom-section mt-auto">
<div
class="agree-terms mb-5"
:class="agreeAnimate ? 'agree-animate' : ''">
<el-checkbox v-model="isRead" label="" :indeterminate="false" />
<span class="tos-link text-sm">
阅读并同意
<a class="link" href="/protocol/term" target="_blank">
《九猫ERP条款与协议》
</a>
<span></span>
<a class="link" href="/protocol/privacy" target="_blank">
《隐私协议》
</a>
</span>
</div>
<div class="register-btn-container mb-5 text-center">
<button
class="register-btn w-full h-10 text-base text-white rounded-lg cursor-pointer rounded-md"
@click="onRegister">
立即注册
</button>
</div>
<div class="bottom-login-link text-sm mb-2 text-center">
已有账号?
<span
class="cursor-pointer"
style="color: var(--primary-color)"
@click="goToLogin">
马上登录
</span>
</div> </div>
</div> </div>
<i class="el-icon-circle-close close-icon" @click="closeDialog"></i> </el-dialog>
</div>
</template> </template>
<script> <script>
...@@ -158,6 +160,12 @@ export default { ...@@ -158,6 +160,12 @@ export default {
inject: { inject: {
scrollParent: 'scrollParent', scrollParent: 'scrollParent',
}, },
props: {
visible: {
type: Boolean,
default: false,
},
},
data() { data() {
var validatePass2 = (rule, value, callback) => { var validatePass2 = (rule, value, callback) => {
if (value === '') { if (value === '') {
...@@ -176,6 +184,7 @@ export default { ...@@ -176,6 +184,7 @@ export default {
isRead: false, isRead: false,
agreeAnimate: false, agreeAnimate: false,
codeCountDown: 0, codeCountDown: 0,
timer: null,
rules: { rules: {
email: [ email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' }, { required: true, message: '请输入邮箱', trigger: 'blur' },
...@@ -214,11 +223,42 @@ export default { ...@@ -214,11 +223,42 @@ export default {
getCodeDisabled() { getCodeDisabled() {
return this.codeCountDown > 0 return this.codeCountDown > 0
}, },
dialogVisible: {
get() {
return this.visible
},
set(val) {
if (!val) {
this.closeDialog()
}
},
},
}, },
mounted() { watch: {
this.getVerifycode() visible(newVal) {
if (!newVal) {
this.clearTimer()
}
},
labelPosition() {
this.initForm()
},
}, },
methods: { methods: {
initForm() {
this.registerForm = {}
this.codeCountDown = 0
if (this.labelPosition === 'phone') {
this.getVerifycode()
}
this.$nextTick(() => {
this.$refs.registerForm && this.$refs.registerForm.clearValidate()
})
},
clearTimer() {
if (this.timer) clearInterval(this.timer)
this.timer = null
},
closeDialog() { closeDialog() {
this.$emit('close') this.$emit('close')
}, },
...@@ -249,10 +289,11 @@ export default { ...@@ -249,10 +289,11 @@ export default {
email: this.registerForm.email, email: this.registerForm.email,
}) })
this.codeCountDown = 60 this.codeCountDown = 60
this.clearTimer()
this.timer = setInterval(() => { this.timer = setInterval(() => {
this.codeCountDown-- this.codeCountDown--
if (this.codeCountDown <= 0) { if (this.codeCountDown <= 0) {
clearInterval(this.timer) this.clearTimer()
} }
}, 1000) }, 1000)
this.$message.success(res.message) this.$message.success(res.message)
...@@ -277,10 +318,11 @@ export default { ...@@ -277,10 +318,11 @@ export default {
verifyCode: this.registerForm.verifyKey, verifyCode: this.registerForm.verifyKey,
}) })
this.codeCountDown = 60 this.codeCountDown = 60
this.clearTimer()
this.timer = setInterval(() => { this.timer = setInterval(() => {
this.codeCountDown-- this.codeCountDown--
if (this.codeCountDown <= 0) { if (this.codeCountDown <= 0) {
clearInterval(this.timer) this.clearTimer()
} }
}, 1000) }, 1000)
this.$message.success(res.message) this.$message.success(res.message)
...@@ -324,76 +366,69 @@ export default { ...@@ -324,76 +366,69 @@ export default {
}, },
getVerifycode() { getVerifycode() {
this.verifyKeyTime = new Date().getTime() this.verifyKeyTime = new Date().getTime()
get('business/user/verifycode', { get(
verifyKey: this.verifyKeyTime, 'business/user/verifycode',
}).then((res) => { {
if (res.code === 200) { verifyKey: this.verifyKeyTime,
this.VerifyUrl = res.message },
} { skipLoading: true }
}) )
.then((res) => {
if (res.code === 200) {
this.VerifyUrl = res.message
} else {
this.VerifyUrl = ''
}
})
.catch(() => {
this.VerifyUrl = ''
})
}, },
clickChange() { handleOpened() {
this.registerForm = {} this.initForm()
}, },
}, },
beforeDestroy() {
this.clearTimer()
},
} }
</script> </script>
<style scoped> <style scoped lang="scss">
.login_bg { ::v-deep .el-dialog {
position: fixed; margin-top: 10vh !important;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
} }
.register-dialog ::v-deep .el-dialog__header {
.login_bg::v-deep .el-input__inner { padding: 40px 0 20px 0;
background-color: #fff;
} }
.el-form--inline .el-form-item { .register-dialog ::v-deep .el-dialog__title {
margin-right: 0px; font-size: 26px;
font-weight: 500;
letter-spacing: 2px;
} }
.login_content {
padding: 30px; .register-dialog ::v-deep .el-dialog__body {
background: #fff; padding: 0 60px 20px;
border-radius: 6px; height: 630px;
box-sizing: border-box;
width: 600px;
height: 700px;
overflow-y: auto;
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.login_content::v-deep .el-form-item__content { @media (max-width: 1100px) {
white-space: nowrap; .forget-dialog ::v-deep .el-dialog {
} margin-top: 10vh;
height: 80%;
.login_form { }
padding: 20px 0px 0px 0px; .register-dialog ::v-deep .el-dialog__title {
} font-size: 20px;
display: flex;
.agree-terms { flex-direction: column;
margin-bottom: 20px; }
} .register-dialog ::v-deep .el-dialog__body {
padding: 0 30px 20px;
.register-btn-container { display: flex;
text-align: center; flex-direction: column;
margin-bottom: 20px; }
}
.bottom-section {
margin-top: auto;
} }
.get-code-button:disabled:hover { .get-code-button:disabled:hover {
...@@ -401,10 +436,6 @@ export default { ...@@ -401,10 +436,6 @@ export default {
color: #666; color: #666;
} }
.tos-link {
font-size: 14px;
}
@keyframes shake { @keyframes shake {
0% { 0% {
transform: translateX(0); transform: translateX(0);
...@@ -427,78 +458,20 @@ export default { ...@@ -427,78 +458,20 @@ export default {
} }
.register-btn { .register-btn {
width: 100%;
height: 38px;
display: block;
margin: 0 auto;
background: var(--primary-color); background: var(--primary-color);
box-shadow: 0 4px 8px 0 var(--shadow-color); box-shadow: 0 4px 8px 0 var(--shadow-color);
border-radius: 4px;
font-size: 16px;
color: #fff;
cursor: pointer;
} }
.code-btn { .code-btn {
margin-left: 10px;
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
var(--primary-color) 0%, var(--primary-color) 0%,
var(--primary-color) 100% var(--primary-color) 100%
); );
border: none;
color: #fff;
} }
.disabled { .disabled {
background-color: #d0d2d8; background-color: #d0d2d8;
color: #666; color: #666;
margin-left: 10px; margin-left: 10px;
} }
.radioGroup {
display: flex;
justify-content: center;
align-items: center;
margin-top: 10px;
}
.bottom-login-link {
font-size: 14px;
text-align: center;
margin-bottom: 10px;
}
.close-icon {
position: absolute;
top: calc(50% - 350px);
left: calc(50% + 330px);
font-size: 30px;
color: #c7c7c7;
cursor: pointer;
z-index: 1000;
}
.close-icon:hover {
color: #ffffff;
}
@media screen and (max-width: 1100px) {
.login_bg {
background: unset;
}
.logo {
position: unset;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.login_content {
position: unset;
transform: unset;
padding: 20px;
}
}
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment