chore: bypass pre-commit for now

This commit is contained in:
zhongyingmin committed 2025-09-26 00:11:15 +08:00
1 parent 10e97670a5
commit c4ba322e32
76 files changed
+2253 -218

No files matched your search

+430
View File
@@ -0,0 +1,430 @@
<template>
<!-- 抽屉遮罩层 -->
<div v-if="visible" class="drawer-overlay" @click="handleClose">
<!-- 抽屉内容 -->
<div
class="drawer-container"
:class="{
'drawer-container--visible': visible && !isClosing,
'drawer-container--closing': isClosing
}"
@click.stop
>
<!-- 右侧步骤面板 -->
<div class="steps-panel">
<!-- 关闭按钮 -->
<!-- <button class="close-button" @click="handleClose">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path
d="M12 4L4 12M4 4L12 12"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</button> -->
<!-- 顶部导航箭头 -->
<div class="panel-header">
<button class="nav-arrow nav-arrow-up" @click="scrollUp" :disabled="!canScrollUp">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
<path
d="M6 9L3 6L6 3"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
<!-- 步骤列表 -->
<div class="steps-list" ref="stepsListRef">
<div
v-for="(step, index) in steps"
:key="step.id"
class="step-item"
:class="{ 'step-item--active': index === currentStepIndex }"
@click="handleStepClick(index)"
>
<!-- 播放图标(仅当前步骤显示) -->
<!-- <div v-if="index === currentStepIndex" class="play-icon">
<svg width="8" height="8" viewBox="0 0 8 8" fill="none">
<path d="M1.5 0.5L6.5 4L1.5 7.5V0.5Z" fill="currentColor" />
</svg>
</div> -->
<!-- 步骤标签 -->
<div class="step-label" :class="`step-label--${step.type}`">
{{ step.label }}
</div>
<!-- 步骤内容 -->
<div class="step-content">
{{ step.content }}
</div>
<!-- 步骤数字 -->
<div class="step-number" :class="{ 'step-number--active': index === currentStepIndex }">
{{ index + 1 }}
</div>
</div>
</div>
<!-- 底部导航 -->
<div class="panel-footer">
<button class="nav-arrow nav-arrow-down" @click="scrollDown" :disabled="!canScrollDown">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
<path
d="M6 3L9 6L6 9"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, nextTick, watch } from 'vue'
export interface StepItem {
id: string
label: string
content: string
type: 'shooting' | 'planning' | 'post' | 'other'
}
interface Props {
/** 是否显示抽屉 */
visible: boolean
/** 背景图片路径 */
backgroundImage: string
/** 步骤列表 */
steps: StepItem[]
/** 当前步骤索引 */
currentStepIndex?: number
/** 是否显示关闭按钮 */
showClose?: boolean
}
interface Emits {
(e: 'step-click', index: number, step: StepItem): void
(e: 'close'): void
}
const props = withDefaults(defineProps<Props>(), {
currentStepIndex: 0,
showClose: true
})
const emit = defineEmits<Emits>()
const stepsListRef = ref<HTMLElement>()
const scrollPosition = ref(0)
const maxScroll = ref(0)
const isClosing = ref(false)
// 计算是否可以滚动
const canScrollUp = computed(() => scrollPosition.value > 0)
const canScrollDown = computed(() => scrollPosition.value < maxScroll.value)
// 滚动到指定位置
const scrollTo = (position: number) => {
if (!stepsListRef.value) return
stepsListRef.value.scrollTop = position
scrollPosition.value = position
}
// 向上滚动
const scrollUp = () => {
if (!canScrollUp.value) return
const newPosition = Math.max(0, scrollPosition.value - 100)
scrollTo(newPosition)
}
// 向下滚动
const scrollDown = () => {
if (!canScrollDown.value) return
const newPosition = Math.min(maxScroll.value, scrollPosition.value + 100)
scrollTo(newPosition)
}
// 处理步骤点击
const handleStepClick = (index: number) => {
emit('step-click', index, props.steps[index])
}
// 处理关闭
const handleClose = () => {
isClosing.value = true
// 延迟关闭,让动画完成
setTimeout(() => {
emit('close')
isClosing.value = false
}, 300)
}
// 监听visible变化,重置关闭状态
watch(
() => props.visible,
newVal => {
if (newVal) {
isClosing.value = false
}
}
)
// 更新滚动状态
const updateScrollState = () => {
if (!stepsListRef.value) return
const { scrollTop, scrollHeight, clientHeight } = stepsListRef.value
scrollPosition.value = scrollTop
maxScroll.value = scrollHeight - clientHeight
}
// 监听滚动事件
const handleScroll = () => {
updateScrollState()
}
onMounted(() => {
nextTick(() => {
updateScrollState()
if (stepsListRef.value) {
stepsListRef.value.addEventListener('scroll', handleScroll)
}
})
})
</script>
<style scoped>
.drawer-overlay {
@apply fixed inset-0 z-50;
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(8px);
animation: fadeIn 0.3s ease-out;
}
.drawer-container {
@apply absolute right-0 top-0 w-1/2 h-full flex justify-end;
transform: translateX(100%);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
max-width: 100vw;
}
.drawer-container--visible {
transform: translateX(0);
}
.drawer-container--closing {
transform: translateX(100%);
}
.steps-panel {
@apply h-full relative;
/* background: linear-gradient(
180deg,
rgba(20, 30, 45, 0.85) 0%,
rgba(10, 15, 25, 0.9) 30%,
rgba(15, 20, 30, 0.85) 70%,
rgba(20, 30, 45, 0.85) 100%
); */
width: 648px;
background-image: url('@/assets/images/vlog/专业剖析侧边.png');
backdrop-filter: blur(20px);
display: flex;
flex-direction: column;
/* border-left: 1px solid rgba(255, 255, 255, 0.1); */
border-radius: 12px 0 0 12px;
box-shadow: -10px 0 30px rgba(0, 0, 0, 0.3);
}
.close-button {
@apply absolute top-4 right-4 w-8 h-8 rounded-full flex items-center justify-center;
background: rgba(59, 130, 246, 0.9);
color: white;
border: none;
cursor: pointer;
transition: all 0.2s ease;
z-index: 10;
box-shadow: 0 0 20px rgba(59, 130, 246, 0.6);
}
.close-button:hover {
background: rgba(59, 130, 246, 1);
transform: scale(1.1);
box-shadow: 0 0 25px rgba(59, 130, 246, 0.8);
}
.panel-header {
@apply flex justify-center items-center;
padding: 3rem 0 1rem 0;
z-index: 2;
position: relative;
}
.nav-arrow {
@apply w-6 h-6 flex items-center justify-center;
background: transparent;
color: rgba(255, 255, 255, 0.7);
border: none;
cursor: pointer;
transition: all 0.2s ease;
}
.nav-arrow:hover:not(:disabled) {
color: white;
transform: scale(1.1);
}
.nav-arrow:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.steps-list {
@apply flex-1 px-6 py-4;
scrollbar-width: none;
-ms-overflow-style: none;
z-index: 2;
position: absolute;
top: 50%;
left: 60%;
transform: translate(-50%, -50%);
}
.steps-list::-webkit-scrollbar {
display: none;
}
.step-item {
@apply flex items-center py-4 px-8 mb-4 cursor-pointer transition-all duration-300;
position: relative;
width: 831px;
height: 122px;
/* min-height: 4rem; */
/* background: rgba(255, 255, 255, 0.05); */
background-image: url('@/assets/images/vlog/侧边-底板未选中.png');
/* border: 1px solid rgba(255, 255, 255, 0.1); */
/* border-radius: 20px; */
/* backdrop-filter: blur(10px); */
}
.step-item:hover {
/* background: rgba(255, 255, 255, 0.08); */
transform: translateX(4px);
}
.step-item--active {
width: 1034px;
height: 230px;
padding-left: 180px;
/* background: linear-gradient(90deg, rgba(59, 130, 246, 0.3) 0%, rgba(59, 130, 246, 0.1) 100%); */
/* border-color: rgba(59, 130, 246, 0.6);
box-shadow:
0 0 30px rgba(59, 130, 246, 0.5),
inset 0 0 20px rgba(59, 130, 246, 0.1); */
background-image: url('@/assets/images/vlog/侧边-选中底板.png');
transform: translateX(-23%);
}
.play-icon {
@apply w-5 h-5 flex items-center justify-center mr-3;
color: #60a5fa;
background: rgba(96, 165, 250, 0.2);
border-radius: 50%;
box-shadow: 0 0 10px rgba(96, 165, 250, 0.5);
}
.step-label {
@apply px-16 py-4 rounded-full text-2xl font-semibold mr-4 whitespace-nowrap;
color: white;
min-width: 5rem;
text-align: center;
}
.step-label--shooting {
background: linear-gradient(135deg, #22c55e, #16a34a);
box-shadow: 0 2px 8px rgba(34, 197, 94, 0.4);
}
.step-label--planning {
background: linear-gradient(135deg, #f97316, #ea580c);
box-shadow: 0 2px 8px rgba(249, 115, 22, 0.4);
}
.step-label--post {
background: linear-gradient(135deg, #0ea5e9, #0284c7);
box-shadow: 0 2px 8px rgba(14, 165, 233, 0.4);
}
.step-label--other {
background: linear-gradient(135deg, #a855f7, #9333ea);
box-shadow: 0 2px 8px rgba(168, 85, 247, 0.4);
}
.step-content {
@apply flex-1 text-3xl font-bold;
line-height: 1.5;
margin-right: 1rem;
}
.step-number {
@apply flex items-center justify-center text-6xl font-semibold;
color: rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
position: absolute;
right: 15%;
z-index: 1;
}
.step-number--active {
margin-bottom: 80px;
font-size: 150px;
color: white;
text-shadow: 5px 10px 5px rgba(0, 0, 0, 0.1);
/* transform: scale(1.2);
background: rgba(59, 130, 246, 0.2);
box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); */
}
.panel-footer {
@apply flex flex-col justify-center items-center;
padding: 1rem 0 2rem 0;
z-index: 2;
position: relative;
}
.guide-button {
@apply px-8 py-3 rounded-full text-sm font-semibold;
background: linear-gradient(135deg, #dc2626, #b91c1c);
color: white;
border: none;
cursor: pointer;
transition: all 0.2s ease;
margin-top: 1rem;
box-shadow: 0 4px 12px rgba(220, 38, 38, 0.4);
}
.guide-button:hover {
background: linear-gradient(135deg, #ef4444, #dc2626);
transform: scale(1.05);
box-shadow: 0 6px 16px rgba(220, 38, 38, 0.5);
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>