chore:名片样式第一个背景

This commit is contained in:
2026-10-15 10:18:04 +08:00
parent e8fc1aca06
commit 5a009130e6
3 changed files with 123 additions and 7 deletions

View File

@@ -401,6 +401,31 @@ export default {
});
// #endif
},
/**
* 契约 §4(2026-10-15): 同意后跳对方公开名片页。
* wap_url 原样使用(后端已带 ?site_id=..&card_id=..), 前端唯一允许的改动是追加
* &back_url=encodeURIComponent(我方名片页完整地址); wap_url 为空(对方刚删卡等)
* 则交给调用方: 人脉已互建, 不跳转只 toast 成功。
*/
jumpToOtherPublic(wapUrl) {
if (!wapUrl) return;
let url = wapUrl;
const back = this.myPageFullUrl();
if (back) {
url += (wapUrl.indexOf('?') >= 0 ? '&' : '?') + 'back_url=' + encodeURIComponent(back);
}
this.gotoPublic(url);
},
// 我方名片页完整地址: H5 运行时取 window.location.href(禁止写死域名, 部署/测试环境不同);
// 非 H5(小程序/App) 无等价 H5 地址, 返回 '' 由 share.vue 中转页原生返回。
myPageFullUrl() {
// #ifdef H5
return window.location.href;
// #endif
// #ifndef H5
return '';
// #endif
},
/**
* 详情接口非 0(未登录/非本人名下/卡片不存在): 后端报错信封照样返回 wap_url,
* 据此匿名落地到公开页(可看、可提交交换请求), 不出现死路。
@@ -506,8 +531,11 @@ export default {
const txt = d.receiver_created === 0 ? '已交换(人脉已存在)' : '已交换,人脉已互加';
uni.showToast({ title: txt, icon: 'none' });
this.loadExchange();
// 参考图: 同意后展示对方的公开名片页(含「企业介绍 / 收下名片」面板)
this.openPublicCard(item.from_card_id);
// 契约 §4(2026-10-15): 同意后用响应里的 wap_url 跳对方公开名片页,
// 仅追加 &back_url=(encodeURIComponent 我方名片页完整地址); wap_url 为空不跳转
if (d.wap_url) {
this.jumpToOtherPublic(d.wap_url);
}
} else if (res.message) {
// 请求已被处理/不存在/对方名片失效: 直接提示后端文案, 不二次弹「没有待处理请求」
uni.showToast({ title: res.message, icon: 'none' });

View File

@@ -117,6 +117,36 @@ export default {
url: '/pages_tool/card/detail?card_id=' + encodeURIComponent(item.from_card_id)
});
},
/**
* 契约 §4(2026-10-15): 同意后跳对方公开名片页。
* wap_url 原样使用, 仅追加 &back_url=encodeURIComponent(我方名片页完整地址);
* wap_url 为空则不跳转(对方刚删卡等, 人脉已互建)。
*/
jumpToOtherPublic(wapUrl) {
if (!wapUrl) return;
let url = wapUrl;
const back = this.myPageFullUrl();
if (back) {
url += (wapUrl.indexOf('?') >= 0 ? '&' : '?') + 'back_url=' + encodeURIComponent(back);
}
// #ifdef H5
window.location.href = url;
// #endif
// #ifndef H5
uni.navigateTo({
url: '/pages_tool/card/share?url=' + encodeURIComponent(url)
});
// #endif
},
// H5: 当前页面完整地址(禁止写死域名); 非 H5 无等价 H5 地址返回 '' 由 share.vue 中转页原生返回
myPageFullUrl() {
// #ifdef H5
return window.location.href;
// #endif
// #ifndef H5
return '';
// #endif
},
onAgree(item) {
this.$cardApi.exchangeAgree({
data: { id: item.id },
@@ -126,7 +156,13 @@ export default {
const d = res.data || {};
const txt = d.receiver_created === 0 ? '已交换(人脉已存在)' : '已交换,人脉已互加';
uni.showToast({ title: txt, icon: 'none' });
this.loadList();
// 契约 §4(2026-10-15): 同意后用响应里的 wap_url 跳对方公开名片页,
// 仅追加 &back_url=; wap_url 为空则退回刷新列表(对方刚删卡等)
if (d.wap_url) {
this.jumpToOtherPublic(d.wap_url);
} else {
this.loadList();
}
} else if (res.message) {
uni.showToast({ title: res.message, icon: 'none' });
}

View File

@@ -12,6 +12,8 @@
- 卡面底色跟随「选择背景」
- 选中的模板决定版式(pv-classic = 第一个模板, 参考图的纸感居中版) -->
<view class="cs-preview" :class="'pv-' + previewTplType" :style="previewStyle">
<!-- 特种纸肌理层: 真实可平铺纤维纹理图(参考图同款棉絮纸), 置于文字之下 -->
<image v-if="previewBgTexture" class="cs-preview-texture" :src="paperTexture" />
<text class="cs-name">{{ card.name }}</text>
<text class="cs-job">{{ card.job_title }}</text>
<text class="cs-company">{{ card.company }}</text>
@@ -65,8 +67,9 @@
<scroll-view scroll-x class="cs-scroll">
<view class="cs-thumbs">
<view v-for="bg in backgrounds" :key="bg.id" class="cs-thumb"
:style="'background-color:' + bg.color + ';' + (bg.border ? 'border:2rpx solid ' + bg.border + ';' : '')"
:style="bgStyle(bg)"
@tap="selectBg(bg.id)">
<image v-if="bg.texture" class="cs-thumb-texture" :src="paperTexture" />
<view v-if="selectedBg === bg.id" class="cs-check">
<view class="cs-check-mark"></view>
</view>
@@ -116,6 +119,8 @@ export default {
return {
seg: 'tpl',
cardId: '',
// 特种纸肌理图(可平铺棉絮纸纹理, scripts/gen-paper-texture.js 生成)
paperTexture: '/static/images/paper-fiber.png',
// 名片资料(真实数据, 由 loadCard 回填)
card: {
name: '',
@@ -136,8 +141,9 @@ export default {
// 默认选中第一个(参考图)
selectedTpl: 't1',
backgrounds: [
// 第一个背景 = 参考图样式(纸感米色), 选中后改变卡面底色
{ id: 'b1', color: '#ece5db' },
// 第一个背景 = 参考图样式: 暖调奶油本白的特种纸(棉絮纸/肌理纸),
// texture: true 时叠加云絮状纤维斑纹(无规则网点), 选中后改变卡面底色
{ id: 'b1', color: '#F3EFE7', texture: true },
{ id: 'b2', color: '#c9ced6' },
{ id: 'b3', color: '#243b5e' },
{ id: 'b4', color: '#8b95a3' },
@@ -162,12 +168,17 @@ export default {
// 卡面底色跟随「选择背景」; 姓名/资料内容始终原样, 不随模板改变
previewStyle() {
const bg = this.backgrounds.find(item => item.id === this.selectedBg);
return bg ? 'background-color:' + bg.color + ';' : '';
return bg ? this.bgStyle(bg) : '';
},
// 当前选中模板的类型(classic/photo/lines/dark/navy), 决定预览的版式类 pv-*
previewTplType() {
const tpl = this.templates.find(item => item.id === this.selectedTpl);
return tpl ? tpl.type : 'classic';
},
// 选中背景是否带特种纸肌理(叠加 paper-fiber 纹理图)
previewBgTexture() {
const bg = this.backgrounds.find(item => item.id === this.selectedBg);
return !!(bg && bg.texture);
}
},
methods: {
@@ -207,6 +218,19 @@ export default {
selectBg(id) {
this.selectedBg = id;
},
/**
* 背景色块/预览卡共用的内联样式(只管底色与描边)。
* texture: true 的肌理由 paper-fiber 纹理图以 <image> 层叠加(见模板),
* 不再用 CSS 渐变模拟 —— 真实纤维纹理才能和参考图一致。
*/
bgStyle(bg) {
if (!bg) return '';
let style = 'background-color:' + bg.color + ';';
if (bg.border) {
style += 'border:2rpx solid ' + bg.border + ';';
}
return style;
},
selectCover(id) {
this.selectedCover = id;
},
@@ -257,6 +281,7 @@ export default {
// 名片预览: 白底 + 蓝色粗描边(姓名/资料原样, 仅底色可被背景覆盖)
.cs-preview {
position: relative;
margin-top: 24rpx;
padding: 32rpx 28rpx;
background-color: #ffffff;
@@ -264,6 +289,24 @@ export default {
border-radius: 12rpx;
box-sizing: border-box;
// 特种纸肌理层: 铺满卡面, 压在底色上、文字下(后续兄弟节点设 relative 保证盖在纹理上)
.cs-preview-texture {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border-radius: 12rpx;
}
> .cs-name,
> .cs-job,
> .cs-company,
> .cs-divider,
> .cs-row {
position: relative;
}
.cs-name {
display: block;
font-size: 44rpx;
@@ -449,6 +492,15 @@ export default {
background-color: #ffffff;
border: 2rpx solid #e8ebee;
// 特种纸肌理层: 铺满色块, 选中角标(.cs-check)在 DOM 之后仍盖在其上
.cs-thumb-texture {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
// 模板内部线条示意
.tpl-inner {
padding: 18rpx 16rpx;