From 5a009130e658866a1bc66226d79f5e740898f9b0 Mon Sep 17 00:00:00 2001 From: jing <1683105490@qq.com> Date: Thu, 15 Oct 2026 10:18:04 +0800 Subject: [PATCH] =?UTF-8?q?chore=EF=BC=9A=E5=90=8D=E7=89=87=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E7=AC=AC=E4=B8=80=E4=B8=AA=E8=83=8C=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages_tool/card/detail.vue | 32 +++++++++++++++++-- pages_tool/card/exchange.vue | 38 ++++++++++++++++++++++- pages_tool/card/style.vue | 60 +++++++++++++++++++++++++++++++++--- 3 files changed, 123 insertions(+), 7 deletions(-) diff --git a/pages_tool/card/detail.vue b/pages_tool/card/detail.vue index 35ff768..0775e5d 100644 --- a/pages_tool/card/detail.vue +++ b/pages_tool/card/detail.vue @@ -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' }); diff --git a/pages_tool/card/exchange.vue b/pages_tool/card/exchange.vue index a582f1f..ee02ba3 100644 --- a/pages_tool/card/exchange.vue +++ b/pages_tool/card/exchange.vue @@ -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' }); } diff --git a/pages_tool/card/style.vue b/pages_tool/card/style.vue index ac44361..eef8555 100644 --- a/pages_tool/card/style.vue +++ b/pages_tool/card/style.vue @@ -12,6 +12,8 @@ - 卡面底色跟随「选择背景」 - 选中的模板决定版式(pv-classic = 第一个模板, 参考图的纸感居中版) --> + + {{ card.name }} {{ card.job_title }} {{ card.company }} @@ -65,8 +67,9 @@ + @@ -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 纹理图以 层叠加(见模板), + * 不再用 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;