Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
ydl-group-course
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
黄志
ydl-group-course
Commits
9d4f7bae
Commit
9d4f7bae
authored
Aug 15, 2024
by
zhengxiao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(custom):
课程拼团裂变改造
parent
fb41884d
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
357 additions
and
12 deletions
+357
-12
ShareCanvas.vue
src/components/ShareCanvas.vue
+256
-0
config.js
src/config.js
+1
-1
my.vue
src/pages/my/my.vue
+28
-0
pay.vue
src/pages/pay/pay.vue
+4
-2
web.vue
src/pages/web/web.vue
+68
-9
No files found.
src/components/ShareCanvas.vue
0 → 100644
View file @
9d4f7bae
<
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
>
src/config.js
View file @
9d4f7bae
...
@@ -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'
...
...
src/pages/my/my.vue
View file @
9d4f7bae
...
@@ -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({
...
...
src/pages/pay/pay.vue
View file @
9d4f7bae
<
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
:
1
0px
0
;
padding
:
3
0px
0
;
height
:
100%
;
height
:
100%
;
background
:
#f8f8f8
;
background
:
#f8f8f8
;
overflow
:
auto
;
overflow
:
auto
;
text-align
:
center
;
}
}
</
style
>
</
style
>
src/pages/web/web.vue
View file @
9d4f7bae
<
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
.
loadU
rl
,
prop
,
query
[
prop
])
url
=
this
.
changeURLArg
(
u
rl
,
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
.
product
Id
}
`
const
url
=
`
${
hostPrefix
}
/h5-course/
pay/groupSuccess?replace=1&courseId=
${
res
.
productId
}
&groupRecordId=
${
res
.
record
Id
}
`
// 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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment