feat: 规范化页面导航与交互体验,优化多端适配

- 统一定制顶部导航组件,支持沉浸式渐变主题与返回逻辑
- 适配 H5 环境的页面跳转逻辑,避免 reLaunch 导致的闪屏问题
- 重构会员、充值、发布等页面布局,改用 Grid 提升移动端适配
- 优化搜索、收藏、消息等页面交互细节,增加点击反馈
- 统一配置页面导航样式,替换原生导航为自定义组件
这个提交包含在:
2026-10-20 13:56:05 +08:00
父节点 c2e0f72b30
当前提交 d508949921
共有 20 个文件被更改,包括 716 次插入 和 182 次删除

查看文件

@@ -1,7 +1,31 @@
<template>
<view class="detail fc-page">
<!-- 顶部视觉 -->
<view class="detail__hero">
<!-- 规范化顶部导航 -->
<fc-navbar title="详情" theme="gradient" :show-back="true" />
<!-- 顶部实拍画廊 / 轮播图或分类插画 -->
<view v-if="imageUrls.length" class="detail__gallery">
<swiper
class="detail__swiper"
circular
:autoplay="imageUrls.length > 1"
:interval="4000"
:duration="400"
@change="onSwiperChange"
>
<swiper-item v-for="(img, idx) in imageUrls" :key="idx" @click="previewImages(idx)">
<image class="detail__swiper-img" :src="img" mode="aspectFill" />
</swiper-item>
</swiper>
<view v-if="imageUrls.length > 1" class="detail__swiper-badge">
<text>{{ activeSwiperIndex + 1 }} / {{ imageUrls.length }}</text>
</view>
<view class="detail__hero-badges detail__hero-badges--float">
<text class="fc-tag detail__badge">{{ post.categoryName }}</text>
<text v-if="post.isPaid" class="fc-tag detail__badge detail__badge--paid">置顶推荐</text>
</view>
</view>
<view v-else class="detail__hero">
<view class="detail__hero-thumb">
<image class="detail__hero-img" :src="catIcon()" mode="aspectFit" />
</view>
@@ -194,8 +218,11 @@ import { fromNow, maskPhone } from '@/common/utils/format.js'
import { pay } from '@/common/utils/pay.js'
import { useUserStore } from '@/common/store/index.js'
import config from '@/common/config/index.js'
import FcNavbar from '@/components/fc-navbar/fc-navbar.vue'
import { assetUrl } from '@/common/utils/format.js'
export default {
components: { FcNavbar },
data() {
return {
id: 0,
@@ -214,6 +241,7 @@ export default {
commentText: '',
// 支付/提交中:防连点重复下单(余额支付是即时扣款)
submitting: false,
activeSwiperIndex: 0,
}
},
computed: {
@@ -221,6 +249,20 @@ export default {
return fromNow(this.post.createdAt)
},
/** 详情是否带真实坐标(契约新增 lat/lng) */
imageUrls() {
const list = []
if (this.post.media && Array.isArray(this.post.media)) {
this.post.media.forEach((m) => {
if (typeof m === 'string' && !m.match(/\.(mp4|mov|avi)$/i)) {
list.push(assetUrl(m))
}
})
}
if (!list.length && this.post.cover) {
list.push(assetUrl(this.post.cover))
}
return list
},
hasLocation() {
return this.post.lat != null && this.post.lng != null
},
@@ -424,6 +466,51 @@ export default {
.detail {
padding-bottom: 40rpx;
}
.detail__gallery {
position: relative;
width: 100%;
height: 480rpx;
overflow: hidden;
background: #000000;
}
.detail__swiper {
width: 100%;
height: 100%;
}
.detail__swiper-img {
width: 100%;
height: 100%;
cursor: pointer;
}
.detail__swiper-badge {
position: absolute;
right: 24rpx;
bottom: 24rpx;
padding: 4rpx 18rpx;
border-radius: 999rpx;
background: rgba(0, 0, 0, 0.55);
color: #ffffff;
font-size: 22rpx;
letter-spacing: 1rpx;
}
.detail__hero-badges--float {
position: absolute;
left: 24rpx;
bottom: 24rpx;
margin-top: 0;
z-index: 2;
}
.detail__content {
white-space: pre-wrap;
word-break: break-all;
line-height: 1.6;
}
.detail__title {
word-break: break-all;
line-height: 1.4;
}
.detail__hero {
padding: 32rpx 24rpx 0;
}