Commit 9d4f7bae by zhengxiao

feat(custom):

课程拼团裂变改造
parent fb41884d
<template>
<view class="ShareCanvas">
<view class="canvas">
<canvas canvas-id="shareCanvas" />
</view>
</view>
</template>
<script>
export default {
name: 'ShareCanvas',
methods: {
// 文本2行换行与显示省略号
// 1、canvas对象 2、文本 3、X轴 4、Y轴 5、单行行高 6、文本的宽度
drawText(ctx, str, axisX, axisY, titleHeight, maxWidth, font = 14) {
// 字体
ctx.font = `normal 500 ${font}px sans-serif`
ctx.letterSpacing = '1px'
// 颜色
ctx.fillStyle = '#000000'
// 文本处理
const strArr = str.split('')
let row = []
let temp = ''
for (let i = 0; i < strArr.length; i++) {
if (ctx.measureText(temp).width < maxWidth) {
temp += strArr[i]
} else {
i-- // 这里添加了i-- 是为了防止字符丢失,效果图中有对比
row.push(temp)
temp = ''
}
}
row.push(temp) // row有多少项则就有多少行
// 如果数组长度大于2,现在只需要显示两行则只截取前两项,把第二行结尾设置成'...'
if (row.length > 2) {
const rowCut = row.slice(0, 2)
const rowPart = rowCut[1]
let test = ''
const empty = []
for (let i = 0; i < rowPart.length; i++) {
if (ctx.measureText(test).width < maxWidth) {
test += rowPart[i]
} else {
break
}
}
empty.push(test)
const group = empty[0].slice(0, -1) + '...' // 这里只显示两行,超出的用...表示
console.log('🚀 ~ drawText ~ group:', group)
rowCut.splice(1, 1, group)
row = rowCut
console.log('🚀 ~ drawText ~ row:', row)
}
// 把文本绘制到画布中
for (let i = 0; i < row.length; i++) {
// 一次渲染一行
ctx.fillText(row[i], axisX, axisY + i * titleHeight, maxWidth)
}
},
calcContainScale(w, h, cw, ch) {
const scaleW = cw / w
const scaleH = ch / h
const scale = Math.max(scaleW, scaleH) // 取大值
return scale
},
calcPos(w, h, cw, ch) {
return {
x: (cw - w) / 2,
y: (ch - h) / 2,
}
},
// 商品分享
setGoodsShareCanvas(info) {
console.log('商品分享--info', info)
return new Promise(async (resolve, reject) => {
try {
const ctx = uni.createCanvasContext('shareCanvas', this)
// 绘制背景图
// ctx.fillStyle = '#FF3E3E'
// ctx.fillRect(0, 0, 211, 170)
try {
const { path } = await this.getImge(info.cardBg)
ctx.drawImage(path, 0, 0, 211, 170)
} catch (error) {
console.error(error)
}
// 商品模块
ctx.save()
this.setRadius(ctx, 4, 8, 62, 195, 99)
ctx.fillStyle = '#ffffff'
ctx.fill()
ctx.restore()
// 商品图
ctx.save()
this.setRadius(ctx, 4, 13, 67, 73, 90)
ctx.fillStyle = '#E5E6EB'
ctx.fill()
ctx.clip() // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内
try {
const { path, width, height } = await this.getImge(info.homeCover)
const scale = this.calcContainScale(width, height, 73, 90)
const w = width * scale // 图片缩放后的宽度
const h = height * scale // 图片缩放后的高度
const { x, y } = this.calcPos(w, h, 73, 90) // 顺便让图片居中
ctx.drawImage(path, x + 12, y + 66, w, h)
} catch (error) {
console.error(error)
}
ctx.restore()
ctx.save()
this.setRadius(ctx, 2, 15, 69, 31, 14)
ctx.fillStyle = '#FF644D'
ctx.fill()
ctx.restore()
ctx.font = '9px sans-serif'
ctx.textAlign = 'left'
ctx.fillStyle = '#ffffff'
ctx.fillText(`${info.requiredNum}人团`, 19, 80)
ctx.restore()
// 商品标题
this.drawText(ctx, info.title, 92, 82, 18, 106, 12)
ctx.restore()
// 已学人数
ctx.font = '10px sans-serif'
ctx.textAlign = 'left'
ctx.fillStyle = 'rgba(28,31,40, 0.4)'
ctx.fillText(`${info.applyNum}人已学`, 92, 118)
// 成团价
ctx.font = `normal bold 11px sans-serif`
ctx.textAlign = 'left'
ctx.fillStyle = '#FF5347'
ctx.fillText(`成团价 `, 92, 136)
// 成团价格
ctx.font = `normal bold 15px sans-serif`
ctx.textAlign = 'left'
ctx.fillStyle = '#FF5347'
ctx.fillText(${info.groupBuyingPrice}`, 127, 137)
// 单独购买价
ctx.font = `10px sans-serif`
ctx.textAlign = 'left'
ctx.fillStyle = '#999999'
ctx.fillText(`单独购买¥${info.salesPrice}`, 92, 153)
ctx.draw(false, () => {
uni.canvasToTempFilePath(
{
canvasId: 'shareCanvas',
success: res => {
return resolve(res.tempFilePath)
},
fail: function (error) {
console.log('fail----fail', error)
// TODO
return reject(error)
},
},
this,
)
})
} catch (error) {
uni.hideLoading()
console.log('画图失败error', error)
return reject(error)
}
})
},
/**
* 设置圆角矩形
*
* @param ctx 绘图上下文
* @param cornerRadius 圆角半径
* @param width 矩形宽度
* @param height 矩形高度
* @param x 矩形左上角的 x 坐标
* @param y 矩形左上角的 y 坐标
* @returns 无返回值
*/
setRadius(ctx, cornerRadius, x, y, width, height) {
// 开始绘制路径
ctx.beginPath()
// 绘制最左侧的圆角
ctx.arc(x + cornerRadius, y + cornerRadius, cornerRadius, Math.PI, Math.PI * 1.5)
// 绘制顶部边缘
ctx.moveTo(x + cornerRadius, y)
ctx.lineTo(x + width - cornerRadius, y)
ctx.lineTo(x + width, y + cornerRadius)
// 绘制最右侧的圆角
ctx.arc(x + width - cornerRadius, y + cornerRadius, cornerRadius, Math.PI * 1.5, Math.PI * 2)
// 绘制右侧边缘
ctx.lineTo(x + width, y + height - cornerRadius)
ctx.lineTo(x + width - cornerRadius, y + height)
// 绘制最下侧的圆角
ctx.arc(x + width - cornerRadius, y + height - cornerRadius, cornerRadius, 0, Math.PI * 0.5)
// 绘制底部边缘
ctx.lineTo(x + cornerRadius, y + height)
ctx.lineTo(x, y + height - cornerRadius)
// 绘制最左侧的圆角
ctx.arc(x + cornerRadius, y + height - cornerRadius, cornerRadius, Math.PI * 0.5, Math.PI)
// 绘制左侧边缘
ctx.lineTo(x, y + cornerRadius)
ctx.lineTo(x + cornerRadius, y)
// 闭合路径
ctx.closePath()
},
// 获取图片地址
getImge(path) {
// 利用promise异步转同步,否则可能显示不了~
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: path,
success: function (res) {
if (res && res.path) {
console.log('🚀 ~ returnnewPromise ~ res:', res)
resolve(res)
} else {
reject(false)
}
},
fail: function (res) {
reject(res)
},
})
})
},
getSales(sales) {
return sales >= 10000 ? sales / 10000 + 'w+' : sales
},
},
}
</script>
<style lang="less" scoped>
// 隐藏画布
.ShareCanvas {
position: absolute;
top: -200px;
z-index: -1;
opacity: 0;
.canvas canvas {
width: 211px;
height: 170px; // +16
}
}
</style>
...@@ -6,7 +6,7 @@ let h2Prefix ...@@ -6,7 +6,7 @@ let h2Prefix
let ydlH5Prefix let ydlH5Prefix
if (isDevelopment) { if (isDevelopment) {
// 开发 // // 开发
// hostPrefix = 'https://testnewm.ydl.com' // hostPrefix = 'https://testnewm.ydl.com'
// // hostPrefix = 'http://192.168.211.138' // // hostPrefix = 'http://192.168.211.138'
// apiPrefix = 'https://testapi.ydl.com' // apiPrefix = 'https://testapi.ydl.com'
......
...@@ -74,6 +74,7 @@ ...@@ -74,6 +74,7 @@
<script> <script>
import { hostPrefix } from '@/config' import { hostPrefix } from '@/config'
import { setTrackData } from '@/utils/util' import { setTrackData } from '@/utils/util'
import { ffrom } from '@/utils/enums'
export default { export default {
name: 'MyPage', name: 'MyPage',
...@@ -147,6 +148,9 @@ export default { ...@@ -147,6 +148,9 @@ export default {
return '' return ''
}, },
}, },
onShow() {
this.getUserInfo()
},
mounted() { mounted() {
// 页面访问埋点 // 页面访问埋点
setTrackData({ setTrackData({
...@@ -161,8 +165,32 @@ export default { ...@@ -161,8 +165,32 @@ export default {
}, },
], ],
}) })
this.getUserInfo()
}, },
methods: { methods: {
// 获取个人信息
getUserInfo() {
if (this.$store.state.user.accessToken) {
const { uid, accessToken } = this.$store.state.user
console.log("🚀 ~ getUserInfo ~ uid:", uid)
this.$request.post(
`/login/v2/get_user_info`,
{
uid,
accessToken,
version: '',
},
{
headers: {
userPort: '1',
ffrom,
version: '',
},
},
)
}
},
// 菜单项的埋点 // 菜单项的埋点
handleSendMenuTrackData(content) { handleSendMenuTrackData(content) {
// setTrackData({ // setTrackData({
......
<template> <template>
<view class="pay-page"> <view class="pay-page">
<div>正在支付中</div> <view>正在支付中...</view>
</view> </view>
</template> </template>
...@@ -170,6 +170,7 @@ export default { ...@@ -170,6 +170,7 @@ export default {
title: '支付失败', title: '支付失败',
icon: 'none', icon: 'none',
}) })
uni.navigateBack()
}, },
}) })
}, },
...@@ -220,9 +221,10 @@ export default { ...@@ -220,9 +221,10 @@ export default {
<style lang="less" scoped> <style lang="less" scoped>
.pay-page { .pay-page {
padding: 10px 0; padding: 30px 0;
height: 100%; height: 100%;
background: #f8f8f8; background: #f8f8f8;
overflow: auto; overflow: auto;
text-align: center;
} }
</style> </style>
<template> <template>
<view>
<web-view <web-view
v-if="!!loadUrl" v-if="!!loadUrl"
:src="loadUrl" :src="loadUrl"
@onPostMessage="handlePostMessage" @onPostMessage="handlePostMessage"
@message="handleMessage" @message="handleMessage"
></web-view> ></web-view>
<view>
<ShareCanvas ref="ShareCanvas" />
</view>
</view>
</template> </template>
<script> <script>
import { hostPrefix } from '@/config.js' import { hostPrefix } from '@/config.js'
import { ffrom } from '@/utils/enums' import { ffrom } from '@/utils/enums'
import ShareCanvas from '@/components/ShareCanvas'
export default { export default {
name: 'WebPage', name: 'WebPage',
components: {
ShareCanvas,
},
data() { data() {
return { return {
loadUrl: '', loadUrl: '',
// 只用于页面第一次初始化的时候,只要加载页面数据一次,防止onShow时重复加载 // 只用于页面第一次初始化的时候,只要加载页面数据一次,防止onShow时重复加载
isMountedPageLoaded: false, isMountedPageLoaded: false,
options: {}, options: {},
shareMessage: {},
} }
}, },
onLoad(options) { onLoad(options) {
...@@ -56,9 +66,12 @@ export default { ...@@ -56,9 +66,12 @@ export default {
} }
}, },
// 分享给朋友 // 分享给朋友
onShareAppMessage() { async onShareAppMessage() {
const getDetailPageUrl = () => { const getDetailPageUrl = (link = '') => {
let url = this.loadUrl let url = this.loadUrl
if (link) {
url = link
}
// 分享页面,去掉登陆信息 // 分享页面,去掉登陆信息
const query = { const query = {
accessToken: '', accessToken: '',
...@@ -67,15 +80,48 @@ export default { ...@@ -67,15 +80,48 @@ export default {
} }
// 更新 url 中的参数 // 更新 url 中的参数
Object.keys(query).forEach(prop => { Object.keys(query).forEach(prop => {
url = this.changeURLArg(this.loadUrl, prop, query[prop]) url = this.changeURLArg(url, prop, query[prop])
}) })
url = `/pages/web/web?loadUrl=${encodeURIComponent(url)}` url = `/pages/web/web?loadUrl=${encodeURIComponent(url)}`
return url return url
} }
// 课程详情页面 // 拼团相关页面分享
if (this.loadUrl.includes('h5-course/detail')) { if (
this.loadUrl.includes('h5-course/detail') ||
this.loadUrl.includes('h5-course/my/components/Buylist') ||
this.loadUrl.includes('h5-course/pay/groupSuccess') ||
this.loadUrl.includes('/h5-course/my/orderDetail/')
) {
if (this.shareMessage.share) {
try {
const courseDetail = this.shareMessage.share
uni.showLoading({
title: '正在唤起分享',
})
const imageUrl = await this.$refs.ShareCanvas.setGoodsShareCanvas({
homeCover: courseDetail.homeCover,
cardBg: 'https://static.ydlcdn.com/m/images/course/miniapp-share-bg.png',
title: courseDetail.title || '',
groupBuyingPrice: courseDetail.groupBuyingPrice,
salesPrice: courseDetail.salesPrice,
applyNum: courseDetail.applyNum,
requiredNum: courseDetail.groupBuyingDesc ? parseInt(courseDetail.groupBuyingDesc) : 0,
})
uni.hideLoading()
console.log(getDetailPageUrl(this.shareMessage.share_url))
return {
title: `我参与了「精品心理课程」拼团活动,快来组团一起学习吧👇`,
imageUrl: imageUrl,
path: getDetailPageUrl(this.shareMessage.share_url),
}
} catch (error) {
console.log("🚀 ~ onShareAppMessage ~ error:", error)
uni.hideLoading()
}
}
return { return {
title: `课程详情`, title: `课程详情`,
imageUrl: this.shareMessage.imageUrl,
path: getDetailPageUrl(), path: getDetailPageUrl(),
} }
} }
...@@ -83,14 +129,24 @@ export default { ...@@ -83,14 +129,24 @@ export default {
computed: { computed: {
// 课程详情页需要回退后,刷新 // 课程详情页需要回退后,刷新
isNeedLoadPageOnShow() { isNeedLoadPageOnShow() {
return this.loadUrl && this.loadUrl.includes('h5-course/detail') return (
this.loadUrl &&
(this.loadUrl.includes('h5-course/detail') ||
this.loadUrl.includes('h5-course/pay/groupSuccess'))
)
}, },
}, },
watch: { watch: {
loadUrl: { loadUrl: {
handler(url) { handler(url) {
// 课程详情时不隐藏,其他都隐藏 const whiteMap = [
if (url && url.includes('h5-course/detail')) { '/h5-course/my/orderDetail/',
'h5-course/detail',
'h5-course/my/components/Buylist',
'h5-course/pay/groupSuccess',
]
// 判断 url 是都包含whiteMap数组中的字符串
if (whiteMap.some(item => url.includes(item))) {
return return
} }
uni.hideShareMenu() uni.hideShareMenu()
...@@ -163,8 +219,9 @@ export default { ...@@ -163,8 +219,9 @@ export default {
.finally(() => (this.loading = false)) .finally(() => (this.loading = false))
if (res) { if (res) {
// `${hostPrefix}/h5-course/pay/groupSuccess?replace=1&courseId=${res.productId}&groupRecordId=${res.recordId}`
// https://testnewm.ydl.com/h5-course/detail/7529 // https://testnewm.ydl.com/h5-course/detail/7529
const url = `${hostPrefix}/h5-course/detail/${res.productId}` const url = `${hostPrefix}/h5-course/pay/groupSuccess?replace=1&courseId=${res.productId}&groupRecordId=${res.recordId}`
// productId 商品id // productId 商品id
// activityId 拼团活动id // activityId 拼团活动id
...@@ -208,11 +265,13 @@ export default { ...@@ -208,11 +265,13 @@ export default {
}, },
// webview向外部发送消息 // webview向外部发送消息
handlePostMessage: function (data) { handlePostMessage: function (data) {
console.log('🚀 ~ data:', data)
console.log('接收到消息:' + JSON.stringify(data.detail)) console.log('接收到消息:' + JSON.stringify(data.detail))
}, },
// webview向外部发送消息 // webview向外部发送消息
handleMessage: function (data) { handleMessage: function (data) {
console.log('接收到消息22 Message:' + JSON.stringify(data.detail)) console.log('接收到消息22 Message:' + JSON.stringify(data.detail))
this.shareMessage = data.detail.data[data.detail.data.length - 1]
}, },
// 更新 url 中的参数 // 更新 url 中的参数
changeURLArg(url, arg, value) { changeURLArg(url, arg, value) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment