@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<section :id="category.id" class="faq-category">
|
||||
<h2 class="faq-category-title">{{ category.name }}</h2>
|
||||
<div class="faq-category-list">
|
||||
<FaqItem
|
||||
v-for="q in category.questions"
|
||||
:key="q.id"
|
||||
:question="q.question"
|
||||
:answer="q.answer"
|
||||
:related-links="q.relatedLinks"
|
||||
:initial-open="initialOpen"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
category: { type: Object, required: true },
|
||||
initialOpen: { type: Boolean, default: false },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.faq-category {
|
||||
margin-bottom: @space-2xl;
|
||||
scroll-margin-top: 80px;
|
||||
}
|
||||
|
||||
.faq-category-title {
|
||||
font-size: @font-size-xl;
|
||||
color: @color-primary;
|
||||
margin-bottom: @space-lg;
|
||||
padding-bottom: @space-sm;
|
||||
border-bottom: 2px solid @color-primary-lighter;
|
||||
}
|
||||
|
||||
.faq-category-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: @space-md;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<nav class="faq-nav" aria-label="问题分类">
|
||||
<ul class="faq-nav-list">
|
||||
<li v-for="cat in categories" :key="cat.id">
|
||||
<a
|
||||
:href="`#${cat.id}`"
|
||||
class="faq-nav-item"
|
||||
:class="{ active: activeCat === cat.id }"
|
||||
@click.prevent="$emit('select', cat.id)"
|
||||
>
|
||||
{{ cat.name }}
|
||||
<span class="faq-nav-count">{{ cat.questions.length }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
categories: { type: Array, required: true },
|
||||
activeCat: { type: String, default: '' },
|
||||
})
|
||||
|
||||
defineEmits(['select'])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.faq-nav {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
// 移动端右侧渐变提示可横滑
|
||||
mask-image: linear-gradient(to right, #000 85%, transparent 100%);
|
||||
-webkit-mask-image: linear-gradient(to right, #000 85%, transparent 100%);
|
||||
|
||||
.respond-md({
|
||||
mask-image: none;
|
||||
-webkit-mask-image: none;
|
||||
overflow-x: visible;
|
||||
});
|
||||
}
|
||||
|
||||
.faq-nav-list {
|
||||
display: flex;
|
||||
gap: @space-sm;
|
||||
min-width: max-content;
|
||||
|
||||
.respond-md({
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
});
|
||||
}
|
||||
|
||||
.faq-nav-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: @space-xs;
|
||||
padding: @space-sm @space-lg;
|
||||
font-size: @font-size-sm;
|
||||
color: @color-text-secondary;
|
||||
background: @color-bg-gray;
|
||||
border-radius: @border-radius-full;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
transition: all @transition-fast;
|
||||
min-height: 44px;
|
||||
touch-action: manipulation;
|
||||
|
||||
&:hover {
|
||||
background: @color-primary-bg;
|
||||
color: @color-primary;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: @color-primary;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.faq-nav-count {
|
||||
font-size: @font-size-xs;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<!--
|
||||
SEO关键设计:
|
||||
1. 用<details>/<summary>确保内容在HTML中始终存在(百度蜘蛛可抓取)
|
||||
2. 问题用<h3>标签,语义化
|
||||
3. 答案用<p>纯文本,AI直接引用
|
||||
-->
|
||||
<details class="faq-item" :open="initialOpen || undefined">
|
||||
<summary class="faq-item-question">
|
||||
<h3 class="faq-item-q-text">{{ question }}</h3>
|
||||
<span class="faq-item-icon" aria-hidden="true"></span>
|
||||
</summary>
|
||||
<div class="faq-item-answer">
|
||||
<p class="faq-item-a-text">{{ answer }}</p>
|
||||
<div v-if="relatedLinks && relatedLinks.length" class="faq-item-links">
|
||||
<NuxtLink
|
||||
v-for="link in relatedLinks"
|
||||
:key="link.url"
|
||||
:to="link.url"
|
||||
class="faq-item-link"
|
||||
>
|
||||
{{ link.text }} →
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
question: { type: String, required: true },
|
||||
answer: { type: String, required: true },
|
||||
relatedLinks: { type: Array, default: () => [] },
|
||||
initialOpen: { type: Boolean, default: false },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.faq-item {
|
||||
background: @color-bg-white;
|
||||
border: 1px solid @color-border;
|
||||
border-radius: @border-radius-md;
|
||||
overflow: hidden;
|
||||
transition: border-color @transition-fast;
|
||||
|
||||
&[open] {
|
||||
border-color: @color-primary-lighter;
|
||||
|
||||
.faq-item-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: @color-primary-lighter;
|
||||
}
|
||||
}
|
||||
|
||||
.faq-item-question {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: @space-lg;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
touch-action: manipulation;
|
||||
|
||||
&::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::marker {
|
||||
display: none;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: @color-bg-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.faq-item-q-text {
|
||||
font-size: @font-size-md;
|
||||
font-weight: @font-weight-medium;
|
||||
color: @color-text-primary;
|
||||
flex: 1;
|
||||
padding-right: @space-md;
|
||||
}
|
||||
|
||||
.faq-item-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
transition: transform @transition-base;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background: @color-text-muted;
|
||||
transition: opacity @transition-fast;
|
||||
}
|
||||
|
||||
&::before {
|
||||
top: 50%;
|
||||
left: 2px;
|
||||
right: 2px;
|
||||
height: 2px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&::after {
|
||||
left: 50%;
|
||||
top: 2px;
|
||||
bottom: 2px;
|
||||
width: 2px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
details[open] & {
|
||||
&::after {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 答案展开动画
|
||||
.faq-item-answer {
|
||||
padding: 0 @space-lg @space-lg;
|
||||
animation: fadeSlideIn @transition-base;
|
||||
}
|
||||
|
||||
@keyframes fadeSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.faq-item-a-text {
|
||||
font-size: @font-size-base;
|
||||
color: @color-text-secondary;
|
||||
line-height: @line-height-base;
|
||||
}
|
||||
|
||||
.faq-item-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: @space-md;
|
||||
margin-top: @space-md;
|
||||
padding-top: @space-md;
|
||||
border-top: 1px solid @color-border;
|
||||
}
|
||||
|
||||
.faq-item-link {
|
||||
font-size: @font-size-sm;
|
||||
color: @color-primary;
|
||||
text-decoration: none;
|
||||
font-weight: @font-weight-medium;
|
||||
|
||||
&:hover {
|
||||
color: @color-primary-light;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
在新工单中引用
屏蔽一个用户