Files
lucky_shop/pages_tool/card/detail.vue
2026-10-13 17:53:38 +08:00

905 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="card-detail">
<view class="page-layer">
<!-- 名片区: 蓝色背景 + 白卡。蓝色自导航栏下沿一路向下延伸到卡片内部后渐隐 -->
<view class="card-wrap" v-if="relation">
<!-- 蓝色背景层: 下沿锚定在卡片底部上方, 故卡片高度变化时蓝色下沿跟着走 -->
<view class="card-wrap-bg"></view>
<!-- 名片卡: 对齐设计稿 —— 姓名/职位/公司与全部联系方式都收在同一张白卡内, 不再拆成上下两块 -->
<view class="detail-card">
<view class="dc-name">{{ relation.name || '未命名名片' }}</view>
<view class="dc-job" v-if="relation.job_title">{{ relation.job_title }}</view>
<view class="dc-company" v-if="relation.company">{{ relation.company }}</view>
<view class="dc-rows" v-if="fieldRows.length > 0">
<view v-for="(row, index) in fieldRows" :key="index" class="field-row"
:class="{ 'field-row-multi': row.multiline }" @tap="onRowTap(row)">
<text v-if="row.icon" class="field-icon iconfont" :class="row.icon"></text>
<!-- 没有对应图标字形的字段(邮箱/网站/社交/自定义)退化为文字标签, 保持与图标列同宽 -->
<text v-else class="field-tag">{{ row.label }}</text>
<view class="field-value" :class="{ 'field-value-multi': row.multiline }">{{ row.value }}</view>
</view>
</view>
</view>
</view>
<!-- 卡下操作条(参考图: 三项等分, 项与项之间不加分隔线) -->
<view class="card-actions" v-if="relation">
<view class="ca-item" @tap="goEdit">
<text class="ca-icon iconfont icon-bianji"></text>
<text>编辑资料</text>
</view>
<view class="ca-item" @tap="onStyleTap">
<text class="ca-icon iconfont icon-erweima"></text>
<text>名片样式</text>
</view>
<view class="ca-item" @tap="goList">
<text class="ca-icon iconfont icon-shuaxin"></text>
<text>切换名片</text>
</view>
</view>
<!-- 发名片: 微信小程序端必须用原生 <button open-type="share"> ——
微信未开放「主动唤起转发面板」的 API, 普通 view 的 @tap 只能弹提示,
原生 button 点一下即拉起「发送给朋友」选择器, 内容取本页 onShareAppMessage。
其它端无等价能力, 退化为打开分享面板(复制链接 / 浏览器分享)。 -->
<view class="send-bar" v-if="relation">
<!-- #ifdef MP-WEIXIN -->
<!-- 不加 :plain —— plain 会强制背景透明, 主按钮需要渐变底, 故用 CSS 完整重置原生样式 -->
<button class="send-btn" open-type="share">发名片</button>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS || MP-HARMONY -->
<view class="send-btn" @tap="openShare">发名片</view>
<!-- #endif -->
</view>
<!-- 功能入口宫格(参考图: 发名片下方五等分图标入口) -->
<view class="entry-grid" v-if="relation">
<view class="eg-item" @tap="goList">
<text class="eg-icon iconfont icon-list"></text>
<text class="eg-text">名片夹</text>
</view>
<view class="eg-item" @tap="goLeads">
<text class="eg-icon iconfont icon-yonghu3"></text>
<text class="eg-text">潜在客户</text>
</view>
<view class="eg-item" @tap="goContacts">
<text class="eg-icon iconfont icon-pengyouquan"></text>
<text class="eg-text">我的人脉</text>
</view>
<view class="eg-item" @tap="openShare">
<text class="eg-icon iconfont icon-erweima"></text>
<text class="eg-text">名片二维码</text>
</view>
<view class="eg-item" @tap="goEdit">
<text class="eg-icon iconfont icon-bianji"></text>
<text class="eg-text">编辑名片</text>
</view>
</view>
<!-- 交换名片请求提醒条(参考图: 宫格下方出现对方要交换的名片) -->
<!-- 数据先用假数据占位(exchangeRequest), 接口就绪后替换数据源即可 -->
<view class="exchange-bar" v-if="relation && exchangeRequest" @tap="goExchangeReq">
<view class="eb-head">
<view class="eb-dot"></view>
<text class="eb-head-text">有 {{ exchangeRequest.count }} 人请求与您交换名片</text>
<text class="eb-arrow iconfont icon-right"></text>
</view>
<view class="eb-card" @tap.stop="viewExchangeCard">
<image v-if="exchangeRequest.avatar" class="eb-avatar" :src="exchangeRequest.avatar" mode="aspectFill" />
<view v-else class="eb-avatar eb-avatar-ph">{{ exchangeRequest.name.charAt(0) }}</view>
<view class="eb-info">
<view class="eb-name-row">
<text class="eb-name">{{ exchangeRequest.name }}</text>
<text class="eb-badge iconfont icon-dui"></text>
</view>
<text class="eb-job">{{ exchangeRequest.job_title }}{{ exchangeRequest.company ? ' · ' + exchangeRequest.company : '' }}</text>
<text class="eb-time">{{ exchangeRequest.time }} 向您发起名片交换</text>
</view>
<view class="eb-actions">
<view class="eb-act-item" @tap.stop="onIgnoreExchange">
<view class="eb-act eb-act-ignore">
<text class="iconfont icon-guanbi"></text>
</view>
<text class="eb-act-text">忽略</text>
</view>
<view class="eb-act-item" @tap.stop="onAgreeExchange">
<view class="eb-act eb-act-agree">
<text class="iconfont icon-dui"></text>
</view>
<text class="eb-act-text">同意</text>
</view>
</view>
</view>
</view>
<!-- 加载中 -->
<view class="detail-loading" v-if="isLoading">加载中…</view>
<!-- 不存在 / 无权查看 -->
<ns-empty v-if="!isLoading && !relation" :isIndex="false"
:text="errorMsg || '卡片不存在或已被删除'"></ns-empty>
</view>
<!-- 分享面板(微信式底部抽屉) -->
<view class="share-mask" v-if="showShare" @tap="closeShare"></view>
<view class="share-sheet" :class="{ 'share-sheet-show': showShare }">
<view class="ss-bar"></view>
<view class="ss-title">分享名片</view>
<view class="ss-sub">客户打开链接即可查看名片并留言留资</view>
<view class="ss-qr-box">
<image v-if="qrUrl" :src="qrUrl" class="ss-qr" mode="widthFix" show-menu-by-longpress="true" />
</view>
<view class="ss-link">{{ shareUrl }}</view>
<view class="ss-btns">
<view class="ss-btn ss-btn-main" @tap="copyLink">复制链接</view>
<!-- #ifdef MP-WEIXIN -->
<view class="ss-btn" @tap="saveQr">保存二维码</view>
<!-- 发给好友: 必须用原生 button(open-type=share) 才能直接拉起转发面板;
纯 @tap 的 view 调不起该面板, 只能弹一句「去点右上角」的提示 -->
<button class="ss-btn" :plain="true" open-type="share">发给好友</button>
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="ss-btn" @tap="h5Share">浏览器分享</view>
<!-- #endif -->
<!-- #ifdef MP-HARMONY -->
<!-- 鸿蒙元服务:uni.saveImageToPhotosAlbum/downloadFile 均支持(先下载后保存的模式不变);
无小程序右上角转发菜单,系统级分享用「复制链接」代替;原生 image 无长按菜单 -->
<view class="ss-btn" @tap="saveQr">保存二维码</view>
<!-- #endif -->
</view>
<view class="ss-tip">
<!-- #ifdef MP-WEIXIN -->长按二维码也可保存到相册<!-- #endif -->
<!-- #ifdef H5 -->长按二维码可保存到相册<!-- #endif -->
<!-- #ifdef MP-HARMONY -->点击「保存二维码」存入相册<!-- #endif -->
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
cardId: '',
relation: null,
source: null,
shareList: [],
isLoading: true,
errorMsg: '',
showShare: false,
shareUrl: '',
qrUrl: '',
// 交换名片请求(静态占位数据, 接口就绪后替换为后端返回)
exchangeRequest: {
count: 1,
name: '名片君',
job_title: '销售经理',
company: '示例科技有限公司',
avatar: '',
time: '今天 14:17'
}
};
},
computed: {
fieldRows() {
const r = this.relation;
if (!r) return [];
const rows = [];
// icon: 图标字形见 common/css/iconfont.css; 邮箱/网站无对应 glyph, 留空 → 模板退化为文字标签
const push = (label, value, action, icon) => {
if (value !== undefined && value !== null && String(value).trim() !== '') {
rows.push({ label, value: String(value), action: action || null, icon: icon || '' });
}
};
push('手机', r.mobile, { type: 'call', text: '拨打' }, 'icon-dianhua');
push('电话', r.phone, { type: 'call', text: '拨打' }, 'icon-dianhua');
push('邮箱', r.email, { type: 'copy', text: '复制' });
push('微信', r.wechat, { type: 'copy', text: '复制' }, 'icon-weixin');
push('网站', r.website);
push('地址', [r.country, r.province, r.city, r.address].filter(Boolean).join(' '), null, 'icon-dizhi');
push('邮编', r.postal_code);
// Telegram / Messenger 已于 2026-10-13 软下线为独立标量:
// 旧值由后端自动合并进 socials_list, 此处不再单独渲染(避免重复行)
// 附加手机号(mobiles_list, 后端 CardRichFields 解码) → 可拨打
(r.mobiles_list || []).forEach((m, i) => {
push('手机' + (i + 2), m, { type: 'call', text: '拨打' }, 'icon-dianhua');
});
// 社交账号(socials_list: {type,label,value}) → label 作行名, 值可复制
// (完整主页链接与纯账号统一复制 value, 链接可粘贴到浏览器打开)
(r.socials_list || []).forEach(s => {
push(s.label || s.type, s.value, { type: 'copy', text: '复制' });
});
// 自定义字段(custom_list: {label,value})
(r.custom_list || []).forEach(c => {
push(c.label, c.value);
});
// 简介(多行, 放最后)
if (r.bio && String(r.bio).trim() !== '') {
rows.push({ label: '简介', value: String(r.bio), action: null, multiline: true });
}
return rows;
}
},
onLoad(options) {
this.cardId = decodeURIComponent(options.card_id || '');
this.loadDetail();
},
onShow() {
// 首次进入由 onLoad 负责加载; 从编辑页返回时(onShow 再次触发)刷新
if (this._loadedOnce) {
this.loadDetail();
}
this._loadedOnce = true;
},
// 小程序端转发: 分享 web-view 中转页(其内部加载 wap H5 名片页),
// 因为 onShareAppMessage 的 path 只能指向小程序页面, 不能直接分享 H5 链接
onShareAppMessage() {
// 右上角「···」转发与原生转发按钮都会直接走这里, 不经过 openShare;
// 兜底生成一次链接, 否则 path 里的 url 为空 → 中转页只会显示「链接无效」
this.buildShareInfo();
const name = (this.relation && this.relation.name) || '我的名片';
return {
title: name + '的名片',
path: '/pages_tool/card/share?url=' + encodeURIComponent(this.shareUrl || ''),
imageUrl: (this.relation && this.relation.avatar) ? this.$util.img(this.relation.avatar) : ''
};
},
methods: {
goEdit() {
if (!this.cardId) return;
uni.navigateTo({
url: '/pages_tool/card/edit?card_id=' + encodeURIComponent(this.cardId)
});
},
// 切换名片: 回名片夹选另一张
goList() {
this.$util.redirectTo('/pages_tool/card/list');
},
goLeads() {
this.$util.redirectTo('/pages_tool/card/leads');
},
goContacts() {
this.$util.redirectTo('/pages_tool/card/contacts');
},
/**
* 资料行整行可点: 电话类拨打, 其余复制
* (设计稿行内没有独立的「拨打/复制」按钮, 交互收到整行上)
*/
onRowTap(row) {
if (!row || !row.action) return;
if (row.action.type === 'call') {
this.callPhone(row.value);
return;
}
this.copyText2(row.value);
},
loadDetail() {
if (!this.cardId) {
this.isLoading = false;
this.errorMsg = '缺少名片编号';
return;
}
this.isLoading = true;
this.$cardApi.cardDetail({
data: { card_id: this.cardId },
success: res => {
this.isLoading = false;
if (res.code == 0) {
const data = res.data || {};
this.relation = data.relation || null;
this.source = data.source || null;
this.shareList = data.share_list || [];
// 详情一到手就算出分享链接/二维码: 用户可能直接点「发名片」或右上角转发
this.buildShareInfo();
} else {
// 后端对"不存在"与"非本人名下"同一报错口径,不区分展示
this.errorMsg = res.message || '卡片不存在或已被删除';
this.relation = null;
}
},
fail: () => {
this.isLoading = false;
this.errorMsg = '网络异常,请稍后重试';
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
}
});
},
callPhone(mobile) {
if (!mobile) return;
uni.makePhoneCall({ phoneNumber: mobile });
},
copyText2(text) {
uni.setClipboardData({
data: text,
success: () => {
uni.showToast({ title: '已复制', icon: 'success' });
}
});
},
/* ---------- 分享 ---------- */
siteId() {
return uni.getStorageSync('uniacid') || this.$config.uniacid || 0;
},
/**
* 生成分享链接与二维码(幂等, 可重复调用)
* ⚠️ 必须在 onShareAppMessage 触发前就绪: 微信右上角「···」转发与本页原生转发按钮
* 都直接读 shareUrl, 不经过 openShare(), 空值会让转出去的名片打不开。
*/
buildShareInfo() {
if (!this.relation) return;
const sid = this.siteId();
const rid = this.relation.id;
const base = this.$config.baseUrl || '';
// wap 公开名片页(客户视角, 无需登录)
this.shareUrl = base + '/card/wap/index/detail?site_id=' + sid + '&id=' + rid;
// 二维码由后端同源生成(项目内置 extend\QRcode), 与链接一一对应
this.qrUrl = base + '/card/wap/index/qr?site_id=' + sid + '&id=' + rid;
},
openShare() {
if (!this.relation) return;
this.buildShareInfo();
this.showShare = true;
},
// 「名片样式」: 与分享二维码无关, 不再打开分享抽屉。
// 样式选择页尚未开发, 先给占位提示; 后续实现后把这里换成跳转/弹层即可。
onStyleTap() {
uni.showToast({ title: '名片样式功能开发中', icon: 'none' });
},
// 「交换名片」提醒条: 静态占位, 接口就绪后替换数据源并接真实请求
goExchangeReq() {
uni.showToast({ title: '交换名片功能开发中', icon: 'none' });
},
viewExchangeCard() {
uni.showToast({ title: '查看对方名片(接口待接入)', icon: 'none' });
},
onIgnoreExchange() {
uni.showToast({ title: '已忽略(接口待接入)', icon: 'none' });
},
onAgreeExchange() {
uni.showToast({ title: '已同意(接口待接入)', icon: 'none' });
},
closeShare() {
this.showShare = false;
},
copyLink() {
if (!this.shareUrl) return;
uni.setClipboardData({
data: this.shareUrl,
success: () => {
uni.showToast({ title: '链接已复制', icon: 'success' });
}
});
},
saveQr() {
if (!this.qrUrl) return;
uni.downloadFile({
url: this.qrUrl,
success: res => {
if (res.statusCode !== 200 || !res.tempFilePath) {
uni.showToast({ title: '二维码下载失败', icon: 'none' });
return;
}
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => uni.showToast({ title: '已保存到相册', icon: 'success' }),
// 文案不提「长按保存」: 鸿蒙元服务的原生 image 无长按菜单, 只微信/H5 有
fail: () => uni.showToast({ title: '保存失败,可复制链接分享', icon: 'none' })
});
},
fail: () => uni.showToast({ title: '二维码下载失败', icon: 'none' })
});
},
h5Share() {
// H5: 优先 navigator.share(移动浏览器), 不支持则复制链接兜底
if (navigator && typeof navigator.share === 'function') {
navigator.share({
title: ((this.relation && this.relation.name) || '我的名片') + '的名片',
url: this.shareUrl
}).catch(() => {});
return;
}
this.copyLink();
}
}
};
</script>
<style lang="scss" scoped>
.card-detail {
min-height: 100vh;
// 参考图: 蓝色以下为白底(非灰底)
background-color: #ffffff;
padding: 0 0 60rpx;
box-sizing: border-box;
}
// 内容层
.page-layer {
position: relative;
}
// 名片区: 高度 = 上留白 + 卡片高度, 蓝色背景层锚在其中
.card-wrap {
position: relative;
padding-top: 40rpx;
}
// 蓝色背景层: 纯色(无渐变), 顶部与导航栏 #2aa5ff 无缝衔接, 下沿是一条向下凸的弧线
// 弧度做法: 底部两角用「横向 240rpx + 纵向 44rpx」的椭圆圆角, 两侧各一条大弧线
// (中段被白卡完全盖住, 所以漏出来的只有左右两条弧边, 和参考图一致)
// bottom: 48rpx —— 弧线最低点比卡片下沿上提 48rpx(向上移一点); 想再高/再低改这个值即可
.card-wrap-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 48rpx;
z-index: 0;
background-color: #2aa5ff;
border-bottom-left-radius: 240rpx 44rpx;
border-bottom-right-radius: 240rpx 44rpx;
pointer-events: none;
}
// 名片卡: 设计稿式白卡 —— 姓名/职位/公司与全部联系方式同卡
// position/z-index: 保证白卡压在蓝色背景层之上
.detail-card {
position: relative;
z-index: 1;
margin: 0 24rpx;
background-color: #ffffff;
border-radius: 20rpx;
padding: 40rpx 36rpx 32rpx;
box-shadow: 0 6rpx 20rpx rgba(0, 30, 80, 0.06);
.dc-name {
font-size: 44rpx;
font-weight: 700;
color: #1a1a1a;
line-height: 1.3;
}
.dc-job {
margin-top: 6rpx;
font-size: 28rpx;
line-height: 1.3;
color: #4a4a4a;
}
.dc-company {
margin-top: 2rpx;
font-size: 26rpx;
line-height: 1.3;
color: #9aa4b2;
}
.dc-rows {
// 参考图: 公司名与资料行之间留一大段空白
margin-top: 56rpx;
}
// 资料行: 全局 view{line-height:1.8} 会把每行撑高, 这里显式收紧到参考图行距
.field-row {
display: flex;
align-items: center;
line-height: 1.2;
padding: 12rpx 0;
&.field-row-multi {
align-items: flex-start;
}
.field-icon {
width: 40rpx;
margin-right: 18rpx;
font-size: 32rpx;
line-height: 1;
color: #8a94a6;
text-align: center;
flex-shrink: 0;
}
.field-tag {
min-width: 40rpx;
margin-right: 18rpx;
font-size: 26rpx;
line-height: 1.2;
color: #9aa4b2;
flex-shrink: 0;
}
.field-value {
flex: 1;
min-width: 0;
font-size: 28rpx;
line-height: 1.25;
color: #333333;
word-break: break-all;
}
.field-value-multi {
line-height: 1.4;
white-space: pre-wrap;
}
}
}
// 卡下操作条: 三项等分, 无白底无边框, 项与项之间不加分隔线(对齐参考图)
.card-actions {
display: flex;
align-items: center;
margin: 28rpx 24rpx 0;
.ca-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
line-height: 1.2;
color: #333333;
.ca-icon {
margin-right: 8rpx;
font-size: 30rpx;
color: #8a94a6;
}
}
}
// 发名片下方的功能入口宫格: 五等分, 图标在上、文字在下
.entry-grid {
display: flex;
align-items: flex-start;
margin: 40rpx 24rpx 0;
.eg-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.eg-icon {
font-size: 52rpx;
line-height: 1;
color: #2aa5ff;
}
.eg-text {
margin-top: 14rpx;
font-size: 22rpx;
line-height: 1.2;
color: #7b8794;
}
}
// 交换名片请求提醒条(参考图: 宫格下方出现对方要交换的名片)
// 数据先用假数据占位(exchangeRequest), 接口就绪后替换数据源即可
.exchange-bar {
margin: 24rpx 24rpx 0;
// 参考图: 整条外框为蓝色描边, 内层名片区白底, 顶部提醒行为浅蓝底
background-color: #ffffff;
border: 2rpx solid #2aa5ff;
border-radius: 16rpx;
overflow: hidden;
box-sizing: border-box;
.eb-head {
display: flex;
align-items: center;
padding: 20rpx 24rpx;
background-color: #eef5ff;
}
.eb-dot {
width: 10rpx;
height: 10rpx;
margin-right: 12rpx;
border-radius: 50%;
background-color: #2aa5ff;
flex-shrink: 0;
}
.eb-head-text {
flex: 1;
font-size: 24rpx;
color: #2aa5ff;
}
.eb-arrow {
font-size: 24rpx;
color: #9fb4cc;
}
.eb-card {
display: flex;
align-items: center;
// 名片区独立白底, 与浅蓝提醒行分块(参考图)
padding: 24rpx;
background-color: #ffffff;
}
.eb-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
flex-shrink: 0;
background-color: #2aa5ff;
}
.eb-avatar-ph {
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-size: 34rpx;
font-weight: 600;
}
.eb-info {
flex: 1;
min-width: 0;
margin-left: 20rpx;
}
.eb-name-row {
display: flex;
align-items: center;
}
.eb-name {
font-size: 28rpx;
font-weight: 600;
color: #333333;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.eb-badge {
margin-left: 8rpx;
font-size: 24rpx;
color: #2aa5ff;
}
.eb-job {
display: block;
margin-top: 6rpx;
font-size: 22rpx;
color: #7b8794;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.eb-time {
display: block;
margin-top: 6rpx;
font-size: 20rpx;
color: #a9b4c0;
}
.eb-actions {
display: flex;
flex-shrink: 0;
margin-left: 20rpx;
}
// 参考图: 上方图标圆 + 下方文字(忽略/同意)
.eb-act-item {
display: flex;
flex-direction: column;
align-items: center;
&:first-child {
margin-right: 24rpx;
}
}
.eb-act {
width: 76rpx;
height: 76rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
box-sizing: border-box;
// 忽略: 白底细描边圆 + 灰色 ✕
&.eb-act-ignore {
background-color: #ffffff;
border: 2rpx solid #bcccdc;
color: #7b8794;
}
// 同意: 蓝底实心圆 + 白色 ✓
&.eb-act-agree {
background-color: #2aa5ff;
color: #ffffff;
}
}
.eb-act-text {
margin-top: 8rpx;
font-size: 20rpx;
line-height: 1.2;
color: #8a94a6;
}
}
/* 分享面板(微信式底部抽屉, 与 wap 留资抽屉同风格) */
.share-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 100;
opacity: 0;
pointer-events: none;
transition: opacity 0.25s;
}
.share-mask {
opacity: 1;
pointer-events: auto;
}
.share-sheet {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #ffffff;
border-radius: 24rpx 24rpx 0 0;
padding: 20rpx 32rpx 40rpx;
z-index: 101;
transform: translateY(100%);
transition: transform 0.25s;
&.share-sheet-show {
transform: translateY(0);
}
.ss-bar {
width: 36rpx;
height: 4rpx;
border-radius: 2rpx;
background-color: #e3e7ee;
margin: 0 auto 20rpx;
}
.ss-title {
font-size: 32rpx;
font-weight: 600;
color: #1a1f36;
text-align: center;
}
.ss-sub {
font-size: 24rpx;
color: #9aa4b8;
text-align: center;
margin: 8rpx 0 24rpx;
}
.ss-qr-box {
display: flex;
justify-content: center;
margin-bottom: 20rpx;
.ss-qr {
width: 320rpx;
height: 320rpx;
}
}
.ss-link {
font-size: 22rpx;
color: #9aa4b8;
background-color: #f6f7f9;
border-radius: 8rpx;
padding: 14rpx 20rpx;
margin-bottom: 24rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.ss-btns {
display: flex;
justify-content: space-between;
.ss-btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
text-align: center;
font-size: 28rpx;
color: #333;
border: 1rpx solid #dcdfe6;
border-radius: 12rpx;
// 「发给好友」在小程序端是原生 <button>: 清掉其默认 margin/padding/背景与 ::after 边框
margin: 0;
padding: 0;
background-color: transparent;
overflow: visible;
&::after {
border: none;
}
& + .ss-btn {
margin-left: 20rpx;
}
}
.ss-btn-main {
background-color: var(--main-color, #0054a5);
border-color: var(--main-color, #0054a5);
color: #ffffff;
}
}
.ss-tip {
text-align: center;
font-size: 22rpx;
color: #c0c4cc;
margin-top: 20rpx;
}
}
// 「发名片」主按钮: 全宽胶囊, 与名片卡左右对齐(24rpx)
.send-bar {
padding: 0 24rpx;
margin-top: 44rpx;
.send-btn {
display: block;
width: 100%;
height: 96rpx;
line-height: 96rpx;
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: #ffffff;
// 设计稿: 亮蓝渐变胶囊
background: linear-gradient(135deg, #2aa5ff 0%, #0d7bf0 100%);
box-shadow: 0 10rpx 24rpx rgba(13, 123, 240, 0.35);
border-radius: 48rpx;
// 小程序原生 <button> 自带 margin/padding/背景/::after 边框, 需清掉才能当普通块用
margin: 0;
padding: 0;
border: none;
&::after {
border: none;
}
}
}
.detail-loading {
text-align: center;
color: #999999;
font-size: 26rpx;
padding: 120rpx 0;
}
</style>