@ -0,0 +1,12 @@ |
|||||
|
# 云开发 quickstart |
||||
|
|
||||
|
这是云开发的快速启动指引,其中演示了如何上手使用云开发的三大基础能力: |
||||
|
|
||||
|
- 数据库:一个既可在小程序前端操作,也能在云函数中读写的 JSON 文档型数据库 |
||||
|
- 文件存储:在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理 |
||||
|
- 云函数:在云端运行的代码,微信私有协议天然鉴权,开发者只需编写业务逻辑代码 |
||||
|
|
||||
|
## 参考文档 |
||||
|
|
||||
|
- [云开发文档](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html) |
||||
|
|
||||
@ -0,0 +1,80 @@ |
|||||
|
import Malls from "./js/Malls"; |
||||
|
import Coupons from "./js/Coupons"; |
||||
|
import CryptoJS from "./crypto-js"; |
||||
|
|
||||
|
App({ |
||||
|
async onLaunch() { |
||||
|
this.malls = new Malls(); |
||||
|
this.coupons = new Coupons(); |
||||
|
this.globalData = {}; |
||||
|
if (!wx.cloud) { |
||||
|
console.error("请使用 2.2.3 或以上的基础库以使用云能力"); |
||||
|
} else { |
||||
|
await wx.cloud.init({ |
||||
|
traceUser: true, |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
async getOpenid() { |
||||
|
if (this.openid) return this.openid; |
||||
|
const apiKey = "29EXdde5aOT7kFE4KLMtGYvIjgT"; |
||||
|
const apiSecret = "bf3fd4a5d79744e8ad87ca6b8c665277"; |
||||
|
const date = new Date(); |
||||
|
let sign = function (timestamp, params) { |
||||
|
console.log("请求参数"); |
||||
|
console.log(params); |
||||
|
// 排序参数
|
||||
|
const sortParamsEncode = Object.keys(params) |
||||
|
.sort() |
||||
|
.map((key) => `${key}=${params[key]}`) |
||||
|
.join("&"); |
||||
|
console.log("排序参数"); |
||||
|
console.log(sortParamsEncode); |
||||
|
// 加密字符串
|
||||
|
const encryptStr = sortParamsEncode + "|" + timestamp + "|" + apiKey; |
||||
|
console.log("加密字符串"); |
||||
|
console.log(encryptStr); |
||||
|
// 加密
|
||||
|
const digest = CryptoJS.enc.Base64.stringify( |
||||
|
CryptoJS.HmacSHA256(encryptStr, apiSecret) |
||||
|
); |
||||
|
console.log("加密值"); |
||||
|
console.log(digest); |
||||
|
return digest; |
||||
|
}; |
||||
|
const { code } = await new Promise((resolve, reject) => { |
||||
|
wx.login({ |
||||
|
success: resolve, |
||||
|
fail: reject, |
||||
|
}); |
||||
|
}); |
||||
|
let timestamp = date.toISOString(); |
||||
|
const body = { |
||||
|
mallCode: "wx1949744ebf85151fwx1949744ebf85151f", |
||||
|
code, |
||||
|
}; |
||||
|
|
||||
|
const signature = sign(timestamp, body); |
||||
|
|
||||
|
const { data } = await new Promise((resolve) => |
||||
|
wx.request({ |
||||
|
url: `https://api.1000my.com/wxmp/session`, |
||||
|
method: "POST", |
||||
|
data: body, |
||||
|
header: { |
||||
|
"x-qm-apikey": apiKey, |
||||
|
"x-qm-datetime": timestamp, |
||||
|
"x-qm-signature": signature, |
||||
|
"Content-Type": "application/json", |
||||
|
}, |
||||
|
success: resolve, |
||||
|
}) |
||||
|
); |
||||
|
console.log(data); |
||||
|
const { result } = await wx.cloud.callFunction({ |
||||
|
name: "login", |
||||
|
}); |
||||
|
this.openid = result; |
||||
|
return this.openid; |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,21 @@ |
|||||
|
{ |
||||
|
"pages": [ |
||||
|
"pages/index/index", |
||||
|
"pages/checked/index", |
||||
|
"pages/mytickets/index", |
||||
|
"pages/ticketdetail/index", |
||||
|
"pages/malls/index" |
||||
|
], |
||||
|
"window": { |
||||
|
"backgroundColor": "#292c3c", |
||||
|
"navigationBarBackgroundColor": "#292c3c", |
||||
|
"navigationBarTextStyle": "white" |
||||
|
}, |
||||
|
"permission": { |
||||
|
"scope.userLocation": { |
||||
|
"desc": "你的位置信息将用于匹配距您最近的商场" |
||||
|
} |
||||
|
}, |
||||
|
"sitemapLocation": "sitemap.json", |
||||
|
"style": "v2" |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
view, |
||||
|
image { |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
import QRCode from '../../js/qrcode' |
||||
|
// components/ticket/ticket.js
|
||||
|
Component({ |
||||
|
/** |
||||
|
* 组件的属性列表 |
||||
|
*/ |
||||
|
properties: { |
||||
|
state: String, //['mall','my','verified','detail']
|
||||
|
code: String, |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 组件的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
url: '' |
||||
|
}, |
||||
|
attached() { |
||||
|
const { |
||||
|
coupons |
||||
|
} = getApp() |
||||
|
const coupon = coupons.get(this.data.code) |
||||
|
coupons.onUpdate(this.data.code, (coupon) => { |
||||
|
this.setData({ |
||||
|
coupon |
||||
|
}) |
||||
|
}) |
||||
|
this.setData({ |
||||
|
coupon, |
||||
|
}, () => { |
||||
|
if (this.data.state === 'detail') { |
||||
|
const query = wx.createSelectorQuery().in(this) |
||||
|
query.select('#qrcode').node((res) => { |
||||
|
const canvas = res.node; |
||||
|
QRCode.toCanvas(canvas, coupon.orderNo, function (error) { |
||||
|
if (error) console.error(error) |
||||
|
}) |
||||
|
}).exec() |
||||
|
} |
||||
|
|
||||
|
|
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 组件的方法列表 |
||||
|
*/ |
||||
|
methods: { |
||||
|
collect() { |
||||
|
this.triggerEvent('collect', { |
||||
|
code: this.data.code |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
@ -0,0 +1,4 @@ |
|||||
|
{ |
||||
|
"component": true, |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
<view class="ticket {{state==='detail'?' detail': state==='verified'?' big':''}}"> |
||||
|
<view class="r1" wx:if="{{state==='verified'||state==='detail'}}"> |
||||
|
<image class="logo" mode="aspectFit" src="{{coupon.filePath}}"></image> |
||||
|
<view class="shop">{{coupon.shopName}}</view> |
||||
|
<view class="floor">{{coupon.mallName}}-{{coupon.floorName}}</view> |
||||
|
</view> |
||||
|
<view class="r1" wx:else> |
||||
|
<image class="logo" mode="aspectFit" src="{{coupon.filePath}}"></image> |
||||
|
<view class="meta">{{coupon.shopName}} {{coupon.floorName}}</view> |
||||
|
<view class="name">{{coupon.title}}</view> |
||||
|
<button wx:if="{{state==='mall'}}" class="btn {{(coupon.received||coupon.isEmpty)?'disabled':''}}" |
||||
|
disabled="{{coupon.received||coupon.isEmpty}}" |
||||
|
bindtap="collect">{{ coupon.received?'已领取': coupon.isEmpty?'已领完' : '领取'}}</button> |
||||
|
<button wx:else class="btn" bindtap="collect">核销</button> |
||||
|
</view> |
||||
|
<view class="r2" wx:if="{{state==='verified'}}"> |
||||
|
<view class="name">{{coupon.title}}</view> |
||||
|
<view class="meta">{{coupon.intro}}</view> |
||||
|
<view class="time" data-label="有效时间:">{{coupon.beginTime}} - {{coupon.endTime}}</view> |
||||
|
<view class="loc" data-label="核销地点:">{{coupon.mallName}}</view> |
||||
|
</view> |
||||
|
<view class="r2" wx:elif="{{state==='detail'}}"> |
||||
|
<view class="name">{{coupon.title}}</view> |
||||
|
<view class="meta">{{coupon.intro}}</view> |
||||
|
<canvas type='2d' class="qrcode" id="qrcode"></canvas> |
||||
|
<view class="code">{{coupon.orderNo}}</view> |
||||
|
<view class="time" data-label="有效时间:"> |
||||
|
<view style="display:inline">{{coupon.beginTime}} - {{coupon.endTime}}</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="{{'r2' + (state==='my'?' hasr3':'')}}" wx:else>{{coupon.intro}}</view> |
||||
|
<view class="r3" wx:if="{{state==='my'}}">{{coupon.mallName}}</view> |
||||
|
</view> |
||||
@ -0,0 +1,288 @@ |
|||||
|
.ticket { |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
height: 110px; |
||||
|
background: #474956; |
||||
|
border-radius: 3px; |
||||
|
padding: 0 14px; |
||||
|
} |
||||
|
|
||||
|
.ticket::before { |
||||
|
content: ''; |
||||
|
display: block; |
||||
|
position: absolute; |
||||
|
width: 14px; |
||||
|
height: 14px; |
||||
|
border-radius: 50%; |
||||
|
top: 63px; |
||||
|
left: -7px; |
||||
|
background: #373946; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ticket::after { |
||||
|
content: ''; |
||||
|
display: block; |
||||
|
position: absolute; |
||||
|
width: 14px; |
||||
|
height: 14px; |
||||
|
border-radius: 50%; |
||||
|
top: 63px; |
||||
|
right: -7px; |
||||
|
background: #373946; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ticket.detail { |
||||
|
height: 342px; |
||||
|
} |
||||
|
|
||||
|
.ticket.detail::before { |
||||
|
content: ''; |
||||
|
display: block; |
||||
|
position: absolute; |
||||
|
width: 14px; |
||||
|
height: 14px; |
||||
|
border-radius: 50%; |
||||
|
top: 63px; |
||||
|
left: -7px; |
||||
|
background: #292c3c; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ticket.detail::after { |
||||
|
content: ''; |
||||
|
display: block; |
||||
|
position: absolute; |
||||
|
width: 14px; |
||||
|
height: 14px; |
||||
|
border-radius: 50%; |
||||
|
top: 63px; |
||||
|
right: -7px; |
||||
|
background: #292c3c; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ticket.big { |
||||
|
height: 214px; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.ticket.big::before { |
||||
|
content: ''; |
||||
|
display: block; |
||||
|
position: absolute; |
||||
|
width: 14px; |
||||
|
height: 14px; |
||||
|
border-radius: 50%; |
||||
|
top: 63px; |
||||
|
left: -7px; |
||||
|
background: #292c3c; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ticket.big::after { |
||||
|
content: ''; |
||||
|
display: block; |
||||
|
position: absolute; |
||||
|
width: 14px; |
||||
|
height: 14px; |
||||
|
border-radius: 50%; |
||||
|
top: 63px; |
||||
|
right: -7px; |
||||
|
background: #292c3c; |
||||
|
} |
||||
|
|
||||
|
.ticket.has-next { |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 { |
||||
|
box-sizing: border-box; |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
height: 70px; |
||||
|
border-bottom: 1px dashed #1b1a21; |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 .logo { |
||||
|
position: absolute; |
||||
|
top: 14px; |
||||
|
left: 3x; |
||||
|
width: 42px; |
||||
|
height: 42px; |
||||
|
border-radius: 2px; |
||||
|
background: #fff; |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 .shop { |
||||
|
text-align: right; |
||||
|
font-size: 16px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: right; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
line-height: 32px; |
||||
|
padding-top: 8px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 .floor { |
||||
|
text-align: right; |
||||
|
font-size: 16px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: right; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
line-height: 18px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 .meta { |
||||
|
padding-left: 59px; |
||||
|
font-size: 12px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
line-height: 36px; |
||||
|
margin-top: 5px; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 .name { |
||||
|
padding-left: 59px; |
||||
|
font-size: 14px; |
||||
|
line-height: 14px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Bold; |
||||
|
font-weight: 700; |
||||
|
color: #d6ab7e; |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 .btn { |
||||
|
position: absolute; |
||||
|
right: 3px; |
||||
|
top: 20px; |
||||
|
width: 64px; |
||||
|
height: 28px; |
||||
|
background: #d6ab7e; |
||||
|
border-radius: 16px; |
||||
|
font-size: 12px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: center; |
||||
|
color: #373338; |
||||
|
line-height: 28px; |
||||
|
min-height: 28px; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.ticket .r1 .btn.disabled { |
||||
|
background: #666; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 { |
||||
|
line-height: 40px; |
||||
|
font-size: 10px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: left; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2.hasr3 { |
||||
|
margin-top: 8px; |
||||
|
line-height: 10px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r3 { |
||||
|
margin-top: 4px; |
||||
|
margin-bottom: 8px; |
||||
|
line-height: 10px; |
||||
|
font-size: 10px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: left; |
||||
|
color: rgba(255, 255, 255, 0.4); |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .name { |
||||
|
font-size: 18px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Bold; |
||||
|
font-weight: 700; |
||||
|
color: #ffffff; |
||||
|
line-height: 34px; |
||||
|
margin-top: 7px; |
||||
|
} |
||||
|
|
||||
|
.ticket.detail .r2 { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.ticket.detail .r2 .meta { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .qrcode { |
||||
|
display: inline-block; |
||||
|
width: 110px; |
||||
|
height: 110px; |
||||
|
background: #ffffff; |
||||
|
border-radius: 2px; |
||||
|
padding: 10px; |
||||
|
box-sizing: border-box; |
||||
|
margin-top: 25px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .code { |
||||
|
font-size: 18px; |
||||
|
font-family: DINPro, DINPro-Bold; |
||||
|
font-weight: 700; |
||||
|
text-align: center; |
||||
|
color: #ffffff; |
||||
|
line-height: 18px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .meta { |
||||
|
font-size: 12px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: left; |
||||
|
color: rgba(255, 255, 255, 0.4); |
||||
|
line-height: 12px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .time { |
||||
|
font-size: 12px; |
||||
|
font-family: DINPro, DINPro-Regular; |
||||
|
font-weight: 400; |
||||
|
color: #ffffff; |
||||
|
line-height: 15px; |
||||
|
margin-top: 34px; |
||||
|
} |
||||
|
|
||||
|
.ticket.detail .r2 .time { |
||||
|
margin-top: 13px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .time::before { |
||||
|
content: attr(data-label); |
||||
|
color: rgba(255, 255, 255, 0.6); |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .loc { |
||||
|
font-size: 12px; |
||||
|
font-family: DINPro, DINPro-Regular; |
||||
|
font-weight: 400; |
||||
|
color: #ffffff; |
||||
|
line-height: 12px; |
||||
|
margin-top: 9px; |
||||
|
} |
||||
|
|
||||
|
.ticket .r2 .loc::before { |
||||
|
content: attr(data-label); |
||||
|
color: rgba(255, 255, 255, 0.6); |
||||
|
} |
||||
|
After Width: | Height: | Size: 38 KiB |
@ -0,0 +1,80 @@ |
|||||
|
import { |
||||
|
axios |
||||
|
} from './libs' |
||||
|
export default class Coupons { |
||||
|
map = {}; |
||||
|
updates = {}; |
||||
|
constructor() { |
||||
|
|
||||
|
} |
||||
|
async getVerified() { |
||||
|
const { |
||||
|
getOpenid |
||||
|
} = getApp() |
||||
|
const openid = await getOpenid() |
||||
|
const list = await axios.get('/Api/Coupon/UserCouponList', { |
||||
|
"userCode": openid, |
||||
|
"couponType": -1, |
||||
|
"verified": true, |
||||
|
"paging": 0, |
||||
|
}) |
||||
|
list.forEach(coupon => { |
||||
|
this.set(coupon) |
||||
|
}) |
||||
|
return list.map(({ |
||||
|
code |
||||
|
}) => code) |
||||
|
} |
||||
|
async getMallCodes(mallCode, mallName) { |
||||
|
const { |
||||
|
getOpenid |
||||
|
} = getApp() |
||||
|
const openid = await getOpenid() |
||||
|
const list = await axios.get('/Api/Coupon/MallCouponPublishList', { |
||||
|
"mallCode": mallCode, |
||||
|
userCode: openid |
||||
|
}) |
||||
|
list.forEach(coupon => { |
||||
|
Object.assign(coupon, { |
||||
|
mallCode, |
||||
|
mallName |
||||
|
}) |
||||
|
this.set(coupon) |
||||
|
}) |
||||
|
return list.map(({ |
||||
|
code |
||||
|
}) => code) |
||||
|
} |
||||
|
async getUserCodes(type) { |
||||
|
const { |
||||
|
getOpenid |
||||
|
} = getApp() |
||||
|
const openid = await getOpenid() |
||||
|
const list = await axios.get('/Api/Coupon/UserCouponList', { |
||||
|
"userCode": openid, |
||||
|
"couponType": type, |
||||
|
"verified": false, |
||||
|
"paging": 0, |
||||
|
}) |
||||
|
list.forEach(coupon => { |
||||
|
this.set(coupon) |
||||
|
}) |
||||
|
return list.map(({ |
||||
|
code |
||||
|
}) => code) |
||||
|
} |
||||
|
get(code) { |
||||
|
return this.map[code] |
||||
|
} |
||||
|
set(coupon) { |
||||
|
this.map[coupon.code] = { |
||||
|
...this.map[coupon.code], |
||||
|
...coupon |
||||
|
} |
||||
|
this.updates[coupon.code] && this.updates[coupon.code].forEach(cb => cb(this.map[coupon.code])) |
||||
|
return this.map[coupon.code] |
||||
|
} |
||||
|
onUpdate(code, cb) { |
||||
|
this.updates[code] = this.updates[code] ? [...this.updates[code], cb] : [cb] |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
import { |
||||
|
getCities |
||||
|
} from './cities' |
||||
|
export default class Malls { |
||||
|
constructor() { |
||||
|
this.currentMall = null |
||||
|
this.malls = [] |
||||
|
} |
||||
|
async init() { |
||||
|
const cities = await getCities() |
||||
|
this.malls = cities.map(({ |
||||
|
name: city, |
||||
|
malls |
||||
|
}) => malls.map(({ |
||||
|
name, |
||||
|
code |
||||
|
}) => ({ |
||||
|
name, |
||||
|
code, |
||||
|
city |
||||
|
}))).reduce((acc, nxt) => acc.concat(nxt), []) |
||||
|
|
||||
|
this.currentMall = this.malls[0] |
||||
|
} |
||||
|
async getCurrentMall() { |
||||
|
if (!this.malls.length || !this.currentMall) |
||||
|
await this.init() |
||||
|
return this.currentMall |
||||
|
} |
||||
|
async getMallByCode(code) { |
||||
|
if (!this.malls.length || !this.currentMall) |
||||
|
await this.init() |
||||
|
this.currentMall = this.malls.find((mall) => mall.code === code) |
||||
|
return this.currentMall |
||||
|
} |
||||
|
setCurrentMall(mall) { |
||||
|
this.currentMall = mall |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
import { |
||||
|
axios |
||||
|
} from './libs' |
||||
|
let cities = [] |
||||
|
const init = async () => { |
||||
|
const db = wx.cloud.database() |
||||
|
const [{ |
||||
|
data: { |
||||
|
value: cityIndexMap |
||||
|
} |
||||
|
}, malls] = await Promise.all([db.collection('config').doc('cityIndexMap').get(), axios.get('/Api/Coupon/MallList')]) |
||||
|
cities = Object.values(malls.reduce((acc, nxt) => { |
||||
|
const mall = { |
||||
|
name: nxt.name, |
||||
|
code: nxt.mallCode |
||||
|
} |
||||
|
if (acc[nxt.areaName]) { |
||||
|
acc[nxt.areaName].malls.push(mall) |
||||
|
} else acc[nxt.areaName] = { |
||||
|
name: nxt.areaName, |
||||
|
malls: [mall], |
||||
|
index: cityIndexMap[nxt.areaName] |
||||
|
} |
||||
|
return acc |
||||
|
}, {})) |
||||
|
cities.sort((a, b) => a.index.charCodeAt(0) - b.index.charCodeAt(0)) |
||||
|
|
||||
|
} |
||||
|
export const getCities = async () => { |
||||
|
if (!cities.length) { |
||||
|
await init() |
||||
|
return cities |
||||
|
} else return cities |
||||
|
} |
||||
|
|
||||
|
|
||||
|
const toRadians = lonlat => lonlat / 180 * Math.PI; |
||||
|
const ToDigits = radian => radian / Math.PI * 180; |
||||
|
const R = 6371 |
||||
|
const r = 50 |
||||
|
const offset = Math.asin(r / 2 / R) * 2 |
||||
|
const getRestrict = (lon, lat) => { |
||||
|
const lonR = toRadians(lon) |
||||
|
const latR = toRadians(lat) |
||||
|
return [lonR - offset, lonR + offset, latR - offset, latR + offset].map(ToDigits) |
||||
|
} |
||||
|
const getMall = ([minLon, maxLon, minLat, maxLat]) => |
||||
|
new Promise(resolve => { |
||||
|
|
||||
|
}) |
||||
|
|
||||
|
export const getNearMall = async ({ |
||||
|
longitude, |
||||
|
latitude |
||||
|
}) => { |
||||
|
const restrict = getRestrict(longitude, latitude) |
||||
|
return (await getCities())[0] |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
const base = 'https://test.1000my.com:8019' |
||||
|
const request = (url, body) => new Promise((resolve, reject) => { |
||||
|
wx.request({ |
||||
|
url: base + url, |
||||
|
data: body, |
||||
|
method: "POST", |
||||
|
success: ({ |
||||
|
data: { |
||||
|
code, |
||||
|
data, |
||||
|
msg |
||||
|
} |
||||
|
}) => { |
||||
|
if (code === '200') resolve(data) |
||||
|
else wx.showToast({ |
||||
|
icon: 'none', |
||||
|
title: msg, |
||||
|
}) |
||||
|
}, |
||||
|
fail: reject, |
||||
|
}) |
||||
|
}) |
||||
|
const axios = { |
||||
|
get: request, |
||||
|
post: request |
||||
|
} |
||||
|
export { |
||||
|
axios |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
// miniprogram/pages/checked/index.js
|
||||
|
Page({ |
||||
|
|
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
async onLoad() { |
||||
|
const { |
||||
|
coupons |
||||
|
} = getApp() |
||||
|
const list = await coupons.getVerified() |
||||
|
this.setData({ |
||||
|
list |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage: function () { |
||||
|
|
||||
|
} |
||||
|
}) |
||||
@ -0,0 +1,5 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"ticket": "../../components/ticket/ticket" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
<scroll-view scroll-y="true" class="checked"> |
||||
|
<ticket wx:for="{{list}}" wx:key="*this" code="{{item}}" state="verified"></ticket> |
||||
|
<image src="../../images/empty.png" style="width:100%" mode="widthFix" wx:if="{{list&&!list.length}}"></image> |
||||
|
</scroll-view> |
||||
@ -0,0 +1,7 @@ |
|||||
|
.checked { |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
background: #292c3c; |
||||
|
padding: 8px 29px; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
@ -0,0 +1,187 @@ |
|||||
|
import { |
||||
|
axios |
||||
|
} from '../../js/libs' |
||||
|
const app = getApp() |
||||
|
|
||||
|
Page({ |
||||
|
data: { |
||||
|
showModal: false, |
||||
|
shareTitle: '', |
||||
|
mall: null, |
||||
|
userCouponNum: 0, |
||||
|
mallCode: null, |
||||
|
couponCode: null, |
||||
|
refresherTriggered: false, |
||||
|
}, |
||||
|
|
||||
|
async onLoad({ |
||||
|
q |
||||
|
}) { |
||||
|
if (q) { |
||||
|
const { |
||||
|
mallCode, |
||||
|
couponCode |
||||
|
} = decodeURIComponent(q).split('?').pop().replace('q=', '').split('&').map(kv => kv.split('=')).reduce((acc, nxt) => Object.assign(acc, { |
||||
|
[nxt[0]]: nxt[1] |
||||
|
}), {}) |
||||
|
this.setData({ |
||||
|
mallCode, |
||||
|
couponCode |
||||
|
}) |
||||
|
} |
||||
|
const db = wx.cloud.database() |
||||
|
const { |
||||
|
data: { |
||||
|
value: shareTitle |
||||
|
} |
||||
|
} = await db.collection('config').doc('shareTitle').get() |
||||
|
this.setData({ |
||||
|
shareTitle |
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
getLocation() { |
||||
|
return new Promise(resolve => { |
||||
|
wx.getLocation({ |
||||
|
type: 'wgs84', |
||||
|
success: resolve |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
async refreshList() { |
||||
|
const mall = this.data.mall |
||||
|
const { |
||||
|
coupons, |
||||
|
} = getApp() |
||||
|
if (mall) { |
||||
|
const codes = await coupons.getMallCodes(mall.code) |
||||
|
mall.coupons = codes |
||||
|
this.setData({ |
||||
|
mall |
||||
|
}) |
||||
|
} |
||||
|
this.setData({ |
||||
|
refresherTriggered: false |
||||
|
}) |
||||
|
}, |
||||
|
async onShow() { |
||||
|
const { |
||||
|
malls, |
||||
|
coupons, |
||||
|
} = getApp() |
||||
|
|
||||
|
const mall = this.data.mallCode ? await malls.getMallByCode(this.data.mallCode) : await malls.getCurrentMall() |
||||
|
const mallCode = this.data.mallCode |
||||
|
if (this.data.mallCode) { |
||||
|
this.setData({ |
||||
|
mallCode: null |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
if (!mall.coupons) { |
||||
|
const codes = await coupons.getMallCodes(mall.code, mall.name) |
||||
|
mall.coupons = codes |
||||
|
} |
||||
|
|
||||
|
|
||||
|
this.setData({ |
||||
|
mall |
||||
|
}) |
||||
|
const userCodes = await coupons.getUserCodes(-1) |
||||
|
this.setData({ |
||||
|
userCouponNum: userCodes.length |
||||
|
}) |
||||
|
if (this.data.couponCode) { |
||||
|
|
||||
|
this.doShowQrcodeModal({ |
||||
|
mallCode, |
||||
|
couponCode: this.data.couponCode |
||||
|
}) |
||||
|
this.setData({ |
||||
|
couponCode: null |
||||
|
}) |
||||
|
} |
||||
|
}, |
||||
|
async doShowQrcodeModal({ |
||||
|
mallCode, |
||||
|
couponCode |
||||
|
}) { |
||||
|
const { |
||||
|
getOpenid, |
||||
|
} = getApp() |
||||
|
wx.showLoading() |
||||
|
try { |
||||
|
const openid = await getOpenid() |
||||
|
await axios.get('/Api/Coupon/GetCoupon', { |
||||
|
couponCode, |
||||
|
mallCode, |
||||
|
"userCode": openid |
||||
|
}) |
||||
|
this.setData({ |
||||
|
couponName: '直播券', |
||||
|
showModal: true |
||||
|
}) |
||||
|
} catch (error) { |
||||
|
wx.showToast({ |
||||
|
icon: 'none', |
||||
|
title: JSON.stringify(error), |
||||
|
}) |
||||
|
} finally { |
||||
|
wx.hideLoading() |
||||
|
} |
||||
|
|
||||
|
}, |
||||
|
async doShowModal({ |
||||
|
detail: { |
||||
|
code |
||||
|
} |
||||
|
}) { |
||||
|
const { |
||||
|
getOpenid, |
||||
|
coupons |
||||
|
} = getApp() |
||||
|
wx.showLoading() |
||||
|
try { |
||||
|
const openid = await getOpenid() |
||||
|
const coupon = coupons.get(code) |
||||
|
await axios.get('/Api/Coupon/GetCoupon', { |
||||
|
"couponCode": coupon.code, |
||||
|
"mallCode": coupon.mallCode, |
||||
|
"userCode": openid |
||||
|
}) |
||||
|
coupons.set({ |
||||
|
...coupon, |
||||
|
received: true |
||||
|
}) |
||||
|
this.setData({ |
||||
|
mall: { |
||||
|
...this.data.mall, |
||||
|
coupons: [...this.data.mall.coupons] |
||||
|
}, |
||||
|
couponName: '优惠券', |
||||
|
showModal: true |
||||
|
}) |
||||
|
} catch (error) { |
||||
|
wx.showToast({ |
||||
|
icon: 'none', |
||||
|
title: JSON.stringify(error), |
||||
|
}) |
||||
|
} finally { |
||||
|
wx.hideLoading() |
||||
|
} |
||||
|
|
||||
|
}, |
||||
|
hideModal() { |
||||
|
this.setData({ |
||||
|
showModal: false |
||||
|
}) |
||||
|
}, |
||||
|
onShareAppMessage() { |
||||
|
return { |
||||
|
title: this.data.shareTitle, |
||||
|
path: "pages/index/index", |
||||
|
imageUrl: "./shareImg.png" |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"ticket": "../../components/ticket/ticket" |
||||
|
}, |
||||
|
"navigationBarTitleText": "优惠券活动" |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
<view class="index"> |
||||
|
<view class="top"> |
||||
|
<navigator wx:if="{{mall}}" class="left" url="../malls/index"> |
||||
|
<image class="img-left" src="./icon.png"></image> {{mall.city}} {{mall.name}} |
||||
|
<image class="img-right" src="./arrow.png"></image> |
||||
|
</navigator> |
||||
|
<navigator class="right" url="../checked/index">核销记录</navigator> |
||||
|
</view> |
||||
|
<scroll-view scroll-y="{{true}}" class="middle" refresher-enabled bindrefresherrefresh="refreshList" |
||||
|
refresher-triggered="{{refresherTriggered}}"> |
||||
|
<ticket wx:for="{{mall.coupons}}" wx:key="*this" code="{{item}}" bindcollect="doShowModal" state="mall"> |
||||
|
</ticket> |
||||
|
<image src="../../images/empty.png" style="width:100%" mode="widthFix" |
||||
|
wx:if="{{mall.coupons&&!mall.coupons.length}}"></image> |
||||
|
<view class="space-bottom"></view> |
||||
|
</scroll-view> |
||||
|
<view class="bottom"> |
||||
|
<navigator url="../mytickets/index"> |
||||
|
<image class="left-icon" src="./ticket.png"></image> |
||||
|
<view wx:if="{{userCouponNum}}" class="banner">{{userCouponNum}}</view> |
||||
|
我的券包 |
||||
|
</navigator> |
||||
|
<button open-type="share"> |
||||
|
<image class="right-icon" src="./share.png"></image> |
||||
|
分享 |
||||
|
</button> |
||||
|
</view> |
||||
|
<view class="modal" wx:if="{{showModal}}"> |
||||
|
<view class="blur"></view> |
||||
|
<view class="content"> |
||||
|
<view class="r1">领取成功</view> |
||||
|
<image class="r2" src="./tick.png"></image> |
||||
|
<view class="r3">{{couponName}}已经放入您的券包</view> |
||||
|
<button class="btn" bindtap="hideModal">确定</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
@ -0,0 +1,226 @@ |
|||||
|
.index { |
||||
|
position: relative; |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
background: #292c3c; |
||||
|
} |
||||
|
|
||||
|
.index .top { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 15px; |
||||
|
right: 15px; |
||||
|
height: 139px; |
||||
|
background: linear-gradient(90deg, #c1c6d0, #e0e2ea); |
||||
|
border-radius: 12px; |
||||
|
z-index: 1; |
||||
|
} |
||||
|
|
||||
|
.index .top .left { |
||||
|
position: absolute; |
||||
|
left: 14px; |
||||
|
top: 14px; |
||||
|
background: #f4f4f4; |
||||
|
border: 1px solid #ececec; |
||||
|
border-radius: 8px; |
||||
|
padding-left: 32px; |
||||
|
padding-right: 29px; |
||||
|
line-height: 30px; |
||||
|
font-size: 14px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
color: rgba(0, 0, 0, 0.85); |
||||
|
max-width: calc(100vw - 114px); |
||||
|
box-sizing: border-box; |
||||
|
white-space: nowrap; |
||||
|
text-overflow: ellipsis; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.index .top .left .img-left { |
||||
|
position: absolute; |
||||
|
display: block; |
||||
|
width: 14px; |
||||
|
height: 16px; |
||||
|
top: 7px; |
||||
|
left: 9px; |
||||
|
} |
||||
|
|
||||
|
.index .top .left .img-right { |
||||
|
position: absolute; |
||||
|
display: block; |
||||
|
width: 5px; |
||||
|
height: 8px; |
||||
|
top: 11px; |
||||
|
right: 9px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.index .top .right { |
||||
|
position: absolute; |
||||
|
right: 14px; |
||||
|
top: 22px; |
||||
|
font-size: 14px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: left; |
||||
|
color: #474956; |
||||
|
line-height: 14px; |
||||
|
} |
||||
|
|
||||
|
.index .middle { |
||||
|
position: absolute; |
||||
|
box-sizing: border-box; |
||||
|
top: 58px; |
||||
|
left: 15px; |
||||
|
right: 15px; |
||||
|
width: calc(100vw - 30px); |
||||
|
bottom: 0; |
||||
|
background: #373946; |
||||
|
border-radius: 12px; |
||||
|
z-index: 2; |
||||
|
padding: 14px; |
||||
|
} |
||||
|
|
||||
|
.index .middle .space-bottom { |
||||
|
width: 100%; |
||||
|
height: 72px; |
||||
|
} |
||||
|
|
||||
|
.index .bottom { |
||||
|
position: absolute; |
||||
|
display: flex; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
width: 100vw; |
||||
|
height: 64px; |
||||
|
background: #292c3c; |
||||
|
border-top: 1px solid #1d202e; |
||||
|
z-index: 3; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.index .bottom>navigator, |
||||
|
.index .bottom>button { |
||||
|
flex: 1; |
||||
|
position: relative; |
||||
|
font-size: 10px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
padding-top: 43px; |
||||
|
background: none; |
||||
|
} |
||||
|
|
||||
|
.index .bottom .left-icon { |
||||
|
position: absolute; |
||||
|
top: 12px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
margin: auto; |
||||
|
width: 32px; |
||||
|
height: 24px; |
||||
|
z-index: 1; |
||||
|
} |
||||
|
|
||||
|
.index .bottom .banner { |
||||
|
position: absolute; |
||||
|
min-width: 16px; |
||||
|
height: 16px; |
||||
|
top: 5px; |
||||
|
left: calc(50% + 9px); |
||||
|
line-height: 16px; |
||||
|
font-size: 10px; |
||||
|
font-family: DINPro, DINPro-Bold; |
||||
|
font-weight: 700; |
||||
|
text-align: center; |
||||
|
color: #d6ab7e; |
||||
|
background: #474956; |
||||
|
border-radius: 50%; |
||||
|
z-index: 2; |
||||
|
} |
||||
|
|
||||
|
.index .bottom .right-icon { |
||||
|
position: absolute; |
||||
|
top: 11px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
margin: auto; |
||||
|
width: 25px; |
||||
|
height: 25px; |
||||
|
} |
||||
|
|
||||
|
.index .modal { |
||||
|
position: absolute; |
||||
|
z-index: 4; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
} |
||||
|
|
||||
|
.index .modal .blur { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background: rgba(0, 0, 0, 0.5); |
||||
|
filter: blur(5px); |
||||
|
z-index: 1; |
||||
|
} |
||||
|
|
||||
|
.index .modal .content { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
margin: auto; |
||||
|
width: 273px; |
||||
|
height: 278px; |
||||
|
background: linear-gradient(180deg, #c1c6d0, #e0e2ea); |
||||
|
border-radius: 14px; |
||||
|
z-index: 2; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.index .modal .content>.r1 { |
||||
|
font-size: 24px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
color: #474956; |
||||
|
margin-top: 30px; |
||||
|
line-height: 50px; |
||||
|
} |
||||
|
|
||||
|
.index .modal .content>.r2 { |
||||
|
width: 95px; |
||||
|
height: 72px; |
||||
|
margin: auto; |
||||
|
} |
||||
|
|
||||
|
.index .modal .content>.r3 { |
||||
|
font-size: 14px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
color: #474956; |
||||
|
line-height: 62px; |
||||
|
} |
||||
|
|
||||
|
.index .modal .content>.btn { |
||||
|
width: 240px; |
||||
|
height: 48px; |
||||
|
background: linear-gradient(180deg, #3e404d, #393b46 97%); |
||||
|
border: 1px solid; |
||||
|
border-image: linear-gradient(180deg, #fadabd, #f4c09c 133%) 1 1; |
||||
|
border-radius: 8px; |
||||
|
box-shadow: 0px 12px 12px -12px #30323c; |
||||
|
font-size: 14px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: center; |
||||
|
color: #f9dab7; |
||||
|
line-height: 48px; |
||||
|
padding: 0; |
||||
|
} |
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 833 B |
@ -0,0 +1,174 @@ |
|||||
|
import { |
||||
|
getCities |
||||
|
} from '../../js/cities' |
||||
|
|
||||
|
Page({ |
||||
|
|
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
q: "", |
||||
|
showList: false, |
||||
|
cities: [], |
||||
|
filteredCities: [], |
||||
|
currentMall: null, |
||||
|
currentCity: null, |
||||
|
currentMalls: [], |
||||
|
isMallExpand: false, |
||||
|
indexedList: [], |
||||
|
scrollIntoView: '' |
||||
|
}, |
||||
|
scrollIntoView(e) { |
||||
|
this.setData({ |
||||
|
scrollIntoView: e.target.id |
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
setCity(e) { |
||||
|
const name = e.target.id; |
||||
|
const city = this.data.filteredCities.find((city) => city.name === name) |
||||
|
|
||||
|
this.setData({ |
||||
|
currentCity: city, |
||||
|
currentMalls: city.malls, |
||||
|
currentMall: city.malls[0], |
||||
|
showList: false |
||||
|
}) |
||||
|
}, |
||||
|
expandMall() { |
||||
|
this.setData({ |
||||
|
isMallExpand: true |
||||
|
}) |
||||
|
}, |
||||
|
hideMallExpand() { |
||||
|
this.setData({ |
||||
|
isMallExpand: false |
||||
|
}) |
||||
|
}, |
||||
|
onInput({ |
||||
|
detail: { |
||||
|
value |
||||
|
} |
||||
|
}) { |
||||
|
this.setData({ |
||||
|
q: value, |
||||
|
filteredCities: this.data.cities.map(({ |
||||
|
name |
||||
|
}) => name === value) |
||||
|
}); |
||||
|
}, |
||||
|
doShowList() { |
||||
|
this.setData({ |
||||
|
showList: true |
||||
|
}); |
||||
|
}, |
||||
|
onBlur() { |
||||
|
!this.data.q && this.setData({ |
||||
|
showList: false |
||||
|
}) |
||||
|
}, |
||||
|
clearQ() { |
||||
|
this.setData({ |
||||
|
q: '' |
||||
|
}) |
||||
|
}, |
||||
|
async setMall(e) { |
||||
|
const name = e.target.id; |
||||
|
const mall = this.data.currentMalls.find((mall) => mall.name === name) |
||||
|
const { |
||||
|
malls |
||||
|
} = getApp() |
||||
|
this.setData({ |
||||
|
currentMall: mall, |
||||
|
isMallExpand: false |
||||
|
}); |
||||
|
malls.setCurrentMall({ |
||||
|
city: this.data.currentCity.name, |
||||
|
name: mall.name, |
||||
|
code: mall.code |
||||
|
}) |
||||
|
wx.navigateBack() |
||||
|
}, |
||||
|
setMallByCity(e) { |
||||
|
const name = e.target.id; |
||||
|
const city = this.data.cities.find((city) => city.name === name) |
||||
|
|
||||
|
this.setData({ |
||||
|
currentCity: city, |
||||
|
currentMalls: city.malls, |
||||
|
currentMall: city.malls[0] |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
async onLoad(options) { |
||||
|
const { |
||||
|
malls |
||||
|
} = getApp() |
||||
|
const cities = await getCities() |
||||
|
const mall = await malls.getCurrentMall() |
||||
|
const city = cities.find(({ |
||||
|
name |
||||
|
}) => name === mall.city) |
||||
|
|
||||
|
this.setData({ |
||||
|
cities, |
||||
|
filteredCities: cities, |
||||
|
currentCity: city, |
||||
|
currentMalls: city.malls, |
||||
|
currentMall: mall |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage: function () { |
||||
|
|
||||
|
} |
||||
|
}) |
||||
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
<view class="malls" bindtap="hideMallExpand"> |
||||
|
<view class="input-wrapper"> |
||||
|
<input value="{{q}}" class="input" placeholder="输入城市进行搜索" placeholder-class="placeholder" bindinput="onInput" |
||||
|
bindfocus="doShowList" bindblur="onBlur"></input> |
||||
|
</view> |
||||
|
<image class="search-icon" src="./search.png"></image> |
||||
|
<image wx:if="{{q}}" class="close" src="./close_white.png" bindtap="clearQ" /> |
||||
|
<view class="list" wx:if="{{showList}}"> |
||||
|
<view wx:for="{{filteredCities}}" id="{{item.name}}" class="item" wx:key="name"> |
||||
|
{{item.name}} |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="main" wx:else> |
||||
|
<view class="r1"> |
||||
|
<view class="left"> |
||||
|
<image class="pos" src="./pos.png"></image> |
||||
|
<text>{{currentCity === null ? "" : currentCity.name}}</text> |
||||
|
<text>{{currentMall === null ? "" : currentMall.name}}</text> |
||||
|
<image class="up" src="./up.png"></image> |
||||
|
</view> |
||||
|
<text class="right">当前定位城市</text> |
||||
|
</view> |
||||
|
<view class="r2">切换商场</view> |
||||
|
<view class="malls-wrapper" bindtap="hideMallExpand"> |
||||
|
<view class="malls1{{isMallExpand ? ' expand' : '' }}" catchtap> |
||||
|
<view wx:for="{{currentMalls}}" wx:key="id" id="{{item.name}}" class="tag" bindtap="setMall"> |
||||
|
{{item.name}} |
||||
|
</view> |
||||
|
<image wx:if="{{isMallExpand}}" class="fold" src="./up.png" catchtap="hideMallExpand"></image> |
||||
|
<view wx:else class="more" catchtap="expandMall"> |
||||
|
更多 |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<scroll-view class="list-container" enable-back-to-top="{{true}}" scroll-into-view="{{scrollIntoView}}" |
||||
|
scroll-y="{{true}}"> |
||||
|
<view class="meta">切换城市</view> |
||||
|
<view class="city-buttons"> |
||||
|
<view wx:for="{{cities}}" wx:key="name" id="{{item.name}}" class="city-button" bindtap="setMallByCity"> |
||||
|
{{item.name}} |
||||
|
</view> |
||||
|
</view> |
||||
|
<view wx:for="{{cities}}" wx:key="name" id="{{item.index}}" class="city-indexed"> |
||||
|
<view class="index {{index===0?' first':''}}" wx:if="{{index===0||cities[index-1].index !== item.index}}"> |
||||
|
{{item.index}}</view> |
||||
|
<view class="name" id="{{item.name}}" bindtap="setMallByCity"> {{item.name}}</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
<view class="indexes"> |
||||
|
<view class="li"></view> |
||||
|
<view wx:for="{{cities}}" wx:key="name" id="{{item.index}}" |
||||
|
wx:if="{{index===0||item.index!==cities[index-1].index }}" class="li" bindtap="scrollIntoView"> |
||||
|
{{item.index}} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
@ -0,0 +1,316 @@ |
|||||
|
.malls { |
||||
|
position: relative; |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
box-sizing: border-box; |
||||
|
color: #5a5a5a; |
||||
|
font-family: SourceHanSansCN-Medium, SourceHanSansCN; |
||||
|
} |
||||
|
|
||||
|
.malls .search-icon { |
||||
|
position: absolute; |
||||
|
width: 13px; |
||||
|
height: 13px; |
||||
|
top: 21px; |
||||
|
left: 26px; |
||||
|
z-index: 1; |
||||
|
} |
||||
|
|
||||
|
.malls .close { |
||||
|
position: absolute; |
||||
|
border-radius: 50%; |
||||
|
background: #8d8d8d; |
||||
|
width: 20px; |
||||
|
height: 20px; |
||||
|
top: 17px; |
||||
|
right: 19px; |
||||
|
} |
||||
|
|
||||
|
.malls .input-wrapper { |
||||
|
padding: 12px 14px 0 14px; |
||||
|
} |
||||
|
|
||||
|
.malls .input-wrapper .input { |
||||
|
padding: 5px 30px; |
||||
|
background: #ececec; |
||||
|
border-radius: 100px; |
||||
|
height: 30px; |
||||
|
line-height: 20px; |
||||
|
font-size: 11px; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
.malls .input-wrapper .placeholder { |
||||
|
color: #a9a9a9; |
||||
|
} |
||||
|
|
||||
|
.malls .list { |
||||
|
padding: 0 50px 0 15px; |
||||
|
line-height: 36px; |
||||
|
height: calc(100vh - 42px); |
||||
|
font-size: 12px; |
||||
|
overflow: scroll; |
||||
|
} |
||||
|
|
||||
|
.malls .list .item { |
||||
|
border-bottom: 1px solid #f4f4f4; |
||||
|
} |
||||
|
|
||||
|
.malls .main .r1 { |
||||
|
padding: 18px 15px; |
||||
|
line-height: 30px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .r1 .left { |
||||
|
position: relative; |
||||
|
display: inline-block; |
||||
|
font-size: 14px; |
||||
|
background: #f4f4f4; |
||||
|
border-radius: 8px; |
||||
|
border: 1px solid #ececec; |
||||
|
padding: 0 30px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .r1 .left .pos { |
||||
|
position: absolute; |
||||
|
width: 14px; |
||||
|
height: 16px; |
||||
|
top: 7px; |
||||
|
left: 9px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .r1 .left .up { |
||||
|
position: absolute; |
||||
|
right: 7.5px; |
||||
|
top: 12.5px; |
||||
|
width: 8px; |
||||
|
height: 5px; |
||||
|
transform-origin: center; |
||||
|
transform: rotate(90deg); |
||||
|
} |
||||
|
|
||||
|
.malls .main .r1 .left Text+Text { |
||||
|
margin-left: 22px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .r1 .right { |
||||
|
margin-left: 15px; |
||||
|
font-size: 11px; |
||||
|
font-weight: 400; |
||||
|
color: darkgray; |
||||
|
} |
||||
|
|
||||
|
.malls .main .r2 { |
||||
|
padding-left: 15px; |
||||
|
color: #a9a9a9; |
||||
|
font-size: 11px; |
||||
|
line-height: 11px; |
||||
|
font-weight: 400; |
||||
|
} |
||||
|
|
||||
|
.malls .main .malls-wrapper {} |
||||
|
|
||||
|
.malls .main .malls-wrapper .malls1 { |
||||
|
position: relative; |
||||
|
margin-top: 11px; |
||||
|
padding-left: 15px; |
||||
|
padding-right: 60px; |
||||
|
height: 32px; |
||||
|
overflow: hidden; |
||||
|
background: #fff; |
||||
|
z-index: 10; |
||||
|
} |
||||
|
|
||||
|
.malls .main .malls-wrapper .malls1 .more { |
||||
|
position: absolute; |
||||
|
line-height: 30px; |
||||
|
color: #a9a9a9; |
||||
|
right: 14px; |
||||
|
font-size: 11px; |
||||
|
top: 0; |
||||
|
} |
||||
|
|
||||
|
.malls .main .malls-wrapper .malls1.expand { |
||||
|
box-shadow: 0px 15px 12px 0px rgba(0, 0, 0, 0.22); |
||||
|
padding-right: 15px; |
||||
|
padding-bottom: 17px; |
||||
|
overflow: auto; |
||||
|
height: auto; |
||||
|
} |
||||
|
|
||||
|
.malls .main .malls-wrapper .malls1 .tag { |
||||
|
color: #878787; |
||||
|
font-size: 12px; |
||||
|
padding: 0 11px; |
||||
|
border-radius: 15px; |
||||
|
border: 1px solid #ececec; |
||||
|
line-height: 30px; |
||||
|
display: inline-block; |
||||
|
margin-bottom: 12px; |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .malls-wrapper .malls1 .fold { |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
width: 8px; |
||||
|
height: 5px; |
||||
|
padding: 8px 6.5px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
margin: auto; |
||||
|
} |
||||
|
|
||||
|
.malls .main .malls-wrapper .malls1 .fold::after { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
left: -5px; |
||||
|
right: -5px; |
||||
|
top: -5px; |
||||
|
bottom: -5px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes { |
||||
|
position: absolute; |
||||
|
top: 178px; |
||||
|
border-top: 1px solid #f4f4f4; |
||||
|
padding: 0 50px 0 15px; |
||||
|
height: calc(100vh - 178px); |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-indexes__menu :first-child { |
||||
|
display: none !important; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-indexes__menu { |
||||
|
top: 204px; |
||||
|
font-size: 11px; |
||||
|
transform: none; |
||||
|
right: 15px; |
||||
|
z-index: 1; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-indexes__menu .at-indexes__menu-item { |
||||
|
display: block; |
||||
|
padding: 0; |
||||
|
font-size: 11px; |
||||
|
color: #a9a9a9; |
||||
|
line-height: 15px; |
||||
|
height: 15px; |
||||
|
width: 15px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-indexes__menu .at-indexes__menu-item:active { |
||||
|
background: #d6ab7e; |
||||
|
color: white; |
||||
|
border-radius: 50%; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-list::after { |
||||
|
content: none; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-indexes__list-title { |
||||
|
line-height: 36px; |
||||
|
color: #878787; |
||||
|
font-size: 12px; |
||||
|
font-weight: 400; |
||||
|
border-bottom: 1px solid #f4f4f4; |
||||
|
background: none; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-list__item { |
||||
|
font-size: 12px; |
||||
|
font-weight: 400; |
||||
|
border-bottom: 1px solid #f4f4f4; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-list__item .item-content__info-title { |
||||
|
color: #5a5a5a; |
||||
|
line-height: 36px; |
||||
|
} |
||||
|
|
||||
|
.malls .main .at-indexes .at-list__item::after { |
||||
|
content: none; |
||||
|
} |
||||
|
|
||||
|
.malls .main .meta { |
||||
|
font-size: 11px; |
||||
|
font-weight: 400; |
||||
|
margin-top: 7px; |
||||
|
padding: 11px 0; |
||||
|
color: #a9a9a9; |
||||
|
} |
||||
|
|
||||
|
.malls .main .city-buttons { |
||||
|
display: grid; |
||||
|
grid-column-gap: 10px; |
||||
|
grid-row-gap: 11px; |
||||
|
grid-auto-rows: 30px; |
||||
|
grid-auto-columns: 70px; |
||||
|
grid-template-columns: 1fr 1fr 1fr 1fr; |
||||
|
} |
||||
|
|
||||
|
.malls .main .city-buttons .city-button { |
||||
|
display: inline-block; |
||||
|
color: #878787; |
||||
|
font-size: 12px; |
||||
|
line-height: 30px; |
||||
|
background: #f4f4f4; |
||||
|
border-radius: 4px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.malls .list-container { |
||||
|
position: absolute; |
||||
|
top: 178px; |
||||
|
border-top: 1px solid #f4f4f4; |
||||
|
padding: 0 50px 0 15px; |
||||
|
height: calc(100vh - 178px); |
||||
|
width: 100vw; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
.malls .city-indexed .index { |
||||
|
height: 36px; |
||||
|
line-height: 36px; |
||||
|
border-top: 1px solid #f4f4f4; |
||||
|
border-bottom: 1px solid #f4f4f4; |
||||
|
} |
||||
|
|
||||
|
.malls .city-indexed .index.first { |
||||
|
border-top: none; |
||||
|
} |
||||
|
|
||||
|
.malls .city-indexed .name { |
||||
|
height: 36px; |
||||
|
line-height: 36px; |
||||
|
} |
||||
|
|
||||
|
.malls .indexes { |
||||
|
position: absolute; |
||||
|
top: 196px; |
||||
|
font-size: 11px; |
||||
|
right: 15px; |
||||
|
z-index: 1; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.malls .indexes .li { |
||||
|
display: block; |
||||
|
padding: 0; |
||||
|
font-size: 11px; |
||||
|
color: #a9a9a9; |
||||
|
line-height: 15px; |
||||
|
height: 15px; |
||||
|
width: 15px; |
||||
|
} |
||||
|
|
||||
|
.malls .indexes .li:active { |
||||
|
background: #d6ab7e; |
||||
|
color: white; |
||||
|
border-radius: 50%; |
||||
|
} |
||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 936 B |
|
After Width: | Height: | Size: 464 B |
@ -0,0 +1,105 @@ |
|||||
|
const couponTypeMap = { |
||||
|
'优惠券': 0, |
||||
|
'直播券': 1 |
||||
|
} |
||||
|
Page({ |
||||
|
|
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
currentTab: '优惠券', |
||||
|
tabList: { |
||||
|
'优惠券': [], |
||||
|
'直播券': [] |
||||
|
}, |
||||
|
refresherTriggered: false, |
||||
|
}, |
||||
|
setTab(e) { |
||||
|
this.setData({ |
||||
|
currentTab: e.target.id |
||||
|
}, () => { |
||||
|
this.getCurrentList() |
||||
|
}) |
||||
|
}, |
||||
|
check({ |
||||
|
detail: { |
||||
|
code |
||||
|
} |
||||
|
}) { |
||||
|
wx.navigateTo({ |
||||
|
url: '../ticketdetail/index?code=' + code, |
||||
|
}) |
||||
|
}, |
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad(options) { |
||||
|
this.getCurrentList() |
||||
|
}, |
||||
|
async refreshList() { |
||||
|
await this.getCurrentList() |
||||
|
this.setData({ |
||||
|
refresherTriggered: false |
||||
|
}) |
||||
|
}, |
||||
|
async getCurrentList() { |
||||
|
const { |
||||
|
coupons |
||||
|
} = getApp() |
||||
|
const list = await coupons.getUserCodes(couponTypeMap[this.data.currentTab]) |
||||
|
this.setData({ |
||||
|
tabList: Object.assign(this.data.tabList, { |
||||
|
[this.data.currentTab]: list |
||||
|
}) |
||||
|
}) |
||||
|
}, |
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow: function () { |
||||
|
this.refreshList() |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage: function () { |
||||
|
|
||||
|
} |
||||
|
}) |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"ticket": "../../components/ticket/ticket" |
||||
|
}, |
||||
|
"navigationBarTitleText": "我的券包" |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
<view class="mt"> |
||||
|
<view class="top"> |
||||
|
<view class="tab {{currentTab==='优惠券'?'active':''}}" id="优惠券" bindtap="setTab">优惠券</view> |
||||
|
<view class="tab {{currentTab==='直播券'?'active':''}}" id="直播券" bindtap="setTab">直播券</view> |
||||
|
</view> |
||||
|
<scroll-view scroll-y="{{true}}" class="middle" bindrefresherrefresh="refreshList" |
||||
|
refresher-triggered="{{refresherTriggered}}" refresher-enabled> |
||||
|
<ticket wx:for="{{tabList[currentTab]}}" wx:key="*this" code="{{item}}" bindcollect="check" state="my"></ticket> |
||||
|
<image src="../../images/empty.png" style="width:100%" mode="widthFix" |
||||
|
wx:if="{{tabList[currentTab]&&!tabList[currentTab].length}}"> |
||||
|
</image> |
||||
|
<view class="space-bottom"></view> |
||||
|
</scroll-view> |
||||
|
</view> |
||||
@ -0,0 +1,82 @@ |
|||||
|
.mt { |
||||
|
position: relative; |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
background: #292c3c; |
||||
|
} |
||||
|
|
||||
|
.mt .top { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 15px; |
||||
|
right: 15px; |
||||
|
height: 139px; |
||||
|
background: linear-gradient(90deg, #c1c6d0, #e0e2ea); |
||||
|
border-radius: 12px; |
||||
|
z-index: 1; |
||||
|
padding-bottom: 81px; |
||||
|
display: flex; |
||||
|
} |
||||
|
|
||||
|
.mt .top .tab { |
||||
|
position: relative; |
||||
|
flex: 1; |
||||
|
width: 48px; |
||||
|
font-size: 16px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Bold; |
||||
|
font-weight: 700; |
||||
|
text-align: center; |
||||
|
color: #8E919B; |
||||
|
line-height: 58px; |
||||
|
} |
||||
|
|
||||
|
.mt .top .tab.active { |
||||
|
color: #474956; |
||||
|
} |
||||
|
|
||||
|
.mt .top .tab.active::after { |
||||
|
content: ''; |
||||
|
position: absolute; |
||||
|
width: 80px; |
||||
|
height: 4px; |
||||
|
background: linear-gradient(270deg, #f54b64, #f78361); |
||||
|
border-radius: 2px; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
margin: auto; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
.mt .top .right { |
||||
|
position: absolute; |
||||
|
right: 14px; |
||||
|
top: 22px; |
||||
|
font-size: 14px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: left; |
||||
|
color: #474956; |
||||
|
line-height: 14px; |
||||
|
} |
||||
|
|
||||
|
.mt .middle { |
||||
|
position: absolute; |
||||
|
box-sizing: border-box; |
||||
|
top: 58px; |
||||
|
left: 15px; |
||||
|
right: 15px; |
||||
|
width: calc(100vw - 30px); |
||||
|
bottom: 0; |
||||
|
background: #373946; |
||||
|
border-radius: 12px; |
||||
|
z-index: 2; |
||||
|
padding: 14px; |
||||
|
} |
||||
|
|
||||
|
.mt .middle .space-bottom { |
||||
|
width: 100%; |
||||
|
height: 72px; |
||||
|
} |
||||
@ -0,0 +1,85 @@ |
|||||
|
// miniprogram/pages/ticketdetail/index.js
|
||||
|
Page({ |
||||
|
|
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad: function ({ |
||||
|
code |
||||
|
}) { |
||||
|
this.setData({ |
||||
|
code, |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
async onShow() { |
||||
|
const openid = await getApp().getOpenid() |
||||
|
wx.connectSocket({ |
||||
|
url: `wss://test.1000my.com:8099?ip=${openid}` |
||||
|
}) |
||||
|
wx.onSocketMessage(() => { |
||||
|
wx.showModal({ |
||||
|
title: '提示', |
||||
|
content: '核销已完成', |
||||
|
showCancel: false, |
||||
|
success(res) { |
||||
|
if (res.confirm) { |
||||
|
wx.navigateBack() |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload: function () { |
||||
|
wx.closeSocket() |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom: function () { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage: function () { |
||||
|
|
||||
|
} |
||||
|
}) |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"ticket": "../../components/ticket/ticket" |
||||
|
}, |
||||
|
"navigationBarTitleText": "券详情" |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
<view class="td"> |
||||
|
<view class="content"> |
||||
|
<ticket wx:if="{{code}}" state="detail" code="{{code}}"></ticket> |
||||
|
<view class="meta">核销时向店家出示该二维码</view> |
||||
|
</view> |
||||
|
|
||||
|
</view> |
||||
@ -0,0 +1,31 @@ |
|||||
|
.td { |
||||
|
position: relative; |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
background: #292c3c; |
||||
|
} |
||||
|
|
||||
|
.td .content { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
bottom: 0; |
||||
|
left: 29px; |
||||
|
right: 29px; |
||||
|
margin: auto; |
||||
|
height: 400px; |
||||
|
} |
||||
|
|
||||
|
.td .content .meta { |
||||
|
width: 196px; |
||||
|
height: 32px; |
||||
|
background: #202330; |
||||
|
border-radius: 16px; |
||||
|
font-size: 12px; |
||||
|
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
text-align: center; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
line-height: 32px; |
||||
|
margin: auto; |
||||
|
margin-top: 16px; |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", |
||||
|
"rules": [{ |
||||
|
"action": "allow", |
||||
|
"page": "*" |
||||
|
}] |
||||
|
} |
||||
@ -0,0 +1,144 @@ |
|||||
|
page { |
||||
|
background: #f6f6f6; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: flex-start; |
||||
|
} |
||||
|
|
||||
|
.list { |
||||
|
margin-top: 40rpx; |
||||
|
height: auto; |
||||
|
width: 100%; |
||||
|
background: #fff; |
||||
|
padding: 0 40rpx; |
||||
|
border: 1px solid rgba(0, 0, 0, 0.1); |
||||
|
border-left: none; |
||||
|
border-right: none; |
||||
|
transition: all 300ms ease; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: stretch; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
.list-item { |
||||
|
width: 100%; |
||||
|
padding: 0; |
||||
|
line-height: 104rpx; |
||||
|
font-size: 34rpx; |
||||
|
color: #007aff; |
||||
|
border-top: 1px solid rgba(0, 0, 0, 0.1); |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
align-content: center; |
||||
|
justify-content: space-between; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
.list-item:first-child { |
||||
|
border-top: none; |
||||
|
} |
||||
|
|
||||
|
.list-item image { |
||||
|
max-width: 100%; |
||||
|
max-height: 20vh; |
||||
|
margin: 20rpx 0; |
||||
|
} |
||||
|
|
||||
|
.request-text { |
||||
|
color: #222; |
||||
|
padding: 20rpx 0; |
||||
|
font-size: 24rpx; |
||||
|
line-height: 36rpx; |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
|
||||
|
.guide { |
||||
|
width: 100%; |
||||
|
padding: 40rpx; |
||||
|
box-sizing: border-box; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.guide .headline { |
||||
|
font-size: 34rpx; |
||||
|
font-weight: bold; |
||||
|
color: #555; |
||||
|
line-height: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.guide .p { |
||||
|
margin-top: 20rpx; |
||||
|
font-size: 28rpx; |
||||
|
line-height: 36rpx; |
||||
|
color: #666; |
||||
|
} |
||||
|
|
||||
|
.guide .code { |
||||
|
margin-top: 20rpx; |
||||
|
font-size: 28rpx; |
||||
|
line-height: 36rpx; |
||||
|
color: #666; |
||||
|
background: white; |
||||
|
white-space: pre; |
||||
|
} |
||||
|
|
||||
|
.guide .code-dark { |
||||
|
margin-top: 20rpx; |
||||
|
background: rgba(0, 0, 0, 0.8); |
||||
|
padding: 20rpx; |
||||
|
font-size: 28rpx; |
||||
|
line-height: 36rpx; |
||||
|
border-radius: 6rpx; |
||||
|
color: #fff; |
||||
|
white-space: pre |
||||
|
} |
||||
|
|
||||
|
.guide image { |
||||
|
max-width: 100%; |
||||
|
} |
||||
|
|
||||
|
.guide .image1 { |
||||
|
margin-top: 20rpx; |
||||
|
max-width: 100%; |
||||
|
width: 356px; |
||||
|
height: 47px; |
||||
|
} |
||||
|
|
||||
|
.guide .image2 { |
||||
|
margin-top: 20rpx; |
||||
|
width: 264px; |
||||
|
height: 100px; |
||||
|
} |
||||
|
|
||||
|
.guide .flat-image { |
||||
|
height: 100px; |
||||
|
} |
||||
|
|
||||
|
.guide .code-image { |
||||
|
max-width: 100%; |
||||
|
} |
||||
|
|
||||
|
.guide .copyBtn { |
||||
|
width: 180rpx; |
||||
|
font-size: 20rpx; |
||||
|
margin-top: 16rpx; |
||||
|
margin-left: 0; |
||||
|
} |
||||
|
|
||||
|
.guide .nav { |
||||
|
margin-top: 50rpx; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
align-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.guide .nav .prev { |
||||
|
margin-left: unset; |
||||
|
} |
||||
|
|
||||
|
.guide .nav .next { |
||||
|
margin-right: unset; |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,115 @@ |
|||||
|
{ |
||||
|
"miniprogramRoot": "miniprogram/", |
||||
|
"cloudfunctionRoot": "cloudfunctions/", |
||||
|
"setting": { |
||||
|
"urlCheck": false, |
||||
|
"es6": true, |
||||
|
"enhance": true, |
||||
|
"postcss": true, |
||||
|
"preloadBackgroundData": false, |
||||
|
"minified": true, |
||||
|
"newFeature": true, |
||||
|
"coverView": true, |
||||
|
"nodeModules": false, |
||||
|
"autoAudits": false, |
||||
|
"showShadowRootInWxmlPanel": true, |
||||
|
"scopeDataCheck": false, |
||||
|
"uglifyFileName": false, |
||||
|
"checkInvalidKey": true, |
||||
|
"checkSiteMap": true, |
||||
|
"uploadWithSourceMap": true, |
||||
|
"compileHotReLoad": false, |
||||
|
"useMultiFrameRuntime": true, |
||||
|
"useApiHook": true, |
||||
|
"babelSetting": { |
||||
|
"ignore": [], |
||||
|
"disablePlugins": [], |
||||
|
"outputPath": "" |
||||
|
}, |
||||
|
"enableEngineNative": false, |
||||
|
"useIsolateContext": true, |
||||
|
"useCompilerModule": true, |
||||
|
"userConfirmedUseCompilerModuleSwitch": false, |
||||
|
"packNpmManually": false, |
||||
|
"packNpmRelationList": [], |
||||
|
"bundle": false, |
||||
|
"useApiHostProcess": false, |
||||
|
"minifyWXSS": true, |
||||
|
"minifyWXML": true, |
||||
|
"disableUseStrict": false, |
||||
|
"useStaticServer": true, |
||||
|
"showES6CompileOption": false, |
||||
|
"useCompilerPlugins": false |
||||
|
}, |
||||
|
"appid": "wx1949744ebf85151f", |
||||
|
"projectname": "ticket", |
||||
|
"libVersion": "2.17.0", |
||||
|
"simulatorType": "wechat", |
||||
|
"simulatorPluginLibVersion": {}, |
||||
|
"condition": { |
||||
|
"plugin": { |
||||
|
"list": [] |
||||
|
}, |
||||
|
"game": { |
||||
|
"list": [] |
||||
|
}, |
||||
|
"gamePlugin": { |
||||
|
"list": [] |
||||
|
}, |
||||
|
"miniprogram": { |
||||
|
"list": [ |
||||
|
{ |
||||
|
"id": -1, |
||||
|
"name": "db guide", |
||||
|
"pathName": "pages/databaseGuide/databaseGuide", |
||||
|
"query": "" |
||||
|
}, |
||||
|
{ |
||||
|
"id": -1, |
||||
|
"name": "核销记录", |
||||
|
"pathName": "pages/checked/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"id": -1, |
||||
|
"name": "我的券包", |
||||
|
"pathName": "pages/mytickets/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"id": -1, |
||||
|
"name": "详情", |
||||
|
"pathName": "pages/ticketdetail/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"id": -1, |
||||
|
"name": "选择商场", |
||||
|
"pathName": "pages/malls/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"name": "二维码进入", |
||||
|
"pathName": "pages/index/index", |
||||
|
"query": "q= https://test.1000my.com:8019/hls?mallCode=d45d0caa-8067-4691-a82e-a6e8a7b84035&couponCode=ZBFB202010301048188151", |
||||
|
"scene": null |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"compileType": "miniprogram", |
||||
|
"srcMiniprogramRoot": "miniprogram/", |
||||
|
"packOptions": { |
||||
|
"ignore": [], |
||||
|
"include": [] |
||||
|
}, |
||||
|
"editorSetting": { |
||||
|
"tabIndent": "insertSpaces", |
||||
|
"tabSize": 2 |
||||
|
}, |
||||
|
"description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html" |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
{ |
||||
|
"setting": {}, |
||||
|
"condition": { |
||||
|
"miniprogram": { |
||||
|
"list": [ |
||||
|
{ |
||||
|
"name": "db guide", |
||||
|
"pathName": "pages/databaseGuide/databaseGuide", |
||||
|
"query": "" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "核销记录", |
||||
|
"pathName": "pages/checked/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"name": "我的券包", |
||||
|
"pathName": "pages/mytickets/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"name": "详情", |
||||
|
"pathName": "pages/ticketdetail/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"name": "选择商场", |
||||
|
"pathName": "pages/malls/index", |
||||
|
"query": "", |
||||
|
"scene": null |
||||
|
}, |
||||
|
{ |
||||
|
"name": "二维码进入", |
||||
|
"pathName": "pages/index/index", |
||||
|
"query": "q=https://test.1000my.com:8019/hls%3FmallCode%3De5e8b29a-1e1b-4202-af95-888d76aad5ec%26couponCode%3DZBFB202106091345058905", |
||||
|
"scene": null |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html" |
||||
|
} |
||||