- 设计令牌层:mm-* CSS 变量与工具类、uView 换肤、优设标题黑字体 - 九个页面全部重写为新风格(列表/详情/下单/出行人/订单/支付成功/登录) - 补齐 H5 运行时缺失的基础样式(uni-view/scroll-view/toast/swiper 等,App.vue 全局) - 修复:详情头图轮播、预订须知弹层滚动、出行人数量按购买数限制、订单详情去箭头 - 新增 gmy-back-touch 返回悬浮钮,除首页外全页接入,点击返回上一页 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
257 lines
5.8 KiB
Vue
257 lines
5.8 KiB
Vue
<template>
|
||
<view class="page mm-page">
|
||
<!-- xuchao: 景区卡片列表 —— 整卡可点进详情,入场逐个渐显 -->
|
||
<view class="list mm-stagger">
|
||
<view class="card mm-card mm-fade-up" v-for="(item,index) in lookList" :key="index"
|
||
@click="toDetail(item.id)">
|
||
<image class="card__img" mode="aspectFill"
|
||
:src="item.mainPic||'https://aliyunoss.hn12301.net/sd/all_moren.png'"></image>
|
||
<view class="card__body">
|
||
<view class="card__name">{{item.name||''}}</view>
|
||
<view class="card__desc" v-if="item.subTypeId">{{item.subTypeId}}</view>
|
||
<view class="card__foot">
|
||
<view class="card__price">
|
||
<view class="card__origin">原价 <text
|
||
class="card__origin-num">¥{{(item.price/100).toFixed(0)}}</text></view>
|
||
<view class="card__now">
|
||
<text class="card__cur">¥</text>
|
||
<text class="card__num mm-display mm-grad-text">{{(item.unitPrice/100).toFixed(0)}}</text>
|
||
<text class="card__unit">元</text>
|
||
</view>
|
||
</view>
|
||
<view class="card__cta mm-grad">
|
||
<text>预订</text>
|
||
<u-icon name="arrow-right" color="#ffffff" size="22"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- xuchao: 空态(首次请求返回空列表才显示,避免加载中闪烁) -->
|
||
<view class="empty mm-fade-up" v-if="showEmpty">
|
||
<u-icon name="empty-coupon" color="#CBD5E1" size="120"></u-icon>
|
||
<view class="empty__text">暂无在售门票产品</view>
|
||
</view>
|
||
|
||
<!-- xuchao: 列表底部:仅分页加载时显示"正在加载…" -->
|
||
<view class="foot" v-if="lookList.length > 0 && !isLoad">
|
||
<text>正在加载…</text>
|
||
</view>
|
||
|
||
<!-- xuchao: 订单悬浮按钮 -->
|
||
<gmy-float-touch @menuClick="floatTouchClick"></gmy-float-touch>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
// xuchao: 门票列表页(启动页/入口页)
|
||
import auth from '@/common/auth.js'
|
||
import gmyFloatTouch from "@/components/gmy-float-touch/gmy-float-touch.vue"
|
||
|
||
var that = ''
|
||
export default {
|
||
components: { gmyFloatTouch },
|
||
data() {
|
||
return {
|
||
pageAll: 2,
|
||
isLoad: true,
|
||
lookList: [],
|
||
// xuchao: 首次请求是否已返回,用于区分"加载中"与"真没数据"
|
||
firstLoaded: false,
|
||
obj: {
|
||
"name": "",
|
||
"typeId": "",
|
||
"cityId": "",
|
||
"pageSize": 10,
|
||
"pageNum": 1,
|
||
"todayAvailable": false
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
showEmpty() {
|
||
return this.firstLoaded && this.lookList.length === 0
|
||
}
|
||
},
|
||
onLoad() {
|
||
that = this
|
||
// xuchao: 未登录则(正式)跳登录页 / (开发)静默假登录
|
||
if (!auth.requireLogin('/pages/ticket/scenic')) return
|
||
this.queryTicketsPageMethod()
|
||
},
|
||
onReachBottom() {
|
||
this.queryTicketsPageMethod()
|
||
},
|
||
methods: {
|
||
queryTicketsPageMethod() {
|
||
if (this.obj.pageNum <= this.pageAll && this.isLoad) {
|
||
this.isLoad = false
|
||
this.$u.api.queryTicketsPage(this.obj).then(res => {
|
||
this.isLoad = true
|
||
this.firstLoaded = true
|
||
this.obj.pageNum = this.obj.pageNum * 1 + 1
|
||
this.pageAll = Math.ceil(res.data.total / 10)
|
||
this.total = res.data.total
|
||
this.lookList = this.lookList.concat(res.data.list)
|
||
})
|
||
}
|
||
},
|
||
toDetail(e) {
|
||
uni.navigateTo({
|
||
url: 'scenicdetail?id=' + e
|
||
})
|
||
},
|
||
// xuchao: 悬浮按钮 —— 跳门票订单列表
|
||
floatTouchClick(e) {
|
||
if (e == 4) {
|
||
uni.navigateTo({
|
||
url: '/pages/ticket/orderlist'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.page {
|
||
padding: 32rpx 32rpx 40rpx;
|
||
}
|
||
|
||
/* ---------- 卡片列表 ---------- */
|
||
.list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.card {
|
||
display: flex;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
transition: transform 0.2s ease-out, box-shadow 0.3s ease-out;
|
||
}
|
||
|
||
.card:active {
|
||
transform: scale(0.985);
|
||
box-shadow: var(--mm-shadow-sm);
|
||
}
|
||
|
||
.card__img {
|
||
width: 208rpx;
|
||
height: 208rpx;
|
||
flex: none;
|
||
border-radius: 18rpx;
|
||
background: var(--mm-muted);
|
||
}
|
||
|
||
.card__body {
|
||
flex: 1;
|
||
min-width: 0;
|
||
margin-left: 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.card__name {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
letter-spacing: -0.01em;
|
||
color: var(--mm-fg);
|
||
overflow: hidden !important;
|
||
text-overflow: ellipsis !important;
|
||
display: -webkit-box !important;
|
||
-webkit-line-clamp: 1;
|
||
-webkit-box-orient: vertical;
|
||
}
|
||
|
||
.card__desc {
|
||
margin-top: 8rpx;
|
||
font-size: 22rpx;
|
||
line-height: 1.45;
|
||
color: var(--mm-muted-fg);
|
||
overflow: hidden !important;
|
||
text-overflow: ellipsis !important;
|
||
display: -webkit-box !important;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
}
|
||
|
||
.card__foot {
|
||
margin-top: auto;
|
||
padding-top: 12rpx;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.card__origin {
|
||
font-size: 20rpx;
|
||
color: var(--mm-muted-fg);
|
||
}
|
||
|
||
.card__origin-num {
|
||
text-decoration: line-through;
|
||
}
|
||
|
||
.card__now {
|
||
display: flex;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.card__cur {
|
||
font-size: 24rpx;
|
||
font-weight: 600;
|
||
color: var(--mm-accent);
|
||
margin-right: 2rpx;
|
||
}
|
||
|
||
.card__num {
|
||
font-size: 46rpx;
|
||
line-height: 1;
|
||
}
|
||
|
||
.card__unit {
|
||
font-size: 20rpx;
|
||
color: var(--mm-muted-fg);
|
||
margin-left: 6rpx;
|
||
}
|
||
|
||
/* xuchao: 预订按钮 —— 渐变胶囊 + 箭头,承担整卡的行动号召 */
|
||
.card__cta {
|
||
flex: none;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6rpx;
|
||
height: 60rpx;
|
||
padding: 0 26rpx;
|
||
border-radius: 999rpx;
|
||
color: #fff;
|
||
font-size: 24rpx;
|
||
box-shadow: 0 6rpx 16rpx rgba(0, 82, 255, 0.25);
|
||
}
|
||
|
||
/* ---------- 空态与底部 ---------- */
|
||
.empty {
|
||
margin-top: 160rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.empty__text {
|
||
font-size: 26rpx;
|
||
color: var(--mm-muted-fg);
|
||
}
|
||
|
||
.foot {
|
||
padding: 44rpx 0 20rpx;
|
||
text-align: center;
|
||
font-size: 22rpx;
|
||
letter-spacing: 0.1em;
|
||
color: var(--mm-muted-fg);
|
||
}
|
||
</style>
|