feat(card-diy): 2.19.10 C 端消费 detail 对齐 + 区块独立样式字段
- mini.vue: 8 detail 字段消费(三列行/复制范围外观/QR 多行/URL 行/hero 徽章) + rowsBlockStyle/qrBlockCustomStyle computed(与操作区 actsBlockStyle 同款模式) + rowsFinalStyle/qrBlockFinalStyle 合并独立块样式 - show.vue/self.vue: miniConfig 透传 14 字段(8 detail + 6 独立样式) - 测试 ×3: 2.19.10 契约锁(配置层/透传/面板/预览消费/反例: layoutCards 已移除) 前端 7 套 123 项全绿
This commit is contained in:
@@ -44,13 +44,17 @@
|
||||
<!-- 二维码·右上角浮层(corner 档: 外观由 qrStyle 决定, 资料行自动让位; 点击预览名片) -->
|
||||
<view v-if="showQrCorner" class="mini-qr mini-qr-corner" :style="qrBlockStyle" @tap.stop="onQrTap">
|
||||
<image class="qr-img" :style="qrImgStyle" :src="$util.img(qrSrc)" mode="aspectFit" />
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle">{{ qrTip || '扫码查看完整名片' }}</text>
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle"><text v-if="qrTipEm" class="qr-tip-em" :style="qrTipEmStyle">{{ qrTipEm }}</text>{{ qrTipLine1 }}</text><text v-if="qrTipSub" class="qr-tip-sub" :style="labelStyle">{{ qrTipSub }}</text><text v-if="qrUrlShow && qrUrlText" class="qr-url" :style="qrUrlStyle">{{ qrUrlText }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 头部·主题渐变整块档(theme): 渐变通铺卡边 + 装饰圆, plain 档不渲染 -->
|
||||
<view v-if="headTheme" class="mini-headtheme" :style="headThemeStyle">
|
||||
<view class="headtheme-decor headtheme-decor--big"></view>
|
||||
<view class="headtheme-decor headtheme-decor--small"></view>
|
||||
<view v-if="badgeShow" class="mini-hero-badge" :style="heroBadgeStyle">
|
||||
<view class="hero-badge-dot"></view>
|
||||
<text class="hero-badge-text" :style="heroBadgeTextStyle">{{ badgeText }}</text>
|
||||
</view>
|
||||
<view class="mini-head" :style="cornerHeadStyle">
|
||||
<view v-if="showAvatarBlock" class="mini-avatar" :style="avatarStyle">
|
||||
<image v-if="card.avatar" class="avatar-img" :src="$util.img(card.avatar)" mode="aspectFill" />
|
||||
@@ -67,13 +71,17 @@
|
||||
<!-- 二维码·头部右侧(head 档: 头像|信息|二维码 三段 flex, 零遮挡) -->
|
||||
<view v-if="showQrHead" class="mini-qr mini-qr-head" :style="qrBlockStyle">
|
||||
<image class="qr-img" :style="qrImgStyle" :src="$util.img(qrSrc)" mode="aspectFit" />
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle">{{ qrTip || '扫码查看完整名片' }}</text>
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle"><text v-if="qrTipEm" class="qr-tip-em" :style="qrTipEmStyle">{{ qrTipEm }}</text>{{ qrTipLine1 }}</text><text v-if="qrTipSub" class="qr-tip-sub" :style="labelStyle">{{ qrTipSub }}</text><text v-if="qrUrlShow && qrUrlText" class="qr-url" :style="qrUrlStyle">{{ qrUrlText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 头部·白卡档(plain, 历史默认) -->
|
||||
<view v-if="!headTheme" class="mini-head" :style="cornerHeadStyle">
|
||||
<view v-if="!headTheme && badgeShow" class="mini-hero-badge" :style="heroBadgeStyle">
|
||||
<view class="hero-badge-dot"></view>
|
||||
<text class="hero-badge-text" :style="heroBadgeTextStyle">{{ badgeText }}</text>
|
||||
</view>
|
||||
<view v-if="!headTheme" class="mini-head" :style="plainHeadFinalStyle">
|
||||
<view v-if="showAvatarBlock" class="mini-avatar" :style="avatarStyle">
|
||||
<image v-if="card.avatar" class="avatar-img" :src="$util.img(card.avatar)" mode="aspectFill" />
|
||||
<text v-else class="avatar-initial">{{ initialOf(card.name) }}</text>
|
||||
@@ -89,7 +97,7 @@
|
||||
<!-- 二维码·头部右侧(head 档: 头像|信息|二维码 三段 flex, 零遮挡; 点击预览名片) -->
|
||||
<view v-if="showQrHead" class="mini-qr mini-qr-head" :style="qrBlockStyle" @tap.stop="onQrTap">
|
||||
<image class="qr-img" :style="qrImgStyle" :src="$util.img(qrSrc)" mode="aspectFit" />
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle">{{ qrTip || '扫码查看完整名片' }}</text>
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle"><text v-if="qrTipEm" class="qr-tip-em" :style="qrTipEmStyle">{{ qrTipEm }}</text>{{ qrTipLine1 }}</text><text v-if="qrTipSub" class="qr-tip-sub" :style="labelStyle">{{ qrTipSub }}</text><text v-if="qrUrlShow && qrUrlText" class="qr-url" :style="qrUrlStyle">{{ qrUrlText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -114,14 +122,14 @@
|
||||
</view>
|
||||
|
||||
<!-- 资料行(可折叠; 有字形字段显图标, 无字形退化为文字标签) -->
|
||||
<view v-if="showRowsBlock && shownRows.length" class="mini-rows" :style="rowsClearStyle">
|
||||
<view v-if="showRowsBlock && shownRows.length" class="mini-rows" :style="rowsFinalStyle">
|
||||
<!-- 资料区标题(2.17 可选): 主题色竖条 + 标题 -->
|
||||
<view v-if="rowsTitleShow" class="mini-rows-title">
|
||||
<view class="rows-title-bar" :style="rowsTitleBarStyle"></view>
|
||||
<text class="rows-title-text" :style="rowsTitleStyle">{{ rowsTitle }}</text>
|
||||
</view>
|
||||
<view v-for="(row, i) in shownRows" :key="i" class="mini-row"
|
||||
:class="{ 'row-tappable': rowTapable(row) }" :hover-class="rowTapable(row) ? 'btn-press' : 'none'" @tap="onRowTap(row)">
|
||||
:class="{ 'row-tappable': rowTapable(row), 'row-3col': showRowLabels }" :hover-class="rowTapable(row) ? 'btn-press' : 'none'" @tap="onRowTap(row)">
|
||||
<!-- CSS 描边图标档(2.17.1): 邮箱/网站无 iconfont 字形, 纯 view 绘制 -->
|
||||
<view v-if="rowCssIcon(row)" class="row-css-wrap">
|
||||
<view v-if="rowCssIcon(row) === 'mail'" class="css-ico-mail css-ico-mail--row" :style="rowCssBorderStyle(row)">
|
||||
@@ -133,9 +141,9 @@
|
||||
</view>
|
||||
</view>
|
||||
<text v-else-if="rowIcon(row)" class="row-icon iconfont" :class="rowIcon(row)" :style="labelStyle"></text>
|
||||
<text v-else class="row-label" :style="rowLabelStyle">{{ row.label }}</text>
|
||||
<text v-if="showRowLabels || (!rowCssIcon(row) && !rowIcon(row))" class="row-label" :style="rowLabelStyle">{{ row.label }}</text>
|
||||
<text class="row-value" :style="valueStyle">{{ row.value }}</text>
|
||||
<text v-if="showCopyBtn && row.value" class="row-copy" :style="copyBtnStyle" @tap.stop="onCopyRow(row)">复制</text>
|
||||
<text v-if="copyBtnVisible(row)" class="row-copy" :style="copyBtnStyle" @tap.stop="onCopyRow(row)">复制</text>
|
||||
</view>
|
||||
<view v-if="hasMoreRows" class="row-toggle" hover-class="btn-press" @tap="expanded = !expanded">
|
||||
<text class="toggle-text" :style="toggleStyle">{{ expanded ? '收起资料' : '展开全部资料(' + hiddenCount + ')' }}</text>
|
||||
@@ -143,9 +151,9 @@
|
||||
</view>
|
||||
|
||||
<!-- 二维码·资料行下方(rows 档, 默认; 点击预览名片); mini-qr-center: 块级居中 -->
|
||||
<view v-if="showQrRows" class="mini-qr mini-qr-center" :style="qrBlockStyle" @tap.stop="onQrTap">
|
||||
<view v-if="showQrRows" class="mini-qr mini-qr-center" :style="qrBlockFinalStyle" @tap.stop="onQrTap">
|
||||
<image class="qr-img" :style="qrImgStyle" :src="$util.img(qrSrc)" mode="aspectFit" />
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle">{{ qrTip || '扫码查看完整名片' }}</text>
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle"><text v-if="qrTipEm" class="qr-tip-em" :style="qrTipEmStyle">{{ qrTipEm }}</text>{{ qrTipLine1 }}</text><text v-if="qrTipSub" class="qr-tip-sub" :style="labelStyle">{{ qrTipSub }}</text><text v-if="qrUrlShow && qrUrlText" class="qr-url" :style="qrUrlStyle">{{ qrUrlText }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 快捷操作·图标宫格档(grid): 彩色浅底图标 + 下方文字 -->
|
||||
@@ -171,9 +179,9 @@
|
||||
</view>
|
||||
|
||||
<!-- 二维码·主按钮上方(bottom 档; 点击预览名片) -->
|
||||
<view v-if="showQrBottom" class="mini-qr mini-qr-center" :style="qrBlockStyle" @tap.stop="onQrTap">
|
||||
<view v-if="showQrBottom" class="mini-qr mini-qr-center" :style="qrBlockFinalStyle" @tap.stop="onQrTap">
|
||||
<image class="qr-img" :style="qrImgStyle" :src="$util.img(qrSrc)" mode="aspectFit" />
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle">{{ qrTip || '扫码查看完整名片' }}</text>
|
||||
<text v-if="showQrTip" class="qr-tip" :style="labelStyle"><text v-if="qrTipEm" class="qr-tip-em" :style="qrTipEmStyle">{{ qrTipEm }}</text>{{ qrTipLine1 }}</text><text v-if="qrTipSub" class="qr-tip-sub" :style="labelStyle">{{ qrTipSub }}</text><text v-if="qrUrlShow && qrUrlText" class="qr-url" :style="qrUrlStyle">{{ qrUrlText }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 发名片(对齐名片详情页: 主题色大按钮; 点击跳原生转发中转页拉起微信转发面板) -->
|
||||
@@ -429,6 +437,47 @@ export default {
|
||||
qrTip() {
|
||||
return this.c.qrTip || '';
|
||||
},
|
||||
// ===== 2.19.10 detail 版式对齐字段 =====
|
||||
/** 资料行三列(图标+灰标签+值, detail 同款): 默认 0 = 历史图标/标签二选一 */
|
||||
showRowLabels() {
|
||||
return flagOn(this.c.showRowLabels, false);
|
||||
},
|
||||
/** hero 徽章(左上「数字名片」): 默认关 */
|
||||
badgeShow() {
|
||||
return flagOn(this.c.badgeShow, false);
|
||||
},
|
||||
badgeText() {
|
||||
return String(this.c.badgeText || '数字名片');
|
||||
},
|
||||
/** 提示加粗段(detail <b>扫码保存名片</b>); 空 = 整行走 qrTip(历史形态) */
|
||||
qrTipEm() {
|
||||
return String(this.c.qrTipEm || '').trim();
|
||||
},
|
||||
/** 提示第一行(加粗段之后): 有 em 时前置「 · 」分隔符 */
|
||||
qrTipLine1() {
|
||||
const tip = String(this.c.qrTip || '').trim();
|
||||
if (this.qrTipEm) return tip ? (' · ' + tip) : '';
|
||||
return tip || '扫码查看完整名片';
|
||||
},
|
||||
/** 提示第二行(detail「同一二维码可写入 NFC 名片贴」): 空 = 不出 */
|
||||
qrTipSub() {
|
||||
return String(this.c.qrTipSub || '').trim();
|
||||
},
|
||||
/** 二维码下 URL 文本行(detail qr-url 同款): 默认关 */
|
||||
qrUrlShow() {
|
||||
return flagOn(this.c.qrUrlShow, false);
|
||||
},
|
||||
qrUrlText() {
|
||||
return (this.card && this.card.wap_url) || '';
|
||||
},
|
||||
/** 复制按钮范围: all=全部行(历史) / mobile=仅手机微信行(detail 口径) */
|
||||
copyBtnScope() {
|
||||
return String(this.c.copyBtnScope || 'all');
|
||||
},
|
||||
/** 复制按钮外观: theme=主题浅底(历史) / gray=浅灰描边胶囊(detail 同款) */
|
||||
copyBtnLook() {
|
||||
return String(this.c.copyBtnLook || 'theme');
|
||||
},
|
||||
detailBtnText() {
|
||||
return this.c.detailBtnText || '';
|
||||
},
|
||||
@@ -586,14 +635,52 @@ export default {
|
||||
fontWeight: '600',
|
||||
});
|
||||
},
|
||||
/** 复制按钮: 主题浅底 + 主题色字(hexToRgba 动态派生, WXSS 无 color-mix) */
|
||||
/** 复制按钮: theme=主题浅底+主题色字(历史); gray=detail 同款浅灰描边胶囊 */
|
||||
copyBtnStyle() {
|
||||
if (this.copyBtnLook === 'gray') {
|
||||
return this.$util.objToStyle({
|
||||
background: '#F7F9FC',
|
||||
color: '#5A6478',
|
||||
border: '2rpx solid #EEF1F6',
|
||||
});
|
||||
}
|
||||
const theme = (this.card && this.card.theme_color) || CardTokens.color.primary;
|
||||
return this.$util.objToStyle({
|
||||
background: hexToRgba(theme, 0.12) || '#F2F3F5',
|
||||
color: theme,
|
||||
});
|
||||
},
|
||||
/** 提示加粗段样式(detail qr-tip b 同款: ink-2 深灰 + 加粗) */
|
||||
qrTipEmStyle() {
|
||||
return this.$util.objToStyle({
|
||||
color: this.c.infoColor || '#5A6478',
|
||||
fontWeight: '600',
|
||||
});
|
||||
},
|
||||
/** 二维码 URL 行样式(detail qr-url 同款: 小字灰 + 断行) */
|
||||
qrUrlStyle() {
|
||||
return this.$util.objToStyle({
|
||||
color: this.c.labelColor || CardTokens.color.textLabel,
|
||||
fontSize: px2rpx(10) + 'rpx',
|
||||
marginTop: px2rpx(8) + 'rpx',
|
||||
wordBreak: 'break-all',
|
||||
textAlign: 'center',
|
||||
});
|
||||
},
|
||||
/** hero 徽章胶囊(theme 档白描边 / plain 档主题描边; 避让企业徽标 badgeStyle) */
|
||||
heroBadgeStyle() {
|
||||
const theme = (this.card && this.card.theme_color) || CardTokens.color.primary;
|
||||
return this.$util.objToStyle({
|
||||
border: '2rpx solid ' + (this.headTheme ? 'rgba(255,255,255,0.35)' : (hexToRgba(theme, 0.35) || theme)),
|
||||
});
|
||||
},
|
||||
heroBadgeTextStyle() {
|
||||
return this.$util.objToStyle({
|
||||
color: this.headTheme ? 'rgba(255,255,255,0.85)' : (this.c.labelColor || CardTokens.color.textLabel),
|
||||
fontSize: px2rpx(11) + 'rpx',
|
||||
letterSpacing: '2rpx',
|
||||
});
|
||||
},
|
||||
badgeStyle() {
|
||||
// 企业徽标固定红底(参考图 2026-10-22 口径), 与头像底色解耦
|
||||
return this.$util.objToStyle({ background: '#FA5151' });
|
||||
@@ -692,6 +779,47 @@ export default {
|
||||
const extra = clear.marginTop ? 'margin-top: ' + clear.marginTop + ';' : '';
|
||||
return ((this.actsBlockStyle || '') + ' ' + extra).trim();
|
||||
},
|
||||
/** 资料区独立块样式(与操作区同款: Bg/Radius/Pad) */
|
||||
rowsBlockStyle() {
|
||||
const c = this.c;
|
||||
const bg = String(c.rowsBlockBg || '').trim();
|
||||
const radius = num(c.rowsBlockRadius, 0);
|
||||
const pad = num(c.rowsBlockPad, 0);
|
||||
const style = {};
|
||||
if (bg) style.background = bg;
|
||||
if (radius > 0) style.borderRadius = px2rpx(radius) + 'rpx';
|
||||
if (pad > 0) style.padding = px2rpx(pad) + 'rpx';
|
||||
return this.$util.objToStyle(style);
|
||||
},
|
||||
/** 二维码独立块样式(与操作区同款: Bg/Radius/Pad) */
|
||||
qrBlockCustomStyle() {
|
||||
const c = this.c;
|
||||
const bg = String(c.qrBlockBg || '').trim();
|
||||
const radius = num(c.qrBlockRadius, 0);
|
||||
const pad = num(c.qrBlockPad, 0);
|
||||
const style = {};
|
||||
if (bg) style.background = bg;
|
||||
if (radius > 0) style.borderRadius = px2rpx(radius) + 'rpx';
|
||||
if (pad > 0) style.padding = px2rpx(pad) + 'rpx';
|
||||
return this.$util.objToStyle(style);
|
||||
},
|
||||
/** 资料区最终样式: 独立块样式 + corner 让位合并 */
|
||||
rowsFinalStyle() {
|
||||
const clear = this.rowsClearStyle || {};
|
||||
const extra = clear.marginTop ? 'margin-top: ' + clear.marginTop + ';' : '';
|
||||
return ((this.rowsBlockStyle || '') + ' ' + extra).trim();
|
||||
},
|
||||
/** 二维码(rows/bottom 流内档)最终样式: 独立块样式 + 尺寸/位移合并 */
|
||||
qrBlockFinalStyle() {
|
||||
const transform = qrTransform(this.c.qrOffsetX, this.c.qrOffsetY);
|
||||
const parts = [this.qrBlockStyle, this.qrBlockCustomStyle];
|
||||
if (transform) parts.push('transform:' + transform + ';');
|
||||
return parts.filter(Boolean).join(' ').trim();
|
||||
},
|
||||
/** plain 头最终样式 */
|
||||
plainHeadFinalStyle() {
|
||||
return this.cornerHeadStyle;
|
||||
},
|
||||
detailBtnStyle() {
|
||||
// 发送名片大按钮: 纯色主题实心(2026-10-22 参考图定稿, 不再用渐变);
|
||||
// 高度 104rpx(用户反馈: 比触达标准 80rpx 加高一档, 参考图观感)
|
||||
@@ -875,6 +1003,15 @@ export default {
|
||||
fontSize: px2rpx(num(this.c.actSize, 12)) + 'rpx',
|
||||
});
|
||||
},
|
||||
/** 复制按钮可见性: 开关 + 值非空 + 范围(mobile=仅手机/微信行, detail 口径) */
|
||||
copyBtnVisible(row) {
|
||||
if (!this.showCopyBtn || !row || !String(row.value || '').trim()) return false;
|
||||
if (this.copyBtnScope === 'mobile') {
|
||||
const f = String(row.field || '').toLowerCase();
|
||||
return f === 'mobile' || f === 'phone' || f === 'wechat' || f === 'wx';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
/** 复制按钮: 复用 row-act 的 copy 分支(rowTap 关闭时仍可独立复制) */
|
||||
onCopyRow(row) {
|
||||
this.$emit('row-act', { type: 'copy', value: row.value });
|
||||
@@ -1046,6 +1183,42 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/* 2.19.10 hero 徽章(detail hero-badge 同款: 绿点 + 描边胶囊) */
|
||||
.mini-hero-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
align-self: flex-start;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 6rpx 18rpx;
|
||||
border-radius: 999rpx;
|
||||
|
||||
.hero-badge-dot {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
border-radius: 50%;
|
||||
background: #07c160;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/* 提示多行(detail qr-tip 同款: 加粗段 + 换行) */
|
||||
.qr-tip-em {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.qr-tip-sub {
|
||||
font-size: 22rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
/* 二维码 URL 行(detail qr-url 同款) */
|
||||
.qr-url {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 复制按钮(2.17): 浅底主题色小按钮(色内联), 不挤压资料值换行 */
|
||||
.row-copy {
|
||||
flex-shrink: 0;
|
||||
@@ -1213,6 +1386,18 @@ export default {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 三列档(2.19.10): 图标+灰标签+值, detail 资料行同款列宽 */
|
||||
&.row-3col {
|
||||
.row-icon,
|
||||
.row-css-wrap {
|
||||
width: 56rpx;
|
||||
}
|
||||
|
||||
.row-label {
|
||||
width: 88rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/* 图标列与文字标签列同宽, 保证值列左缘对齐(参考图口径) */
|
||||
.row-icon {
|
||||
flex-shrink: 0;
|
||||
|
||||
Reference in New Issue
Block a user