Commit a311f76a by wusiyi

feat: 帮助页优化

parent bbb8f250
......@@ -10,14 +10,6 @@
</div>
<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-8">
<a class="nav-link relative" :index="nav.path" :href="nav.path">
{{ nav.name }}
</a>
</div>
<div
class="mr-2 flex items-center justify-center gap-2"
v-if="!userInfo">
<div
......@@ -62,10 +54,10 @@
</div>
<div class="flex items-center justify-center gap-2">
<div class="text-sm" v-if="!userInfo">
<span @click="login" class="border-r-2 border-solid border-gray-200">
<span @click="login" class="border-r border-solid border-gray-200">
登录
</span>
<span @click="register">注册</span>
<span @click="register" class="ml-1">注册</span>
</div>
<div class="text-sm flex items-center justify-center" v-else>
<span>{{ userInfo.companyName }}</span>
......@@ -90,11 +82,33 @@
</div>
</div>
</div>
<transition name="head-helper-overlay">
<div v-show="showing" class="head-helper-overlay">
<div class="flex items-center justify-between p-2.5">
<img src="../assets/logo.png" class="w-32" />
<i
class="el-icon-close text-xl font-bold cursor-pointer"
@click="toggleShow" />
</div>
<el-menu
:unique-opened="true"
:default-active="$route.path"
:default-openeds="openedMenus">
<menu-item
v-for="item in menuList"
:key="item.id"
:menu-item="item"
@close-overlay="toggleShow" />
</el-menu>
</div>
</transition>
</div>
</template>
<script>
import { Icon } from '@iconify/vue2'
import { mapMutations } from 'vuex'
import MenuItem from '../views/help/components/MenuItem.vue'
import { menuList } from '../views/help/menuConfig'
export default {
......@@ -104,6 +118,7 @@ export default {
},
components: {
Icon,
MenuItem,
},
props: {
userInfo: {
......@@ -112,14 +127,50 @@ export default {
},
data() {
return {
navs: [
{
name: '首页',
path: '/',
},
],
showing: false,
menuList,
}
},
computed: {
// 需要展开的父级菜单
openedMenus() {
const currentPath = this.$route.path
// 递归查找匹配的菜单项及其父级菜单
const findMenuItem = (items, parentIds = []) => {
for (const item of items) {
// 构建菜单项的完整路径(与 MenuItem.vue 中的逻辑保持一致)
let itemPath = ''
if (item.url) {
// 如果有 url,路径格式为 /help/path/url
itemPath = item.path
? `/help/${item.path}/${item.url}`
: `/help/${item.url}`
} else if (item.path) {
// 如果只有 path,路径格式为 /help/path
itemPath = `/help/${item.path}`
}
// 如果当前路径完全匹配
if (itemPath && itemPath === currentPath) {
return parentIds
}
// 如果有子菜单,递归查找
if (item.children && item.children.length > 0) {
const newParentIds = [...parentIds, String(item.id)]
const result = findMenuItem(item.children, newParentIds)
if (result !== null) {
return result
}
}
}
return null
}
const result = findMenuItem(this.menuList)
return result || []
},
},
methods: {
...mapMutations(['setUserInfo', 'setShopKey']),
......@@ -171,7 +222,7 @@ export default {
window.location.reload()
},
toggleShow() {
console.log(menuList, '???')
this.showing = !this.showing
},
},
}
......@@ -219,4 +270,26 @@ export default {
color: var(--secondary-color);
}
}
.head-helper-overlay-enter-active,
.head-helper-overlay-leave-active {
transition: 0.3s;
}
.head-helper-overlay-enter,
.head-helper-overlay-leave-to {
transform: translateX(100%);
}
.head-helper-overlay {
position: fixed;
top: 0;
right: 0;
width: 100vw;
height: 100vh;
z-index: 99999;
background-color: #fff;
display: flex;
flex-direction: column;
}
</style>
......@@ -100,6 +100,13 @@ const routes = [
props: true,
},
{
path: 'videoTutorial/:id',
name: 'VideoTutorial',
component: (resolve) =>
require(['../views/help/components/picTutorial.vue'], resolve),
props: true,
},
{
path: 'artical1',
name: 'Artical1',
component: (resolve) =>
......
// 默认的帮助中心路径
const DEFAULT_HELP_CENTER = { name: '帮助中心', path: 'index' }
// 确保数组第一个元素是帮助中心
const ensureHelpCenterFirst = (pathNames) => {
if (!pathNames || pathNames.length === 0) {
return [DEFAULT_HELP_CENTER]
}
// 如果第一个元素已经是帮助中心,直接返回
if (pathNames[0].name === '帮助中心') {
return pathNames
}
const filtered = pathNames.filter((item) => item.name !== '帮助中心')
// 将帮助中心添加到第一位
return [DEFAULT_HELP_CENTER, ...filtered]
}
// 从 localStorage 初始化 currentPathNames
const initCurrentPathNames = () => {
try {
const stored = localStorage.getItem('currentPathNames')
const parsed = stored ? JSON.parse(stored) : []
return ensureHelpCenterFirst(parsed)
return stored ? JSON.parse(stored) : []
} catch (e) {
return [DEFAULT_HELP_CENTER]
return []
}
}
......@@ -36,16 +15,14 @@ export default {
},
mutations: {
setCurrentPathNames(state, pathNames) {
// 确保第一个元素是帮助中心
state.currentPathNames = ensureHelpCenterFirst(pathNames || [])
state.currentPathNames = pathNames || []
localStorage.setItem(
'currentPathNames',
JSON.stringify(state.currentPathNames)
)
},
clearCurrentPathNames(state) {
// 清除时保留帮助中心
state.currentPathNames = [DEFAULT_HELP_CENTER]
state.currentPathNames = []
localStorage.setItem(
'currentPathNames',
JSON.stringify(state.currentPathNames)
......
......@@ -9,7 +9,8 @@
<menu-item
v-for="child in menuItem.children"
:key="child.id"
:menu-item="child" />
:menu-item="child"
@close-overlay="$emit('close-overlay')" />
</el-submenu>
<el-menu-item
v-else
......@@ -18,7 +19,7 @@
? '/help/' + menuItem.path + '/' + menuItem.url
: '/help/' + menuItem.path
"
@click="handleMenuItemClick">
@click.native.prevent="handleMenuItemClick">
<span>{{ menuItem.name }}</span>
</el-menu-item>
</div>
......@@ -37,11 +38,41 @@ export default {
},
methods: {
handleMenuItemClick() {
// 构建目标路径
const targetPath = this.menuItem.url
? `/help/${this.menuItem.path}/${this.menuItem.url}`
: `/help/${this.menuItem.path}`
// 如果当前路径已经是目标路径,且没有 link 参数变化,则不跳转
if (this.$route.path === targetPath && !this.menuItem.link) {
return
}
// 如果有 link 属性,需要带上 query 参数
if (this.menuItem.link) {
this.$router.push({
path: `/help/${this.menuItem.path}/${this.menuItem.url}`,
query: { url: this.menuItem.link },
})
this.$router
.push({
path: targetPath,
query: { url: this.menuItem.link },
})
.catch((err) => {
// 忽略导航重复的错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
} else {
// 没有 link 时,使用 replace 避免产生历史记录
this.$router
.replace({
path: targetPath,
})
.catch((err) => {
// 忽略导航重复的错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
const id = [...String(this.menuItem.id)].map(Number)
......@@ -60,6 +91,11 @@ export default {
})
this.$store.dispatch('path/setCurrentPathNames', result)
// 如果是手机端,通知父组件关闭遮罩层
if (this.$isMobile) {
this.$emit('close-overlay')
}
},
},
}
......
<template>
<div>
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item v-for="(item, index) in breadList" :key="item.id">
<a
v-if="index === 0"
href="javascript:void(0)"
@click="handleBreadClick(index)"
:class="{ 'breadcrumb-clickable': true }">
{{ item.name }}
</a>
<span v-else class="breadcrumb-disabled">{{ item.name }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-breadcrumb separator-class="el-icon-arrow-right" class="mb-3">
<el-breadcrumb-item v-for="item in breadList" :key="item.id">
<span class="breadcrumb-disabled">{{ item.name }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script>
export default {
......@@ -31,28 +22,17 @@ export default {
const newPathNames = currentPathNames.slice(0, index + 1)
this.$store.dispatch('path/setCurrentPathNames', newPathNames)
// 如果是帮助中心,跳转到 /help/index
if (index === 0) {
this.$router.push('/help/index')
} else {
this.$router.push(`/help/${clickedItem.path}`)
}
const targetPath =
clickedItem.path === 'index'
? '/help/index'
: `/help/${clickedItem.path}`
this.$router.push(targetPath)
}
},
},
}
</script>
<style scoped>
.breadcrumb-clickable {
color: var(--primary-color);
cursor: pointer;
text-decoration: none;
}
.breadcrumb-clickable:hover {
color: var(--el-color-primary-light-4);
}
.breadcrumb-disabled {
color: #606266;
cursor: default;
......
<template>
<div>
<div
v-for="(tab, tabIndex) in tabs"
:key="tabIndex"
class="rounded-md bg-white p-5 mb-10">
<div v-for="(tab, tabIndex) in tabs" :key="tabIndex">
<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 class="lg:text-lg text-base font-bold ml-3">{{ tab.title }}</div>
</div>
<div
class="more flex justify-center items-center"
@click="goToMore(tab)">
<div class="text-sm">查看更多</div>
<div class="lg:text-sm text-xs">查看更多</div>
<i class="el-icon-d-arrow-right"></i>
</div>
</div>
......@@ -84,7 +81,6 @@ export default {
goToArticle(content) {
const articlePath = content.url.replace('/help/', '')
const breadcrumbPath = [
{ name: '帮助中心', path: 'index' },
{ name: '入门必看', path: 'beginner' },
{ name: content.article, path: articlePath },
]
......
......@@ -5,7 +5,7 @@
</template>
<script>
import { FEISHU_BASE_URL } from '../menuConfig.js'
import { FEISHU_PIC_URL, FEISHU_VIDEO_URL } from '../menuConfig.js'
export default {
name: 'PicTutorial',
......@@ -25,7 +25,10 @@ export default {
const anchor = this.$route.query.url || ''
if (!anchor) return ''
if (this.$route.name === 'PicTutorial') {
return FEISHU_BASE_URL + anchor
return FEISHU_PIC_URL + anchor
}
if (this.$route.name === 'VideoTutorial') {
return FEISHU_VIDEO_URL + anchor
}
return ''
},
......
......@@ -15,9 +15,8 @@
<div class="content p-5">
<sideNav v-if="!$isMobile" />
<div
class="right-content w-full lg:p-5 p-0"
style="height: 90vh"
:class="{ 'rounded-md bg-white': $route.path !== '/help/index' }">
class="right-content w-full lg:p-5 p-2 rounded-md bg-white"
style="height: 90vh">
<Bread v-if="$route.path !== '/help/index'" />
<router-view></router-view>
</div>
......
// 飞书文档基础 URL
const FEISHU_BASE_URL =
// 飞书文档 图文 URL
const FEISHU_PIC_URL =
'https://rcntf4nac0ma.feishu.cn/wiki/OJcBwBJTLi4L0ekvFIPcrHQDnNh'
const FEISHU_VIDEO_URL =
'https://jcnq3gaihyh3.feishu.cn/wiki/PQQzwsNNOiHbg5kGjiVcqHGxnhg'
export const menuList = [
{
id: 1,
......@@ -649,10 +652,128 @@ export const menuList = [
},
],
},
// { id: 3, path: 'video', name: '视频教程' },
{
id: 3,
path: '',
name: '视频教程',
children: [
{
id: 31,
path: 'videoTutorial',
url: '31',
name: '基础数据维护流程教程',
link: '#MAIEdz4uzowUaUxI00XcLzKWnOd',
},
{
id: 32,
path: 'videoTutorial',
url: '32',
name: '平台新增店铺流程教程',
link: '#EkgbdmZVeoTbYixbssYc0wden4c',
},
{
id: 33,
path: 'videoTutorial',
url: '33',
name: '独立站新增店铺流程教程',
link: '#MZqrduLgxoODyPxug52cmzE2ntb',
},
{
id: 34,
path: 'videoTutorial',
url: '34',
name: 'shopify新增店铺流程教程',
link: '#WNk9dtpgTovhCLx8K1GcGAjCnGc',
},
{
id: 35,
path: 'videoTutorial',
url: '35',
name: '仓库信息维护流程教程',
link: '#XqIYdav7OoAB32xsEsccqdiVnih',
},
{
id: 36,
path: 'videoTutorial',
url: '36',
name: '供应商管理维护流程教程',
link: '#HiVUdsJLBok3UUxdZa7cEsvZnKc',
},
{
id: 37,
path: 'videoTutorial',
url: '37',
name: '物流信息维护流程教程',
link: '#XQJ5ddEmRoR10SxM1LicgXj3nig',
},
{
id: 38,
path: 'videoTutorial',
url: '38',
name: '新增普通商品、局部印商品',
link: '#WutLdLTFZooze1xjM7ScJPaSnOb',
},
{
id: 39,
path: 'videoTutorial',
url: '39',
name: '待处理订单流程教程',
link: '#SuREd1RPKoQcRbxgzPYcVTWinMy',
},
{
id: 40,
path: 'videoTutorial',
url: '40',
name: 'BASE异常单流程教程',
link: '#NvKxdLL1sojlgZxyo1AcJnnKn4d',
},
{
id: 41,
path: 'videoTutorial',
url: '41',
name: 'variant异常单流程教程',
link: '#NWh7dIjdDojzsYxFgGVci5L0n0b',
},
{
id: 42,
path: 'videoTutorial',
url: '42',
name: '采购流程教程',
link: '#GnjMdjHZmoguHjxyMYhcyjYSnsG',
},
{
id: 43,
path: 'videoTutorial',
url: '43',
name: '生产流程教程',
link: '#F85qdbqPAoCfhIxjvHacCOM6nMf',
},
{
id: 44,
path: 'videoTutorial',
url: '44',
name: '美国工厂流程教程',
link: '#YG7gdHuOXo2jJhxVQXEcAB17nYg',
},
{
id: 45,
path: 'videoTutorial',
url: '45',
name: '美国仅胚衣流程教程',
link: '#SmHNd6CWFoTcwnxOObLcQglbnJc',
},
{
id: 46,
path: 'videoTutorial',
url: '46',
name: '一件定制流程教程',
link: '#QZNtd6IzFoFNcUxMVcTcUCr6nPg',
},
],
},
// { id: 4, path: 'problem', name: '常见问题' },
// { id: 5, path: 'contact', name: '联系我们' },
]
// 导出基础 URL,供组件使用
export { FEISHU_BASE_URL }
export { FEISHU_PIC_URL, FEISHU_VIDEO_URL }
......@@ -3,13 +3,15 @@
<el-input
class="mt-3 ml-5 w-4/5 mb-5"
v-model="searchKeyword"
placeholder="在目录中搜索..."></el-input>
placeholder="在目录中搜索..." />
<el-menu
router
:unique-opened="true"
:default-active="$route.path"
:default-openeds="openedMenus">
<menu-item v-for="item in menuList" :key="item.id" :menu-item="item" />
<menu-item
v-for="item in filteredMenuList"
:key="item.id"
:menu-item="item" />
</el-menu>
</div>
</template>
......@@ -29,6 +31,14 @@ export default {
}
},
computed: {
// 根据搜索关键词过滤菜单
filteredMenuList() {
if (!this.searchKeyword || this.searchKeyword.trim() === '') {
return this.menuList
}
const keyword = this.searchKeyword.trim().toLowerCase()
return this.filterMenuItems(this.menuList, keyword)
},
// 需要展开的父级菜单
openedMenus() {
const currentPath = this.$route.path
......@@ -68,6 +78,39 @@ export default {
return result || []
},
},
methods: {
// 递归过滤菜单项
filterMenuItems(items, keyword) {
if (!items || items.length === 0) {
return []
}
return items
.map((item) => {
// 检查当前项的名称是否匹配
const nameMatch =
item.name && item.name.toLowerCase().includes(keyword)
// 递归过滤子项
let filteredChildren = []
if (item.children && item.children.length > 0) {
filteredChildren = this.filterMenuItems(item.children, keyword)
}
// 如果当前项匹配或有匹配的子项,则保留该项
if (nameMatch || filteredChildren.length > 0) {
return {
...item,
// 如果当前项匹配,保留所有子项;否则只保留匹配的子项
children: nameMatch ? item.children : filteredChildren,
}
}
return null
})
.filter((item) => item !== null)
},
},
}
</script>
<style scoped lang="scss">
......
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