956 lines
25 KiB
Vue
956 lines
25 KiB
Vue
<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-divider"></view>
|
||
<view class="ca-item" @tap="onStyleTap">
|
||
<text class="ca-icon iconfont icon-erweima"></text>
|
||
<text>名片样式</text>
|
||
</view>
|
||
<view class="ca-divider"></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>
|
||
|
||
<!-- 交换名片请求提醒条(参考图: 宫格下方出现对方要交换的名片) -->
|
||
<!-- 数据先用假数据占位(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">
|
||
<!-- ✕ 用 CSS 画, 避免字体图标自带圆圈 -->
|
||
<view class="eb-x">
|
||
<view class="eb-x-line"></view>
|
||
<view class="eb-x-line"></view>
|
||
</view>
|
||
</view>
|
||
<text class="eb-act-text">忽略</text>
|
||
</view>
|
||
<view class="eb-act-item" @tap.stop="onAgreeExchange">
|
||
<view class="eb-act eb-act-agree">
|
||
<!-- ✓ 用 CSS 画, 避免字体图标自带圆圈 -->
|
||
<view class="eb-check"></view>
|
||
</view>
|
||
<text class="eb-act-text eb-act-text-main">同意</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() {
|
||
const url = this.cardId
|
||
? '/pages_tool/card/style?card_id=' + encodeURIComponent(this.cardId)
|
||
: '/pages_tool/card/style';
|
||
uni.navigateTo({ url: url });
|
||
},
|
||
// 「交换名片」提醒条: 点右侧箭头/整条 → 进入交换请求列表页
|
||
goExchangeReq() {
|
||
uni.navigateTo({ url: '/pages_tool/card/exchange' });
|
||
},
|
||
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;
|
||
}
|
||
}
|
||
|
||
// 参考图: 项与项之间一根浅灰竖线(约半个字高)
|
||
.ca-divider {
|
||
width: 2rpx;
|
||
height: 28rpx;
|
||
flex-shrink: 0;
|
||
background-color: #e5e7eb;
|
||
}
|
||
}
|
||
|
||
// 发名片下方的功能入口宫格: 五等分, 图标在上、文字在下
|
||
.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;
|
||
box-sizing: border-box;
|
||
|
||
// 忽略: 白底细描边圆 + 灰色 ✕
|
||
&.eb-act-ignore {
|
||
background-color: #ffffff;
|
||
border: 2rpx solid #dfe4ea;
|
||
}
|
||
|
||
// 同意: 蓝底实心圆 + 白色 ✓
|
||
&.eb-act-agree {
|
||
background-color: #2aa5ff;
|
||
}
|
||
}
|
||
|
||
// 参考图: ✕ 用 CSS 画(两条交叉短线), 不用字体图标以免自带圆圈
|
||
.eb-x {
|
||
position: relative;
|
||
width: 34rpx;
|
||
height: 34rpx;
|
||
|
||
.eb-x-line {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 3rpx;
|
||
margin-top: -1.5rpx;
|
||
border-radius: 3rpx;
|
||
background-color: #5a6572;
|
||
|
||
&:first-child {
|
||
transform: rotate(45deg);
|
||
}
|
||
|
||
&:last-child {
|
||
transform: rotate(-45deg);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 参考图: ✓ 用 CSS 画(左下两边框的方块旋转 -45°)
|
||
.eb-check {
|
||
width: 24rpx;
|
||
height: 12rpx;
|
||
margin-top: -6rpx;
|
||
border-left: 5rpx solid #ffffff;
|
||
border-bottom: 5rpx solid #ffffff;
|
||
transform: rotate(-45deg);
|
||
}
|
||
|
||
.eb-act-text {
|
||
margin-top: 8rpx;
|
||
font-size: 20rpx;
|
||
line-height: 1.2;
|
||
color: #8a94a6;
|
||
}
|
||
|
||
// 参考图: 「同意」文字为蓝色, 「忽略」为灰色
|
||
.eb-act-text-main {
|
||
color: #2aa5ff;
|
||
}
|
||
}
|
||
|
||
/* 分享面板(微信式底部抽屉, 与 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>
|