更新
This commit is contained in:
534
pages/custom/detail.js
Normal file
534
pages/custom/detail.js
Normal file
@@ -0,0 +1,534 @@
|
||||
const requireCustom = wx.requireCustom
|
||||
const customRequest = requireCustom(9887)
|
||||
// S.Jv 生成 returnUrl
|
||||
const S = requireCustom(2012)
|
||||
// ko.A.getOpenId 获取 openid
|
||||
const ko = requireCustom(3816)
|
||||
// Uo.JV 获取 dmChannel
|
||||
const Uo = requireCustom(5059)
|
||||
// 生成 s1-s7 的参数
|
||||
const Oo = requireCustom(3716)
|
||||
|
||||
Page({
|
||||
data: {
|
||||
id: '',
|
||||
globalCode: 'ali.china.damai',
|
||||
ttid: '#t#ip##_h5_2014',
|
||||
getDetailParam: {
|
||||
api: 'mtop.alibaba.detail.subpage.getdetail',
|
||||
v: '2.0',
|
||||
data: {},
|
||||
},
|
||||
detailResult: {},
|
||||
getCustomerListParam: {
|
||||
api: 'mtop.damai.wireless.user.customerlist.get',
|
||||
v: '2.0',
|
||||
data: {},
|
||||
},
|
||||
customerListResult: [],
|
||||
orderBuildParam: {
|
||||
api: 'mtop.damai.trade.order.build.h5',
|
||||
v: '1.0',
|
||||
data: {},
|
||||
timeout: 15e3,
|
||||
method: 'POST',
|
||||
},
|
||||
orderBuildResult: {},
|
||||
orderCreateParam: {
|
||||
api: 'mtop.damai.trade.order.create.h5',
|
||||
v: '1.0',
|
||||
data: {},
|
||||
timeout: 15e3,
|
||||
method: 'POST',
|
||||
},
|
||||
orderCreateResult: {},
|
||||
dataTags: {},
|
||||
viewDetail: {
|
||||
mainImg: '',
|
||||
status: '',
|
||||
title: '',
|
||||
time: '',
|
||||
location: '',
|
||||
price: '',
|
||||
skuList: [],
|
||||
},
|
||||
selectedSku: '',
|
||||
selectedCustomer: [],
|
||||
customerList: [],
|
||||
cd: {
|
||||
days: '0',
|
||||
hours: '00',
|
||||
minutes: '00',
|
||||
seconds: '00',
|
||||
},
|
||||
sellStartTime: '',
|
||||
reBuildOrderCount: 0,
|
||||
},
|
||||
onLoad(options) {
|
||||
if (!options.id) {
|
||||
this.showToast('没有项目 ID')
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
id: options.id,
|
||||
})
|
||||
},
|
||||
|
||||
async onShow() {
|
||||
if (!this.data.id) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取演出详情
|
||||
let result = await this.getDetail()
|
||||
|
||||
if (result[0]) {
|
||||
this.showToast(result[0].message)
|
||||
return
|
||||
}
|
||||
|
||||
let resultData = result[1]
|
||||
this.setData({
|
||||
detailResult: resultData,
|
||||
})
|
||||
|
||||
const { itemBasicInfo, itemBuyBtn, perform } = resultData
|
||||
|
||||
// 获取观演人
|
||||
result = await this.getCustomerList()
|
||||
|
||||
if (result[0]) {
|
||||
this.showToast(result[0].message)
|
||||
return
|
||||
}
|
||||
|
||||
resultData = result[1]
|
||||
this.setData({
|
||||
customerListResult: resultData,
|
||||
})
|
||||
|
||||
const viewDetail = {
|
||||
mainImg: itemBasicInfo.mainImageUrl,
|
||||
status: itemBuyBtn.btnText,
|
||||
title: itemBasicInfo.itemTitle,
|
||||
time: perform.performName,
|
||||
location: itemBasicInfo.venueName,
|
||||
price: itemBasicInfo.priceRange,
|
||||
skuList: perform.skuList,
|
||||
}
|
||||
|
||||
this.setData({
|
||||
viewDetail,
|
||||
selectedSku: perform.skuList[0].skuId,
|
||||
customerList: resultData,
|
||||
sellStartTime: itemBuyBtn.sellStartTime || '',
|
||||
})
|
||||
|
||||
this.startCountdown(this.data.sellStartTime)
|
||||
},
|
||||
onUnload() {
|
||||
this.stopCountdown()
|
||||
},
|
||||
onHide() {
|
||||
this.stopCountdown()
|
||||
},
|
||||
getDetail() {
|
||||
const param = {
|
||||
bizCode: 'ali.china.damai',
|
||||
scenario: 'itemsku',
|
||||
itemId: this.data.id,
|
||||
exParams: JSON.stringify({
|
||||
dataType: 4,
|
||||
dataId: '',
|
||||
activityId: '',
|
||||
}),
|
||||
}
|
||||
|
||||
return new customRequest.p({
|
||||
...this.data.getDetailParam,
|
||||
...param,
|
||||
}).create()
|
||||
},
|
||||
getCustomerList() {
|
||||
const param = {
|
||||
customerType: 'default',
|
||||
platform: '42',
|
||||
comboChannel: '4',
|
||||
}
|
||||
|
||||
return new customRequest.p({
|
||||
...this.data.getCustomerListParam,
|
||||
...param,
|
||||
}).create()
|
||||
},
|
||||
buildOrder() {
|
||||
const { itemBasicInfo, actionControl } = this.data.detailResult
|
||||
const { reBuildOrderCount, selectedCustomer, selectedSku, ttid, orderBuildParam, globalCode } = this.data
|
||||
|
||||
if (!itemBasicInfo.t) {
|
||||
return [
|
||||
{
|
||||
message: '没有t',
|
||||
},
|
||||
]
|
||||
}
|
||||
if (selectedCustomer.length == 0) {
|
||||
return [
|
||||
{
|
||||
message: '请选择观演人',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const { tradeControl } = actionControl
|
||||
const exParams = {
|
||||
channel: 'damai_app',
|
||||
damai: '1',
|
||||
umpChannel: '100031002',
|
||||
subChannel: 'damai@weixin_weapp',
|
||||
atomSplit: 1,
|
||||
signKey: itemBasicInfo.t,
|
||||
rtc: tradeControl.rtc ? 1 : 0,
|
||||
}
|
||||
|
||||
const personCount = selectedCustomer.length
|
||||
const param = {
|
||||
buyNow: true,
|
||||
exParams: JSON.stringify({
|
||||
...exParams,
|
||||
serviceVersion: '2.0.0',
|
||||
customerType: 'default',
|
||||
}),
|
||||
buyParam: itemBasicInfo.itemId + '_' + personCount + '_' + selectedSku,
|
||||
}
|
||||
|
||||
this.setData({
|
||||
dataTags: param,
|
||||
})
|
||||
|
||||
const currentPages = getCurrentPages()
|
||||
const lastE = currentPages.length - 1
|
||||
currentPages[lastE].options = {
|
||||
...param,
|
||||
exParams: JSON.stringify({
|
||||
...exParams,
|
||||
subChannel: 'weapp@damai_h5',
|
||||
}),
|
||||
spm: 'a2obt.project.bottom.dbuy',
|
||||
}
|
||||
|
||||
return new customRequest.p({
|
||||
...orderBuildParam,
|
||||
...param,
|
||||
ext_querys: {
|
||||
ttid: ttid,
|
||||
},
|
||||
headers: {
|
||||
globalCode: globalCode,
|
||||
},
|
||||
ext_headers: {
|
||||
globalCode: globalCode,
|
||||
},
|
||||
}).create()
|
||||
},
|
||||
async createOrder() {
|
||||
const { detailResult, orderBuildResult, dataTags, selectedCustomer, customerList, selectedSku } = this.data
|
||||
const { itemBasicInfo, perform } = detailResult
|
||||
const { global, hierarchy, data, linkage } = orderBuildResult
|
||||
|
||||
const step1 = {
|
||||
subChannel: Uo.JV(),
|
||||
returnUrl: S.Jv({
|
||||
page: 'shows_pay_result',
|
||||
query: {
|
||||
itemId: itemBasicInfo.itemId,
|
||||
},
|
||||
}),
|
||||
serviceVersion: '2.0.0',
|
||||
wxOpenId: ko.A.getOpenId(),
|
||||
}
|
||||
|
||||
const quantity = selectedCustomer.length
|
||||
const step2 = {
|
||||
$taroTimestamp: Date.now(),
|
||||
...dataTags,
|
||||
isQuickBuy: false,
|
||||
isSpliceOrder: false,
|
||||
itemId: itemBasicInfo.itemId,
|
||||
quantity: quantity,
|
||||
skuId: selectedSku,
|
||||
spm: 'a2obt.project.buttom.dbuy',
|
||||
}
|
||||
|
||||
const step2DataTags = this.genDataTags(step2)
|
||||
if (step2DataTags) {
|
||||
step1.dataTags = step2DataTags
|
||||
}
|
||||
|
||||
const { structure } = hierarchy
|
||||
const blocks = structure.dmViewerBlock_DmViewerBlock
|
||||
const compName = blocks[blocks.length - 1]
|
||||
data[compName]['componentDataName'] = compName
|
||||
data[compName]['componentType'] = 'dmviewer'
|
||||
data[compName]['inParentIndex'] = 1
|
||||
data[compName]['isInParentLastIndex'] = true
|
||||
data[compName]['parentComponentName'] = 'dmViewerBlock_DmViewerBlock'
|
||||
data[compName]['submit'] = true
|
||||
data[compName].fields.selectedNum = quantity
|
||||
|
||||
const indices = selectedCustomer.map((id) => customerList.findIndex((obj) => obj.identityHash == id))
|
||||
|
||||
for (let i = 0; i < indices.length; i++) {
|
||||
const index = indices[i]
|
||||
data[compName].fields.viewerList[index].isUsed = true
|
||||
}
|
||||
|
||||
const requestData = {
|
||||
params: JSON.stringify({
|
||||
data: JSON.stringify(data),
|
||||
linkage: JSON.stringify({
|
||||
common: linkage.common,
|
||||
signature: linkage.signature,
|
||||
}),
|
||||
hierarchy: JSON.stringify({
|
||||
structure: hierarchy.structure,
|
||||
}),
|
||||
}),
|
||||
feature: JSON.stringify(step1),
|
||||
}
|
||||
|
||||
requestData[global.secretKey] = global.secretValue
|
||||
|
||||
const s17 = await Oo.A.getWasmHeader(itemBasicInfo.itemId)
|
||||
|
||||
const h = JSON.stringify({
|
||||
...s17,
|
||||
...JSON.parse(requestData.feature),
|
||||
})
|
||||
|
||||
const v = {
|
||||
...requestData,
|
||||
feature: h,
|
||||
}
|
||||
|
||||
const param = {
|
||||
...this.data.orderCreateParam,
|
||||
}
|
||||
|
||||
const querys = {
|
||||
isSec: 1,
|
||||
AntiCreep: true,
|
||||
ttid: this.data.ttid,
|
||||
tb_eagleeyex_scm_project: '20190509-aone2-join-test',
|
||||
}
|
||||
|
||||
querys[global.secretKey] = global.secretValue
|
||||
|
||||
return new customRequest.p({
|
||||
...this.data.orderBuildParam,
|
||||
...param,
|
||||
data: v,
|
||||
ext_querys: querys,
|
||||
headers: {
|
||||
globalCode: this.data.globalCode,
|
||||
},
|
||||
ext_headers: {
|
||||
globalCode: this.data.globalCode,
|
||||
},
|
||||
}).create()
|
||||
},
|
||||
async goPay() {
|
||||
const { itemBasicInfo } = this.data.detailResult
|
||||
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
if (!itemBasicInfo.t) {
|
||||
console.log('没有t')
|
||||
|
||||
// 获取演出详情
|
||||
let result = await this.getDetail()
|
||||
|
||||
if (result[0]) {
|
||||
this.showToast(result[0].message)
|
||||
return
|
||||
}
|
||||
|
||||
let resultData = result[1]
|
||||
this.setData({
|
||||
detailResult: resultData,
|
||||
})
|
||||
|
||||
await sleep(200);
|
||||
console.log('重试')
|
||||
await this.goPay();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let buildOrderResult = await this.buildOrder()
|
||||
|
||||
if (buildOrderResult[0]) {
|
||||
this.showToast(buildOrderResult[0].message)
|
||||
await sleep(200);
|
||||
console.log('重试')
|
||||
await this.goPay();
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
orderBuildResult: buildOrderResult[1],
|
||||
})
|
||||
|
||||
let createOrderResult = await this.createOrder()
|
||||
|
||||
if (createOrderResult[0]) {
|
||||
this.showToast(createOrderResult[0].message)
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
orderCreateResult: createOrderResult[1],
|
||||
})
|
||||
|
||||
const payInfo = JSON.parse(decodeURIComponent(createOrderResult[1].alipayWapCashierUrl))
|
||||
|
||||
wx.requestPayment({
|
||||
signType: 'MD5',
|
||||
timeStamp: payInfo.timeStamp + '',
|
||||
nonceStr: payInfo.nonceStr,
|
||||
package: payInfo.package,
|
||||
paySign: payInfo.paySign,
|
||||
success: function (e) {
|
||||
if ('requestPayment:ok' === e.errMsg) {
|
||||
wx.showToast({ title: '支付成功', icon: 'none' })
|
||||
} else {
|
||||
wx.showToast({ title: '支付失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: function () {
|
||||
wx.showToast({ title: '拉起支付失败', icon: 'none' })
|
||||
},
|
||||
})
|
||||
},
|
||||
showToast(msg) {
|
||||
wx.showToast({
|
||||
title: msg,
|
||||
icon: 'none',
|
||||
})
|
||||
},
|
||||
onSelectSku(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
this.setData({
|
||||
selectedSku: id,
|
||||
})
|
||||
},
|
||||
// 点击整行切换选中
|
||||
onToggleSelect(e) {
|
||||
const index = e.currentTarget.dataset.index
|
||||
const options = this.data.customerList.slice()
|
||||
const item = options[index]
|
||||
|
||||
item['checked'] = item.checked == undefined ? false : item.checked
|
||||
item['checked'] = !item['checked']
|
||||
options[index] = item
|
||||
|
||||
const selectedIds = options.filter((x) => x.checked).map((x) => x.identityHash)
|
||||
|
||||
this.setData({
|
||||
customerList: options,
|
||||
selectedCustomer: selectedIds,
|
||||
})
|
||||
},
|
||||
startCountdown(rawTs) {
|
||||
this.stopCountdown()
|
||||
|
||||
const target = this.normalizeTimestamp(rawTs)
|
||||
if (!target) return
|
||||
|
||||
// 先立刻刷新一次,避免首次渲染延迟 1s
|
||||
this.tickCountdown(target)
|
||||
|
||||
this._cdTimer = setInterval(() => {
|
||||
this.tickCountdown(target)
|
||||
}, 1000)
|
||||
},
|
||||
stopCountdown() {
|
||||
if (this._cdTimer) {
|
||||
clearInterval(this._cdTimer)
|
||||
this._cdTimer = null
|
||||
}
|
||||
},
|
||||
tickCountdown(targetMs) {
|
||||
const now = Date.now()
|
||||
let diff = targetMs - now
|
||||
|
||||
if (diff <= 0) {
|
||||
// 归零并触发结束回调
|
||||
this.setData({
|
||||
cd: { days: '0', hours: '00', minutes: '00', seconds: '00' },
|
||||
})
|
||||
this.stopCountdown()
|
||||
this.onCountdownFinish() // 自动执行方法
|
||||
return
|
||||
}
|
||||
|
||||
const totalSeconds = Math.floor(diff / 1000)
|
||||
|
||||
const days = Math.floor(totalSeconds / (24 * 3600))
|
||||
const remain1 = totalSeconds % (24 * 3600)
|
||||
const hours = Math.floor(remain1 / 3600)
|
||||
const remain2 = remain1 % 3600
|
||||
const minutes = Math.floor(remain2 / 60)
|
||||
const seconds = remain2 % 60
|
||||
|
||||
this.setData({
|
||||
cd: {
|
||||
days: String(days),
|
||||
hours: this.pad2(hours),
|
||||
minutes: this.pad2(minutes),
|
||||
seconds: this.pad2(seconds),
|
||||
},
|
||||
})
|
||||
},
|
||||
normalizeTimestamp(ts) {
|
||||
const n = Number(ts)
|
||||
if (!Number.isFinite(n) || n <= 0) return null
|
||||
|
||||
// 10位通常是秒级;13位通常是毫秒级
|
||||
// 这里用阈值判断:小于 1e12 认为是秒
|
||||
return n < 1e12 ? n * 1000 : n
|
||||
},
|
||||
pad2(n) {
|
||||
return n < 10 ? '0' + n : String(n)
|
||||
},
|
||||
// 倒计时结束后自动执行的方法(你把业务逻辑写这里)
|
||||
onCountdownFinish() {
|
||||
// 示例:倒计时结束后执行你的动作
|
||||
// 1) 变更状态
|
||||
// 2) 刷新票档/库存
|
||||
// 3) 弹窗提示
|
||||
this.showToast('倒计时结束')
|
||||
|
||||
// TODO:你自己的逻辑
|
||||
// this.refreshSkus();
|
||||
this.setData({
|
||||
sellStartTime: '',
|
||||
})
|
||||
|
||||
// this.goPay()
|
||||
},
|
||||
genDataTags(param) {
|
||||
const result = []
|
||||
|
||||
if (param.utm) {
|
||||
result.push('utm:'.concat(param.utm))
|
||||
}
|
||||
|
||||
if (param.sqm) {
|
||||
result.push('sqm:'.concat(param.sqm))
|
||||
}
|
||||
|
||||
return result.length > 0 ? result.join(';') : ''
|
||||
},
|
||||
})
|
||||
3
pages/custom/detail.json
Normal file
3
pages/custom/detail.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
91
pages/custom/detail.wxml
Normal file
91
pages/custom/detail.wxml
Normal file
@@ -0,0 +1,91 @@
|
||||
<view class="page">
|
||||
<view class="card section">
|
||||
<view class="img-wrapper">
|
||||
<image src="{{viewDetail.mainImg}}" mode="aspectFill" class="img"></image>
|
||||
<view class="status-tag">{{viewDetail.status}}</view>
|
||||
</view>
|
||||
|
||||
<view class="right">
|
||||
<view class="top">
|
||||
<view class="title">{{viewDetail.title}}</view>
|
||||
<view class="meta">{{viewDetail.time}}</view>
|
||||
<view class="meta">{{viewDetail.location}}</view>
|
||||
</view>
|
||||
|
||||
<view class="bottom">
|
||||
<view class="price-wrap">
|
||||
<view class="price">{{viewDetail.price}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card" wx:if="{{sellStartTime}}">
|
||||
<view class="section-hd">
|
||||
<text class="section-title">距离开售</text>
|
||||
<text class="section-sub">倒计时</text>
|
||||
</view>
|
||||
|
||||
<view class="countdown">
|
||||
<view class="cd-block">
|
||||
<text class="cd-num">{{cd.days}}</text>
|
||||
<text class="cd-unit">天</text>
|
||||
</view>
|
||||
|
||||
<view class="cd-block">
|
||||
<text class="cd-num">{{cd.hours}}</text>
|
||||
<text class="cd-unit">时</text>
|
||||
</view>
|
||||
|
||||
<view class="cd-block">
|
||||
<text class="cd-num">{{cd.minutes}}</text>
|
||||
<text class="cd-unit">分</text>
|
||||
</view>
|
||||
|
||||
<view class="cd-block">
|
||||
<text class="cd-num">{{cd.seconds}}</text>
|
||||
<text class="cd-unit">秒</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<button type="primary" bindtap="goPay">抢票</button>
|
||||
</view>
|
||||
|
||||
<!-- 票类型(单选) -->
|
||||
<view class="card">
|
||||
|
||||
<view class="type-group">
|
||||
<view class="type-btn {{item.skuId === selectedSku ? 'type-btn-active' : ''}}" wx:for="{{viewDetail.skuList}}"
|
||||
wx:key="id" bindtap="onSelectSku" data-id="{{item.skuId}}">
|
||||
{{item.priceName}} {{ item.otherTag ? '(' + item.otherTag.tagDesc + ')' : '' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 观影人 多选列表 -->
|
||||
<view class="card">
|
||||
<view class="section-hd">
|
||||
<text class="section-title">请选择</text>
|
||||
<text class="section-sub">已选 {{selectedCustomer.length}} 项</text>
|
||||
</view>
|
||||
|
||||
<view class="multi-list">
|
||||
<view class="multi-item" wx:for="{{customerList}}" wx:key="id" bindtap="onToggleSelect" data-index="{{index}}">
|
||||
<!-- 左侧:基础信息 -->
|
||||
<view class="multi-left">
|
||||
<text class="multi-title">{{item.maskedName}}</text>
|
||||
<text class="multi-sub">{{item.identityNo}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 右侧:是否选中 -->
|
||||
<view class="multi-right">
|
||||
<view class="check {{item.checked ? 'check-on' : ''}}">
|
||||
<text wx:if="{{item.checked}}" class="check-mark">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
197
pages/custom/detail.wxss
Normal file
197
pages/custom/detail.wxss
Normal file
@@ -0,0 +1,197 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 32rpx;
|
||||
background: #fff;
|
||||
|
||||
margin-top: 32rpx;
|
||||
}
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.card .img-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card .status-tag {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
|
||||
padding: 4rpx 10rpx;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.2;
|
||||
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
|
||||
border-radius: 6rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card .img-wrapper image {
|
||||
width: 180rpx;
|
||||
height: 220rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #eaeaea;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.card .right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.card .right .top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rpx;
|
||||
}
|
||||
|
||||
.card .right .top .title {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.card .right .top .meta {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.card .right .bottom .price {
|
||||
font-size: 30rpx;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.type-group {
|
||||
margin-top: 16rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 14rpx;
|
||||
}
|
||||
|
||||
.type-btn {
|
||||
padding: 16rpx 22rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f3f4f6;
|
||||
color: #333;
|
||||
font-size: 26rpx;
|
||||
line-height: 1;
|
||||
border: 2rpx solid transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.type-btn-active {
|
||||
background: #fff0f0;
|
||||
border-color: #ff4d4f;
|
||||
color: #ff4d4f;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.multi-list {
|
||||
margin-top: 12rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.multi-item {
|
||||
padding: 18rpx 6rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.multi-item:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.multi-left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
padding-right: 16rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.multi-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.multi-sub {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.multi-right {
|
||||
width: 76rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.check {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 999rpx;
|
||||
border: 2rpx solid #cfcfcf;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.check-on {
|
||||
border-color: #ff4d4f;
|
||||
background: #fff0f0;
|
||||
}
|
||||
|
||||
.check-mark {
|
||||
font-size: 28rpx;
|
||||
line-height: 1;
|
||||
color: #ff4d4f;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.multi-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.countdown {
|
||||
margin-top: 16rpx;
|
||||
display: flex;
|
||||
gap: 18rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cd-block {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8rpx;
|
||||
padding: 14rpx 16rpx;
|
||||
background: #f3f4f6;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.cd-num {
|
||||
font-size: 36rpx;
|
||||
font-weight: 900;
|
||||
color: #111;
|
||||
min-width: 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cd-unit {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
@@ -1,40 +1,17 @@
|
||||
const requireCustom = wx.requireCustom;
|
||||
const customRequest = requireCustom(9887);
|
||||
const Ay = requireCustom(4752).Ay;
|
||||
const requireCustom = wx.requireCustom
|
||||
const customRequest = requireCustom(9887)
|
||||
// S.Jv 生成 returnUrl
|
||||
const S = requireCustom(2012)
|
||||
// ko.A.getOpenId 获取 openid
|
||||
const ko = requireCustom(3816)
|
||||
// Uo.JV 获取 dmChannel
|
||||
const Uo = requireCustom(5059)
|
||||
// 生成 s1-s7 的参数
|
||||
const Oo = requireCustom(3716)
|
||||
|
||||
Page({
|
||||
data: {
|
||||
globalCode: 'ali.china.damai',
|
||||
ttid: '#t#ip##_h5_2014',
|
||||
getDetailParam: {
|
||||
api: 'mtop.alibaba.detail.subpage.getdetail',
|
||||
v: '2.0',
|
||||
data: {}
|
||||
},
|
||||
detailResult: {},
|
||||
ticketPriceParam: {
|
||||
api: 'mtop.damai.item.calcTicketPrice',
|
||||
v: '2.0',
|
||||
method: 'GET',
|
||||
data: {}
|
||||
},
|
||||
ticketPriceResult: {},
|
||||
orderBuildParam: {
|
||||
api: 'mtop.damai.trade.order.build.h5',
|
||||
v: '1.0',
|
||||
data: {},
|
||||
timeout: 15e3,
|
||||
method: 'POST'
|
||||
},
|
||||
orderBuildResult: {},
|
||||
orderCreateParam: {
|
||||
api: 'mtop.damai.trade.order.create.h5',
|
||||
v: '1.0',
|
||||
data: {},
|
||||
timeout: 15e3,
|
||||
method: 'POST'
|
||||
},
|
||||
orderCreateResult: {}
|
||||
|
||||
},
|
||||
async onLoad(options) {
|
||||
let detailResult = await this.getDetail('1001240724661')
|
||||
@@ -45,21 +22,21 @@ Page({
|
||||
}
|
||||
|
||||
this.setData({
|
||||
detailResult: detailResult[1]
|
||||
detailResult: detailResult[1],
|
||||
})
|
||||
|
||||
let ticketPrice = await this.calcTicketPrice();
|
||||
// let ticketPrice = await this.calcTicketPrice()
|
||||
|
||||
if (ticketPrice[0]) {
|
||||
this.showToast(ticketPrice[0].message)
|
||||
return
|
||||
}
|
||||
// if (ticketPrice[0]) {
|
||||
// this.showToast(ticketPrice[0].message)
|
||||
// return
|
||||
// }
|
||||
|
||||
this.setData({
|
||||
ticketPriceResult: ticketPrice[1]
|
||||
})
|
||||
// this.setData({
|
||||
// ticketPriceResult: ticketPrice[1],
|
||||
// })
|
||||
|
||||
let orderBuildResult = await this.buildOrder();
|
||||
let orderBuildResult = await this.buildOrder()
|
||||
|
||||
if (orderBuildResult[0]) {
|
||||
this.showToast(orderBuildResult[0].message)
|
||||
@@ -67,23 +44,46 @@ Page({
|
||||
}
|
||||
|
||||
this.setData({
|
||||
orderBuildResult: orderBuildResult[1]
|
||||
orderBuildResult: orderBuildResult[1],
|
||||
})
|
||||
|
||||
console.log(this.data.orderBuildResult)
|
||||
let createOrderResult = await this.createOrder()
|
||||
|
||||
if (createOrderResult[0]) {
|
||||
this.showToast(createOrderResult[0].message)
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
orderCreateResult: createOrderResult[1],
|
||||
})
|
||||
|
||||
const payInfo = JSON.parse(decodeURIComponent(createOrderResult[1].alipayWapCashierUrl))
|
||||
|
||||
wx.requestPayment({
|
||||
signType: 'MD5',
|
||||
timeStamp: payInfo.timeStamp + '',
|
||||
nonceStr: payInfo.nonceStr,
|
||||
package: payInfo.package,
|
||||
paySign: payInfo.paySign,
|
||||
success: function (e) {
|
||||
if ('requestPayment:ok' === e.errMsg) {
|
||||
wx.showToast({ title: '支付成功', icon: 'none' })
|
||||
} else {
|
||||
wx.showToast({ title: '支付失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: function () {
|
||||
wx.showToast({ title: '拉起支付失败', icon: 'none' })
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
onReady() {
|
||||
onReady() {},
|
||||
|
||||
},
|
||||
onShow() {},
|
||||
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
onHide() {
|
||||
|
||||
},
|
||||
onHide() {},
|
||||
showToast(msg) {
|
||||
wx.showToast({
|
||||
title: msg,
|
||||
@@ -98,101 +98,205 @@ Page({
|
||||
exParams: JSON.stringify({
|
||||
dataType: 4,
|
||||
dataId: '',
|
||||
activityId: ''
|
||||
})
|
||||
activityId: '',
|
||||
}),
|
||||
}
|
||||
|
||||
return new customRequest.p({
|
||||
...this.data.getDetailParam,
|
||||
...param
|
||||
}).create();
|
||||
...param,
|
||||
}).create()
|
||||
},
|
||||
calcTicketPrice() {
|
||||
const calculatePriceControl = this.data.detailResult.actionControl.calculatePriceControl;
|
||||
const itemBasicInfo = this.data.detailResult.itemBasicInfo;
|
||||
const perform = this.data.detailResult.perform;
|
||||
const sku = perform.skuList[perform.skuList.length - 1];
|
||||
|
||||
const calculatePriceControl = this.data.detailResult.actionControl.calculatePriceControl
|
||||
const itemBasicInfo = this.data.detailResult.itemBasicInfo
|
||||
const perform = this.data.detailResult.perform
|
||||
const sku = perform.skuList[perform.skuList.length - 1]
|
||||
|
||||
const param = {
|
||||
itemId: itemBasicInfo.itemId,
|
||||
performId: perform.performId,
|
||||
calculateTag: calculatePriceControl.calculateTag,
|
||||
skuParamListJson: JSON.stringify([{
|
||||
priceId: sku.priceId,
|
||||
price: Number(sku.price),
|
||||
count: 1,
|
||||
}]),
|
||||
exParams: {}
|
||||
skuParamListJson: JSON.stringify([
|
||||
{
|
||||
priceId: sku.priceId,
|
||||
price: Number(sku.price),
|
||||
count: 1,
|
||||
},
|
||||
]),
|
||||
exParams: {},
|
||||
}
|
||||
|
||||
return new customRequest.p({
|
||||
...this.data.ticketPriceParam,
|
||||
...param
|
||||
}).create();
|
||||
...param,
|
||||
}).create()
|
||||
},
|
||||
buildOrder() {
|
||||
const itemBasicInfo = this.data.detailResult.itemBasicInfo;
|
||||
const perform = this.data.detailResult.perform;
|
||||
const itemBasicInfo = this.data.detailResult.itemBasicInfo
|
||||
const perform = this.data.detailResult.perform
|
||||
const exParams = {
|
||||
channel: 'damai_app',
|
||||
damai: '1',
|
||||
umpChannel: '100031002',
|
||||
subChannel: 'damai@weixin_weapp',
|
||||
atomSplit: 1,
|
||||
signKey: itemBasicInfo.t,
|
||||
rtc: this.data.detailResult.actionControl.tradeControl.rtc ? 1 : 0,
|
||||
}
|
||||
|
||||
const param = {
|
||||
buyNow: true,
|
||||
exParams: JSON.stringify({
|
||||
channel: 'damai_app',
|
||||
damai: '1',
|
||||
umpChannel: '100031002',
|
||||
subChannel: 'damai@weixin_weapp',
|
||||
atomSplit: 1,
|
||||
signKey: itemBasicInfo.t,
|
||||
rtc: this.data.detailResult.actionControl.tradeControl.rtc ? 1 : 0,
|
||||
...exParams,
|
||||
serviceVersion: '2.0.0',
|
||||
customerType: 'default',
|
||||
}),
|
||||
buyParam: itemBasicInfo.itemId + '_' + 1 + '_' + perform.skuList[0].skuId
|
||||
buyParam: itemBasicInfo.itemId + '_' + 1 + '_' + perform.skuList[0].skuId,
|
||||
}
|
||||
|
||||
this.setData({
|
||||
dataTags: param,
|
||||
})
|
||||
|
||||
const currentPages = getCurrentPages()
|
||||
const lastE = currentPages.length - 1
|
||||
currentPages[lastE].options = {
|
||||
...param,
|
||||
exParams: JSON.stringify({
|
||||
...exParams,
|
||||
subChannel: 'weapp@damai_h5',
|
||||
}),
|
||||
spm: 'a2obt.project.bottom.dbuy',
|
||||
}
|
||||
|
||||
return new customRequest.p({
|
||||
...this.data.orderBuildParam,
|
||||
...param,
|
||||
ext_querys: {
|
||||
ttid: this.data.ttid
|
||||
ttid: this.data.ttid,
|
||||
},
|
||||
headers: {
|
||||
globalCode: this.data.globalCode,
|
||||
},
|
||||
ext_headers: {
|
||||
globalCode: this.data.globalCode,
|
||||
}
|
||||
}).create();
|
||||
},
|
||||
}).create()
|
||||
},
|
||||
createOrder() {
|
||||
const global = this.data.orderBuildResult.global;
|
||||
const param = {
|
||||
async createOrder() {
|
||||
const itemBasicInfo = this.data.detailResult.itemBasicInfo
|
||||
const perform = this.data.detailResult.perform
|
||||
const buildResult = this.data.orderBuildResult
|
||||
const global = buildResult.global
|
||||
|
||||
const step1 = {
|
||||
subChannel: Uo.JV(),
|
||||
returnUrl: S.Jv({
|
||||
page: 'shows_pay_result',
|
||||
query: {
|
||||
itemId: itemBasicInfo.itemId,
|
||||
},
|
||||
}),
|
||||
serviceVersion: '2.0.0',
|
||||
wxOpenId: ko.A.getOpenId(),
|
||||
}
|
||||
|
||||
const step2 = {
|
||||
$taroTimestamp: Date.now(),
|
||||
...this.data.dataTags,
|
||||
isQuickBuy: false,
|
||||
isSpliceOrder: false,
|
||||
itemId: itemBasicInfo.itemId,
|
||||
quantity: '1',
|
||||
skuId: perform.skuList[0].skuId,
|
||||
spm: 'a2obt.project.buttom.dbuy',
|
||||
}
|
||||
|
||||
const dataTags = this.genDataTags(step2)
|
||||
if (dataTags) {
|
||||
step1.dataTags = dataTags
|
||||
}
|
||||
|
||||
const blocks = buildResult.hierarchy.structure.dmViewerBlock_DmViewerBlock
|
||||
const compName = blocks[blocks.length - 1]
|
||||
const data = buildResult.data
|
||||
data[compName]['componentDataName'] = compName
|
||||
data[compName]['componentType'] = 'dmviewer'
|
||||
data[compName]['inParentIndex'] = 1
|
||||
data[compName]['isInParentLastIndex'] = true
|
||||
data[compName]['parentComponentName'] = 'dmViewerBlock_DmViewerBlock'
|
||||
data[compName]['submit'] = true
|
||||
data[compName].fields.selectedNum = 1
|
||||
data[compName].fields.viewerList[6].isUsed = true
|
||||
|
||||
const requestData = {
|
||||
params: JSON.stringify({
|
||||
data: JSON.stringify(data),
|
||||
linkage: JSON.stringify({
|
||||
common: buildResult.linkage.common,
|
||||
signature: buildResult.linkage.signature,
|
||||
}),
|
||||
hierarchy: JSON.stringify({
|
||||
structure: buildResult.hierarchy.structure,
|
||||
}),
|
||||
}),
|
||||
feature: JSON.stringify(step1),
|
||||
}
|
||||
|
||||
requestData[global.secretKey] = global.secretValue
|
||||
|
||||
const s17 = await Oo.A.getWasmHeader(itemBasicInfo.itemId)
|
||||
|
||||
const h = JSON.stringify({
|
||||
...s17,
|
||||
...JSON.parse(requestData.feature),
|
||||
})
|
||||
|
||||
console.log('h', h)
|
||||
|
||||
const v = {
|
||||
...requestData,
|
||||
feature: h,
|
||||
}
|
||||
|
||||
const param = {
|
||||
...this.data.orderCreateParam,
|
||||
}
|
||||
|
||||
const querys = {
|
||||
isSec: 1,
|
||||
AntiCreep: true,
|
||||
ttid: this.data.ttid,
|
||||
tb_eagleeyex_scm_project: '20190509-aone2-join-test'
|
||||
tb_eagleeyex_scm_project: '20190509-aone2-join-test',
|
||||
}
|
||||
|
||||
querys[global.secretKey] = global.secretValue;
|
||||
querys[global.secretKey] = global.secretValue
|
||||
|
||||
return new customRequest.p({
|
||||
...this.data.orderBuildParam,
|
||||
...param,
|
||||
data: {},
|
||||
ext_querys: {
|
||||
ttid
|
||||
},
|
||||
data: v,
|
||||
ext_querys: querys,
|
||||
headers: {
|
||||
globalCode,
|
||||
globalCode: this.data.globalCode,
|
||||
},
|
||||
ext_headers: {
|
||||
globalCode
|
||||
}
|
||||
}).create();
|
||||
}
|
||||
})
|
||||
globalCode: this.data.globalCode,
|
||||
},
|
||||
}).create()
|
||||
},
|
||||
genDataTags(param) {
|
||||
const result = []
|
||||
|
||||
if (param.utm) {
|
||||
result.push('utm:'.concat(param.utm))
|
||||
}
|
||||
|
||||
if (param.sqm) {
|
||||
result.push('sqm:'.concat(param.sqm))
|
||||
}
|
||||
|
||||
return result.length > 0 ? result.join(';') : ''
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
<!--pages/custom/index.wxml-->
|
||||
<text>pages/custom/index.wxml</text>
|
||||
105
pages/custom/search.js
Normal file
105
pages/custom/search.js
Normal file
@@ -0,0 +1,105 @@
|
||||
const requireCustom = wx.requireCustom
|
||||
const customRequest = requireCustom(9887)
|
||||
const utils = requireCustom(1395);
|
||||
|
||||
Page({
|
||||
data: {
|
||||
keyword: '',
|
||||
searched: false,
|
||||
results: [],
|
||||
searchParam: {
|
||||
api: 'mtop.damai.mec.aristotle.get',
|
||||
v: '3.0',
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
|
||||
onKeywordInput(e) {
|
||||
this.setData({ keyword: e.detail.value })
|
||||
},
|
||||
|
||||
async onSearch() {
|
||||
const keyword = (this.data.keyword || '').trim()
|
||||
this.setData({ searched: true })
|
||||
|
||||
const param = {
|
||||
args: JSON.stringify({
|
||||
pageNo: 1,
|
||||
keyword: keyword,
|
||||
comboDamaiCityId: 852,
|
||||
comboChannel: 4,
|
||||
}),
|
||||
patternName: 'searchHome',
|
||||
patternVersion: '5.3'
|
||||
}
|
||||
|
||||
const config = {
|
||||
downgradeOpt: {
|
||||
reqParam: {
|
||||
pageIndex: 1,
|
||||
patternName: 'searchHome',
|
||||
patternVersion: '5.3',
|
||||
urlElements: ['searchHome', '5.3', 'bak', 4, '3.0', keyword],
|
||||
useCdnWhenNodesNull: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await this.buildSearchRequest(param, config)
|
||||
|
||||
if (result[0]) {
|
||||
wx.showToast({
|
||||
title: result[0].message,
|
||||
icon: 'none'
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
const data = result[1];
|
||||
const nodes = data.nodes;
|
||||
const nodesLevel1 = nodes[0]
|
||||
const nodesLevel2 = nodesLevel1.nodes
|
||||
|
||||
if (!nodesLevel2[0].nodes) {
|
||||
this.setData({
|
||||
results: []
|
||||
})
|
||||
wx.showToast({
|
||||
title: '没有搜到对应的演出~',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const nodesLevel3 = nodesLevel2[0].nodes;
|
||||
const resultNodes = [];
|
||||
|
||||
for (let i = 0; i < nodesLevel3.length; i++) {
|
||||
const nodeData = nodesLevel3[i].data;
|
||||
resultNodes.push({
|
||||
id: nodeData.id,
|
||||
imageUrl: nodeData.verticalPic,
|
||||
title: nodeData.cityName + '|' + nodeData.name,
|
||||
time: nodeData.showTime,
|
||||
location: nodeData.cityName + ' ' + nodeData.venueName,
|
||||
price: nodeData.priceStr,
|
||||
statusText: nodeData.showStatus.desc
|
||||
});
|
||||
}
|
||||
|
||||
this.setData({
|
||||
results: resultNodes
|
||||
})
|
||||
},
|
||||
onItemTap(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
wx.navigateTo({ url: `/pages/custom/detail?id=${id}` });
|
||||
},
|
||||
buildSearchRequest(param, config) {
|
||||
return new customRequest.p({
|
||||
...this.data.searchParam,
|
||||
...param,
|
||||
downgradeConfig: config
|
||||
}).create();
|
||||
}
|
||||
})
|
||||
3
pages/custom/search.json
Normal file
3
pages/custom/search.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
49
pages/custom/search.wxml
Normal file
49
pages/custom/search.wxml
Normal file
@@ -0,0 +1,49 @@
|
||||
<view class="page">
|
||||
<!-- 上部分:搜索栏 -->
|
||||
<view class="top">
|
||||
<input class="search-input" placeholder="请输入关键词" value="{{keyword}}" confirm-type="search"
|
||||
bindinput="onKeywordInput" bindconfirm="onSearch" />
|
||||
<button class="search-btn" type="primary" bindtap="onSearch">搜索</button>
|
||||
</view>
|
||||
|
||||
<!-- 下部分:结果区 -->
|
||||
<view class="bottom">
|
||||
<!-- 无结果 -->
|
||||
<view wx:if="{{searched && results.length === 0}}" class="empty">
|
||||
没有相关项目
|
||||
</view>
|
||||
|
||||
<!-- 列表结果 -->
|
||||
<scroll-view wx:elif="{{results.length > 0}}" class="list" scroll-y="true">
|
||||
<view class="item" wx:for="{{results}}" wx:key="id" bindtap="onItemTap" data-id="{{item.id}}">
|
||||
<!-- 左边图片 -->
|
||||
<view class="img-wrapper">
|
||||
<image class="item-img" src="{{item.imageUrl}}" mode="aspectFill"></image>
|
||||
|
||||
<!-- 右上角状态矩形 -->
|
||||
<view class="status-tag">
|
||||
{{item.statusText}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 右边信息 -->
|
||||
<view class="item-right">
|
||||
<!-- 右上:标题/时间/地点 -->
|
||||
<view class="item-top">
|
||||
<text class="title">{{item.title}}</text>
|
||||
<text class="meta">{{item.time}}</text>
|
||||
<text class="meta">{{item.location}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 右下:价格 -->
|
||||
<view class="item-bottom">
|
||||
<text class="price">¥{{item.price}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 初始未搜索时占位(可选,不显示任何文案) -->
|
||||
<view wx:else class="placeholder"></view>
|
||||
</view>
|
||||
</view>
|
||||
173
pages/custom/search.wxss
Normal file
173
pages/custom/search.wxss
Normal file
@@ -0,0 +1,173 @@
|
||||
.page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
/* 上部分:搜索栏 */
|
||||
.top {
|
||||
padding: 16rpx;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1rpx solid #eeeeee;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
padding: 0 20rpx;
|
||||
background: #f3f4f6;
|
||||
border-radius: 12rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
height: 72rpx;
|
||||
line-height: 72rpx;
|
||||
padding: 0 28rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 下部分:结果区 */
|
||||
.bottom {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
padding: 16rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.list {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 无结果:正中央 */
|
||||
.empty {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #999999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 列表项 */
|
||||
.item {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
|
||||
/* 原来是 16rpx,这里加大 */
|
||||
padding: 24rpx;
|
||||
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 左边图片 */
|
||||
.item-img {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #eaeaea;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 右边区域:上下两部分 */
|
||||
.item-right {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
/* 原来是 space-between,这里保留 */
|
||||
justify-content: space-between;
|
||||
|
||||
/* 增加最小高度,跟随图片 */
|
||||
min-height: 200rpx;
|
||||
}
|
||||
|
||||
.item-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
/* 原来 gap: 8rpx,稍微拉开 */
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #222222;
|
||||
line-height: 1.5;
|
||||
|
||||
/* 多行换行显示 */
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
|
||||
/* 限制最多显示 2 行(可按需改为 3 行) */
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
.meta {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 右下:价格 */
|
||||
.item-bottom {
|
||||
padding-top: 12rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
/* 图片包裹层,用于绝对定位 */
|
||||
.img-wrapper {
|
||||
position: relative;
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 保持图片原样 */
|
||||
.item-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12rpx;
|
||||
background: #eaeaea;
|
||||
}
|
||||
|
||||
/* 右上角状态矩形 */
|
||||
.status-tag {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
|
||||
padding: 4rpx 10rpx;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.2;
|
||||
|
||||
color: #ffffff;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
|
||||
border-radius: 6rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -3057,7 +3057,12 @@ var e = require("../../@babel/runtime/helpers/slicedToArray"),
|
||||
case 2:
|
||||
Jn = e.v;
|
||||
case 3:
|
||||
return c = (r = Jn || {}).longitude, d = r.latitude, u = f === p.ALL ? "5.3" : "5.0", m = f === p.TRAVEL ? "1.0" : u, e.n = 4, En({
|
||||
c = (r = Jn || {}).longitude
|
||||
d = r.latitude
|
||||
u = f === p.ALL ? "5.3" : "5.0"
|
||||
m = f === p.TRAVEL ? "1.0" : u
|
||||
e.n = 4
|
||||
return En({
|
||||
args: JSON.stringify({
|
||||
pageNo: lt[f],
|
||||
pageSize: f === p.ALL ? void 0 : 15,
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user