diff --git a/frontend/pages/asset-detail/asset-detail.vue b/frontend/pages/asset-detail/asset-detail.vue index ba0fa4e..a9f1f09 100644 --- a/frontend/pages/asset-detail/asset-detail.vue +++ b/frontend/pages/asset-detail/asset-detail.vue @@ -6,14 +6,11 @@ - + - + @@ -116,8 +113,8 @@ - - + + - - + - - + + :class="{ 'no-transition': disableTransition }" :style="getCardStyle(index)"> - + - - - + - - {{ category.name }} - - - + - - - - @@ -60,35 +38,14 @@ export default { onShow() { try { - uni.hideToast(); - } catch (e) { - /* noop */ - } - try { - uni.hideLoading(); - } catch (e) { - /* noop */ - } + uni.hideToast() + uni.hideLoading() + } catch (e) { } }, data() { return { selectedCategoryIndex: 0, - selectedIndex: 0, - touchStartY: 0, - // 大分类名称 → 页面路由映射,方便扩展 - cardRoutes: { - '光栅卡': '/pages/castlove/lenticular/lenticular-create', - '拍立得': '/pages/castlove/create', - '镭射卡': '/pages/castlove/create', - '撕拉片': '/pages/castlove/create', - }, - // 大分类列表 - categoryList: [ - { name: '星卡' }, - { name: '吧唧' }, - { name: '海报' }, - ], - // 各分类下的工艺卡片 + categoryList: [{ name: '星卡' }, { name: '吧唧' }, { name: '海报' }], cardListMap: { '星卡': [ { name: '光栅卡', image: '/static/castlove/guangshanka.png', comingSoon: false }, @@ -97,20 +54,8 @@ export default { { name: '镭射卡', image: '/static/castlove/leisheka.png', comingSoon: false }, { name: '撕拉片', image: '/static/castlove/silapian.png', comingSoon: false }, ], - '吧唧': [ - // { name: '光栅卡', image: '/static/castlove/guangshanka.png', comingSoon: false }, - // { name: '拍立得', image: '/static/castlove/pailide.png', comingSoon: false }, - // { name: '镭射卡', image: '/static/castlove/leisheka.png', comingSoon: false }, - // { name: '撕拉片', image: '/static/castlove/silapian.png', comingSoon: false }, - // { name: '开发中', image: '/static/castlove/daikaifa.png', comingSoon: true } - ], - '海报': [ - // { name: '光栅卡', image: '/static/castlove/guangshanka.png', comingSoon: false }, - // { name: '拍立得', image: '/static/castlove/pailide.png', comingSoon: false }, - // { name: '镭射卡', image: '/static/castlove/leisheka.png', comingSoon: false }, - // { name: '撕拉片', image: '/static/castlove/silapian.png', comingSoon: false }, - // { name: '开发中', image: '/static/castlove/daikaifa.png', comingSoon: true } - ] + '吧唧': [], + '海报': [] }, cardList: [ { name: '光栅卡', image: '/static/castlove/guangshanka.png', comingSoon: false }, @@ -118,152 +63,152 @@ export default { { name: '镭射卡', image: '/static/castlove/leisheka.png', comingSoon: false }, { name: '撕拉片', image: '/static/castlove/silapian.png', comingSoon: false }, { name: '开发中', image: '/static/castlove/daikaifa.png', comingSoon: true } - ] + ], + cardRoutes: { + '光栅卡': '/pages/castlove/lenticular/lenticular-create', + '拍立得': '/pages/castlove/create', + '镭射卡': '/pages/castlove/create', + '撕拉片': '/pages/castlove/create', + }, + + totalCard: 5, + selectedIndex: 1, // 默认第2张 + touchStartY: 0, + dragOffset: 0, + isDragging: false, + disableTransition: false, + SWIPE_STEP: 100, } }, computed: { currentCardList() { - const categoryName = this.categoryList[this.selectedCategoryIndex].name - return this.cardListMap[categoryName] || this.cardList + const name = this.categoryList[this.selectedCategoryIndex]?.name + return this.cardListMap[name] || this.cardList } }, methods: { - // 选择大分类 selectCategory(index) { this.selectedCategoryIndex = index - this.selectedIndex = 0 // 重置子选项选中 + this.selectedIndex = 1 + this.dragOffset = 0 + this.isDragging = false }, - // 触摸开始 onTouchStart(e) { this.touchStartY = e.touches[0].clientY + this.isDragging = true + this.disableTransition = true }, - // 触摸结束 - 滑动切换工艺卡片 - onTouchEnd(e) { - const touchEndY = e.changedTouches[0].clientY - const diff = this.touchStartY - touchEndY - const threshold = 50 // 滑动阈值 + onTouchMove(e) { + if (!this.isDragging) return + const moveY = e.touches[0].clientY + this.dragOffset = moveY - this.touchStartY + }, + onTouchEnd() { + if (!this.isDragging) return + this.isDragging = false + this.disableTransition = false - if (diff > threshold) { - // 向上滑动 → 下一个工艺卡片 - let newIndex = this.selectedIndex + 1 - if (newIndex < this.currentCardList.length) { - this.selectCard(newIndex) - } - } else if (diff < -threshold) { - // 向下滑动 → 上一个工艺卡片 - let newIndex = this.selectedIndex - 1 - if (newIndex >= 0) { - this.selectCard(newIndex) - } - } + const moveCount = Math.round(-this.dragOffset / this.SWIPE_STEP) + let newIdx = this.selectedIndex + moveCount + newIdx = ((newIdx % 5) + 5) % 5 + this.selectedIndex = newIdx + this.dragOffset = 0 }, - // 获取卡片样式 - 循环滚动布局 - // positions 定义了5个位置的固定样式(位置0最上,位置2中间,位置4最下) - // 当选中某个卡片时,该卡片显示在位置2(中间),其他卡片循环填充 + + // ====================== 核心修复:z-index + 层级 + 循环 ====================== getCardStyle(index) { const positions = [ - { left: 9 * 32, top: 2 * 32, rotate: 25, scale: 0.75 }, // 位置0 - 最上 - { left: 3.75 * 32, top: 9 * 32, rotate: 12, scale: 0.95 }, // 位置1 - 中上 - { left: 60, top: 580, rotate: 0, scale: 1 }, // 位置2 - 中间 - { left: 3.75 * 32, top: 27.75 * 32, rotate: -12, scale: 0.95 }, // 位置3 - 中下 - { left: 7 * 32, top: 34.25 * 32, rotate: -25, scale: 0.75 } // 位置4 - 最下 - ]; + { left: 288, top: 64, rotate: 25, scale: 0.75 }, + { left: 120, top: 288, rotate: 12, scale: 0.95 }, + { left: 60, top: 580, rotate: 0, scale: 1 }, + { left: 120, top: 888, rotate: -12, scale: 0.95 }, + { left: 224, top: 1096, rotate: -25, scale: 0.75 }, + ] - // 计算当前卡片应该显示在哪个位置 - // 循环移位:selectedIndex 的卡片显示在位置2(中间) - const cardPos = (index - this.selectedIndex + 2 + 5) % 5; - const pos = positions[cardPos]; + const progress = -this.dragOffset / this.SWIPE_STEP + const centerIdx = this.selectedIndex + progress - // 选中卡片在中间位置时放大 - if (cardPos === 2) { + // 循环最短差值(关键) + let diff = index - centerIdx + if (diff > 2) diff -= 5 + if (diff < -2) diff += 5 + const cardPos = diff + 2 + + // 插值计算 + let pos + if (Number.isInteger(cardPos)) { + pos = positions[cardPos] ?? positions[2] + } else { + const prev = Math.floor(cardPos) + const next = (prev + 1) % 5 + const t = cardPos - prev + const p = positions[prev] ?? positions[2] + const n = positions[next] ?? positions[2] + pos = { + left: p.left + (n.left - p.left) * t, + top: p.top + (n.top - p.top) * t, + rotate: p.rotate + (n.rotate - p.rotate) * t, + scale: p.scale + (n.scale - p.scale) * t, + } + } + + // ====================== Z‑INDEX 终极修复 ====================== + const distance = Math.abs(cardPos - 2) + const zIndex = Math.round(100 - distance * 30) // 越靠近中间层级越高 + const isCenter = distance < 0.02 + + if (isCenter) { return { - left: `${pos.left}rpx`, - top: `${pos.top}rpx`, - transform: `scale(${pos.scale * 1.15}) rotate(0deg)`, - zIndex: 100 - }; + left: pos.left + 'rpx', + top: pos.top + 'rpx', + transform: `scale(${pos.scale * 1.15}) rotate(${pos.rotate}deg)`, + zIndex: 999, // 中心永远最高 + } } return { - left: `${pos.left}rpx`, - top: `${pos.top}rpx`, + left: pos.left + 'rpx', + top: pos.top + 'rpx', transform: `scale(${pos.scale}) rotate(${pos.rotate}deg)`, - zIndex: 30 - Math.abs(cardPos - 2) * 10 - }; + zIndex, + } }, - // 选择卡片 - selectCard(index) { - this.selectedIndex = index; - }, - /** 当前叠卡在弧形布局中的槽位:2=正中主图(最大),1=中上「第二张」叠层,0最上… */ + getCardStackPosition(index) { - return (index - this.selectedIndex + 2 + 5) % 5; + const progress = -this.dragOffset / this.SWIPE_STEP + const centerIdx = this.selectedIndex + progress + let diff = index - centerIdx + if (diff > 2) diff -= 5 + if (diff < -2) diff += 5 + return diff + 2 }, - /** - * 点击卡图区域: - * - 正中主图(槽位 2)→ 进入对应工艺创建页(光栅卡即进入已接入预览的 create) - * - 中上叠层(槽位 1,常为拍立得示意)在选中光栅时 → 同样进入光栅卡创建(与设计稿「点第二张进光栅」一致) - * - 其余叠层 → 仅切换选中 - */ + onCardFrameTap(index) { - const card = this.currentCardList[index]; - if (!card) { - return; - } - const pos = this.getCardStackPosition(index); - // 只有中间位置的卡片点击才会进入创建页 - // 其他位置点击只是切换选中(把卡片移到中间),再次点击中间卡片才进入 - if (pos === 2) { + const card = this.currentCardList[index] + if (!card) return + const pos = this.getCardStackPosition(index) + if (Math.abs(pos - 2) < 0.2) { if (card.name === '光栅卡') { - const route = this.cardRoutes[card.name]; - if (route) { - uni.navigateTo({ - url: `${route}?name=${encodeURIComponent(card.name)}`, - }); - } + uni.navigateTo({ + url: this.cardRoutes['光栅卡'] + '?name=' + encodeURIComponent(card.name), + }) } else { - uni.showToast({ - title: '激情开发中', - icon: 'none', - }); + uni.showToast({ title: '激情开发中', icon: 'none' }) } - return; + return } - this.selectCard(index); - }, - handleBack() { - uni.navigateBack() + this.selectedIndex = index }, + scrollUp() { - let newIndex = this.selectedCategoryIndex - 1; - if (newIndex >= 0) { - this.selectCategory(newIndex); - } + if (this.selectedCategoryIndex > 0) this.selectCategory(this.selectedCategoryIndex - 1) }, scrollDown() { - let newIndex = this.selectedCategoryIndex + 1; - if (newIndex < this.categoryList.length) { - this.selectCategory(newIndex); + if (this.selectedCategoryIndex < this.categoryList.length - 1) { + this.selectCategory(this.selectedCategoryIndex + 1) } }, - handleSkip() { - const card = this.cardList[this.selectedIndex] - if (card.name === '光栅卡') { - const route = this.cardRoutes[card.name] - if (route) { - uni.navigateTo({ - url: `${route}?name=${encodeURIComponent(card.name)}` - }) - } - } else { - uni.showToast({ - title: '激情开发中', - icon: 'none', - }); - } - - } - } + }, } @@ -274,14 +219,13 @@ export default { overflow: hidden; } -/* 背景图片 */ .bg-wrapper { - position: fixed; - top: -16rpx; - left: 0; - width: 100%; - height: 110%; - z-index: 0; + position: fixed; + top: -16rpx; + left: 0; + width: 100%; + height: 110%; + z-index: 0; } .main-container { @@ -303,11 +247,12 @@ export default { position: absolute; width: 344rpx; height: 344rpx; - transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); + transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); + will-change: transform, z-index; } -.card-frame--tappable { - cursor: pointer; +.card-item.no-transition { + transition: none !important; } .card-frame { @@ -316,21 +261,18 @@ export default { height: 100%; border-radius: 20rpx; padding: 10rpx; - overflow: visible; background-image: url('/static/square/cangpinkuang1.png'); background-size: cover; - box-shadow: 0 0 0 rgba(0, 0, 0, 0.5); +} - &.no-border { - background-image: none; - } +.card-frame.no-border { + background-image: none; } .card-image { width: 100%; height: 100%; border-radius: 14rpx; - display: block; object-fit: cover; } @@ -343,26 +285,18 @@ export default { height: 160rpx; } -// .card-selected .card-frame { -// border-color: #ffd700; -// box-shadow: -// 0 0 60rpx rgba(255, 215, 0, 0.8), -// 0 20rpx 60rpx rgba(0, 0, 0, 0.4), -// inset 0 2rpx 10rpx rgba(255, 255, 255, 0.6); -// } - .text-panel { position: absolute; right: 30rpx; top: 50%; transform: translateY(-50%); width: 200rpx; - height: 392rpx; // 18rem = 360rpx + height: 392rpx; display: flex; flex-direction: column; align-items: center; justify-content: center; - background: url('/static/castlove/xiahualan.png') no-repeat center center; + background: url('/static/castlove/xiahualan.png') no-repeat center; background-size: 130%; border-radius: 20rpx; } @@ -374,10 +308,6 @@ export default { align-items: center; justify-content: center; opacity: 0.8; - - &:active { - opacity: 0.6; - } } .arrow-icon { @@ -388,84 +318,30 @@ export default { .text-list { display: flex; flex-direction: column; - justify-content: center; padding: 0 20rpx; } .text-item { - color: rgba(255, 255, 255); + color: #fff; font-size: 26rpx; font-weight: 500; - transition: all 0.3s ease; - position: relative; padding: 10rpx 20rpx; border-radius: 14rpx; display: flex; justify-content: center; - - &.active { - color: #fff; - font-weight: bold; - text-shadow: 0 0 10rpx rgba(0, 0, 0, 0.8); - background: url('/static/nft/dingbutubiao_liang.png') no-repeat center center; - background-size: 100% 100%; - } - - &.font-large { - font-size: 34rpx; - } - - &.font-mid { - font-size: 30rpx; - } - - &.font-small { - font-size: 26rpx; - } } -.nav-bar { - position: absolute; - bottom: 0; - left: 0; - right: 0; - display: flex; - padding: 30rpx 40rpx; - padding-bottom: calc(30rpx + env(safe-area-inset-bottom)); - z-index: 20; +.text-item.active { + font-weight: bold; + background: url('/static/nft/dingbutubiao_liang.png') no-repeat center; + background-size: 100% 100%; } -.btn-secondary, -.btn-skip { - flex: 1; - height: 88rpx; - line-height: 88rpx; - border-radius: 44rpx; - font-size: 36rpx; - font-family: 'yt', sans-serif; - font-weight: 600; - border: none; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3); - text-shadow: 0 4rpx 4rpx rgba(0, 0, 0, 0.3); +.font-large { + font-size: 34rpx; } -.btn-secondary { - background: rgba(255, 255, 255, 0.2); - backdrop-filter: blur(10rpx); - color: #e6e6e6; - border: 2rpx solid rgba(255, 255, 255, 0.4); - margin-right: 20rpx; -} - -.btn-secondary::after { - border: none; -} - -.btn-skip { - background: linear-gradient(165deg, #F0E4B1 0%, #F08399 50%, #B94E73 90%, #834B9E 100%); - color: #e6e6e6; +.font-mid { + font-size: 30rpx; } \ No newline at end of file diff --git a/frontend/pages/components/Header.vue b/frontend/pages/components/Header.vue index bc1de9f..3227b40 100644 --- a/frontend/pages/components/Header.vue +++ b/frontend/pages/components/Header.vue @@ -125,15 +125,15 @@ const props = defineProps({ }, showTaskIcon: { type: Boolean, - default: true, + default: false, }, showGuideIcon: { type: Boolean, - default: true, + default: false, }, showStarActivityIcon: { type: Boolean, - default: true, + default: false, }, }); @@ -480,14 +480,14 @@ defineExpose({ /* --- 上层图标样式 --- */ .task-icon-box { position: absolute; - top: 40rpx; + top: 32rpx; /* 固定在顶部 */ left: 50%; transform: translateX(-50%); /* 水平居中 */ width: 34rpx; /* 图标宽度 */ - height: 40rpx; + height: 48rpx; /* 图标高度 */ z-index: 10; /* 确保图标在文字块上面 */ diff --git a/frontend/pages/profile/profile.vue b/frontend/pages/profile/profile.vue index f8d6afe..e4efdef 100644 --- a/frontend/pages/profile/profile.vue +++ b/frontend/pages/profile/profile.vue @@ -34,7 +34,7 @@ {{ nickname }} - +