This commit is contained in:
MagicalKudzu
2025-12-17 14:19:22 +08:00
parent 8dd492b3e4
commit f67fb8b6b3
21 changed files with 4510 additions and 241 deletions

534
pages/custom/detail.js Normal file
View 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
View File

@@ -0,0 +1,3 @@
{
"usingComponents": {}
}

91
pages/custom/detail.wxml Normal file
View 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
View 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;
}

View File

@@ -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(';') : ''
},
})

View File

@@ -1,2 +0,0 @@
<!--pages/custom/index.wxml-->
<text>pages/custom/index.wxml</text>

105
pages/custom/search.js Normal file
View 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
View File

@@ -0,0 +1,3 @@
{
"usingComponents": {}
}

49
pages/custom/search.wxml Normal file
View 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
View 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;
}

View File

@@ -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