feat: 实现微信小程序码生成功能
- 新增 pages/scan/result/ 扫码结果页,展示预约详情 - 实现微信小程序码生成(wxacode.getUnlimited) - 添加环境版本自动检测(release/trial/develop) - 优化 qrcode-modal 组件,使用 Base64 图片替代本地生成 - 统一 API 接口抽离到 api.js 和 config.js - 优化代码结构,提升可读性和维护性 主要变更: 1. utils/api.js: 新增 getWxacode() 接口,支持生成小程序码 2. components/qrcode-modal: 改用 API 生成小程序码,移除本地 QRCode 依赖 3. pages/scan/result: 新增扫码结果展示页,解析 scene 参数 4. utils/config.js: 新增 WXACODE 配置项
This commit is contained in:
@@ -1,33 +1,28 @@
|
|||||||
const drawQrcode = require('../../utils/weapp.qrcode.esm.js').default
|
const { getWxacode } = require('../../utils/api')
|
||||||
|
|
||||||
Component({
|
Component({
|
||||||
data: {
|
data: {
|
||||||
visible: false,
|
visible: false,
|
||||||
qrcodeId: '',
|
qrcodeId: '',
|
||||||
loading: true
|
loading: true,
|
||||||
|
qrcodePath: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
show(id) {
|
async show(id) {
|
||||||
this.setData({ visible: true, qrcodeId: id, loading: true })
|
this.setData({ visible: true, qrcodeId: id, loading: true, qrcodePath: '' })
|
||||||
wx.nextTick(() => {
|
try {
|
||||||
drawQrcode({
|
const base64Image = await getWxacode(id, 'pages/scan/result/index')
|
||||||
width: 200,
|
this.setData({ qrcodePath: base64Image, loading: false })
|
||||||
height: 200,
|
} catch (err) {
|
||||||
canvasId: 'qrcodeCanvas',
|
console.error('获取小程序码失败', err)
|
||||||
_this: this,
|
wx.showToast({ title: '二维码生成失败', icon: 'none' })
|
||||||
text: id,
|
|
||||||
callback: () => {
|
|
||||||
this.setData({ loading: false })
|
this.setData({ loading: false })
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onClose() {
|
onClose() {
|
||||||
this.setData({ visible: false, qrcodeId: '' })
|
this.setData({ visible: false, qrcodeId: '', qrcodePath: '' })
|
||||||
},
|
}
|
||||||
|
|
||||||
noop() {}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<view class="qrcode-modal" wx:if="{{visible}}" bindtap="onClose" catchtouchmove="noop">
|
<view class="qrcode-modal" wx:if="{{visible}}" bindtap="onClose" catchtouchmove="noop">
|
||||||
<view class="qrcode-container" catchtap catchtouchmove="noop">
|
<view class="qrcode-container" catchtap catchtouchmove="noop">
|
||||||
<view class="qrcode-title">预约凭证</view>
|
<view class="qrcode-title">预约凭证</view>
|
||||||
<view class="qrcode-canvas-wrap">
|
<view class="qrcode-image-wrap">
|
||||||
<canvas canvas-id="qrcodeCanvas" class="qrcode-canvas"></canvas>
|
<image wx:if="{{qrcodePath && !loading}}" class="qrcode-image" src="{{qrcodePath}}" mode="aspectFit" />
|
||||||
<view class="qrcode-loading" wx:if="{{loading}}">
|
<view class="qrcode-loading" wx:if="{{loading}}">
|
||||||
<view class="qrcode-spinner"></view>
|
<view class="qrcode-spinner"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -29,16 +29,20 @@
|
|||||||
letter-spacing: 4rpx;
|
letter-spacing: 4rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qrcode-canvas-wrap {
|
.qrcode-image-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 400rpx;
|
width: 400rpx;
|
||||||
height: 400rpx;
|
height: 400rpx;
|
||||||
border: 1rpx solid #e8eef5;
|
border: 1rpx solid #e8eef5;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qrcode-canvas {
|
.qrcode-image {
|
||||||
width: 400rpx;
|
width: 400rpx;
|
||||||
height: 400rpx;
|
height: 400rpx;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-17
@@ -1,4 +1,3 @@
|
|||||||
// pages/scan/result/index.js
|
|
||||||
const { appointmentDB, formatRecord } = require('../../../utils/api')
|
const { appointmentDB, formatRecord } = require('../../../utils/api')
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
@@ -9,48 +8,49 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
const id = options.id
|
const id = this.extractId(options)
|
||||||
if (!id) {
|
if (!id) {
|
||||||
this.setData({
|
this.setData({ loading: false, error: '缺少预约记录ID' })
|
||||||
loading: false,
|
|
||||||
error: '缺少预约记录ID'
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.loadRecordDetail(id)
|
this.loadRecordDetail(id)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
extractId(options) {
|
||||||
|
if (options.id) return options.id
|
||||||
|
if (!options.scene) return null
|
||||||
|
|
||||||
|
const scene = decodeURIComponent(options.scene)
|
||||||
|
return scene.startsWith('id=') ? scene.substring(3) : scene
|
||||||
|
},
|
||||||
|
|
||||||
async loadRecordDetail(id) {
|
async loadRecordDetail(id) {
|
||||||
try {
|
try {
|
||||||
this.setData({ loading: true })
|
this.setData({ loading: true })
|
||||||
const result = await appointmentDB.getDetail(id)
|
const result = await appointmentDB.getDetail(id)
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
this.setData({
|
this.setData({ loading: false, error: '预约记录不存在' })
|
||||||
loading: false,
|
|
||||||
error: '预约记录不存在'
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const formatted = formatRecord(result)
|
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'pending': '待审核',
|
'pending': '待审核',
|
||||||
'approved': '已通过',
|
'approved': '已通过',
|
||||||
'rejected': '已拒绝',
|
'rejected': '已拒绝',
|
||||||
'cancelled': '已取消'
|
'cancelled': '已取消'
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
record: {
|
record: {
|
||||||
...formatted,
|
...formatRecord(result),
|
||||||
statusText: statusMap[formatted.status] || formatted.status
|
statusText: statusMap[result.status] || result.status
|
||||||
},
|
},
|
||||||
loading: false
|
loading: false
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('加载预约记录详情失败', err)
|
console.error('加载预约记录详情失败', err)
|
||||||
this.setData({
|
this.setData({ loading: false, error: '加载失败,请稍后重试' })
|
||||||
loading: false,
|
|
||||||
error: '加载失败,请稍后重试'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
+29
-3
@@ -144,7 +144,33 @@ const appointmentDB = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
/**
|
||||||
formatRecord,
|
* 获取小程序码
|
||||||
appointmentDB
|
* @param {string} scene - 场景值
|
||||||
|
* @param {string} page - 页面路径
|
||||||
|
* @returns {Promise<string>} Base64图片数据
|
||||||
|
*/
|
||||||
|
async function getWxacode(scene, page = 'pages/scan/result/index') {
|
||||||
|
const envVersion = wx.getAccountInfoSync().miniProgram.envVersion
|
||||||
|
|
||||||
|
const base64Data = await request({
|
||||||
|
url: BASE_URL + API.WXACODE,
|
||||||
|
method: 'POST',
|
||||||
|
header: { 'content-type': 'application/json' },
|
||||||
|
data: {
|
||||||
|
scene,
|
||||||
|
page,
|
||||||
|
width: 430,
|
||||||
|
envVersion
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return `data:image/jpeg;base64,${base64Data}`
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
request,
|
||||||
|
formatRecord,
|
||||||
|
appointmentDB,
|
||||||
|
getWxacode
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -26,7 +26,8 @@ const API = {
|
|||||||
APPOINTMENT_LIST: '/api/wx-mini/appointment/list',
|
APPOINTMENT_LIST: '/api/wx-mini/appointment/list',
|
||||||
APPOINTMENT_CREATE: '/api/wx-mini/appointment/create',
|
APPOINTMENT_CREATE: '/api/wx-mini/appointment/create',
|
||||||
APPOINTMENT_CANCEL: '/api/wx-mini/appointment/cancel',
|
APPOINTMENT_CANCEL: '/api/wx-mini/appointment/cancel',
|
||||||
APPOINTMENT_DETAIL: '/api/wx-mini/appointment/detail'
|
APPOINTMENT_DETAIL: '/api/wx-mini/appointment/detail',
|
||||||
|
WXACODE: '/api/wx-mini/wxacode'
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[config] 当前环境:', wx.getAccountInfoSync().miniProgram.envVersion, 'BASE_URL:', BASE_URL)
|
console.log('[config] 当前环境:', wx.getAccountInfoSync().miniProgram.envVersion, 'BASE_URL:', BASE_URL)
|
||||||
|
|||||||
Reference in New Issue
Block a user