Add profile sharing pages and verified invitation contact flow
This commit is contained in:
parent
b6b1cc37ce
commit
190db7446d
17
src/app.wpy
17
src/app.wpy
@ -20,6 +20,7 @@ import promisify from '@wepy/use-promisify'
|
|||||||
import {wx_login} from './utils/util'
|
import {wx_login} from './utils/util'
|
||||||
import {IM} from './utils/im'
|
import {IM} from './utils/im'
|
||||||
import {initEid} from './mp_ecard_sdk/main'
|
import {initEid} from './mp_ecard_sdk/main'
|
||||||
|
import {invitationFromOptions} from './utils/invitation'
|
||||||
// import {service} from './config'
|
// import {service} from './config'
|
||||||
|
|
||||||
wepy.use(promisify)
|
wepy.use(promisify)
|
||||||
@ -50,10 +51,11 @@ wepy.app({
|
|||||||
|
|
||||||
onLaunch(e) {
|
onLaunch(e) {
|
||||||
let vm = this
|
let vm = this
|
||||||
|
const invitationID = invitationFromOptions(e)
|
||||||
|
if (invitationID) wx.setStorageSync('from_user_id', invitationID)
|
||||||
console.log(e, 'uuu=')
|
console.log(e, 'uuu=')
|
||||||
vm.appLogin()
|
vm.appLogin()
|
||||||
console.log(e, 'e=')
|
console.log(e, 'e=')
|
||||||
console.log(decodeURIComponent(e.query.scene), 'e=')
|
|
||||||
// if (e.path === 'pages/home/informationV2') {
|
// if (e.path === 'pages/home/informationV2') {
|
||||||
// wx.redirectTo({ url: `/pages/home/information?${decodeURIComponent(e.query.scene)}` })
|
// wx.redirectTo({ url: `/pages/home/information?${decodeURIComponent(e.query.scene)}` })
|
||||||
// }
|
// }
|
||||||
@ -95,15 +97,19 @@ wepy.app({
|
|||||||
if (options.path === 'pages/tabBar/home1') {
|
if (options.path === 'pages/tabBar/home1') {
|
||||||
wx.switchTab({url: `/pages/tabBar/home?${decodeURIComponent(options.query.scene)}`})
|
wx.switchTab({url: `/pages/tabBar/home?${decodeURIComponent(options.query.scene)}`})
|
||||||
}
|
}
|
||||||
if (options.query.scene) {
|
if (options.query && options.query.scene) {
|
||||||
let sceneList = decodeURIComponent(options.query.scene).split(/[= &]/)
|
let sceneList = []
|
||||||
|
try { sceneList = decodeURIComponent(options.query.scene).split(/[= &]/) } catch (_) {}
|
||||||
sceneList.forEach((item, index) => {
|
sceneList.forEach((item, index) => {
|
||||||
if (item == 'userId') {
|
if (item == 'userId') {
|
||||||
wx.setStorageSync('agent_user_id', sceneList[index + 1])
|
wx.setStorageSync('agent_user_id', sceneList[index + 1])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (options.query && options.query.from_user_id) {
|
const invitationScene = invitationFromOptions(options)
|
||||||
|
if (invitationScene) {
|
||||||
|
wx.setStorageSync('from_user_id', invitationScene)
|
||||||
|
} else if (options.query && options.query.from_user_id) {
|
||||||
wx.setStorageSync('from_user_id', options.query.from_user_id)
|
wx.setStorageSync('from_user_id', options.query.from_user_id)
|
||||||
} else {
|
} else {
|
||||||
if (options.path && options.path === 'pages/sub_mall/confirmOrder') {
|
if (options.path && options.path === 'pages/sub_mall/confirmOrder') {
|
||||||
@ -235,6 +241,9 @@ subPackages: [
|
|||||||
'orderDetails',
|
'orderDetails',
|
||||||
'exclusiveService',
|
'exclusiveService',
|
||||||
'myDynamic',
|
'myDynamic',
|
||||||
|
'more',
|
||||||
|
'myShare',
|
||||||
|
'shareCard',
|
||||||
'logoutDefault',
|
'logoutDefault',
|
||||||
'ImageCropper',
|
'ImageCropper',
|
||||||
'myDynamicDetail',
|
'myDynamicDetail',
|
||||||
|
|||||||
BIN
src/images/ambassador-contact.jpg
Normal file
BIN
src/images/ambassador-contact.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
BIN
src/images/fulian-logo.png
Normal file
BIN
src/images/fulian-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
@ -358,12 +358,6 @@ wepy.page({
|
|||||||
type: 'navigateTo',
|
type: 'navigateTo',
|
||||||
path: '/pages/users/upgradeVIP'
|
path: '/pages/users/upgradeVIP'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: 'https://image.fulllinkai.com/202305/18/986abe4366a59ebc8c5437a63d4f957f.png',
|
|
||||||
title: '专属客服',
|
|
||||||
type: 'navigateTo',
|
|
||||||
path: '/pages/users/exclusiveService'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: 'https://image.fulllinkai.com/202201/13/0c8d92e86946c9a4244a92cacd4bd8d0.png',
|
icon: 'https://image.fulllinkai.com/202201/13/0c8d92e86946c9a4244a92cacd4bd8d0.png',
|
||||||
title: '我的发布',
|
title: '我的发布',
|
||||||
@ -371,22 +365,22 @@ wepy.page({
|
|||||||
path: '/pages/users/myDynamic'
|
path: '/pages/users/myDynamic'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://image.fulllinkai.com/202202/17/0cb2fe566b98d607136bde08e7f27f4d.png',
|
icon: 'https://image.fulllinkai.com/202302/06/4092bc34b48ef2b8b95e9d3a5954f803.png',
|
||||||
title: '福恋指南',
|
title: '我的分享',
|
||||||
type: 'navigateTo',
|
type: 'navigateTo',
|
||||||
path: 'https://love.ufutx.com/h5/#/guide'
|
path: '/pages/users/myShare'
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'https://image.fulllinkai.com/202202/21/c982ff4f02b9f834e6f4cd6886547f71.png',
|
|
||||||
title: '意见反馈',
|
|
||||||
type: 'navigateTo',
|
|
||||||
path: '/pages/users/report?type=user'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://image.fulllinkai.com/202302/06/4092bc34b48ef2b8b95e9d3a5954f803.png',
|
icon: 'https://image.fulllinkai.com/202302/06/4092bc34b48ef2b8b95e9d3a5954f803.png',
|
||||||
title: '分享我的卡片',
|
title: '分享我的卡片',
|
||||||
type: 'share',
|
type: 'navigateTo',
|
||||||
path: ''
|
path: '/pages/users/shareCard'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'https://image.fulllinkai.com/202202/17/0cb2fe566b98d607136bde08e7f27f4d.png',
|
||||||
|
title: '更多',
|
||||||
|
type: 'navigateTo',
|
||||||
|
path: '/pages/users/more'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://image.fulllinkai.com/202201/13/0b3e132b03ee70e1325229ef8885ba29.png',
|
icon: 'https://image.fulllinkai.com/202201/13/0b3e132b03ee70e1325229ef8885ba29.png',
|
||||||
@ -776,7 +770,7 @@ wepy.page({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (text === '分享我的卡片') {
|
if (text === '分享我的卡片') {
|
||||||
vm.hide = false
|
wx.navigateTo({url: '/pages/users/shareCard'})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (url && url.includes('page')) {
|
if (url && url.includes('page')) {
|
||||||
|
|||||||
37
src/pages/users/more.wpy
Normal file
37
src/pages/users/more.wpy
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<view class="more-page">
|
||||||
|
<view class="more-heading">更多服务</view>
|
||||||
|
<view class="more-list">
|
||||||
|
<view class="more-row" @tap="openService"><text>专属客服</text><text>{{serviceLoading ? '加载中…' : '›'}}</text></view>
|
||||||
|
<view class="more-row" @tap="guide"><text>福恋指南</text><text>›</text></view>
|
||||||
|
<view class="more-row" @tap="open('/pages/users/report?type=user')"><text>意见反馈</text><text>›</text></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import wepy from '@wepy/core'
|
||||||
|
import https from '../../mixins/https'
|
||||||
|
import {service} from '../../config'
|
||||||
|
wepy.page({mixins:[https],data:{serviceLoading:false},methods: {
|
||||||
|
async openService() {
|
||||||
|
if (this.serviceLoading) return
|
||||||
|
this.serviceLoading=true
|
||||||
|
try {
|
||||||
|
const result=await this.$get({url:`${service.host}/crm/alone/cs/qrcode`})
|
||||||
|
if (result.data.qrcode) wx.previewImage({urls:[result.data.qrcode],current:result.data.qrcode})
|
||||||
|
else this.open('/pages/users/exclusiveService')
|
||||||
|
} catch (_) { wx.showToast({title:'客服信息加载失败,请重试',icon:'none'}) }
|
||||||
|
finally { this.serviceLoading=false }
|
||||||
|
},
|
||||||
|
open(url) { wx.navigateTo({url}) },
|
||||||
|
guide() { wx.navigateTo({url: '/pages/books/bookDetail?url=' + encodeURIComponent('https://love.ufutx.com/h5/#/guide')}) }
|
||||||
|
}})
|
||||||
|
</script>
|
||||||
|
<style lang="less">
|
||||||
|
.more-page { min-height:100vh; padding:32rpx; box-sizing:border-box; background:#FFF9F5; color:#4E4145; }
|
||||||
|
.more-heading { font-size:36rpx; font-weight:600; color:#A3294D; margin:16rpx 0 32rpx; }
|
||||||
|
.more-list { background:#FFF1F4; border-radius:24rpx; padding:0 28rpx; }
|
||||||
|
.more-row { display:flex; justify-content:space-between; padding:32rpx 0; font-size:30rpx; border-bottom:1rpx solid #EED3DB; }
|
||||||
|
.more-row:last-child { border-bottom:0; }
|
||||||
|
</style>
|
||||||
|
<config>{navigationBarTitleText:'更多',navigationBarBackgroundColor:'#FFF9F5'}</config>
|
||||||
139
src/pages/users/myShare.wpy
Normal file
139
src/pages/users/myShare.wpy
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<view class="sharing-page">
|
||||||
|
<view class="eyebrow">把美好的相遇分享出去</view><view class="sharing-title">我的分享</view>
|
||||||
|
<view v-if="loading" class="sharing-state">正在加载邀请数据…</view>
|
||||||
|
<view v-else-if="error" class="sharing-state"><view>{{error}}</view><button @tap="load">重试</button></view>
|
||||||
|
<block v-else>
|
||||||
|
<view class="sharing-stats"><view class="sharing-stat"><text class="sharing-number">{{total}}</text>邀请用户总数</view><view class="sharing-stat"><text class="sharing-number">{{verified}}</text>真人认证人数</view></view>
|
||||||
|
<view class="sharing-section">申请婚恋使者</view>
|
||||||
|
<view class="sharing-state">邀请的用户中有7位通过真人认证,即可联系荣耀老师申请婚恋使者。</view>
|
||||||
|
<view class="sharing-subtitle">已完成 {{verified}} 位<text v-if="remaining > 0">,还差 {{remaining}} 位</text></view>
|
||||||
|
<button :disabled="!canApply || checkingEligibility" @tap="openApplication">{{checkingEligibility ? '正在确认资格…' : '申请婚恋使者'}}</button>
|
||||||
|
<view v-if="eligibilityError" class="sharing-state">申请资格查询失败,请稍后重试<button @tap="refreshEligibility">重新查询</button></view>
|
||||||
|
<view class="sharing-section">邀请用户</view>
|
||||||
|
<view v-if="!invitees.length && !listError" class="sharing-state">还没有邀请用户,分享福恋给身边的朋友吧。</view>
|
||||||
|
<view class="sharing-row" v-for="item in invitees" :key="item.id"><text>{{item.nickname || '福恋用户'}}</text><text class="sharing-status">{{item.verified ? '真人认证已通过' : '未完成真人认证'}}</text></view>
|
||||||
|
<view v-if="listError" class="sharing-state">列表加载失败,请重试</view>
|
||||||
|
<button v-if="hasMore || listError" :disabled="listLoading" @tap="loadMore">{{listLoading ? '正在加载…' : listError ? '重试加载' : '加载更多'}}</button>
|
||||||
|
<view class="sharing-section">邀请订单</view><view class="sharing-state">仅婚恋使者可查看</view>
|
||||||
|
<view class="sharing-section">邀请朋友加入福恋</view>
|
||||||
|
<view class="sharing-subtitle">把福恋分享给认真寻找爱情的人。</view>
|
||||||
|
<image v-if="poster" class="sharing-poster" src="{{poster}}" mode="widthFix" @tap="preview"></image>
|
||||||
|
<view v-if="posterError" class="sharing-state">{{posterError}}</view>
|
||||||
|
<view class="sharing-actions"><button :disabled="generating || saving" @tap="posterAction">{{generating ? '正在生成…' : saving ? '正在保存…' : poster ? '保存邀请海报' : '生成邀请海报'}}</button><button open-type="share" :disabled="!profile.id">分享小程序卡片</button></view>
|
||||||
|
</block>
|
||||||
|
<view v-if="showApplication" class="application-mask" @tap="closeApplication">
|
||||||
|
<view class="application-dialog" @tap.stop="keepApplicationOpen">
|
||||||
|
<view class="application-title">联系荣耀老师</view>
|
||||||
|
<view class="application-note">添加微信时请备注“申请婚恋使者”,与老师沟通申请事宜。</view>
|
||||||
|
<image class="application-code" src="{{contactImage}}" mode="widthFix" show-menu-by-longpress="true" @tap="previewContact"></image>
|
||||||
|
<view class="application-hint">点击放大二维码,或保存后在微信扫一扫中选择相册识别。</view>
|
||||||
|
<button :disabled="savingContact" @tap="saveContact">{{savingContact ? '正在保存…' : '保存二维码'}}</button>
|
||||||
|
<button class="application-close" @tap="closeApplication">关闭</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<canvas canvas-id="fulianPoster" style="position:fixed;left:-2000px;top:0;width:750px;height:1120px;"></canvas>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import wepy from '@wepy/core'
|
||||||
|
import https from '../../mixins/https'
|
||||||
|
import {service} from '../../config'
|
||||||
|
import {sharingPath, renderSharingPoster, renderSharingCover, saveSharingPoster, storeSharingCode} from '../../utils/sharing'
|
||||||
|
wepy.page({
|
||||||
|
mixins:[https],
|
||||||
|
data:{loading:true,error:'',total:0,verified:0,remaining:7,invitees:[],page:0,hasMore:false,listLoading:false,listError:false,profile:{id:0,nickname:'',qrcode:''},poster:'',cover:'',posterError:'',generating:false,saving:false,canApply:false,checkingEligibility:false,eligibilityError:false,showApplication:false,savingContact:false,contactImage:'/images/ambassador-contact.jpg'},
|
||||||
|
onLoad() { this.load() },
|
||||||
|
onShow() { if (!this.loading && !this.error) this.refreshEligibility() },
|
||||||
|
onShareAppMessage() {
|
||||||
|
return {title:'邀请你加入福恋,上福恋认真找对象',path:this.profile.id ? sharingPath(this.profile.id,false) : '/pages/tabBar/welcome',imageUrl:this.cover || '/images/fulian-logo.png'}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
setOverview(data) {
|
||||||
|
this.total=Number(data.total) || 0
|
||||||
|
this.verified=Number(data.verified) || 0
|
||||||
|
this.remaining=Math.max(0,7-this.verified)
|
||||||
|
this.canApply=data.can_apply === true && this.verified >= 7
|
||||||
|
},
|
||||||
|
async refreshEligibility() {
|
||||||
|
if (this.checkingEligibility) return false
|
||||||
|
this.checkingEligibility=true; this.eligibilityError=false
|
||||||
|
try {
|
||||||
|
const result=await this.$get({url:`${service.user}/sharing/overview`})
|
||||||
|
this.setOverview(result.data)
|
||||||
|
return this.canApply
|
||||||
|
} catch (_) {
|
||||||
|
this.canApply=false; this.showApplication=false; this.eligibilityError=true
|
||||||
|
return false
|
||||||
|
} finally { this.checkingEligibility=false }
|
||||||
|
},
|
||||||
|
async openApplication() {
|
||||||
|
if (!this.canApply || this.checkingEligibility) return
|
||||||
|
if (await this.refreshEligibility()) this.showApplication=true
|
||||||
|
},
|
||||||
|
closeApplication() { this.showApplication=false },
|
||||||
|
keepApplicationOpen() {},
|
||||||
|
previewContact() { wx.previewImage({urls:[this.contactImage],current:this.contactImage}) },
|
||||||
|
async saveContact() {
|
||||||
|
if (this.savingContact) return
|
||||||
|
this.savingContact=true
|
||||||
|
try {
|
||||||
|
const image=await new Promise((resolve,reject)=>wx.getImageInfo({src:this.contactImage,success:resolve,fail:reject}))
|
||||||
|
await saveSharingPoster(image.path)
|
||||||
|
wx.showToast({title:'二维码已保存',icon:'success'})
|
||||||
|
} catch (_) {
|
||||||
|
wx.showModal({title:'未能保存',content:'请检查相册权限后重试,也可以点击二维码放大查看。',showCancel:false})
|
||||||
|
} finally { this.savingContact=false }
|
||||||
|
},
|
||||||
|
async load() {
|
||||||
|
this.loading=true; this.error=''; this.invitees=[]; this.page=0; this.canApply=false; this.showApplication=false; this.eligibilityError=false
|
||||||
|
try {
|
||||||
|
const results=await Promise.all([this.$get({url:`${service.user}/sharing/overview`}),this.$get({url:`${service.user}/sharing/profile`})])
|
||||||
|
this.setOverview(results[0].data)
|
||||||
|
this.profile={id:results[1].data.id,nickname:results[1].data.nickname || '一位朋友',qrcode:''}
|
||||||
|
this.hasMore=true
|
||||||
|
await this.loadMore()
|
||||||
|
} catch (_) { this.error='邀请信息加载失败,请重试' }
|
||||||
|
finally {
|
||||||
|
this.loading=false
|
||||||
|
if (this.profile.id) this.$nextTick(async()=>{
|
||||||
|
this.generating=true
|
||||||
|
try { this.cover=await renderSharingCover(this,this.profile,false) } catch (_) {}
|
||||||
|
finally { this.generating=false }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadMore() {
|
||||||
|
if (this.listLoading) return
|
||||||
|
this.listLoading=true; this.listError=false
|
||||||
|
try {
|
||||||
|
const result=await this.$get({url:`${service.user}/sharing/invitees`,data:{page:this.page+1}})
|
||||||
|
const known=new Set(this.invitees.map(item=>item.id))
|
||||||
|
this.invitees=this.invitees.concat(result.data.data.filter(item=>!known.has(item.id)))
|
||||||
|
this.page=result.data.page; this.hasMore=result.data.has_more
|
||||||
|
} catch (_) { this.listError=true }
|
||||||
|
finally { this.listLoading=false }
|
||||||
|
},
|
||||||
|
async posterAction() {
|
||||||
|
if (this.generating || this.saving) return
|
||||||
|
if (this.poster) {
|
||||||
|
this.saving=true
|
||||||
|
try { await saveSharingPoster(this.poster); wx.showToast({title:'已保存到相册'}) }
|
||||||
|
catch (_) { wx.showModal({title:'未能保存',content:'请在微信设置中允许保存到相册后重试。',showCancel:false}) }
|
||||||
|
finally { this.saving=false }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.generating=true; this.posterError=''
|
||||||
|
try {
|
||||||
|
const result=await this.$post({url:`${service.user}/sharing/code`,data:{kind:'invite'}})
|
||||||
|
this.profile.qrcode=await storeSharingCode(result.data,'invite')
|
||||||
|
this.poster=await renderSharingPoster(this,this.profile,false)
|
||||||
|
} catch (_) { this.posterError='邀请海报生成失败,请稍后重试' }
|
||||||
|
finally { this.generating=false }
|
||||||
|
},
|
||||||
|
preview() { wx.previewImage({urls:[this.poster],current:this.poster}) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="less" src="../../styles/sharing.less"></style>
|
||||||
|
<config>{navigationBarTitleText:'我的分享',navigationBarBackgroundColor:'#FFF9F5'}</config>
|
||||||
74
src/pages/users/shareCard.wpy
Normal file
74
src/pages/users/shareCard.wpy
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<view class="sharing-page">
|
||||||
|
<view class="eyebrow">我的个人名片</view>
|
||||||
|
<view class="sharing-title">让合适的人,认识你</view>
|
||||||
|
<view class="sharing-subtitle">分享你的照片与介绍,开启一次认真相识。</view>
|
||||||
|
<view v-if="loading" class="sharing-state">正在准备你的卡片…</view>
|
||||||
|
<view v-else-if="error" class="sharing-state"><view>{{error}}</view><button @tap="load">重试</button></view>
|
||||||
|
<block v-else>
|
||||||
|
<image v-if="poster" class="sharing-poster" src="{{poster}}" mode="widthFix" @tap="preview"></image>
|
||||||
|
<view v-else class="sharing-preview">
|
||||||
|
<image class="sharing-logo" src="/images/fulian-logo.png" mode="aspectFit"></image>
|
||||||
|
<image v-if="profile.photo" class="sharing-photo" src="{{profile.photo}}" mode="aspectFill"></image>
|
||||||
|
<view class="sharing-title">{{profile.nickname}}</view><view>{{profile.details}}</view>
|
||||||
|
<view class="sharing-intro">{{profile.introduction}}</view>
|
||||||
|
<view class="sharing-state">{{posterError || '正在生成海报…'}}</view>
|
||||||
|
<button v-if="posterError" @tap="generate">重新生成</button>
|
||||||
|
</view>
|
||||||
|
<view class="sharing-actions"><button :disabled="!poster || saving" @tap="save">{{saving ? '正在保存…' : '保存个人海报'}}</button><button open-type="share">分享我的卡片</button></view>
|
||||||
|
</block>
|
||||||
|
<canvas canvas-id="fulianPoster" style="position:fixed;left:-2000px;top:0;width:750px;height:1120px;"></canvas>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import wepy from '@wepy/core'
|
||||||
|
import https from '../../mixins/https'
|
||||||
|
import {service} from '../../config'
|
||||||
|
import {sharingPath, renderSharingPoster, renderSharingCover, saveSharingPoster, storeSharingCode} from '../../utils/sharing'
|
||||||
|
wepy.page({
|
||||||
|
mixins:[https],
|
||||||
|
data:{loading:true,error:'',poster:'',cover:'',posterError:'',saving:false,generating:false,profile:{id:0,nickname:'',photo:'',details:'',introduction:'',qrcode:''}},
|
||||||
|
onLoad() { this.load() },
|
||||||
|
onShareAppMessage() {
|
||||||
|
if (!this.profile.id) return {title:'上福恋认真找对象',path:'/pages/tabBar/welcome'}
|
||||||
|
return {title:`我是${this.profile.nickname},期待与你相识`,path:sharingPath(this.profile.id,true),imageUrl:this.cover || this.profile.photo || '/images/fulian-logo.png'}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
async load() {
|
||||||
|
this.loading=true; this.error=''; this.poster=''
|
||||||
|
try {
|
||||||
|
const result=await this.$get({url:`${service.user}/sharing/profile`})
|
||||||
|
const data=result.data
|
||||||
|
this.profile={id:data.id,nickname:data.nickname || '福恋用户',photo:data.photo || '',details:[data.city,data.degree,data.industry].filter(Boolean).join(' · '),introduction:data.introduction || '',idealMate:data.ideal_mate || '',qrcode:''}
|
||||||
|
this.loading=false
|
||||||
|
this.$nextTick(() => this.generate())
|
||||||
|
} catch (_) { this.error='卡片加载失败,请重试'; this.loading=false }
|
||||||
|
},
|
||||||
|
async generate() {
|
||||||
|
if (this.generating) return
|
||||||
|
this.generating=true
|
||||||
|
this.posterError=''
|
||||||
|
try {
|
||||||
|
this.cover=await renderSharingCover(this,this.profile,true)
|
||||||
|
if (!this.profile.qrcode) {
|
||||||
|
const result=await this.$post({url:`${service.user}/sharing/code`,data:{kind:'personal'}})
|
||||||
|
this.profile.qrcode=await storeSharingCode(result.data,'personal')
|
||||||
|
}
|
||||||
|
this.poster=await renderSharingPoster(this,this.profile,true)
|
||||||
|
}
|
||||||
|
catch (_) { this.posterError='海报暂未生成,请检查分享码及图片后重试' }
|
||||||
|
finally { this.generating=false }
|
||||||
|
},
|
||||||
|
preview() { wx.previewImage({urls:[this.poster],current:this.poster}) },
|
||||||
|
async save() {
|
||||||
|
if (!this.poster || this.saving) return
|
||||||
|
this.saving=true
|
||||||
|
try { await saveSharingPoster(this.poster); wx.showToast({title:'已保存到相册'}) }
|
||||||
|
catch (_) { wx.showModal({title:'未能保存',content:'请在微信设置中允许保存到相册后重试。',showCancel:false}) }
|
||||||
|
finally { this.saving=false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="less" src="../../styles/sharing.less"></style>
|
||||||
|
<config>{navigationBarTitleText:'分享我的卡片',navigationBarBackgroundColor:'#FFF9F5'}</config>
|
||||||
29
src/styles/sharing.less
Normal file
29
src/styles/sharing.less
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
.sharing-page { min-height:100vh; background:#FFF9F5; color:#4E4145; padding:36rpx 32rpx 64rpx; box-sizing:border-box; }
|
||||||
|
.eyebrow { color:#D92554; font-size:24rpx; margin-bottom:16rpx; }
|
||||||
|
.sharing-title { color:#A3294D; font-size:40rpx; font-weight:600; margin-bottom:16rpx; }
|
||||||
|
.sharing-subtitle { font-size:26rpx; color:#97717D; line-height:1.7; margin-bottom:32rpx; }
|
||||||
|
.sharing-poster { display:block; width:100%; border-radius:20rpx; }
|
||||||
|
.sharing-preview { border-radius:24rpx; background:#FFF1F4; padding:28rpx; }
|
||||||
|
.sharing-photo { width:100%; height:400rpx; border-radius:16rpx; margin:24rpx 0; }
|
||||||
|
.sharing-logo { width:64rpx; height:64rpx; }
|
||||||
|
.sharing-intro { margin:28rpx 0; font-size:28rpx; line-height:1.8; }
|
||||||
|
.sharing-actions { display:flex; flex-wrap:wrap; gap:16rpx; margin-top:28rpx; }
|
||||||
|
.sharing-page button { background:#D92554; color:#FFF9F5; border-radius:16rpx; font-size:28rpx; margin:0; }
|
||||||
|
.sharing-page button[disabled] { background:#EED3DB; color:#4E4145; }
|
||||||
|
.sharing-actions button { flex:1; min-width:240rpx; }
|
||||||
|
.sharing-state { font-size:26rpx; color:#97717D; padding:32rpx 0; line-height:1.8; }
|
||||||
|
.sharing-state button { margin-top:20rpx; }
|
||||||
|
.sharing-section { margin-top:36rpx; font-size:32rpx; color:#A3294D; font-weight:600; }
|
||||||
|
.sharing-stats { display:flex; gap:20rpx; padding:30rpx; background:#FFF1F4; border-radius:24rpx; }
|
||||||
|
.sharing-stat { flex:1; font-size:26rpx; }
|
||||||
|
.sharing-number { display:block; font-size:48rpx; color:#A3294D; margin-bottom:12rpx; }
|
||||||
|
.sharing-row { display:flex; justify-content:space-between; gap:20rpx; padding:28rpx 0; border-bottom:1rpx solid #EED3DB; font-size:28rpx; }
|
||||||
|
.sharing-row text:first-child { overflow-wrap:anywhere; }
|
||||||
|
.sharing-status { color:#97717D; flex-shrink:0; }
|
||||||
|
.application-mask { position:fixed; inset:0; z-index:1000; background:rgba(78,65,69,.6); display:flex; align-items:center; justify-content:center; padding:24rpx; box-sizing:border-box; }
|
||||||
|
.application-dialog { width:100%; max-width:640rpx; max-height:90vh; overflow-y:auto; background:#FFF9F5; border-radius:28rpx; padding:28rpx; box-sizing:border-box; }
|
||||||
|
.application-title { color:#A3294D; font-size:34rpx; font-weight:600; text-align:center; }
|
||||||
|
.application-note { color:#4E4145; font-size:28rpx; line-height:1.7; margin:18rpx 0; }
|
||||||
|
.application-code { display:block; width:100%; }
|
||||||
|
.application-hint { font-size:24rpx; color:#97717D; line-height:1.6; margin:20rpx 0; }
|
||||||
|
.sharing-page .application-close { margin-top:16rpx; color:#A3294D; background:#FFF1F4; }
|
||||||
10
src/utils/invitation.js
Normal file
10
src/utils/invitation.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export function invitationFromOptions(options) {
|
||||||
|
const query = (options && options.query) || {}
|
||||||
|
let sceneID = ''
|
||||||
|
try {
|
||||||
|
const match = decodeURIComponent(query.scene || '').match(/(?:^|&)from_user_id=([1-9][0-9]*)(?:&|$)/)
|
||||||
|
if (match) sceneID = match[1]
|
||||||
|
} catch (_) {}
|
||||||
|
const value = String(sceneID || query.from_user_id || '')
|
||||||
|
return /^[1-9][0-9]*$/.test(value) && Number.isSafeInteger(Number(value)) ? value : ''
|
||||||
|
}
|
||||||
116
src/utils/sharing.js
Normal file
116
src/utils/sharing.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Sharing destinations stay separate: inviting someone never advertises the
|
||||||
|
// inviter as a person seeking a relationship.
|
||||||
|
export function sharingPath(id, personal) {
|
||||||
|
const userID = Number(id)
|
||||||
|
if (!Number.isSafeInteger(userID) || userID <= 0) throw new Error('请先登录后分享')
|
||||||
|
return personal
|
||||||
|
? `/pages/home/information?id=${userID}`
|
||||||
|
: `/pages/tabBar/welcome?from_user_id=${userID}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function storeSharingCode(data, kind) {
|
||||||
|
const extension = data.mime === 'image/png' ? 'png' : data.mime === 'image/jpeg' ? 'jpg' : ''
|
||||||
|
if (!extension || !data.image) return Promise.reject(new Error('分享码格式无效'))
|
||||||
|
const filePath = `${wx.env.USER_DATA_PATH}/fulian-${kind}.${extension}`
|
||||||
|
return new Promise((resolve,reject) => wx.getFileSystemManager().writeFile({filePath,data:data.image,encoding:'base64',success:()=>resolve(filePath),fail:reject}))
|
||||||
|
}
|
||||||
|
|
||||||
|
function imageInfo(src) {
|
||||||
|
return new Promise((resolve, reject) => wx.getImageInfo({src, success: resolve, fail: reject}))
|
||||||
|
}
|
||||||
|
|
||||||
|
function textLines(ctx, text, x, y, width, lineHeight, maxLines) {
|
||||||
|
let line = '', row = 0
|
||||||
|
const chars = Array.from(String(text || '').replace(/\s+/g, ' ').trim())
|
||||||
|
for (let i = 0; i < chars.length; i++) {
|
||||||
|
if (ctx.measureText(line + chars[i]).width > width) {
|
||||||
|
if (row === maxLines - 1) {
|
||||||
|
while (line && ctx.measureText(line + '…').width > width) line = line.slice(0, -1)
|
||||||
|
ctx.fillText(line + '…', x, y + row * lineHeight)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Keep closing punctuation with the preceding character on the next line.
|
||||||
|
const carry = /[,。!?;:、)】》」』]/.test(chars[i]) ? line.slice(-1) : ''
|
||||||
|
if (carry) line = line.slice(0, -1)
|
||||||
|
ctx.fillText(line, x, y + row * lineHeight)
|
||||||
|
row++
|
||||||
|
line = carry
|
||||||
|
}
|
||||||
|
line += chars[i]
|
||||||
|
}
|
||||||
|
ctx.fillText(line, x, y + row * lineHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function renderSharingPoster(page, profile, personal) {
|
||||||
|
if (!profile.qrcode) throw new Error('分享码暂未准备好,请稍后重试')
|
||||||
|
const sources = ['/images/fulian-logo.png', profile.qrcode]
|
||||||
|
if (personal && profile.photo) sources.push(profile.photo)
|
||||||
|
const images = await Promise.all(sources.map(imageInfo))
|
||||||
|
const ctx = wx.createCanvasContext('fulianPoster', page.$wx)
|
||||||
|
ctx.setFillStyle('#FFF9F5'); ctx.fillRect(0, 0, 750, 1120)
|
||||||
|
ctx.drawImage(images[0].path, 48, 42, 64, 64)
|
||||||
|
ctx.setFillStyle('#A3294D'); ctx.setFontSize(30); ctx.fillText('福恋', 126, 84)
|
||||||
|
ctx.setFontSize(22); ctx.fillText('上福恋认真找对象', 440, 82)
|
||||||
|
if (personal) {
|
||||||
|
ctx.setFillStyle('#FFF1F4'); ctx.fillRect(48, 138, 654, 430)
|
||||||
|
if (images[2]) {
|
||||||
|
const im = images[2], ratio = Math.max(654 / im.width, 430 / im.height)
|
||||||
|
const sw = 654 / ratio, sh = 430 / ratio
|
||||||
|
ctx.drawImage(im.path, (im.width - sw) / 2, (im.height - sh) / 2, sw, sh, 48, 138, 654, 430)
|
||||||
|
}
|
||||||
|
ctx.setFillStyle('#A3294D'); ctx.setFontSize(40)
|
||||||
|
textLines(ctx, profile.nickname || '我的个人卡片', 48, 628, 654, 48, 1)
|
||||||
|
ctx.setFillStyle('#97717D'); ctx.setFontSize(24)
|
||||||
|
textLines(ctx, profile.details, 48, 674, 654, 32, 1)
|
||||||
|
ctx.setFillStyle('#4E4145'); ctx.setFontSize(28)
|
||||||
|
textLines(ctx, profile.introduction || '很高兴在福恋与你相遇。', 48, 730, 654, 38, 2)
|
||||||
|
if (profile.idealMate) {
|
||||||
|
ctx.setFontSize(24)
|
||||||
|
textLines(ctx, '期待的你:' + profile.idealMate, 48, 824, 654, 32, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.setFillStyle('#FFF1F4'); ctx.fillRect(48, 160, 654, 640)
|
||||||
|
ctx.setFillStyle('#A3294D'); ctx.setFontSize(52)
|
||||||
|
ctx.fillText('把福恋分享给', 88, 300); ctx.fillText('认真寻找爱情的人', 88, 380)
|
||||||
|
ctx.setFillStyle('#4E4145'); ctx.setFontSize(28)
|
||||||
|
textLines(ctx, '认识新朋友,开启认真交往的第一步。', 88, 470, 560, 46, 2)
|
||||||
|
ctx.setFontSize(25)
|
||||||
|
textLines(ctx, `${profile.nickname || '一位朋友'} 邀请你加入福恋`, 88, 690, 560, 38, 2)
|
||||||
|
}
|
||||||
|
ctx.setFillStyle('#EED3DB'); ctx.fillRect(48, 860, 654, 1)
|
||||||
|
ctx.drawImage(images[1].path, 48, 906, 164, 164)
|
||||||
|
ctx.setFillStyle('#A3294D'); ctx.setFontSize(28)
|
||||||
|
ctx.fillText(personal ? '扫码认识我' : '扫码加入福恋', 244, 965)
|
||||||
|
ctx.setFillStyle('#97717D'); ctx.setFontSize(23)
|
||||||
|
ctx.fillText(personal ? '查看我的完整个人资料' : '上福恋认真找对象', 244, 1010)
|
||||||
|
await new Promise(resolve => ctx.draw(false, resolve))
|
||||||
|
return new Promise((resolve, reject) => wx.canvasToTempFilePath({
|
||||||
|
canvasId: 'fulianPoster', width:750, height:1120, destWidth:750, destHeight:1120,
|
||||||
|
success: result => resolve(result.tempFilePath), fail: reject
|
||||||
|
}, page.$wx))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveSharingPoster(filePath) {
|
||||||
|
return new Promise((resolve, reject) => wx.saveImageToPhotosAlbum({filePath, success:resolve, fail:reject}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function renderSharingCover(page, profile, personal) {
|
||||||
|
const logo=await imageInfo('/images/fulian-logo.png')
|
||||||
|
const photo=personal && profile.photo ? await imageInfo(profile.photo) : null
|
||||||
|
const ctx=wx.createCanvasContext('fulianPoster',page.$wx)
|
||||||
|
ctx.setFillStyle('#FFF9F5'); ctx.fillRect(0,0,750,600)
|
||||||
|
ctx.drawImage(logo.path,40,32,64,64)
|
||||||
|
ctx.setFillStyle('#A3294D'); ctx.setFontSize(28); ctx.fillText('上福恋认真找对象',124,74)
|
||||||
|
if (photo) {
|
||||||
|
const ratio=Math.max(290/photo.width,360/photo.height),sw=290/ratio,sh=360/ratio
|
||||||
|
ctx.drawImage(photo.path,(photo.width-sw)/2,(photo.height-sh)/2,sw,sh,420,150,290,360)
|
||||||
|
}
|
||||||
|
ctx.setFillStyle('#A3294D');ctx.setFontSize(42)
|
||||||
|
textLines(ctx,personal ? profile.nickname || '我的个人卡片' : '邀请你加入福恋',40,210,personal ? 350 : 670,56,2)
|
||||||
|
ctx.setFillStyle('#4E4145');ctx.setFontSize(28)
|
||||||
|
textLines(ctx,personal ? profile.introduction || '期待与你认真相识' : '把福恋分享给认真寻找爱情的人',40,350,personal ? 350 : 670,44,3)
|
||||||
|
ctx.setFillStyle('#97717D');ctx.setFontSize(25)
|
||||||
|
ctx.fillText(personal ? '点击认识我' : '点击开启认真相识',40,550)
|
||||||
|
await new Promise(resolve=>ctx.draw(false,resolve))
|
||||||
|
return new Promise((resolve,reject)=>wx.canvasToTempFilePath({canvasId:'fulianPoster',width:750,height:600,destWidth:750,destHeight:600,success:res=>resolve(res.tempFilePath),fail:reject},page.$wx))
|
||||||
|
}
|
||||||
27
tools/sharing/check-contact.cjs
Normal file
27
tools/sharing/check-contact.cjs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const fs=require('fs'),path=require('path'),vm=require('vm'),assert=require('assert')
|
||||||
|
const source=fs.readFileSync(path.join(__dirname,'../../src/pages/users/myShare.wpy'),'utf8').match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^import .*$/gm,'')
|
||||||
|
let definition,failed=false,saves=0,overview={total:12,verified:7,can_apply:true},requestFailed=false
|
||||||
|
const notices=[]
|
||||||
|
const sandbox={wepy:{page(value){definition=value}},https:{},service:{user:'synthetic-api'},wx:{getImageInfo({success}){success({path:'synthetic-contact.jpg'})},showToast(value){notices.push(value)},showModal(value){notices.push(value)},previewImage(value){notices.push(value)}},saveSharingPoster:async()=>{saves++;if(failed)throw Error('synthetic denial')}}
|
||||||
|
vm.createContext(sandbox);vm.runInContext(source,sandbox)
|
||||||
|
const page={...definition.data,...definition.methods,$get:async()=>{if(requestFailed)throw Error('synthetic');return {data:overview}}}
|
||||||
|
;(async()=>{
|
||||||
|
page.setOverview({total:100,verified:6,can_apply:false})
|
||||||
|
await page.openApplication();assert.equal(page.showApplication,false);assert.equal(page.remaining,1)
|
||||||
|
page.setOverview({total:12,verified:7,can_apply:true})
|
||||||
|
await page.openApplication();assert.equal(page.showApplication,true);assert.equal(page.remaining,0)
|
||||||
|
page.keepApplicationOpen();assert.equal(page.showApplication,true)
|
||||||
|
page.closeApplication();assert.equal(page.showApplication,false)
|
||||||
|
overview={total:12,verified:6,can_apply:false}
|
||||||
|
await page.openApplication();assert.equal(page.showApplication,false);assert.equal(page.canApply,false)
|
||||||
|
overview={total:12,verified:8,can_apply:true};await page.refreshEligibility();assert.equal(page.canApply,true)
|
||||||
|
requestFailed=true;await page.openApplication();assert.equal(page.showApplication,false);assert.equal(page.canApply,false);assert.equal(page.eligibilityError,true);assert.equal(page.checkingEligibility,false)
|
||||||
|
requestFailed=false;await page.refreshEligibility();assert.equal(page.canApply,true)
|
||||||
|
page.setOverview({total:100,verified:6,can_apply:true});assert.equal(page.canApply,false)
|
||||||
|
await page.saveContact();assert.equal(saves,1);assert.equal(page.savingContact,false)
|
||||||
|
assert.equal(notices.pop().title,'二维码已保存')
|
||||||
|
failed=true;await page.saveContact();assert.equal(page.savingContact,false);assert.equal(notices.pop().title,'未能保存')
|
||||||
|
page.savingContact=true;await page.saveContact();assert.equal(saves,2)
|
||||||
|
assert(!notices.some(x=>/申请成功|审核通过/.test(x.title||'')))
|
||||||
|
console.log('PASS: 6/7/8 verified eligibility, total not used, stale eligibility, request failure/retry, modal, image save failure/success and duplicate-save guard; no application submission.')
|
||||||
|
})().catch(e=>{console.error(e.message);process.exitCode=1})
|
||||||
22
tools/sharing/check.cjs
Normal file
22
tools/sharing/check.cjs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
const fs=require('fs'),vm=require('vm'),assert=require('assert'),path=require('path')
|
||||||
|
const source=fs.readFileSync(path.join(__dirname,'../../src/utils/sharing.js'),'utf8').replace(/export /g,'')
|
||||||
|
const calls=[]
|
||||||
|
const context={fillRect(){},drawImage(...a){calls.push(['image',...a])},setFillStyle(){},setFontSize(){},fillText(t){calls.push(['text',t])},measureText(t){return {width:t.length*28}},draw(_,cb){cb()}}
|
||||||
|
const sandbox={wx:{getImageInfo({src,success}){success({path:src,width:500,height:500})},createCanvasContext(){return context},canvasToTempFilePath({success}){success({tempFilePath:'synthetic.png'})}}}
|
||||||
|
vm.createContext(sandbox);vm.runInContext(source,sandbox)
|
||||||
|
assert.equal(sandbox.sharingPath(42,false),'/pages/tabBar/welcome?from_user_id=42')
|
||||||
|
assert.equal(sandbox.sharingPath(42,true),'/pages/home/information?id=42')
|
||||||
|
for(const id of [0,-1,'bad',1.5]) assert.throws(()=>sandbox.sharingPath(id,true))
|
||||||
|
;(async()=>{
|
||||||
|
await assert.rejects(sandbox.renderSharingPoster({$wx:{}},{},false))
|
||||||
|
const profile={nickname:'合成用户',photo:'synthetic-photo.png',qrcode:'synthetic-code.png',introduction:'这是用于离线验证的合成介绍。'.repeat(30),details:'合成城市 · 合成职业'}
|
||||||
|
await sandbox.renderSharingPoster({$wx:{}},profile,true)
|
||||||
|
assert(calls.some(c=>c[1]==='扫码认识我'))
|
||||||
|
assert(calls.some(c=>c[0]==='image'&&c[1]==='synthetic-photo.png'))
|
||||||
|
assert(calls.some(c=>c[0]==='text'&&c[1].endsWith('…')))
|
||||||
|
calls.length=0
|
||||||
|
await sandbox.renderSharingPoster({$wx:{}},profile,false)
|
||||||
|
assert(calls.some(c=>c[1]==='扫码加入福恋'))
|
||||||
|
assert(!calls.some(c=>c[0]==='image'&&c[1]==='synthetic-photo.png'))
|
||||||
|
console.log('PASS: separate destinations, invalid IDs, missing QR, personal/invite content and long-text truncation (offline mocks).')
|
||||||
|
})().catch(e=>{console.error(e.message);process.exitCode=1})
|
||||||
36
tools/sharing/regression.cjs
Normal file
36
tools/sharing/regression.cjs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
const fs=require('fs'),path=require('path'),vm=require('vm'),assert=require('assert')
|
||||||
|
const root=path.resolve(__dirname,'../..')
|
||||||
|
function script(name){return fs.readFileSync(path.join(root,'src',name),'utf8').match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^import .*$/gm,'')}
|
||||||
|
const invitation=fs.readFileSync(path.join(root,'src/utils/invitation.js'),'utf8').replace(/export /g,'')
|
||||||
|
const s={};vm.createContext(s);vm.runInContext(invitation,s)
|
||||||
|
assert.equal(s.invitationFromOptions({query:{scene:'from_user_id%3D42'}}),'42')
|
||||||
|
assert.equal(s.invitationFromOptions({query:{from_user_id:43}}),'43')
|
||||||
|
for(const query of [{scene:'%'},{scene:'id=42'},{scene:'from_user_id=-1'},{from_user_id:'invalid'},{}])assert.equal(s.invitationFromOptions({query}),'')
|
||||||
|
const storage=new Map(),nav=[],previews=[]
|
||||||
|
let appDef,pageDef
|
||||||
|
const wx={setStorageSync(k,v){storage.set(k,v)},getStorageSync(k){return storage.get(k)},removeStorageSync(k){storage.delete(k)},switchTab(x){nav.push(x)},getSystemInfo({success}){success({screenHeight:800,safeArea:{bottom:780}})},getSystemInfoSync(){return {screenWidth:375,windowHeight:700,statusBarHeight:20}},getMenuButtonBoundingClientRect(){return {left:280,top:24,height:32,bottom:56}},navigateTo(x){nav.push(x)},previewImage(x){previews.push(x)},showToast(){}}
|
||||||
|
const context={...s,wx,console:{log(){}},wepy:{use(){},app(x){appDef=x},page(x){pageDef=x}},vuex:{},promisify:{},initEid(){},https:{},service:{host:'synthetic-host'},base:{},getApp(){return {$wepy:{$options:{globalData:{systemInfo:{system:'synthetic OS'}}}}}}}
|
||||||
|
vm.createContext(context);vm.runInContext(script('app.wpy'),context)
|
||||||
|
const app={$options:{globalData:{}},appLogin(){assert.equal(storage.get('from_user_id'),'42')}}
|
||||||
|
appDef.onLaunch.call(app,{query:{scene:'from_user_id%3D42'}})
|
||||||
|
appDef.onShow.call(app,{path:'pages/tabBar/welcome',query:{scene:'from_user_id%3D42'}});assert.equal(storage.get('from_user_id'),'42')
|
||||||
|
appDef.onShow.call(app,{path:'pages/sub_mall/confirmOrder',query:{}});assert.equal(storage.get('from_user_id'),'42')
|
||||||
|
appDef.onShow.call(app,{path:'pages/tabBar/home',query:{}});assert.equal(storage.has('from_user_id'),false)
|
||||||
|
appDef.onShow.call(app,{path:'pages/tabBar/welcome',query:{scene:'%'}})
|
||||||
|
appDef.onShow.call(app,{path:'pages/tabBar/welcome',query:{scene:'userId=88'}});assert.equal(storage.get('agent_user_id'),'88')
|
||||||
|
vm.runInContext(script('pages/tabBar/user.wpy'),context)
|
||||||
|
assert.deepEqual(Array.from(pageDef.data.list,x=>x.title),['会员中心','我的发布','我的分享','分享我的卡片','更多','设置'])
|
||||||
|
assert.equal(pageDef.data.list[0].path,'/pages/users/upgradeVIP');assert.equal(pageDef.data.list[1].path,'/pages/users/myDynamic');assert.equal(pageDef.data.list[5].path,'/pages/users/setTing')
|
||||||
|
vm.runInContext(script('pages/users/more.wpy'),context)
|
||||||
|
const more={...pageDef.data,...pageDef.methods,$get:async()=>({data:{qrcode:'synthetic-assigned-code'}})}
|
||||||
|
;(async()=>{
|
||||||
|
await more.openService();assert.equal(previews[0].current,'synthetic-assigned-code')
|
||||||
|
more.$get=async()=>({data:{}});await more.openService();assert.equal(nav.pop().url,'/pages/users/exclusiveService')
|
||||||
|
more.$get=async()=>{throw Error('synthetic')};await more.openService();assert.equal(more.serviceLoading,false)
|
||||||
|
more.guide();assert(nav.pop().url.includes(encodeURIComponent('https://love.ufutx.com/h5/#/guide')))
|
||||||
|
const configText=fs.readFileSync(path.join(root,'src/app.wpy'),'utf8').match(/<config>([\s\S]*?)<\/config>/)[1]
|
||||||
|
const config=vm.runInNewContext('('+configText+')')
|
||||||
|
const users=config.subPackages.find(x=>x.root==='pages/users')
|
||||||
|
for(const name of ['more','myShare','shareCard','myDynamic','exclusiveService','setTing'])assert.equal(users.pages.filter(x=>x===name).length,1)
|
||||||
|
console.log('PASS: cold-start attribution, malformed QR, old agent/shopping paths, menu order, preserved member/publish/settings routes, assigned customer service, route registration.')
|
||||||
|
})().catch(e=>{console.error(e.stack);process.exitCode=1})
|
||||||
Loading…
Reference in New Issue
Block a user