chore:微信小程序分享正常
This commit is contained in:
@@ -199,7 +199,25 @@ export default {
|
|||||||
* 全局默认 onShareAppMessage:
|
* 全局默认 onShareAppMessage:
|
||||||
* uni-app 规范:组件自身的钩子优先级 > mixin,因此已显式声明的页面不受影响。
|
* uni-app 规范:组件自身的钩子优先级 > mixin,因此已显式声明的页面不受影响。
|
||||||
*/
|
*/
|
||||||
onShareAppMessage() {
|
onShareAppMessage(options) {
|
||||||
|
// 名片「发送名片」按钮(open-type="share")触发: dataset 携带名片信息 → 精准转发该名片
|
||||||
|
// (覆盖默认 cfg 逻辑; 微信小程序无法在组件内直接定义转发, 只能由页面 onShareAppMessage 提供)
|
||||||
|
if (
|
||||||
|
options &&
|
||||||
|
options.from === 'button' &&
|
||||||
|
options.target &&
|
||||||
|
options.target.dataset &&
|
||||||
|
options.target.dataset.cardId
|
||||||
|
) {
|
||||||
|
const d = options.target.dataset;
|
||||||
|
const name = d.cardName || '我的名片';
|
||||||
|
const img = (this.$util && this.$util.img ? this.$util.img(d.cardQr) : d.cardQr) || '';
|
||||||
|
return {
|
||||||
|
title: name + ' 的电子名片',
|
||||||
|
path: '/pages_tool/card/detail?card_id=' + d.cardId,
|
||||||
|
imageUrl: img
|
||||||
|
};
|
||||||
|
}
|
||||||
// 命中禁用列表的页面:即使 wx.hideShareMenu 因某些原因没生效,
|
// 命中禁用列表的页面:即使 wx.hideShareMenu 因某些原因没生效,
|
||||||
// 这里直接 return undefined / 也不主动拼 cfg,让微信回退到默认行为
|
// 这里直接 return undefined / 也不主动拼 cfg,让微信回退到默认行为
|
||||||
// (主防线是 wx.hideShareMenu,这里只是兜底)
|
// (主防线是 wx.hideShareMenu,这里只是兜底)
|
||||||
|
|||||||
@@ -169,9 +169,9 @@ export function rowIconFor(field) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 资料行点击动作: 由服务端下发的 href 派生(tel:/mailto:/url/空)
|
* 资料行点击动作: 由服务端下发的 href 派生(tel:/mailto:/url/空)
|
||||||
* tel: → 拨号 mailto: → 邮箱(H5) / 复制(其它端)
|
* tel: → 拨号 mailto: → 邮箱(H5 调起 / 其它端复制引导)
|
||||||
* http(s) → 复制链接 空 → 无动作(纯展示, 如地址/自定义)
|
* http(s) → web(跳转网站, 经 web-view 承载页) 空 → 无动作(纯展示, 如地址/自定义)
|
||||||
* 返回 null 表示不可点; type 取值与父组件 doAct 的 tel/mail/copy 分支对齐
|
* 返回 null 表示不可点; type 取值与父组件 doAct 的 tel/mail/web/copy 分支对齐
|
||||||
*/
|
*/
|
||||||
export function rowActOf(row) {
|
export function rowActOf(row) {
|
||||||
const href = String((row && row.href) || '').trim();
|
const href = String((row && row.href) || '').trim();
|
||||||
@@ -179,6 +179,7 @@ export function rowActOf(row) {
|
|||||||
if (!href || !value) return null;
|
if (!href || !value) return null;
|
||||||
if (/^tel:/i.test(href)) return { type: 'tel', value: value };
|
if (/^tel:/i.test(href)) return { type: 'tel', value: value };
|
||||||
if (/^mailto:/i.test(href)) return { type: 'mail', value: value };
|
if (/^mailto:/i.test(href)) return { type: 'mail', value: value };
|
||||||
|
if (/^https?:\/\//i.test(href)) return { type: 'web', value: value };
|
||||||
return { type: 'copy', value: value };
|
return { type: 'copy', value: value };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
<!-- 横滑布局 -->
|
<!-- 横滑布局 -->
|
||||||
<scroll-view v-else-if="layout === 'scroll' && list.length" class="wall-scroll" scroll-x show-scrollbar="false">
|
<scroll-view v-else-if="layout === 'scroll' && list.length" class="wall-scroll" scroll-x show-scrollbar="false">
|
||||||
<view v-for="(item, index) in list" :key="'s' + index" class="scroll-item fade-up" :style="scrollItemStyle" hover-class="btn-press" @tap="goDetail(item)">
|
<view v-for="(item, index) in list" :key="item.card_id || index" class="scroll-item fade-up" :style="scrollItemStyle" hover-class="btn-press" @tap="goDetail(item)">
|
||||||
<view class="item-avatar" :style="avatarStyle(item)">
|
<view class="item-avatar" :style="avatarStyle(item)">
|
||||||
<image v-if="item.avatar" class="avatar-img" :src="$util.img(item.avatar)" mode="aspectFill" />
|
<image v-if="item.avatar" class="avatar-img" :src="$util.img(item.avatar)" mode="aspectFill" />
|
||||||
<text v-else class="avatar-initial">{{ initialOf(item.name) }}</text>
|
<text v-else class="avatar-initial">{{ initialOf(item.name) }}</text>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
<!-- 网格/列表布局 -->
|
<!-- 网格/列表布局 -->
|
||||||
<view v-else-if="list.length" :class="['wall-grid', layout === 'list' ? 'is-list' : 'is-grid']">
|
<view v-else-if="list.length" :class="['wall-grid', layout === 'list' ? 'is-list' : 'is-grid']">
|
||||||
<view v-for="(item, index) in list" :key="'g' + index" class="wall-item fade-up"
|
<view v-for="(item, index) in list" :key="item.card_id || index" class="wall-item fade-up"
|
||||||
:style="[itemStyle, { animationDelay: (index * 60) + 'ms' }]" hover-class="btn-press" @tap="goDetail(item)">
|
:style="[itemStyle, { animationDelay: (index * 60) + 'ms' }]" hover-class="btn-press" @tap="goDetail(item)">
|
||||||
<!-- 内层卡片: 布局盒(wall-item)只负责 50% 宽+左右 gutter, 视觉在此层
|
<!-- 内层卡片: 布局盒(wall-item)只负责 50% 宽+左右 gutter, 视觉在此层
|
||||||
(WXSS 不支持 calc(), 不能用 calc(50% - gap/2)) -->
|
(WXSS 不支持 calc(), 不能用 calc(50% - gap/2)) -->
|
||||||
|
|||||||
@@ -108,10 +108,20 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 发送名片(白色名片外面下方, 与精选名片「发名片」同款布局; 点击弹分享抽屉) -->
|
<!-- 发送名片: 小程序端用原生转发(open-type=share 直接拉起「发送给朋友」面板, 与微信分享一致);
|
||||||
|
H5 端保持弹自定义分享抽屉(原生分享在 H5 不可用) -->
|
||||||
|
<!-- #ifdef MP-WEIXIN || MP-HARMONY -->
|
||||||
|
<button v-if="showDetailBtn" class="mini-detail" :style="detailBtnStyle" hover-class="btn-press"
|
||||||
|
open-type="share"
|
||||||
|
:data-card-id="card && card.card_id" :data-card-name="card && card.name" :data-card-qr="card && card.qr_url">
|
||||||
|
<text class="detail-text">{{ detailBtnText || '发送名片' }}</text>
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
<view v-if="showDetailBtn" class="mini-detail" :style="detailBtnStyle" hover-class="btn-press" @tap.stop="openCardShare">
|
<view v-if="showDetailBtn" class="mini-detail" :style="detailBtnStyle" hover-class="btn-press" @tap.stop="openCardShare">
|
||||||
<text class="detail-text">{{ detailBtnText || '发送名片' }}</text>
|
<text class="detail-text">{{ detailBtnText || '发送名片' }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
<!-- 分享名片抽屉(2026-10-23 参考图定稿: 与精选名片 show 同款版式/文案,
|
<!-- 分享名片抽屉(2026-10-23 参考图定稿: 与精选名片 show 同款版式/文案,
|
||||||
复刻 pages_tool/card/detail.vue 的 share-sheet; 类名 cs- 前缀, scoped 隔离) -->
|
复刻 pages_tool/card/detail.vue 的 share-sheet; 类名 cs- 前缀, scoped 隔离) -->
|
||||||
@@ -121,7 +131,8 @@
|
|||||||
<view class="ss-title">分享名片</view>
|
<view class="ss-title">分享名片</view>
|
||||||
<view class="ss-sub">客户打开链接即可查看名片并留言留资</view>
|
<view class="ss-sub">客户打开链接即可查看名片并留言留资</view>
|
||||||
<view class="ss-qr-box">
|
<view class="ss-qr-box">
|
||||||
<image v-if="card && card.qr_url" :src="$util.img(card.qr_url)" class="ss-qr" mode="widthFix" show-menu-by-longpress="true" />
|
<image v-if="card && card.qr_url" :src="$util.img(card.qr_url)" class="ss-qr" mode="widthFix"
|
||||||
|
show-menu-by-longpress="true" @tap="previewQr" />
|
||||||
</view>
|
</view>
|
||||||
<view class="ss-link">{{ (card && card.wap_url) || '' }}</view>
|
<view class="ss-link">{{ (card && card.wap_url) || '' }}</view>
|
||||||
<view class="ss-btns">
|
<view class="ss-btns">
|
||||||
@@ -455,6 +466,13 @@ export default {
|
|||||||
fail: () => uni.showToast({ title: '二维码下载失败', icon: 'none' }),
|
fail: () => uni.showToast({ title: '二维码下载失败', icon: 'none' }),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 分享抽屉二维码: 点击放大预览(预览页长按必出「识别图中二维码」菜单, 比 image 直接长按更可靠)
|
||||||
|
previewQr() {
|
||||||
|
const url = (this.card && this.card.qr_url) || '';
|
||||||
|
if (!url) return;
|
||||||
|
const src = this.$util.img(url);
|
||||||
|
uni.previewImage({ urls: [src], current: src });
|
||||||
|
},
|
||||||
/** 二维码点击 → 预览名片(进详情页; qrTapPreview 开关控制, 默认开) */
|
/** 二维码点击 → 预览名片(进详情页; qrTapPreview 开关控制, 默认开) */
|
||||||
onQrTap() {
|
onQrTap() {
|
||||||
if (flagOn(this.c.qrTapPreview, true)) this.$emit('detail', this.card);
|
if (flagOn(this.c.qrTapPreview, true)) this.$emit('detail', this.card);
|
||||||
@@ -779,6 +797,16 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
/* 小程序端为 <button open-type="share">: 去掉原生默认灰底/边框, 背景由 detailBtnStyle 内联主题色给出 */
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
line-height: normal;
|
||||||
|
font-size: 26rpx;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
.detail-text {
|
.detail-text {
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
|
|||||||
@@ -185,13 +185,30 @@ export default {
|
|||||||
success: () => uni.showToast({ title: '微信号已复制', icon: 'none' }),
|
success: () => uni.showToast({ title: '微信号已复制', icon: 'none' }),
|
||||||
});
|
});
|
||||||
} else if (act.type === 'mail') {
|
} else if (act.type === 'mail') {
|
||||||
|
// H5/公众号: 直接调起系统邮件客户端(满足「点击邮箱发邮件」)
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
window.location.href = 'mailto:' + act.value;
|
window.location.href = 'mailto:' + act.value;
|
||||||
// #endif
|
// #endif
|
||||||
|
// 小程序/App(非 H5): 微信沙箱不支持 mailto 拉起, 复制地址并引导去邮件 App 粘贴
|
||||||
// #ifndef H5
|
// #ifndef H5
|
||||||
uni.setClipboardData({
|
uni.setClipboardData({
|
||||||
data: act.value,
|
data: act.value,
|
||||||
success: () => uni.showToast({ title: '邮箱已复制', icon: 'none' }),
|
success: () => uni.showToast({ title: '邮箱已复制,请前往邮件App粘贴发送', icon: 'none' }),
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
} else if (act.type === 'web') {
|
||||||
|
// 网站行点击 → 跳转到该网址
|
||||||
|
// H5/公众号: 直接在本页打开(微信内置浏览器同)
|
||||||
|
// #ifdef H5
|
||||||
|
window.location.href = act.value;
|
||||||
|
// #endif
|
||||||
|
// 小程序/App(非 H5): 经 web-view 承载页在微信内打开(需微信后台配置业务域名)
|
||||||
|
// #ifndef H5
|
||||||
|
const title = (this.card && this.card.name) || '网站';
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages_tool/webview/webview?src=' + encodeURIComponent(act.value) +
|
||||||
|
'&title=' + encodeURIComponent(title) + '&enable_set_title=1',
|
||||||
|
fail: () => uni.showToast({ title: '打开网站失败', icon: 'none' }),
|
||||||
});
|
});
|
||||||
// #endif
|
// #endif
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -104,7 +104,8 @@
|
|||||||
<view class="ss-title">分享名片</view>
|
<view class="ss-title">分享名片</view>
|
||||||
<view class="ss-sub">客户打开链接即可查看名片并留言留资</view>
|
<view class="ss-sub">客户打开链接即可查看名片并留言留资</view>
|
||||||
<view class="ss-qr-box">
|
<view class="ss-qr-box">
|
||||||
<image v-if="card && card.qr_url" :src="$util.img(card.qr_url)" class="ss-qr" mode="widthFix" show-menu-by-longpress="true" />
|
<image v-if="card && card.qr_url" :src="$util.img(card.qr_url)" class="ss-qr" mode="widthFix"
|
||||||
|
show-menu-by-longpress="true" @tap="previewQr" />
|
||||||
</view>
|
</view>
|
||||||
<view class="ss-link">{{ (card && card.wap_url) || '' }}</view>
|
<view class="ss-link">{{ (card && card.wap_url) || '' }}</view>
|
||||||
<view class="ss-btns">
|
<view class="ss-btns">
|
||||||
@@ -399,13 +400,30 @@ export default {
|
|||||||
success: () => uni.showToast({ title: '微信号已复制', icon: 'none' }),
|
success: () => uni.showToast({ title: '微信号已复制', icon: 'none' }),
|
||||||
});
|
});
|
||||||
} else if (act.type === 'mail') {
|
} else if (act.type === 'mail') {
|
||||||
|
// H5/公众号: 直接调起系统邮件客户端(满足「点击邮箱发邮件」)
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
window.location.href = 'mailto:' + act.value;
|
window.location.href = 'mailto:' + act.value;
|
||||||
// #endif
|
// #endif
|
||||||
|
// 小程序/App(非 H5): 微信沙箱不支持 mailto 拉起, 复制地址并引导去邮件 App 粘贴
|
||||||
// #ifndef H5
|
// #ifndef H5
|
||||||
uni.setClipboardData({
|
uni.setClipboardData({
|
||||||
data: act.value,
|
data: act.value,
|
||||||
success: () => uni.showToast({ title: '邮箱已复制', icon: 'none' }),
|
success: () => uni.showToast({ title: '邮箱已复制,请前往邮件App粘贴发送', icon: 'none' }),
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
} else if (act.type === 'web') {
|
||||||
|
// 网站行点击 → 跳转到该网址
|
||||||
|
// H5/公众号: 直接在本页打开(微信内置浏览器同)
|
||||||
|
// #ifdef H5
|
||||||
|
window.location.href = act.value;
|
||||||
|
// #endif
|
||||||
|
// 小程序/App(非 H5): 经 web-view 承载页在微信内打开(需微信后台配置业务域名)
|
||||||
|
// #ifndef H5
|
||||||
|
const title = (this.card && this.card.name) || '网站';
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages_tool/webview/webview?src=' + encodeURIComponent(act.value) +
|
||||||
|
'&title=' + encodeURIComponent(title) + '&enable_set_title=1',
|
||||||
|
fail: () => uni.showToast({ title: '打开网站失败', icon: 'none' }),
|
||||||
});
|
});
|
||||||
// #endif
|
// #endif
|
||||||
} else {
|
} else {
|
||||||
@@ -472,6 +490,13 @@ export default {
|
|||||||
fail: () => uni.showToast({ title: '二维码下载失败', icon: 'none' })
|
fail: () => uni.showToast({ title: '二维码下载失败', icon: 'none' })
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 分享抽屉二维码: 点击放大预览(预览页长按必出「识别图中二维码」菜单, 比 image 直接长按更可靠)
|
||||||
|
previewQr() {
|
||||||
|
const url = (this.card && this.card.qr_url) || '';
|
||||||
|
if (!url) return;
|
||||||
|
const src = this.$util.img(url);
|
||||||
|
uni.previewImage({ urls: [src], current: src });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ test('common: rowActOf 由 href 派生点击动作', async () => {
|
|||||||
const m = await import('../components-diy/diy-card-common.js');
|
const m = await import('../components-diy/diy-card-common.js');
|
||||||
assert.deepEqual(m.rowActOf({ field: 'phone', value: '22644212509', href: 'tel:22644212509' }), { type: 'tel', value: '22644212509' });
|
assert.deepEqual(m.rowActOf({ field: 'phone', value: '22644212509', href: 'tel:22644212509' }), { type: 'tel', value: '22644212509' });
|
||||||
assert.deepEqual(m.rowActOf({ field: 'email', value: 'a@b.com', href: 'mailto:a@b.com' }), { type: 'mail', value: 'a@b.com' });
|
assert.deepEqual(m.rowActOf({ field: 'email', value: 'a@b.com', href: 'mailto:a@b.com' }), { type: 'mail', value: 'a@b.com' });
|
||||||
assert.deepEqual(m.rowActOf({ field: 'website', value: 'https://x.com', href: 'https://x.com' }), { type: 'copy', value: 'https://x.com' });
|
// 网站行: http(s) 派生 web(点击经 web-view 承载页跳转, 2026-10-23 用户需求)
|
||||||
|
assert.deepEqual(m.rowActOf({ field: 'website', value: 'https://x.com', href: 'https://x.com' }), { type: 'web', value: 'https://x.com' });
|
||||||
// 空 href(地址/自定义)或空值 → 不可点
|
// 空 href(地址/自定义)或空值 → 不可点
|
||||||
assert.equal(m.rowActOf({ field: 'address', value: '上海', href: '' }), null);
|
assert.equal(m.rowActOf({ field: 'address', value: '上海', href: '' }), null);
|
||||||
assert.equal(m.rowActOf({ field: 'phone', value: '', href: 'tel:' }), null);
|
assert.equal(m.rowActOf({ field: 'phone', value: '', href: 'tel:' }), null);
|
||||||
|
|||||||
@@ -94,9 +94,14 @@ test('mini: showDetailBtn 默认开(历史配置无此字段时也显示, 开箱
|
|||||||
assert.match(miniSrc, /flagOn\(this\.c\.showDetailBtn,\s*true\)/);
|
assert.match(miniSrc, /flagOn\(this\.c\.showDetailBtn,\s*true\)/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('mini: 存在全宽主按钮节点并弹分享抽屉(2026-10-23 参考图定稿, 与精选 show 同款)', () => {
|
test('mini: 发送名片按钮(小程序原生转发 + H5 弹抽屉, 双分支)', () => {
|
||||||
assert.match(miniSrc, /class="mini-detail"/);
|
assert.match(miniSrc, /class="mini-detail"/);
|
||||||
// 主按钮点击 → 弹「分享名片」抽屉(不再 emit detail 跳详情)
|
// 小程序端: <button open-type="share"> 直接拉起「发送给朋友」面板(与微信分享一致)
|
||||||
|
assert.match(miniSrc, /open-type="share"/);
|
||||||
|
assert.match(miniSrc, /:data-card-id="card && card\.card_id"/);
|
||||||
|
assert.match(miniSrc, /:data-card-name="card && card\.name"/);
|
||||||
|
assert.match(miniSrc, /:data-card-qr="card && card\.qr_url"/);
|
||||||
|
// H5 端: 仍弹「分享名片」抽屉(原生分享在 H5 不可用)
|
||||||
assert.match(miniSrc, /@tap\.stop="openCardShare"/);
|
assert.match(miniSrc, /@tap\.stop="openCardShare"/);
|
||||||
assert.match(miniSrc, /openCardShare\(\)\s*\{\s*this\.showShare = true;/);
|
assert.match(miniSrc, /openCardShare\(\)\s*\{\s*this\.showShare = true;/);
|
||||||
// 抽屉版式与 show 同款: 标题/副文案/二维码/复制链接
|
// 抽屉版式与 show 同款: 标题/副文案/二维码/复制链接
|
||||||
|
|||||||
Reference in New Issue
Block a user