From 6f9ac29aa6502f17ab6d0ac9fc4087199a46e7b4 Mon Sep 17 00:00:00 2001
From: jing <1683105490@qq.com>
Date: Wed, 21 Oct 2026 18:16:49 +0800
Subject: [PATCH] =?UTF-8?q?chore=EF=BC=9A=E4=BA=8C=E7=BB=B4=E7=A0=81?=
=?UTF-8?q?=E4=BD=8D=E7=BD=AE=E5=92=8C=E5=90=8E=E5=8F=B0=E5=90=8C=E6=AD=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components-diy/diy-card-show.vue | 86 ++++++++++++++++++++++++++++++--
tests/diy-card-qr-style.test.js | 23 +++++++--
2 files changed, 102 insertions(+), 7 deletions(-)
diff --git a/components-diy/diy-card-show.vue b/components-diy/diy-card-show.vue
index ba99689..6f8308d 100644
--- a/components-diy/diy-card-show.vue
+++ b/components-diy/diy-card-show.vue
@@ -30,7 +30,8 @@
{{ card.name || '未命名名片' }}
{{ jobLine }}
-
+
+
{{ qrTipText }}
@@ -51,6 +52,18 @@
+
+
+
+ {{ qrTipText }}
+
+
+
+
+
+ {{ qrTipText }}
+
+
+
+
+
+ {{ qrTipText }}
+
+
发名片
@@ -102,7 +121,7 @@
// 图标资料行 + 卡外「发名片」胶囊。面板仅颜色/底色/圆角/阴影/行数继续生效。
import {
CardTokens, px2rpx, num, flagOn, initialOf, avatarBg, themeGradient, visibleRows, rowIconFor, rowActOf,
- resolveQrSize,
+ resolveQrSize, normalizeQrPosition, qrTransform,
} from './diy-card-common.js';
export default {
@@ -147,6 +166,24 @@ export default {
showQrBlock() {
return flagOn(this.c.showQr, true);
},
+ /** 二维码位置(四档, 与面板下拉/mini 基件同口径): rows 资料行下方 / head 头部右侧 /
+ * corner 右上角浮层 / bottom 主按钮上方; 未配置回落 rows(面板默认档) */
+ qrPos() {
+ return normalizeQrPosition(this.c.qrPosition);
+ },
+ /** 位置分档显隐(共用 showQrBlock + qr_url 前置) */
+ showQrBase() {
+ return this.showQrBlock && !!(this.card && this.card.qr_url);
+ },
+ showQrHead() { return this.showQrBase && this.qrPos === 'head'; },
+ showQrRows() { return this.showQrBase && this.qrPos === 'rows'; },
+ showQrCorner() { return this.showQrBase && this.qrPos === 'corner'; },
+ showQrBottom() { return this.showQrBase && this.qrPos === 'bottom'; },
+ /** 二维码微调(qrOffsetX/Y, 任一轴非零才输出 transform) */
+ qrShiftStyle() {
+ const t = qrTransform(this.c.qrOffsetX, this.c.qrOffsetY);
+ return t ? this.$util.objToStyle({ transform: t }) : '';
+ },
/** 二维码提示文字: 面板 qrTip, 未配置回落「扫码查看完整名片」 */
qrTipText() {
return this.c.qrTip || '扫码查看完整名片';
@@ -195,11 +232,12 @@ export default {
const card = this.card || {};
return card.job_title || card.company || card.card_title || '';
},
- /** 二维码边长: 面板 qrSize > 0 用自定义(px), 0/空 = 「按位自动」走头部右侧档(120rpx)。
+ /** 二维码边长: 面板 qrSize > 0 用自定义(px), 0/空 = 「按位自动」按位置档位取值
+ * (rows/bottom 180rpx, head/corner 120rpx, 见 common.QR_SIZES)。
* 之前用 num(qrSize, 48) 兜底 —— 面板默认 0 是合法数字不触发默认值,
* 算出 0rpx 宽高, 二维码图被渲染成 0 尺寸「看不见」 */
qrSide() {
- return resolveQrSize('head', this.c.qrSize);
+ return resolveQrSize(this.qrPos, this.c.qrSize);
},
qrImgStyle() {
return this.$util.objToStyle({
@@ -574,6 +612,46 @@ export default {
}
}
}
+
+ /* 右上角浮层档: 白底描边小卡浮在名片右上角(z-index 压过头部信息) */
+ .card-qr-corner {
+ position: absolute;
+ top: 20rpx;
+ right: 20rpx;
+ z-index: 2;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 10rpx;
+ background-color: #ffffff;
+ border: 2rpx solid #EEF0F3;
+ border-radius: 12rpx;
+ box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.10);
+
+ .qr-tip-corner {
+ font-size: 20rpx;
+ margin-top: 4rpx;
+ white-space: nowrap;
+ }
+ }
+ }
+
+ /* 资料行下方 / 主按钮上方档: 大码居中(边长走 qrImgStyle 内联) */
+ .qr-center {
+ margin-top: 24rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .qr-tip-c {
+ font-size: 22rpx;
+ margin-top: 8rpx;
+ }
+
+ /* 卡外(主按钮上方): 与上下元素拉开间距 */
+ &.qr-center-bottom {
+ margin: 32rpx 24rpx 0;
+ }
}
/* 发名片: 卡片外下方胶囊(背景色由 sendBtnStyle 内联) */
diff --git a/tests/diy-card-qr-style.test.js b/tests/diy-card-qr-style.test.js
index 936adad..08d7dcf 100644
--- a/tests/diy-card-qr-style.test.js
+++ b/tests/diy-card-qr-style.test.js
@@ -196,12 +196,29 @@ test('show: 快捷操作开关(面板「显示快捷操作」, 默认显示, 关
assert.match(showSrc, /@tap\.stop="doAct\(act\)"/);
});
+test('show: 二维码位置四档(与面板下拉/mini 基件同口径, 未配置回落 rows)', () => {
+ assert.match(showSrc, /qrPos\(\)\s*\{\s*return normalizeQrPosition\(this\.c\.qrPosition\)/);
+ // 四档各自的条件渲染块
+ assert.match(showSrc, /showQrHead\(\)\s*\{\s*return this\.showQrBase && this\.qrPos === 'head';\s*\}/);
+ assert.match(showSrc, /showQrRows\(\)\s*\{\s*return this\.showQrBase && this\.qrPos === 'rows';\s*\}/);
+ assert.match(showSrc, /showQrCorner\(\)\s*\{\s*return this\.showQrBase && this\.qrPos === 'corner';\s*\}/);
+ assert.match(showSrc, /showQrBottom\(\)\s*\{\s*return this\.showQrBase && this\.qrPos === 'bottom';\s*\}/);
+ // 模板四个位置都有落点(头部/资料行下/浮层/主按钮上方)
+ assert.match(showSrc, /v-if="showQrHead" class="card-qr"/);
+ assert.match(showSrc, /v-if="showQrRows" class="qr-center"/);
+ assert.match(showSrc, /v-if="showQrCorner" class="card-qr-corner"/);
+ assert.match(showSrc, /v-if="showQrBottom" class="qr-center qr-center-bottom"/);
+ // 微调位移(qrOffsetX/Y → transform)
+ assert.match(showSrc, /qrTransform\(this\.c\.qrOffsetX,\s*this\.c\.qrOffsetY\)/);
+});
+
test('show: 自绘版式自带小二维码(开关可关 + 点击进详情, 尺寸/提示文字面板可调)', () => {
assert.match(showSrc, /class="card-qr"/);
assert.match(showSrc, /\$util\.img\(card\.qr_url\)/);
// 二维码块受面板「显示二维码」开关控制(与头像/资料行/快捷操作同口径: flagOn 默认显示)
assert.match(showSrc, /showQrBlock\(\)\s*\{\s*return flagOn\(this\.c\.showQr,\s*true\)/);
- assert.match(showSrc, /v-if="showQrBlock && card\.qr_url" class="card-qr"/);
+ // 开关 + 位置统一收敛在 showQrBase / showQrHead 等分档计算属性里(模板只消费分档结果)
+ assert.match(showSrc, /showQrBase\(\)\s*\{\s*return this\.showQrBlock && !!\(this\.card && this\.card\.qr_url\)/);
// 提示文字消费面板 qrTip, 未配置回落「扫码查看完整名片」(与 mini 基件同口径)
assert.match(showSrc, /qrTipText\(\)\s*\{\s*return this\.c\.qrTip \|\| '扫码查看完整名片';/);
// 点二维码弹「分享名片」抽屉(复刻 detail.vue: 码 + 链接 + 复制链接/浏览器分享/保存二维码)
@@ -211,10 +228,10 @@ test('show: 自绘版式自带小二维码(开关可关 + 点击进详情, 尺
assert.match(showSrc, /分享名片<\/view>/);
assert.match(showSrc, /客户打开链接即可查看名片并留言留资/);
assert.match(showSrc, /copyCardLink\(\)\s*\{\s*const url = \(this\.card && this\.card\.wap_url\) \|\| '';/);
- // 尺寸走 resolveQrSize: 面板 qrSize>0 用自定义, 0/空 = 自动档(head 120rpx)。
+ // 尺寸走 resolveQrSize: 面板 qrSize>0 用自定义, 0/空 = 按位置档位自动(rows/bottom 180, head/corner 120)。
// 反例形态: 不允许 num(qrSize, 48) 兜底 —— 面板默认 0 是合法数字, 会算出 0rpx 宽高,
// 二维码图渲染成 0 尺寸「看不见」(2026-10-21 线上问题)
- assert.match(showSrc, /qrSide\(\)\s*\{\s*return resolveQrSize\('head',\s*this\.c\.qrSize\)/);
+ assert.match(showSrc, /qrSide\(\)\s*\{\s*return resolveQrSize\(this\.qrPos,\s*this\.c\.qrSize\)/);
assert.ok(!showSrc.includes("num(this.c.qrSize"));
});