fix: 提交

This commit is contained in:
wangdongbo 2026-02-02 08:53:26 +08:00
parent 68e4f01bd2
commit dcc84cf449
6 changed files with 1311 additions and 700 deletions

View 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

View File

@ -42,8 +42,8 @@
</view> </view>
<view class="px-15 text-base text-gray leading-normal text-center">进入团队首页即可发起线上咨询建档授权等服务</view> <view class="px-15 text-base text-gray leading-normal text-center">进入团队首页即可发起线上咨询建档授权等服务</view>
<view class="mt-10 flex px-15"> <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="mr-10 border-auto rounded py-10 text-base text-primary text-center flex-grow" @click="saveImage">保存图片</view>
<view class="bg-primary rounded py-10 text-base text-white text-center flex-grow">分享微信</view> <button class=" bg-primary rounded py-10 text-base text-white text-center flex-grow" open-type="share">分享微信</button>
</view> </view>
</view> </view>
</view> </view>
@ -56,7 +56,7 @@ import { onLoad } from "@dcloudio/uni-app";
import useAccountStore from "@/store/account.js"; import useAccountStore from "@/store/account.js";
import useGuard from '@/hooks/useGuard'; import useGuard from '@/hooks/useGuard';
import api from "@/utils/api.js"; 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 emptyData from "@/components/empty-data.vue";
import renamePopup from "./rename-popup.vue"; import renamePopup from "./rename-popup.vue";
@ -69,6 +69,7 @@ const current = ref(0);
const list = ref([]); const list = ref([]);
const visible = ref(false); const visible = ref(false);
const teamId = ref('') const teamId = ref('')
const qrcodes = ref(null);
const indicator = computed(() => ({ const indicator = computed(() => ({
prev: current.value > 0, prev: current.value > 0,
next: current.value < list.value.length - 1 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 => { onLoad(opts => {
teamId.value = opts.teamId || ''; teamId.value = opts.teamId || '';
}) })
@ -121,6 +181,12 @@ useShow(() => {
getTeams() getTeams()
}) })
// 使
defineExpose({
onShareAppMessage,
onShareTimeline
})
</script> </script>
<style> <style>
.w-100 { .w-100 {
@ -148,4 +214,15 @@ useShow(() => {
.h-30 { .h-30 {
height: 60rpx; height: 60rpx;
} }
.share-btn {
border: none;
padding: 0;
line-height: normal;
background: transparent;
}
.share-btn::after {
border: none;
}
</style> </style>

View 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
View 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
}
}

View File

@ -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('分享失败')
}
}
} }