fix: 提交
This commit is contained in:
parent
68e4f01bd2
commit
dcc84cf449
89
components/share-actions.vue
Normal file
89
components/share-actions.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<view class="share-actions">
|
||||
<view v-if="showSave" class="action-btn save-btn" @click="handleSave">
|
||||
<text class="btn-text">{{ saveText }}</text>
|
||||
</view>
|
||||
<button
|
||||
v-if="showShare"
|
||||
class="action-btn share-btn"
|
||||
open-type="share"
|
||||
>
|
||||
<text class="btn-text">{{ shareText }}</text>
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
// 是否显示保存按钮
|
||||
showSave: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示分享按钮
|
||||
showShare: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 保存按钮文字
|
||||
saveText: {
|
||||
type: String,
|
||||
default: '保存图片'
|
||||
},
|
||||
// 分享按钮文字
|
||||
shareText: {
|
||||
type: String,
|
||||
default: '分享微信'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['save', 'share'])
|
||||
|
||||
function handleSave() {
|
||||
emit('save')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.share-actions {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
border: 2rpx solid #0074ff;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.save-btn .btn-text {
|
||||
color: #0074ff;
|
||||
}
|
||||
|
||||
.share-btn {
|
||||
background: #0074ff;
|
||||
border: none;
|
||||
padding: 0;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.share-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.share-btn .btn-text {
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -42,8 +42,8 @@
|
||||
</view>
|
||||
<view class="px-15 text-base text-gray leading-normal text-center">进入团队首页,即可发起线上咨询、建档授权等服务</view>
|
||||
<view class="mt-10 flex px-15">
|
||||
<view class="mr-10 border-auto rounded py-10 text-base text-primary text-center flex-grow">保存图片</view>
|
||||
<view class="bg-primary rounded py-10 text-base text-white text-center flex-grow">分享微信</view>
|
||||
<view class="mr-10 border-auto rounded py-10 text-base text-primary text-center flex-grow" @click="saveImage">保存图片</view>
|
||||
<button class=" bg-primary rounded py-10 text-base text-white text-center flex-grow" open-type="share">分享微信</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -56,7 +56,7 @@ import { onLoad } from "@dcloudio/uni-app";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import useGuard from '@/hooks/useGuard';
|
||||
import api from "@/utils/api.js";
|
||||
import { toast } from "@/utils/widget";
|
||||
import { toast, saveImageToPhotosAlbum, shareToWeChat } from "@/utils/widget";
|
||||
|
||||
import emptyData from "@/components/empty-data.vue";
|
||||
import renamePopup from "./rename-popup.vue";
|
||||
@ -69,6 +69,7 @@ const current = ref(0);
|
||||
const list = ref([]);
|
||||
const visible = ref(false);
|
||||
const teamId = ref('')
|
||||
const qrcodes = ref(null);
|
||||
const indicator = computed(() => ({
|
||||
prev: current.value > 0,
|
||||
next: current.value < list.value.length - 1
|
||||
@ -113,6 +114,65 @@ async function change(name) {
|
||||
}
|
||||
}
|
||||
|
||||
// 保存二维码图片
|
||||
async function saveImage() {
|
||||
if (!team.value || !team.value.qrcode) {
|
||||
toast('暂无二维码');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const qrcodeComponent = qrcodes.value[current.value];
|
||||
if (!qrcodeComponent) {
|
||||
toast('二维码未加载完成');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取二维码临时文件路径
|
||||
const tempFilePath = qrcodeComponent.toTempFilePath();
|
||||
if (tempFilePath) {
|
||||
await saveImageToPhotosAlbum(tempFilePath);
|
||||
} else {
|
||||
toast('获取二维码失败');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('保存图片失败:', err);
|
||||
toast('保存失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 分享配置
|
||||
function onShareAppMessage() {
|
||||
if (!team.value) {
|
||||
return shareToWeChat({
|
||||
title: '邀请患者加入团队',
|
||||
path: '/pages/work/team/invite/invite-patient'
|
||||
});
|
||||
}
|
||||
|
||||
return shareToWeChat({
|
||||
title: `邀请您加入${team.value.name}`,
|
||||
path: `/pages/work/team/invite/invite-patient?teamId=${team.value.teamId}`,
|
||||
imageUrl: team.value.qrcode || ''
|
||||
});
|
||||
}
|
||||
|
||||
// 分享到朋友圈
|
||||
function onShareTimeline() {
|
||||
if (!team.value) {
|
||||
return {
|
||||
title: '邀请患者加入团队',
|
||||
path: '/pages/work/team/invite/invite-patient'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: `邀请您加入${team.value.name}`,
|
||||
query: `teamId=${team.value.teamId}`,
|
||||
imageUrl: team.value.qrcode || ''
|
||||
};
|
||||
}
|
||||
|
||||
onLoad(opts => {
|
||||
teamId.value = opts.teamId || '';
|
||||
})
|
||||
@ -121,6 +181,12 @@ useShow(() => {
|
||||
getTeams()
|
||||
})
|
||||
|
||||
// 导出分享方法供页面使用
|
||||
defineExpose({
|
||||
onShareAppMessage,
|
||||
onShareTimeline
|
||||
})
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.w-100 {
|
||||
@ -148,4 +214,15 @@ useShow(() => {
|
||||
.h-30 {
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.share-btn {
|
||||
border: none;
|
||||
padding: 0;
|
||||
line-height: normal;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.share-btn::after {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
234
utils/share-usage-example.md
Normal file
234
utils/share-usage-example.md
Normal file
@ -0,0 +1,234 @@
|
||||
# 微信小程序分享功能使用指南
|
||||
|
||||
## 功能说明
|
||||
|
||||
提供了完整的微信小程序分享功能,包括:
|
||||
- 分享给好友
|
||||
- 分享到朋友圈
|
||||
- 保存图片到相册
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 基础分享(在页面中)
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<button open-type="share">分享给好友</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { createShareMessage, createShareTimeline } from '@/utils/share'
|
||||
|
||||
// 分享给好友
|
||||
function onShareAppMessage() {
|
||||
return createShareMessage({
|
||||
title: '分享标题',
|
||||
path: '/pages/index/index?id=123',
|
||||
imageUrl: 'https://example.com/share.jpg'
|
||||
})
|
||||
}
|
||||
|
||||
// 分享到朋友圈(需要在 app.json 中配置)
|
||||
function onShareTimeline() {
|
||||
return createShareTimeline({
|
||||
title: '朋友圈标题',
|
||||
query: 'id=123',
|
||||
imageUrl: 'https://example.com/share.jpg'
|
||||
})
|
||||
}
|
||||
|
||||
// 导出分享方法
|
||||
defineExpose({
|
||||
onShareAppMessage,
|
||||
onShareTimeline
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 使用分享组件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<share-actions
|
||||
@save="handleSave"
|
||||
:show-save="true"
|
||||
:show-share="true"
|
||||
save-text="保存图片"
|
||||
share-text="分享微信"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { saveImageToAlbum, createShareMessage } from '@/utils/share'
|
||||
import shareActions from '@/components/share-actions.vue'
|
||||
|
||||
// 保存图片
|
||||
async function handleSave() {
|
||||
const imagePath = 'https://example.com/image.jpg'
|
||||
await saveImageToAlbum(imagePath)
|
||||
}
|
||||
|
||||
// 分享配置
|
||||
function onShareAppMessage() {
|
||||
return createShareMessage({
|
||||
title: '分享标题',
|
||||
path: '/pages/index/index'
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
onShareAppMessage
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 保存二维码图片
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<uqrcode ref="qrcode" canvasId="qrcode" :value="qrcodeUrl" />
|
||||
<button @click="saveQrcode">保存二维码</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { saveImageToAlbum } from '@/utils/share'
|
||||
import { toast } from '@/utils/widget'
|
||||
|
||||
const qrcode = ref(null)
|
||||
const qrcodeUrl = ref('https://example.com')
|
||||
|
||||
async function saveQrcode() {
|
||||
try {
|
||||
if (!qrcode.value) {
|
||||
toast('二维码未加载完成')
|
||||
return
|
||||
}
|
||||
|
||||
// 获取二维码临时文件路径
|
||||
const tempFilePath = qrcode.value.toTempFilePath()
|
||||
if (tempFilePath) {
|
||||
await saveImageToAlbum(tempFilePath)
|
||||
} else {
|
||||
toast('获取二维码失败')
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('保存失败:', err)
|
||||
toast('保存失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 4. 动态分享内容
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { createShareMessage } from '@/utils/share'
|
||||
|
||||
const currentItem = ref({
|
||||
id: '123',
|
||||
title: '商品标题',
|
||||
image: 'https://example.com/product.jpg'
|
||||
})
|
||||
|
||||
// 动态生成分享配置
|
||||
function onShareAppMessage() {
|
||||
return createShareMessage({
|
||||
title: currentItem.value.title,
|
||||
path: `/pages/detail/detail?id=${currentItem.value.id}`,
|
||||
imageUrl: currentItem.value.image
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
onShareAppMessage
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 1. 启用分享到朋友圈
|
||||
|
||||
在 `pages.json` 中配置页面:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页",
|
||||
"enableShareTimeline": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 全局分享配置
|
||||
|
||||
在 `App.vue` 中配置全局分享:
|
||||
|
||||
```vue
|
||||
<script>
|
||||
export default {
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '默认分享标题',
|
||||
path: '/pages/index/index'
|
||||
}
|
||||
},
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '默认朋友圈标题'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## API 说明
|
||||
|
||||
### createShareMessage(options)
|
||||
|
||||
创建分享给好友的配置
|
||||
|
||||
**参数:**
|
||||
- `title` (string): 分享标题
|
||||
- `path` (string): 分享路径
|
||||
- `imageUrl` (string): 分享图片URL
|
||||
|
||||
**返回:** 分享配置对象
|
||||
|
||||
### createShareTimeline(options)
|
||||
|
||||
创建分享到朋友圈的配置
|
||||
|
||||
**参数:**
|
||||
- `title` (string): 分享标题
|
||||
- `query` (string): 分享路径参数
|
||||
- `imageUrl` (string): 分享图片URL
|
||||
|
||||
**返回:** 分享配置对象
|
||||
|
||||
### saveImageToAlbum(filePath)
|
||||
|
||||
保存图片到相册
|
||||
|
||||
**参数:**
|
||||
- `filePath` (string): 图片路径(本地临时路径或网络路径)
|
||||
|
||||
**返回:** Promise<boolean>
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 分享图片建议尺寸:5:4,推荐 500x400px
|
||||
2. 分享路径必须是已注册的页面路径
|
||||
3. 保存图片需要用户授权相册权限
|
||||
4. 分享到朋友圈需要在页面配置中启用
|
||||
5. 网络图片会自动下载后保存到相册
|
||||
169
utils/share.js
Normal file
169
utils/share.js
Normal file
@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 微信小程序分享工具
|
||||
*/
|
||||
|
||||
import { toast } from './widget'
|
||||
|
||||
/**
|
||||
* 创建分享到好友的配置
|
||||
* @param {Object} options 分享配置
|
||||
* @param {string} options.title 分享标题
|
||||
* @param {string} options.path 分享路径
|
||||
* @param {string} options.imageUrl 分享图片URL
|
||||
* @returns {Object} 分享配置对象
|
||||
*/
|
||||
export function createShareMessage(options = {}) {
|
||||
const { title = '', path = '', imageUrl = '' } = options
|
||||
|
||||
return {
|
||||
title,
|
||||
path,
|
||||
imageUrl,
|
||||
success: () => {
|
||||
toast('分享成功')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('分享失败:', err)
|
||||
toast('分享失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分享到朋友圈的配置
|
||||
* @param {Object} options 分享配置
|
||||
* @param {string} options.title 分享标题
|
||||
* @param {string} options.query 分享路径参数
|
||||
* @param {string} options.imageUrl 分享图片URL
|
||||
* @returns {Object} 分享配置对象
|
||||
*/
|
||||
export function createShareTimeline(options = {}) {
|
||||
const { title = '', query = '', imageUrl = '' } = options
|
||||
|
||||
return {
|
||||
title,
|
||||
query,
|
||||
imageUrl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在页面中启用分享功能
|
||||
* 使用方法:在页面的 setup 中调用
|
||||
*
|
||||
* @example
|
||||
* import { enableShare } from '@/utils/share'
|
||||
*
|
||||
* // 在 setup 中
|
||||
* enableShare({
|
||||
* message: {
|
||||
* title: '分享标题',
|
||||
* path: '/pages/index/index',
|
||||
* imageUrl: 'https://example.com/image.jpg'
|
||||
* },
|
||||
* timeline: {
|
||||
* title: '朋友圈标题',
|
||||
* query: 'id=123',
|
||||
* imageUrl: 'https://example.com/image.jpg'
|
||||
* }
|
||||
* })
|
||||
*/
|
||||
export function enableShare(config = {}) {
|
||||
const { message, timeline } = config
|
||||
|
||||
// 分享给好友
|
||||
if (message) {
|
||||
uni.$on('onShareAppMessage', () => {
|
||||
return createShareMessage(message)
|
||||
})
|
||||
}
|
||||
|
||||
// 分享到朋友圈
|
||||
if (timeline) {
|
||||
uni.$on('onShareTimeline', () => {
|
||||
return createShareTimeline(timeline)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片到相册
|
||||
* @param {string} filePath 图片路径(本地临时路径或网络路径)
|
||||
*/
|
||||
export async function saveImageToAlbum(filePath) {
|
||||
try {
|
||||
// 如果是网络图片,先下载
|
||||
let localPath = filePath
|
||||
if (filePath.startsWith('http')) {
|
||||
const res = await uni.downloadFile({ url: filePath })
|
||||
if (res[0]) {
|
||||
throw new Error('下载图片失败')
|
||||
}
|
||||
localPath = res[1].tempFilePath
|
||||
}
|
||||
|
||||
// 检查授权
|
||||
const authRes = await uni.getSetting()
|
||||
if (!authRes[1].authSetting['scope.writePhotosAlbum']) {
|
||||
// 请求授权
|
||||
try {
|
||||
await uni.authorize({ scope: 'scope.writePhotosAlbum' })
|
||||
} catch (err) {
|
||||
// 用户拒绝授权,引导去设置
|
||||
const [modalErr, modalRes] = await uni.showModal({
|
||||
title: '提示',
|
||||
content: '需要您授权保存相册',
|
||||
confirmText: '去设置',
|
||||
cancelText: '取消'
|
||||
})
|
||||
|
||||
if (modalRes && modalRes.confirm) {
|
||||
await uni.openSetting()
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 保存图片
|
||||
const [saveErr] = await uni.saveImageToPhotosAlbum({ filePath: localPath })
|
||||
if (saveErr) {
|
||||
throw saveErr
|
||||
}
|
||||
|
||||
await toast('保存成功')
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error('保存图片失败:', err)
|
||||
await toast('保存失败')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带参数的小程序码
|
||||
* 需要后端接口支持
|
||||
* @param {Object} options
|
||||
* @param {string} options.scene 场景值
|
||||
* @param {string} options.page 页面路径
|
||||
* @returns {Promise<string>} 返回小程序码图片URL
|
||||
*/
|
||||
export async function generateMiniCode(options = {}) {
|
||||
// 这里需要调用后端接口生成小程序码
|
||||
// 示例代码,需要根据实际后端接口调整
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url: '/api/wechat/generateMiniCode',
|
||||
method: 'POST',
|
||||
data: options
|
||||
})
|
||||
|
||||
if (res[0] || !res[1].data.success) {
|
||||
throw new Error('生成小程序码失败')
|
||||
}
|
||||
|
||||
return res[1].data.data.url
|
||||
} catch (err) {
|
||||
console.error('生成小程序码失败:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@ -50,4 +50,47 @@ export async function confirm(content, opt = {}) {
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 保存图片到相册
|
||||
export async function saveImageToPhotosAlbum(filePath) {
|
||||
try {
|
||||
// 检查授权
|
||||
const authRes = await uni.getSetting()
|
||||
if (!authRes[1].authSetting['scope.writePhotosAlbum']) {
|
||||
// 请求授权
|
||||
try {
|
||||
await uni.authorize({ scope: 'scope.writePhotosAlbum' })
|
||||
} catch (err) {
|
||||
await confirm('需要您授权保存相册', { title: '提示', showCancel: false })
|
||||
await uni.openSetting()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 保存图片
|
||||
await uni.saveImageToPhotosAlbum({ filePath })
|
||||
await toast('保存成功')
|
||||
} catch (err) {
|
||||
console.error('保存图片失败:', err)
|
||||
await toast('保存失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 分享到微信
|
||||
export function shareToWeChat(options = {}) {
|
||||
const { title = '', path = '', imageUrl = '' } = options
|
||||
|
||||
return {
|
||||
title,
|
||||
path,
|
||||
imageUrl,
|
||||
success: () => {
|
||||
toast('分享成功')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('分享失败:', err)
|
||||
toast('分享失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user