Commit a7e95afc by wusiyi

feat: 官网2.0样式优化

parent 9193748d
......@@ -1078,6 +1078,14 @@ ul li {
background-color: var(--background-color);
}
.primary-color {
color: var(--primary-color);
}
.secondary-color {
color: var(--secondary-color);
}
/* Element UI 主题色覆盖 - 颜色变量已在 src/styles/index.scss 中基于 $primary-color 生成 */
.el-button--text {
......
......@@ -209,17 +209,9 @@ export default {
{ name: '价格', path: '/price' },
{ name: '一件定制', path: 'https://jomalls.com/custom/' },
{
name: '关于',
name: '关于我们',
path: '/about',
expanding: false,
children: [
{
name: '关于我们',
subTitle: '九猫ERP以精细化管理方案,帮助卖家实现业务增长',
path: '/about',
icon: 'fluent:people-16-filled',
},
],
},
{ name: '帮助', path: '/help' },
],
......
......@@ -3,28 +3,70 @@
<div class="top pt-3 pl-5 flex justify-between">
<div class="flex items-center gap-2 cursor-pointer" @click="goHelp">
<img class="h-8" :src="Logo" alt="logo" />
<h2 class="text-white text-2xl font-bold mt-2">九猫帮助中心</h2>
<h2
class="text-lg font-bold mt-2 border-l border-solid border-gray-300 pl-2">
九猫ERP帮助中心
</h2>
</div>
<div class="flex items-center">
<div class="flex items-center justify-center pb-2">
<div
v-for="nav in navs"
:key="nav.path"
class="flex flex-col items-center justify-center mr-10">
class="flex flex-col items-center justify-center mr-8">
<a class="nav-link relative" :index="nav.path" :href="nav.path">
{{ nav.name }}
</a>
<div class="nav-line"></div>
</div>
<el-button plain class="mr-10 mb-2" size="medium">免费试用</el-button>
<div
class="mr-2 flex items-center justify-center gap-2"
v-if="!userInfo">
<div
class="text-gray-500 font-semibold cursor-pointer pr-2 border-r-2 border-solid border-gray-200 hover:text-secondary-color"
@click="login">
登录
</div>
<div
class="text-gray-500 font-semibold cursor-pointer pr-2 hover:text-secondary-color"
@click="register">
注册
</div>
</div>
<div class="flex items-center" v-else>
<div class="text-gray-600 mr-10 cursor-default">
<span class="mr-2">{{ userInfo.companyName }}</span>
<span>欢迎您</span>
</div>
<el-popconfirm title="确定退出登录吗?" @confirm="logout">
<div
class="logout mr-5 cursor-pointer"
title="退出登录"
slot="reference">
<Icon
icon="mdi:logout"
width="20"
height="20"
color="var(--primary-color)" />
</div>
</el-popconfirm>
</div>
<!-- <el-button plain class="mr-10 mb-2" size="medium">免费试用</el-button> -->
</div>
</div>
</div>
</template>
<script>
import { Icon } from '@iconify/vue2'
import { mapMutations } from 'vuex'
import Logo from '../assets/logo.png'
export default {
name: 'headHelper',
inject: {
scrollParent: 'scrollParent',
},
components: {
Icon,
},
data() {
return {
Logo,
......@@ -33,61 +75,92 @@ export default {
name: '首页',
path: '/',
},
{
name: '价格',
path: '/price',
},
{
name: '关于九猫',
path: '/about',
},
],
userInfo: JSON.parse(localStorage.getItem('userInfo')),
}
},
methods: {
...mapMutations(['setUserInfo', 'setShopKey']),
goHelp() {
if (this.$route.path === '/help/index') return
this.$router.push('/help')
},
async login() {
if (this.$route.query && this.$route.query.shopKey) {
this.setShopKey(this.$route.query.shopKey)
}
// 跳转到首页
await this.$router.push('/home').catch(() => {})
this.$nextTick(() => {
this.scrollParent().scrollTo({
top: 0,
behavior: 'smooth',
})
})
},
async register() {
// 跳转到首页并请求打开注册弹窗(若已在首页,则变更查询参数强制触发监听)
if (this.$route && this.$route.path === '/home') {
const query = Object.assign({}, this.$route.query, {
openRegister: '1',
_r: Date.now().toString(),
})
await this.$router.replace({ path: '/home', query }).catch(() => {})
} else {
await this.$router
.push({
path: '/home',
query: { openRegister: '1', _r: Date.now().toString() },
})
.catch(() => {})
}
this.$nextTick(() => {
this.scrollParent().scrollTo({
top: 0,
behavior: 'smooth',
})
})
},
logout() {
localStorage.removeItem('userInfo')
this.setUserInfo(undefined)
this.$router.push('/help/index')
// 刷新页面
window.location.reload()
},
},
}
</script>
<style scoped lang="scss">
.top {
background-color: var(--primary-color);
height: 60px;
img {
filter: brightness(0) invert(1);
}
}
.nav-link {
color: #fff;
font-size: 16px;
font-weight: 530;
display: inline-block;
transition: all 0.2s ease;
&:hover {
color: var(--secondary-text-color);
color: var(--primary-color);
}
&::after {
content: '';
position: absolute;
bottom: -7px;
left: 50%;
transform: translateX(-50%) scaleX(0);
transform-origin: center;
width: 120%;
height: 2px;
background-image: linear-gradient(
to right,
#ffffff00 5%,
var(--primary-color),
#ffffff00 95%
);
transition: transform 0.2s ease;
}
&:hover::after {
transform: translateX(-50%) scaleX(1);
}
}
.nav-line {
width: 120%;
height: 2px;
background-image: linear-gradient(
to right,
#ffffff00 5%,
var(--secondary-color),
#ffffff00 95%
);
margin-top: 5px;
transform: scaleX(0);
transform-origin: center;
transition: transform 0.2s ease;
}
.nav-link:hover + .nav-line {
transform: scaleX(1);
}
::v-deep .el-button--default {
......
......@@ -207,7 +207,11 @@
class="reason-list flex justify-between flex-col mt-6 gap-5 lg:gap-0 lg:mt-10 lg:flex-row">
<div class="section-reason-item">
<div class="season-top flex flex-col items-center">
<img src="../assets/images/product/universe.svg" width="80" />
<Icon
icon="icon-park-twotone:planet"
width="80"
height="80"
color="var(--primary-color)" />
<p class="reason-card-title">全生态产品</p>
<p class="text-textPrimary font-normal mt-2 text-sm lg:text-lg">
贴合跨境卖家核心使用场景
......@@ -235,8 +239,11 @@
<div class="section-reason-item">
<div class="season-top flex flex-col items-center">
<img src="../assets/images/product/safety.svg" width="80" />
<Icon
icon="icon-park-twotone:shield-add"
width="80"
height="80"
color="var(--primary-color)" />
<p class="reason-card-title">全方位保障</p>
<p class="text-textPrimary font-normal mt-2 text-sm lg:text-lg">
深度开发能力与数据安全护航
......@@ -260,7 +267,11 @@
</div>
<div class="section-reason-item">
<div class="season-top flex flex-col items-center">
<img src="../assets/images/product/service.svg" width="80" />
<Icon
icon="mingcute:hand-heart-line"
width="80"
height="80"
color="var(--primary-color)" />
<p class="reason-card-title">全周期服务</p>
<p class="text-textPrimary font-normal mt-2 text-sm lg:text-lg">
全程专业服务,满足卖家需求
......@@ -287,12 +298,16 @@
</div>
</template>
<script>
import { Icon } from '@iconify/vue2'
import purchaseImg from '../assets/images/home/01.png'
import financesImg from '../assets/images/home/02.png'
import statementsImg from '../assets/images/home/03.png'
import adImg from '../assets/images/home/04.png'
export default {
name: 'productIntro',
components: {
Icon,
},
data() {
return {
activeTab: 0,
......@@ -728,8 +743,7 @@ export default {
flex-direction: column;
align-items: center;
justify-content: space-between;
box-shadow: 0 0 16px 0 rgb(224, 217, 195), 0 6px 14px 0 hsla(0, 0%, 100%, 0.3),
0 16px 20px 0 rgba(230, 223, 191, 0.25);
box-shadow: 0 0 16px 0 var(--shadow-color);
transition: all 0.4s ease-in-out;
.reason-card-type {
overflow: hidden;
......@@ -739,7 +753,7 @@ export default {
color: rgba(255, 255, 255, 1);
width: 100%;
border-radius: 0 0 16px 16px;
background-color: #eca217;
background-color: var(--primary-color);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80' viewBox='0 0 80 80'%3E%3Cg fill='%23f6cd80' fill-opacity='0.32'%3E%3Cpath fill-rule='evenodd' d='M0 0h40v40H0V0zm40 40h40v40H40V40zm0-40h2l-2 2V0zm0 4l4-4h2l-6 6V4zm0 4l8-8h2L40 10V8zm0 4L52 0h2L40 14v-2zm0 4L56 0h2L40 18v-2zm0 4L60 0h2L40 22v-2zm0 4L64 0h2L40 26v-2zm0 4L68 0h2L40 30v-2zm0 4L72 0h2L40 34v-2zm0 4L76 0h2L40 38v-2zm0 4L80 0v2L42 40h-2zm4 0L80 4v2L46 40h-2zm4 0L80 8v2L50 40h-2zm4 0l28-28v2L54 40h-2zm4 0l24-24v2L58 40h-2zm4 0l20-20v2L62 40h-2zm4 0l16-16v2L66 40h-2zm4 0l12-12v2L70 40h-2zm4 0l8-8v2l-6 6h-2zm4 0l4-4v2l-2 2h-2z'/%3E%3C/g%3E%3C/svg%3E");
background-size: 50px 50px;
background-repeat: repeat;
......@@ -754,9 +768,7 @@ export default {
}
.section-reason-item:hover {
transform: translateY(-8px);
box-shadow: 10px 10px 38px 0 hsla(0, 0%, 100%, 0.3),
0 0 14px 0 rgba(202, 210, 238, 0.2),
28px 36px 50px 0 rgba(221, 214, 180, 0.46);
box-shadow: 10px 10px 38px 0 var(--el-color-primary-light-9);
}
.season-top {
padding: 24px 40px 36px;
......
<template>
<div class="py-16">
<h3 class="timeline-title">发展历程</h3>
<div class="timeline-content flex justify-center items-center">
<div class="w-full">
<div class="flex justify-center items-center mb-14">
<div v-for="(item, index) in timelineItems" :key="index">
<div class="flex items-center">
<div
class="timeline-dot w-5 h-5 rounded-full cursor-pointer transition-all duration-200"
class="timeline-dot rounded-full cursor-pointer transition-all duration-200"
@click="selectTime(index)"
:class="{ 'timeline-dot-current': currentIndex === index }"></div>
<div
v-if="index !== timelineItems.length - 1"
class="timeline-line"></div>
class="timeline-line w-64 h-px"></div>
</div>
<div class="-ml-3 mt-2 text-gray-600 font-semibold text-base">
{{ item.title }}
</div>
<div class="-ml-3">{{ item.title }}</div>
</div>
</div>
<VueSlickCarousel
......@@ -22,16 +22,16 @@
@beforeChange="beforeChange">
<div v-for="(item, index) in timelineItems" :key="index">
<div
class="timeline-card"
class="timeline-card p-10 h-80 w-104 shadow-xl rounded-lg cursor-pointer"
:class="{ 'timeline-card-current': currentIndex === index }">
<div class="card-title">
<div class="w-full text-gray-600 font-semibold text-2xl">
{{ item.title }}
</div>
<div class="card-devider"></div>
<div class="bg-gray-200 mt-3 h-px" />
<div
v-for="(content, index) in item.content"
:key="index"
class="card-content">
class="card-content text-gray-600 relative pt-5 pl-5">
{{ content }}
</div>
</div>
......@@ -59,8 +59,7 @@ export default {
dots: false,
centerMode: true,
focusOnSelect: true,
// 这里使用false会导致后半内容无法居中
infinite: true,
infinite: true, // 这里使用false会导致后半内容无法居中
slidesToShow: 3,
autoplay: false,
},
......@@ -108,51 +107,28 @@ export default {
outline: none; /* 防止点击时出现默认 outline 导致“深色”闪烁感 */
}
.timeline-container {
padding: 50px 0;
}
.timeline-title {
width: 100%;
font-size: 30px;
font-weight: 600;
color: #414141;
text-align: center;
}
.timeline-content {
height: 100px;
}
.timeline-times {
display: flex;
align-items: center;
}
.timeline-dot {
width: 20px;
height: 20px;
background-color: #eca1177a;
transition: all 0.2s ease;
}
.timeline-dot:hover {
background-color: var(--primary-color);
transition: all 0.2s ease;
}
.timeline-dot-current {
border: 5px solid var(--el-color-primary-light-7);
background-color: var(--primary-color);
}
.timeline-line {
width: 300px;
height: 1px;
background-color: var(--light-color);
}
.timeline-card {
height: 300px;
width: 400px;
margin-right: 30px;
box-shadow: 0 5px 10px 4px rgba(0, 0, 0, 0.1);
border-radius: 10px;
cursor: pointer;
border: 1px solid transparent;
background-image: linear-gradient(
to bottom,
......@@ -173,33 +149,12 @@ export default {
border-color: rgba(153, 151, 148, 0.548);
}
.card-title {
height: 60px;
width: 100%;
padding: 35px 0 0 40px;
font-size: 20px;
font-weight: 600;
color: #414141;
}
.card-devider {
height: 1px;
width: 80%;
background-color: #e0e0e0;
margin: 12px auto 0;
}
.card-content {
padding: 20px 0 0 70px;
font-size: 16px;
color: #414141;
position: relative;
&::before {
background-color: var(--primary-color);
border-radius: 50%;
position: absolute;
left: 50px;
left: 5px;
top: 30px;
content: '';
width: 6px;
......
<template>
<div>
<div
v-for="(tab, tabIndex) in tabs"
:key="tabIndex"
class="rounded-md bg-white p-5 mb-10">
<div class="title flex place-content-between mb-5">
<div class="title-left flex items-center">
<img class="h-8" :src="Logo" alt="logo" />
<div class="text-lg font-bold ml-3">{{ tab.title }}</div>
</div>
<div
class="more flex justify-center items-center"
@click="goToMore(tab)">
<div class="text-sm">查看更多</div>
<i class="el-icon-d-arrow-right"></i>
</div>
</div>
<div class="tabs flex gap-5">
<div
class="tab flex justify-center items-center text-gray-700 font-medium text-sm cursor-pointer"
v-for="(sub, index) in tab.content"
@click="setCurrentTab(tabIndex, index)"
:key="sub.key"
:class="{ active: getCurrentTab(tabIndex) === index }">
{{ sub.subtitle }}
</div>
</div>
<div class="tab-content grid grid-cols-3 gap-x-10 gap-y-8 mt-5">
<div
v-for="c in tab.content[getCurrentTab(tabIndex)].articles"
:key="c.article">
<a
@click.prevent="goToArticle(c)"
class="content-title text-gray-500 ml-8 cursor-pointer">
{{ c.article }}
</a>
</div>
</div>
</div>
</div>
</template>
<script>
import Logo from '../../../assets/jomall.png'
export default {
name: 'HomeGuides',
data() {
return {
Logo,
tabs: [
{
title: '入门必看',
url: 'beginner',
content: [
{
subtitle: '新手入门',
key: 'beginner',
articles: [
{
article: '九猫erp是什么?',
url: '/help/artical1',
},
{
article: '如何使用九猫erp?',
url: '/help/artical2',
},
],
},
{
subtitle: '新手入门',
key: 'beginner2',
articles: [
{
article: '九猫erp是什么?',
url: '/help/artical1',
},
],
},
],
},
{
title: '入门必看',
url: 'beginner',
content: [
{
subtitle: '新手入门',
key: 'beginner',
articles: [
{
article: '九猫erp是什么?',
url: '/help/artical1',
},
{
article: '如何使用九猫erp?',
url: '/help/artical2',
},
],
},
{
subtitle: '新手入门',
key: 'beginner2',
articles: [
{
article: '九猫erp是什么?',
url: '/help/artical1',
},
],
},
{
subtitle: '新手入门',
key: 'beginner3',
articles: [
{
article: '九猫erp是什么?',
url: '/help/artical1',
},
{
article: '如何使用九猫erp??',
url: '/help/artical2',
},
{
article: '如何使用九猫erp?',
url: '/help/artical2',
},
],
},
],
},
],
currentTabs: {}, // 为每个tab组维护独立的currentTab
}
},
methods: {
setCurrentTab(tabIndex, index) {
this.$set(this.currentTabs, tabIndex, index)
},
getCurrentTab(tabIndex) {
return this.currentTabs[tabIndex] || 0
},
goToArticle(content) {
const articlePath = content.url.replace('/help/', '')
const breadcrumbPath = [
{ name: '帮助中心', path: 'index' },
{ name: '入门必看', path: 'beginner' },
{ name: content.article, path: articlePath },
]
this.$store.dispatch('path/setCurrentPathNames', breadcrumbPath)
this.$router.push(content.url)
},
goToMore(tab) {
const breadcrumbPath = [
{ name: '帮助中心', path: 'index' },
{ name: tab.title, path: tab.url },
]
this.$store.dispatch('path/setCurrentPathNames', breadcrumbPath)
this.$router.push(`/help/${tab.url}`)
},
},
}
</script>
<style scoped lang="scss">
.more {
color: var(--primary-color);
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
color: var(--light-color);
}
}
.tab {
width: 100px;
height: 40px;
border-radius: 60px;
background-color: var(--el-color-primary-light-9);
transition: all 0.2s ease;
&.active {
background-color: var(--el-color-primary-light-2);
color: white;
font-weight: 600;
}
&:hover:not(.active) {
color: var(--primary-color);
}
}
.content-title {
position: relative;
transition: all 0.2s ease;
&::before {
content: '';
display: block;
width: 6px;
height: 6px;
border-radius: 50%;
position: absolute;
left: -23px;
top: 8px;
background-color: var(--primary-color);
box-shadow: 0 0 0 5px #e6c07977;
}
&:hover {
color: var(--primary-color);
}
}
</style>
<template>
<div class="rounded-md bg-white p-5">
<div class="title flex place-content-between mb-5">
<div class="title-left flex items-center">
<img class="w-10 h-10" :src="beginnerLogo" alt="入门必看" />
<div class="text-lg font-bold ml-3">入门必看</div>
</div>
<div class="more flex justify-center items-center">
<div class="text-sm">查看更多</div>
<i class="el-icon-d-arrow-right"></i>
</div>
</div>
<div class="tabs flex gap-5">
<div
class="tab flex justify-center items-center text-white font-medium text-sm cursor-pointer"
v-for="(tab, index) in tabs"
@click="currentTab = index"
:key="tab.key">
{{ tab.name }}
</div>
</div>
<div class="tab-content grid grid-cols-3 gap-x-10 gap-y-8 mt-5">
<div v-for="content in tabs[currentTab].content" :key="content.title">
<a
@click.prevent="goToArticle(content)"
class="content-title text-gray-500 ml-8 cursor-pointer">
{{ content.title }}
</a>
</div>
</div>
</div>
</template>
<script>
import beginnerLogo from '../../../assets/images/help/beginner.svg'
export default {
name: 'HomeBeginner',
data() {
return {
beginnerLogo,
tabs: [
{
name: '新手入门',
key: 'beginner',
content: [
{
title: '九猫erp是什么?',
url: '/help/artical1',
},
{
title: '如何使用九猫erp?',
url: '/help/artical2',
},
],
},
],
currentTab: 0,
}
},
methods: {
goToArticle(content) {
const articlePath = content.url.replace('/help/', '')
const breadcrumbPath = [
{ name: '帮助中心', path: 'index' },
{ name: '入门必看', path: 'beginner' },
{ name: this.tabs[this.currentTab].name, path: 'beginner' },
{ name: content.title, path: articlePath },
]
this.$store.dispatch('path/setCurrentPathNames', breadcrumbPath)
this.$router.push(content.url)
},
},
}
</script>
<style scoped lang="scss">
.more {
color: var(--primary-color);
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
color: var(--light-color);
}
}
.tab {
width: 100px;
height: 50px;
border-radius: 40px;
background-color: var(--primary-color);
}
.content-title {
position: relative;
transition: all 0.2s ease;
&::before {
content: '';
display: block;
width: 6px;
height: 6px;
border-radius: 50%;
position: absolute;
left: -23px;
top: 8px;
background-color: var(--primary-color);
box-shadow: 0 0 0 5px #e6c07977;
}
&:hover {
color: var(--primary-color);
}
}
</style>
<template>
<div>
<div class="top flex flex-col items-center">
<div class="text-white text-4xl font-bold">帮助中心</div>
<div class="top flex flex-col items-center py-16">
<div class="text-gray-700 text-4xl font-bold">帮助中心</div>
<el-input
v-model="keyword"
class="w-1/3 mt-5 search-input"
......@@ -43,11 +43,6 @@ export default {
}
</script>
<style scoped lang="scss">
.top {
background-color: var(--primary-color);
height: 150px;
}
::v-deep .search-input .el-input__inner {
background-color: #ffffff;
height: 45px;
......@@ -63,11 +58,11 @@ export default {
::v-deep .el-input-group__append {
color: #eceaea;
background-color: #3f419e;
background-color: var(--secondary-color);
border: none;
transition: all 0.2s ease;
&:hover {
background-color: var(--secondary-color-light1);
background-color: var(--secondary-color-light2);
}
}
......
<template>
<div class="flex flex-col w-full gap-5">
<HomeNewer />
<HomeNewer />
<HomeNewer />
<div class="flex flex-col w-full">
<HomeGuides />
</div>
</template>
<script>
import HomeNewer from '../components/homeNewer.vue'
import HomeGuides from '../components/homeGuides.vue'
export default {
components: {
HomeNewer,
HomeGuides,
},
}
</script>
......@@ -11,31 +11,6 @@
</div>
<div class="content-body">
<PriceTable />
<!-- <div class="price-container">
<div class="price-columns">
<div
v-for="(c, i) in priceColumns"
:key="i"
class="price-column"
:class="`${c.labelClass || ''} ${c.class || ''} ${
i === priceColumns.length - 1 ? 'last-column' : ''
}`">
{{ c.label }}
</div>
</div>
<div class="price-items">
<div v-for="(p, i) in prices" :key="i" class="price-item">
<div
v-for="(c, j) in priceColumns"
:key="j"
class="price-value"
:class="`${c.valueClass || ''} ${c.class || ''} ${
j === priceColumns.length - 1 ? 'last-value' : ''
}`"
v-html="value(c, p)"></div>
</div>
</div>
</div> -->
</div>
<div class="lx-section py-8 bg-colorBg lg:px-0 lg:mt-28 lg:py-16">
<div
......
......@@ -285,6 +285,10 @@ export default {
</script>
<style scoped>
/* 表头背景色 */
::v-deep .el-table__header th {
background-color: var(--background-color) !important;
}
/* 高亮表格hover */
::v-deep .el-table tbody tr:hover > td {
background-color: #f5f7fa !important;
......@@ -292,21 +296,21 @@ export default {
/* 高亮当前列(表头与表体) */
::v-deep .el-table td.col-hover,
::v-deep .el-table th.col-hover {
border-right: 2px solid #eca217;
border-left: 2px solid #eca217;
border-right: 2px solid var(--primary-color);
border-left: 2px solid var(--primary-color);
}
/* 表头顶部边框 */
::v-deep .el-table thead th.col-hover {
border-top: 2px solid #eca217;
background-color: #eca217 !important;
border-top: 2px solid var(--primary-color);
background-color: var(--primary-color) !important;
border-radius: 10px 10px 0 0;
color: #ffffff;
}
/* 表体最后一列底部边框 */
::v-deep .el-table tbody tr:last-child td.col-hover {
border-bottom: 2px solid #eca217;
border-bottom: 2px solid var(--primary-color);
border-radius: 0 0 10px 10px;
}
</style>
......@@ -3,6 +3,10 @@ module.exports = {
purge: ['./src/**/*.{vue,js,ts,jsx,tsx}'],
theme: {
extend: {
colors: {
'primary-color': 'var(--primary-color)',
'secondary-color': 'var(--secondary-color)',
},
width: {
104: '26rem',
112: '28rem',
......
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