|
|
@@ -138,28 +138,52 @@
|
|
|
<div class="sbox-title">分享给好友</div>
|
|
|
<image class="close" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/10/10/7d1c7cf4-199a-4008-8114-ee0e1a8f0cc3.png" @click="share=false"></image>
|
|
|
<div class="sbox-items adfac">
|
|
|
- <div class="sbox-items-pre adffcac">
|
|
|
+ <div class="sbox-items-pre adffcac" @click="shareToFriend">
|
|
|
<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/10/10/a993c721-a4c7-4f5e-95cc-6451a50bfdce.png"></image>
|
|
|
<text>分享页面</text>
|
|
|
</div>
|
|
|
- <div class="sbox-items-pre adffcac">
|
|
|
+ <div class="sbox-items-pre adffcac" @click="generatePoster">
|
|
|
<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/10/10/0c87d8a1-d7c5-466c-84aa-87ec5f163955.png"></image>
|
|
|
<text>生成海报</text>
|
|
|
</div>
|
|
|
- <div class="sbox-items-pre adffcac">
|
|
|
+ <div class="sbox-items-pre adffcac" @click="shareToTimeline">
|
|
|
<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/10/10/732ac5fd-af58-44d8-9625-aaf96c24fed0.png"></image>
|
|
|
<text>分享到朋友圈</text>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 添加海报生成的canvas -->
|
|
|
+ <canvas
|
|
|
+ canvas-id="posterCanvas"
|
|
|
+ :style="{width: canvasWidth + 'px', height: canvasHeight + 'px'}"
|
|
|
+ style="position: fixed; top: -9999px; left: -9999px;"
|
|
|
+ ></canvas>
|
|
|
+
|
|
|
+ <!-- 海报预览弹窗 -->
|
|
|
+ <div class="poster-preview" v-if="showPoster">
|
|
|
+ <div class="poster-box">
|
|
|
+ <div class="poster-header">
|
|
|
+ <text>生成海报</text>
|
|
|
+ <image class="close" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/10/10/7d1c7cf4-199a-4008-8114-ee0e1a8f0cc3.png" @click="showPoster=false"></image>
|
|
|
+ </div>
|
|
|
+ <div class="poster-content">
|
|
|
+ <image :src="posterUrl" mode="widthFix" class="poster-img"></image>
|
|
|
+ </div>
|
|
|
+ <div class="poster-actions">
|
|
|
+ <button class="save-btn" @click="savePoster">保存到相册</button>
|
|
|
+ <button class="share-btn" @click="sharePoster">分享给好友</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script setup name="">
|
|
|
import CusHeader from '@/components/CusHeader/index.vue'
|
|
|
- import { onShareAppMessage, onLoad } from '@dcloudio/uni-app';
|
|
|
- import { ref } from 'vue'
|
|
|
+ import { onShareAppMessage, onShareTimeline, onLoad } from '@dcloudio/uni-app';
|
|
|
+ import { ref, reactive } from 'vue'
|
|
|
|
|
|
const id = ref('')
|
|
|
const imgList = ref(['https://transcend.ringzle.com/xiaozhi-app/profile/2025/10/10/5378bfeb-32f5-4325-aaef-5270e4a55a3a.png'])
|
|
|
@@ -173,6 +197,16 @@
|
|
|
])
|
|
|
const fail = ref(false)
|
|
|
const share = ref(false)
|
|
|
+ const showPoster = ref(false)
|
|
|
+ const posterUrl = ref('')
|
|
|
+ const canvasWidth = ref(375)
|
|
|
+ const canvasHeight = ref(667)
|
|
|
+ const activityData = reactive({
|
|
|
+ title: '《环保知识知多少》让孩子成为大自然的守护者!',
|
|
|
+ time: '06.01-12:00 ~ 06.02-12:00',
|
|
|
+ address: '深圳市南山区南山街道丰潭路',
|
|
|
+ organizer: '锦鲤俱乐部'
|
|
|
+ })
|
|
|
|
|
|
const handleReviewMembers = () => {
|
|
|
uni.navigateTo({
|
|
|
@@ -188,15 +222,256 @@
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ // 分享给好友
|
|
|
+ const shareToFriend = () => {
|
|
|
+ share.value = false
|
|
|
+ uni.showShareMenu({
|
|
|
+ withShareTicket: true,
|
|
|
+ menus: ['shareAppMessage']
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分享到朋友圈
|
|
|
+ const shareToTimeline = () => {
|
|
|
+ share.value = false
|
|
|
+ // 朋友圈分享会触发 onShareTimeline
|
|
|
+ uni.showShareMenu({
|
|
|
+ withShareTicket: true,
|
|
|
+ menus: ['shareTimeline']
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成海报
|
|
|
+ const generatePoster = async () => {
|
|
|
+ share.value = false
|
|
|
+ uni.showLoading({
|
|
|
+ title: '正在生成海报...'
|
|
|
+ })
|
|
|
+
|
|
|
+ try {
|
|
|
+ await createPoster()
|
|
|
+ uni.hideLoading()
|
|
|
+ showPoster.value = true
|
|
|
+ } catch (error) {
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({
|
|
|
+ title: '海报生成失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建海报
|
|
|
+ const createPoster = () => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const ctx = uni.createCanvasContext('posterCanvas')
|
|
|
+
|
|
|
+ // 设置画布尺寸
|
|
|
+ const width = canvasWidth.value
|
|
|
+ const height = canvasHeight.value
|
|
|
+
|
|
|
+ // 绘制背景
|
|
|
+ const gradient = ctx.createLinearGradient(0, 0, 0, height)
|
|
|
+ gradient.addColorStop(0, '#87CEEB')
|
|
|
+ gradient.addColorStop(1, '#98FB98')
|
|
|
+ ctx.fillStyle = gradient
|
|
|
+ ctx.fillRect(0, 0, width, height)
|
|
|
+
|
|
|
+ // 加载并绘制背景图片(山峰)
|
|
|
+ const bgImg = 'https://transcend.ringzle.com/xiaozhi-app/profile/2025/10/10/5378bfeb-32f5-4325-aaef-5270e4a55a3a.png'
|
|
|
+
|
|
|
+ uni.getImageInfo({
|
|
|
+ src: bgImg,
|
|
|
+ success: (res) => {
|
|
|
+ // 绘制背景图
|
|
|
+ ctx.drawImage(res.path, 0, 0, width, height * 0.6)
|
|
|
+
|
|
|
+ // 绘制绿色标签
|
|
|
+ ctx.fillStyle = '#B7F358'
|
|
|
+ ctx.fillRect(20, 30, 120, 30)
|
|
|
+
|
|
|
+ // 绘制标签文字
|
|
|
+ ctx.fillStyle = '#000000'
|
|
|
+ ctx.font = 'bold 14px PingFang-SC'
|
|
|
+ ctx.fillText('节能低碳小妙招', 30, 50)
|
|
|
+
|
|
|
+ // 绘制主标题
|
|
|
+ ctx.fillStyle = '#FFFFFF'
|
|
|
+ ctx.font = 'bold 24px PingFang-SC'
|
|
|
+ ctx.fillText('环保知识', 50, 120)
|
|
|
+ ctx.fillText('知多少', 50, 150)
|
|
|
+
|
|
|
+ // 绘制白色信息区域背景
|
|
|
+ ctx.fillStyle = '#FFFFFF'
|
|
|
+ ctx.fillRect(20, height * 0.6 + 20, width - 40, height * 0.35)
|
|
|
+
|
|
|
+ // 绘制活动信息
|
|
|
+ ctx.fillStyle = '#000000'
|
|
|
+ ctx.font = '16px PingFang-SC'
|
|
|
+ const startY = height * 0.6 + 50
|
|
|
+
|
|
|
+ // 活动标题
|
|
|
+ ctx.font = 'bold 16px PingFang-SC'
|
|
|
+ ctx.fillText(activityData.title.substring(0, 20), 30, startY)
|
|
|
+ if (activityData.title.length > 20) {
|
|
|
+ ctx.fillText(activityData.title.substring(20), 30, startY + 25)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 时间图标和文字
|
|
|
+ ctx.font = '14px PingFang-SC'
|
|
|
+ ctx.fillStyle = '#666666'
|
|
|
+ ctx.fillText('🕐', 30, startY + 60)
|
|
|
+ ctx.fillText(activityData.time, 50, startY + 60)
|
|
|
+
|
|
|
+ // 地址图标和文字
|
|
|
+ ctx.fillText('📍', 30, startY + 85)
|
|
|
+ ctx.fillText(activityData.address, 50, startY + 85)
|
|
|
+
|
|
|
+ // 组织方
|
|
|
+ ctx.fillText('👥', 30, startY + 110)
|
|
|
+ ctx.fillText(activityData.organizer, 50, startY + 110)
|
|
|
+
|
|
|
+ // 绘制小程序码区域
|
|
|
+ ctx.fillStyle = '#F5F5F5'
|
|
|
+ ctx.fillRect(width - 120, height - 140, 100, 100)
|
|
|
+
|
|
|
+ ctx.fillStyle = '#000000'
|
|
|
+ ctx.font = '12px PingFang-SC'
|
|
|
+ ctx.fillText('微信扫一扫', width - 110, height - 25)
|
|
|
+
|
|
|
+ // 执行绘制
|
|
|
+ ctx.draw(false, () => {
|
|
|
+ // 导出图片
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ canvasId: 'posterCanvas',
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ destWidth: width * 2,
|
|
|
+ destHeight: height * 2,
|
|
|
+ success: (res) => {
|
|
|
+ posterUrl.value = res.tempFilePath
|
|
|
+ resolve(res.tempFilePath)
|
|
|
+ },
|
|
|
+ fail: reject
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ fail: () => {
|
|
|
+ // 如果图片加载失败,绘制纯色背景
|
|
|
+ drawSimplePoster(ctx, width, height, resolve, reject)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 绘制简单海报(备用方案)
|
|
|
+ const drawSimplePoster = (ctx, width, height, resolve, reject) => {
|
|
|
+ // 绘制渐变背景
|
|
|
+ const gradient = ctx.createLinearGradient(0, 0, 0, height)
|
|
|
+ gradient.addColorStop(0, '#87CEEB')
|
|
|
+ gradient.addColorStop(1, '#98FB98')
|
|
|
+ ctx.fillStyle = gradient
|
|
|
+ ctx.fillRect(0, 0, width, height)
|
|
|
+
|
|
|
+ // 绘制白色内容区域
|
|
|
+ ctx.fillStyle = '#FFFFFF'
|
|
|
+ ctx.fillRect(20, 100, width - 40, height - 200)
|
|
|
+
|
|
|
+ // 绘制标题
|
|
|
+ ctx.fillStyle = '#000000'
|
|
|
+ ctx.font = 'bold 20px PingFang-SC'
|
|
|
+ ctx.fillText('公益活动邀请', width / 2 - 70, 150)
|
|
|
+
|
|
|
+ // 绘制活动信息
|
|
|
+ ctx.font = '16px PingFang-SC'
|
|
|
+ ctx.fillText(activityData.title.substring(0, 15), 30, 200)
|
|
|
+ if (activityData.title.length > 15) {
|
|
|
+ ctx.fillText(activityData.title.substring(15), 30, 225)
|
|
|
+ }
|
|
|
+
|
|
|
+ ctx.font = '14px PingFang-SC'
|
|
|
+ ctx.fillStyle = '#666666'
|
|
|
+ ctx.fillText('活动时间:' + activityData.time, 30, 270)
|
|
|
+ ctx.fillText('活动地点:' + activityData.address.substring(0, 12), 30, 295)
|
|
|
+
|
|
|
+ ctx.draw(false, () => {
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ canvasId: 'posterCanvas',
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ destWidth: width * 2,
|
|
|
+ destHeight: height * 2,
|
|
|
+ success: (res) => {
|
|
|
+ posterUrl.value = res.tempFilePath
|
|
|
+ resolve(res.tempFilePath)
|
|
|
+ },
|
|
|
+ fail: reject
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存海报到相册
|
|
|
+ const savePoster = () => {
|
|
|
+ uni.saveImageToPhotosAlbum({
|
|
|
+ filePath: posterUrl.value,
|
|
|
+ success: () => {
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存成功',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ showPoster.value = false
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ if (err.errMsg.includes('auth deny')) {
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '需要您授权保存图片到相册',
|
|
|
+ confirmText: '去设置',
|
|
|
+ success: (res) => {
|
|
|
+ if (res.confirm) {
|
|
|
+ uni.openSetting()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分享海报给好友
|
|
|
+ const sharePoster = () => {
|
|
|
+ // 这里可以实现分享海报的逻辑
|
|
|
+ uni.showToast({
|
|
|
+ title: '请保存后手动分享',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
onLoad(options=>{
|
|
|
id.value = options?.id;
|
|
|
})
|
|
|
|
|
|
+ // 分享给好友
|
|
|
onShareAppMessage(() => {
|
|
|
- return {
|
|
|
- title: '公益活动详情',
|
|
|
- path: '/pagesHome/activityDetail?id='+id.value
|
|
|
- };
|
|
|
+ return {
|
|
|
+ title: activityData.title,
|
|
|
+ path: '/pagesHome/activityDetail?id=' + id.value,
|
|
|
+ imageUrl: imgList.value[0] // 使用活动图片作为分享图
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ // 分享到朋友圈
|
|
|
+ onShareTimeline(() => {
|
|
|
+ return {
|
|
|
+ title: activityData.title,
|
|
|
+ query: 'id=' + id.value,
|
|
|
+ imageUrl: posterUrl.value || imgList.value[0] // 优先使用海报,否则使用活动图片
|
|
|
+ };
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
@@ -677,5 +952,83 @@
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ .poster-preview {
|
|
|
+ position: fixed;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ top: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(0,0,0,0.8);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ z-index: 9999;
|
|
|
+
|
|
|
+ .poster-box {
|
|
|
+ width: 80%;
|
|
|
+ max-width: 600rpx;
|
|
|
+ background: #FFFFFF;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .poster-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 30rpx;
|
|
|
+ border-bottom: 1rpx solid #E7E7E7;
|
|
|
+
|
|
|
+ text {
|
|
|
+ font-family: PingFang-SC, PingFang-SC;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #151B29;
|
|
|
+ }
|
|
|
+
|
|
|
+ .close {
|
|
|
+ width: 40rpx;
|
|
|
+ height: 40rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .poster-content {
|
|
|
+ padding: 30rpx;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ .poster-img {
|
|
|
+ width: 100%;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .poster-actions {
|
|
|
+ display: flex;
|
|
|
+ padding: 0 30rpx 30rpx;
|
|
|
+ gap: 20rpx;
|
|
|
+
|
|
|
+ button {
|
|
|
+ flex: 1;
|
|
|
+ height: 80rpx;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ border: none;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+
|
|
|
+ .save-btn {
|
|
|
+ background: #F5F5F5;
|
|
|
+ color: #151B29;
|
|
|
+ }
|
|
|
+
|
|
|
+ .share-btn {
|
|
|
+ background: #B7F358;
|
|
|
+ color: #151B29;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|