优化小程序推荐码处理逻辑,支持通过扫码场景解析推荐码和初始章节ID。新增获取用户邀请码的功能以便于分享。更新分享配置,确保分享时自动带上推荐码。调整部分页面逻辑以提升用户体验。
This commit is contained in:
157
miniprogram/pages/scan/scan.js
Normal file
157
miniprogram/pages/scan/scan.js
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Soul创业派对 - 扫码解析页
|
||||
* 扫描二维码/条形码,展示解析内容
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
// 最近一次解析结果
|
||||
lastResult: null,
|
||||
scanType: '',
|
||||
charSet: '',
|
||||
// 小程序码解析(路径、参数)
|
||||
parsedPath: null,
|
||||
parsedQuery: [],
|
||||
canNavigate: false,
|
||||
// 历史记录
|
||||
history: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight || 44
|
||||
})
|
||||
this.loadHistory()
|
||||
},
|
||||
|
||||
loadHistory() {
|
||||
try {
|
||||
const history = wx.getStorageSync('scanHistory') || []
|
||||
this.setData({ history })
|
||||
} catch (e) {
|
||||
console.log('加载扫码历史失败:', e)
|
||||
}
|
||||
},
|
||||
|
||||
saveToHistory(result, scanType, charSet) {
|
||||
const item = { result, scanType, charSet, time: new Date().toLocaleString() }
|
||||
let history = wx.getStorageSync('scanHistory') || []
|
||||
history = [item, ...history].slice(0, 10)
|
||||
wx.setStorageSync('scanHistory', history)
|
||||
this.setData({ history })
|
||||
},
|
||||
|
||||
// 解析小程序码内容:path?key=val 或 path
|
||||
parseMiniProgramCode(result) {
|
||||
if (!result || typeof result !== 'string') return { path: null, query: [], canNavigate: false }
|
||||
const idx = result.indexOf('?')
|
||||
let path = idx >= 0 ? result.slice(0, idx) : result
|
||||
const qs = idx >= 0 ? result.slice(idx + 1) : ''
|
||||
path = path.replace(/^\//, '').trim()
|
||||
const query = []
|
||||
if (qs) {
|
||||
qs.split('&').forEach(pair => {
|
||||
const eq = pair.indexOf('=')
|
||||
const k = eq >= 0 ? pair.slice(0, eq) : pair
|
||||
const v = eq >= 0 ? pair.slice(eq + 1) : ''
|
||||
try {
|
||||
if (k) query.push({ key: decodeURIComponent(k), value: decodeURIComponent(v) })
|
||||
} catch (_) {
|
||||
if (k) query.push({ key: k, value: v })
|
||||
}
|
||||
})
|
||||
}
|
||||
const isMiniProgramPath = /^pages\/[\w-]+\/[\w-]+$/.test(path)
|
||||
return { path: path || null, query, canNavigate: isMiniProgramPath }
|
||||
},
|
||||
|
||||
// 发起扫码(支持小程序码)
|
||||
doScan() {
|
||||
wx.scanCode({
|
||||
onlyFromCamera: false,
|
||||
scanType: ['qrCode', 'barCode'],
|
||||
success: (res) => {
|
||||
const { result, scanType, charSet } = res
|
||||
const parsed = this.parseMiniProgramCode(result)
|
||||
this.setData({
|
||||
lastResult: result,
|
||||
scanType: scanType || '未知',
|
||||
charSet: charSet || '',
|
||||
parsedPath: parsed.path,
|
||||
parsedQuery: parsed.query,
|
||||
canNavigate: parsed.canNavigate
|
||||
})
|
||||
this.saveToHistory(result, scanType, charSet)
|
||||
},
|
||||
fail: (err) => {
|
||||
if (err.errMsg && err.errMsg.includes('cancel')) {
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: err.errMsg || '扫码失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 复制内容
|
||||
copyResult() {
|
||||
const { lastResult } = this.data
|
||||
if (!lastResult) {
|
||||
wx.showToast({ title: '暂无解析内容', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.setClipboardData({
|
||||
data: lastResult,
|
||||
success: () => wx.showToast({ title: '已复制', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
// 清空当前结果
|
||||
clearResult() {
|
||||
this.setData({
|
||||
lastResult: null, scanType: '', charSet: '',
|
||||
parsedPath: null, parsedQuery: [], canNavigate: false
|
||||
})
|
||||
},
|
||||
|
||||
// 打开解析出的小程序页面
|
||||
openParsedPage() {
|
||||
const { parsedPath, parsedQuery } = this.data
|
||||
if (!parsedPath || !this.data.canNavigate) {
|
||||
wx.showToast({ title: '非本小程序页面', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const queryStr = parsedQuery.length
|
||||
? '?' + parsedQuery.map(q => `${encodeURIComponent(q.key)}=${encodeURIComponent(q.value)}`).join('&')
|
||||
: ''
|
||||
const url = `/${parsedPath}${queryStr}`
|
||||
const tabPages = ['pages/index/index', 'pages/chapters/chapters', 'pages/match/match', 'pages/my/my']
|
||||
if (tabPages.includes(parsedPath)) {
|
||||
wx.switchTab({ url: `/${parsedPath}` })
|
||||
} else {
|
||||
wx.navigateTo({ url })
|
||||
}
|
||||
},
|
||||
|
||||
// 清空历史
|
||||
clearHistory() {
|
||||
wx.setStorageSync('scanHistory', [])
|
||||
this.setData({ history: [], lastResult: null, scanType: '', charSet: '' })
|
||||
wx.showToast({ title: '已清空', icon: 'success' })
|
||||
},
|
||||
|
||||
// 点击历史项复制
|
||||
onHistoryItemTap(e) {
|
||||
const result = e.currentTarget.dataset.result
|
||||
if (!result) return
|
||||
wx.setClipboardData({
|
||||
data: result,
|
||||
success: () => wx.showToast({ title: '已复制', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
goBack() {
|
||||
wx.navigateBack()
|
||||
}
|
||||
})
|
||||
1
miniprogram/pages/scan/scan.json
Normal file
1
miniprogram/pages/scan/scan.json
Normal file
@@ -0,0 +1 @@
|
||||
{"usingComponents":{},"navigationStyle":"custom","navigationBarTitleText":"扫码解析"}
|
||||
81
miniprogram/pages/scan/scan.wxml
Normal file
81
miniprogram/pages/scan/scan.wxml
Normal file
@@ -0,0 +1,81 @@
|
||||
<!--pages/scan/scan.wxml-->
|
||||
<!--扫码解析页 - 扫描二维码/条形码展示解析内容-->
|
||||
<view class="page">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-content">
|
||||
<view class="back-btn" bindtap="goBack">
|
||||
<text class="back-icon">←</text>
|
||||
</view>
|
||||
<text class="nav-title">扫码解析</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<view class="main-content" style="padding-top: {{statusBarHeight + 56}}px;">
|
||||
<!-- 扫码按钮 -->
|
||||
<view class="scan-action">
|
||||
<view class="scan-btn" bindtap="doScan">
|
||||
<text class="scan-icon">📷</text>
|
||||
<text class="scan-text">扫描小程序码 / 二维码</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 解析结果 -->
|
||||
<view class="result-card" wx:if="{{lastResult}}">
|
||||
<view class="result-header">
|
||||
<text class="result-label">解析内容</text>
|
||||
<view class="result-actions">
|
||||
<view class="action-btn" bindtap="copyResult">复制</view>
|
||||
<view class="action-btn" wx:if="{{canNavigate}}" bindtap="openParsedPage">打开</view>
|
||||
<view class="action-btn secondary" bindtap="clearResult">清空</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 小程序码解析:路径 + 参数(仅当为 pages/ 路径时展示) -->
|
||||
<view class="parsed-section" wx:if="{{parsedPath && (parsedPath.indexOf('pages/') === 0 || parsedQuery.length > 0)}}">
|
||||
<view class="parsed-row">
|
||||
<text class="parsed-label">路径</text>
|
||||
<text class="parsed-value">{{parsedPath}}</text>
|
||||
</view>
|
||||
<view class="parsed-row" wx:for="{{parsedQuery}}" wx:key="key" wx:for-item="q">
|
||||
<text class="parsed-label">{{q.key}}</text>
|
||||
<text class="parsed-value">{{q.value}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="result-meta" wx:if="{{scanType}}">
|
||||
<text class="meta-item">类型: {{scanType}}</text>
|
||||
<text class="meta-item" wx:if="{{charSet}}">字符集: {{charSet}}</text>
|
||||
</view>
|
||||
<scroll-view class="result-content" scroll-y="{{true}}">
|
||||
<text class="result-text" selectable="{{true}}">{{lastResult}}</text>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 无结果提示 -->
|
||||
<view class="empty-tip" wx:else>
|
||||
<text class="empty-icon">📷</text>
|
||||
<text class="empty-text">点击上方按钮扫码</text>
|
||||
<text class="empty-desc">支持小程序码、二维码、条形码</text>
|
||||
</view>
|
||||
|
||||
<!-- 扫码历史 -->
|
||||
<view class="history-section" wx:if="{{history.length > 0}}">
|
||||
<view class="history-header">
|
||||
<text class="history-title">扫码历史</text>
|
||||
<view class="clear-history" bindtap="clearHistory">清空</view>
|
||||
</view>
|
||||
<view class="history-list">
|
||||
<view
|
||||
class="history-item"
|
||||
wx:for="{{history}}"
|
||||
wx:key="index"
|
||||
bindtap="onHistoryItemTap"
|
||||
data-result="{{item.result}}"
|
||||
>
|
||||
<text class="history-content">{{item.result}}</text>
|
||||
<text class="history-time">{{item.time}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
248
miniprogram/pages/scan/scan.wxss
Normal file
248
miniprogram/pages/scan/scan.wxss
Normal file
@@ -0,0 +1,248 @@
|
||||
/* 扫码解析页样式 */
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(180deg, #0a0a0a 0%, #111111 100%);
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
background: rgba(10, 10, 10, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8rpx 24rpx;
|
||||
height: 88rpx;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
font-size: 40rpx;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
margin-right: 60rpx;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
/* 扫码按钮 */
|
||||
.scan-action {
|
||||
padding: 60rpx 0;
|
||||
}
|
||||
|
||||
.scan-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, rgba(0, 206, 209, 0.2) 0%, rgba(32, 178, 170, 0.15) 100%);
|
||||
border: 2rpx solid rgba(0, 206, 209, 0.4);
|
||||
border-radius: 32rpx;
|
||||
padding: 80rpx 48rpx;
|
||||
}
|
||||
|
||||
.scan-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.scan-text {
|
||||
font-size: 32rpx;
|
||||
color: #00CED1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 解析结果卡片 */
|
||||
.result-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx;
|
||||
margin-top: 32rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.result-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-actions {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
font-size: 26rpx;
|
||||
color: #00CED1;
|
||||
padding: 8rpx 20rpx;
|
||||
}
|
||||
|
||||
.action-btn.secondary {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 小程序码解析:路径+参数 */
|
||||
.parsed-section {
|
||||
background: rgba(0, 206, 209, 0.08);
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: 1rpx solid rgba(0, 206, 209, 0.2);
|
||||
}
|
||||
|
||||
.parsed-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.parsed-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.parsed-label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
min-width: 120rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.parsed-value {
|
||||
font-size: 26rpx;
|
||||
color: #00CED1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.result-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.result-content {
|
||||
max-height: 400rpx;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.result-text {
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* 无结果提示 */
|
||||
.empty-tip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 60rpx 0;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 30rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.empty-desc {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
/* 扫码历史 */
|
||||
.history-section {
|
||||
margin-top: 48rpx;
|
||||
}
|
||||
|
||||
.history-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.history-title {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.clear-history {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.history-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.history-content {
|
||||
font-size: 26rpx;
|
||||
color: #fff;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.history-time {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-top: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
Reference in New Issue
Block a user