diy: 名片 DIY 组件原生渲染(禁 webview) + diy-group 分发

- 新增 diy-card-entry/list/show/self.vue(easycom 自动加载):
  头像/资料行/快捷操作原生渲染, tel 走 makePhoneCall,
  wx/mail/web 走复制, 点击卡片跳 pages_tool/card/detail
- diy-card-self 登录态自适应: hasToken watch 自动刷新,
  未登录兜底(企业卡/指定卡/登录引导)由后端 /card/api/diy/mycard 决定
- diy-group.vue: DiyCard* 四个 componentName 分发分支
This commit is contained in:
2026-10-21 09:13:56 +08:00
parent 699787528c
commit d0fe005c4a
5 changed files with 1000 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
<template>
<view data-component-name="diy-card-entry" class="diy-card-entry" :style="wrapStyle" @tap="goLink">
<view class="entry-left">
<text class="entry-title" :style="textStyle">{{ value.title || '扫名片 · 谈合作' }}</text>
<text v-if="value.subtitle" class="entry-sub" :style="subStyle">{{ value.subtitle }}</text>
</view>
<view v-if="value.btnText" class="entry-btn" :style="btnStyle">
<text class="entry-btn-text">{{ value.btnText }}</text>
</view>
</view>
</template>
<script>
// 数字名片 · 名片入口横幅(装修组件, 原生渲染不依赖 webview)
import DiyMinx from './minx.js';
import golbalConfig from '@/common/js/golbalConfig.js';
export default {
name: 'diy-card-entry',
props: {
value: { type: Object }
},
mixins: [DiyMinx, golbalConfig],
computed: {
wrapStyle() {
const v = this.value || {};
return this.$util.objToStyle({
background: 'linear-gradient(135deg, ' + (v.bgColorStart || '#2F6BFF') + ' 0%, ' + (v.bgColorEnd || '#1E40AF') + ' 100%)',
borderRadius: this.px2rpx(v.borderRadius || 12) + 'rpx',
padding: this.px2rpx(v.padding || 16) + 'rpx ' + this.px2rpx(v.padding || 16) + 'rpx'
});
},
textStyle() {
return this.$util.objToStyle({ color: (this.value || {}).textColor || '#FFFFFF' });
},
subStyle() {
return this.$util.objToStyle({ color: (this.value || {}).textColor || '#FFFFFF', opacity: 0.85 });
},
btnStyle() {
return this.$util.objToStyle({ background: (this.value || {}).accentColor || '#FFEB3B' });
}
},
methods: {
px2rpx(v) {
const n = Number(v);
return isNaN(n) ? 0 : Math.round(n * 2);
},
goLink() {
const v = this.value || {};
let url = '';
if (v.linkMode === 'contacts') {
url = '/pages_tool/card/contacts';
} else if (v.linkMode === 'custom') {
url = String(v.customUrl || '').trim();
if (url !== '' && url.indexOf('/') !== 0) {
uni.showToast({ title: '自定义路径需以 / 开头', icon: 'none' });
return;
}
} else {
url = '/pages_tool/card/list';
}
if (url === '') {
uni.showToast({ title: '未配置跳转路径', icon: 'none' });
return;
}
this.$util.redirectTo(url);
}
}
};
</script>
<style lang="scss" scoped>
.diy-card-entry {
width: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
overflow: hidden;
.entry-left {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
.entry-title {
font-size: 32rpx;
font-weight: 700;
line-height: 1.4;
}
.entry-sub {
font-size: 24rpx;
line-height: 1.5;
margin-top: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
.entry-btn {
flex-shrink: 0;
margin-left: 20rpx;
padding: 12rpx 28rpx;
border-radius: 999rpx;
.entry-btn-text {
font-size: 24rpx;
font-weight: 600;
color: #333333;
}
}
}
</style>

View File

@@ -0,0 +1,230 @@
<template>
<view data-component-name="diy-card-list" class="diy-card-list">
<view class="card-wall" :style="wallStyle">
<text v-if="value.title" class="wall-title" :style="titleStyle">{{ value.title }}</text>
<view v-if="list.length" class="wall-grid">
<view v-for="(item, index) in list" :key="index" class="wall-item" :style="itemStyle" @tap="goDetail(item)">
<view class="item-avatar" :style="avatarStyle(item)">
<image v-if="item.avatar" class="avatar-img" :src="$util.img(item.avatar)" mode="aspectFill" />
<text v-else class="avatar-initial" :style="initialStyle(item)">{{ (item.name || '名').substring(0, 1) }}</text>
</view>
<view class="item-info">
<text class="item-name" :style="nameStyle">{{ item.name || '未命名名片' }}</text>
<text v-if="infoLine(item)" class="item-meta" :style="infoStyle">{{ infoLine(item) }}</text>
</view>
<text v-if="showArrow" class="item-arrow" :style="infoStyle">›</text>
</view>
</view>
<view v-else class="wall-empty" :style="infoStyle">
<text>{{ emptyTip }}</text>
</view>
</view>
</view>
</template>
<script>
// 数字名片 · 团队名片墙(装修组件)
// 数据口径: 商家在设计面板手动挑选 card_ids, 走 /card/api/diy/cards 公开摘要
import DiyMinx from './minx.js';
import golbalConfig from '@/common/js/golbalConfig.js';
export default {
name: 'diy-card-list',
props: {
value: { type: Object }
},
mixins: [DiyMinx, golbalConfig],
data() {
return {
list: []
};
},
computed: {
cardIds() {
return String((this.value || {}).cardIds || '')
.split(',')
.map(s => s.trim())
.filter(Boolean)
.slice(0, 20)
.join(',');
},
showArrow() {
const flag = this.getDiyToggle(['showArrow']);
return flag === undefined ? true : flag;
},
emptyTip() {
const v = this.value || {};
return String(v.cardIds || '').trim() === '' ? '商家还未挑选名片' : '暂无可展示的名片';
},
wallStyle() {
const v = this.value || {};
return this.$util.objToStyle({
background: v.bgColor || '#FFFFFF',
borderRadius: this.px2rpx(v.borderRadius || 12) + 'rpx',
padding: this.px2rpx(v.padding || 12) + 'rpx'
});
},
titleStyle() {
return this.$util.objToStyle({ color: (this.value || {}).titleColor || '#333333' });
},
nameStyle() {
return this.$util.objToStyle({ color: (this.value || {}).nameColor || '#1F2329' });
},
infoStyle() {
return this.$util.objToStyle({ color: (this.value || {}).infoColor || '#888888' });
},
itemStyle() {
const v = this.value || {};
const gap = Number(v.gap) || 10;
const cols = Number(v.columns) === 1 ? 1 : 2;
const width = cols === 1 ? '100%' : 'calc(50% - ' + this.px2rpx(gap / 2) + 'rpx)';
return this.$util.objToStyle({
width: width,
marginBottom: this.px2rpx(gap) + 'rpx'
});
}
},
watch: {
'value.cardIds'() {
this.fetchData();
}
},
mounted() {
this.fetchData();
},
methods: {
px2rpx(v) {
const n = Number(v);
return isNaN(n) ? 0 : Math.round(n * 2);
},
fetchData() {
if (this.cardIds === '') {
this.list = [];
return;
}
this.$api.sendRequest({
url: '/card/api/diy/cards',
data: { card_ids: this.cardIds },
success: res => {
if (res.code == 0 && res.data) {
this.list = res.data.list || [];
}
}
});
},
avatarStyle(item) {
return this.$util.objToStyle({ background: item.theme_color || '#2F6BFF' });
},
initialStyle(item) {
return this.$util.objToStyle({ color: '#FFFFFF' });
},
infoLine(item) {
const v = this.value || {};
const parts = [];
const showJob = this.getDiyToggle(['showJob']);
const showCompany = this.getDiyToggle(['showCompany']);
if ((showJob === undefined || showJob) && item.job_title) parts.push(item.job_title);
if ((showCompany === undefined || showCompany) && item.company) parts.push(item.company);
return parts.join(' · ');
},
goDetail(item) {
if (!item || !item.card_id) return;
this.$util.redirectTo('/pages_tool/card/detail', { card_id: item.card_id });
}
}
};
</script>
<style lang="scss" scoped>
.diy-card-list {
width: 100%;
.card-wall {
width: 100%;
box-sizing: border-box;
.wall-title {
display: block;
font-size: 32rpx;
font-weight: 700;
margin-bottom: 20rpx;
}
.wall-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.wall-item {
box-sizing: border-box;
display: flex;
align-items: center;
border: 2rpx solid #f0f0f0;
border-radius: 16rpx;
padding: 20rpx;
overflow: hidden;
.item-avatar {
flex-shrink: 0;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
.avatar-img {
width: 100%;
height: 100%;
display: block;
}
.avatar-initial {
font-size: 36rpx;
font-weight: 700;
}
}
.item-info {
flex: 1;
min-width: 0;
margin-left: 16rpx;
display: flex;
flex-direction: column;
.item-name {
font-size: 28rpx;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.item-meta {
font-size: 22rpx;
margin-top: 4rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.item-arrow {
flex-shrink: 0;
margin-left: 8rpx;
font-size: 32rpx;
}
}
.wall-empty {
padding: 30rpx 0;
font-size: 24rpx;
text-align: center;
}
}
}
</style>

View File

@@ -0,0 +1,335 @@
<template>
<view data-component-name="diy-card-self" class="diy-card-self">
<!-- 未登录 + 登录引导兜底 -->
<view v-if="!hasToken && fallbackMode === 'none'" class="self-login" :style="boxStyle" @tap="goLogin">
<text class="login-tip" :style="nameStyle">{{ value.loginTip || '登录后这里展示我的名片' }}</text>
<view class="login-btn" :style="detailStyle">
<text class="login-btn-text">{{ value.loginBtnText || '去登录' }}</text>
</view>
</view>
<!-- 名片卡(已登录=本人名片 / 未登录=兜底名片) -->
<view v-else-if="card" class="self-box" :style="boxStyle">
<view v-if="isSelf" class="self-badge" :style="badgeStyle">
<text class="badge-text">我的名片</text>
</view>
<view class="card-head">
<view class="head-avatar" :style="avatarStyle">
<image v-if="card.avatar" class="avatar-img" :src="$util.img(card.avatar)" mode="aspectFill" />
<text v-else class="avatar-initial">{{ (card.name || '名').substring(0, 1) }}</text>
</view>
<view class="head-info">
<text class="head-name" :style="nameStyle">{{ card.name || '未命名名片' }}</text>
<text v-if="subLine" class="head-sub" :style="infoStyle">{{ subLine }}</text>
</view>
</view>
<view v-if="showQuick && card.acts && card.acts.length" class="card-acts">
<view v-for="(act, index) in card.acts" :key="index" class="act-btn" :style="actStyle" @tap.stop="doAct(act)">
<text class="act-text" :style="actTextStyle">{{ act.label }}</text>
</view>
</view>
<view v-if="showDetailBtn" class="detail-btn" :style="detailStyle" @tap.stop="goDetail">
<text class="detail-text">{{ value.detailBtnText || '查看完整名片' }}</text>
</view>
</view>
<!-- 已登录但没有任何名片可显示 -->
<view v-else class="self-empty" :style="boxStyle">
<text class="empty-tip" :style="infoStyle">登录后即可展示我的名片</text>
</view>
</view>
</template>
<script>
// 数字名片 · 我的名片(装修组件)
// 运行时判定: 操作者已登录 → 本人名片(optionalAuth); 未登录 → 配置的兜底名片
// fallbackMode: enterprise=店铺企业名片 / card=指定 fallbackCardId / none=登录引导
import DiyMinx from './minx.js';
import golbalConfig from '@/common/js/golbalConfig.js';
export default {
name: 'diy-card-self',
props: {
value: { type: Object }
},
mixins: [DiyMinx, golbalConfig],
data() {
return {
card: null,
isSelf: false
};
},
computed: {
hasToken() {
try {
return !!(this.$store && this.$store.state && this.$store.state.token);
} catch (e) {
return false;
}
},
fallbackMode() {
const m = String((this.value || {}).fallbackMode || 'enterprise');
return ['enterprise', 'card', 'none'].includes(m) ? m : 'enterprise';
},
showQuick() {
const flag = this.getDiyToggle(['showQuick']);
return flag === undefined ? true : flag;
},
showDetailBtn() {
const flag = this.getDiyToggle(['showDetailBtn']);
return flag === undefined ? true : flag;
},
subLine() {
const c = this.card || {};
return [c.job_title, c.company].filter(Boolean).join(' · ');
},
boxStyle() {
const v = this.value || {};
return this.$util.objToStyle({
background: v.bgColor || '#FFFFFF',
borderRadius: this.px2rpx(v.borderRadius || 16) + 'rpx',
padding: this.px2rpx(v.padding || 16) + 'rpx'
});
},
avatarStyle() {
return this.$util.objToStyle({ background: (this.card || {}).theme_color || '#2F6BFF' });
},
nameStyle() {
return this.$util.objToStyle({ color: (this.value || {}).nameColor || '#1F2329' });
},
infoStyle() {
return this.$util.objToStyle({ color: (this.value || {}).infoColor || '#888888' });
},
actStyle() {
const theme = (this.card || {}).theme_color || '#2F6BFF';
return this.$util.objToStyle({ borderColor: theme });
},
actTextStyle() {
return this.$util.objToStyle({ color: (this.card || {}).theme_color || '#2F6BFF' });
},
detailStyle() {
return this.$util.objToStyle({ background: (this.card || {}).theme_color || '#2F6BFF' });
},
badgeStyle() {
return this.$util.objToStyle({ background: (this.card || {}).theme_color || '#2F6BFF' });
}
},
watch: {
hasToken() {
this.fetchData();
},
'value.fallbackMode'() {
this.fetchData();
},
'value.fallbackCardId'() {
this.fetchData();
}
},
mounted() {
this.fetchData();
},
methods: {
px2rpx(v) {
const n = Number(v);
return isNaN(n) ? 0 : Math.round(n * 2);
},
fetchData() {
if (!this.hasToken && this.fallbackMode === 'none') {
this.card = null;
return;
}
this.$api.sendRequest({
url: '/card/api/diy/mycard',
data: {
fallback_mode: this.fallbackMode,
fallback_card_id: String((this.value || {}).fallbackCardId || '').trim()
},
success: res => {
if (res.code == 0 && res.data) {
this.card = res.data.card || null;
this.isSelf = res.data.is_self == 1;
} else {
this.card = null;
this.isSelf = false;
}
}
});
},
goLogin() {
this.$util.redirectTo('/pages_tool/login/login');
},
doAct(act) {
if (!act || !act.value) return;
if (act.type === 'tel') {
uni.makePhoneCall({ phoneNumber: act.value, fail: () => {} });
} else if (act.type === 'wx') {
uni.setClipboardData({
data: act.value,
success: () => uni.showToast({ title: '微信号已复制', icon: 'none' })
});
} else if (act.type === 'mail') {
// #ifdef H5
window.location.href = 'mailto:' + act.value;
// #endif
// #ifndef H5
uni.setClipboardData({
data: act.value,
success: () => uni.showToast({ title: '邮箱已复制', icon: 'none' })
});
// #endif
} else {
uni.setClipboardData({
data: act.value,
success: () => uni.showToast({ title: '已复制', icon: 'none' })
});
}
},
goDetail() {
if (!this.card || !this.card.card_id) return;
this.$util.redirectTo('/pages_tool/card/detail', { card_id: this.card.card_id });
}
}
};
</script>
<style lang="scss" scoped>
.diy-card-self {
width: 100%;
position: relative;
.self-box {
width: 100%;
box-sizing: border-box;
.self-badge {
position: absolute;
top: 0;
right: 0;
border-radius: 0 16rpx 0 16rpx;
padding: 6rpx 20rpx;
.badge-text {
font-size: 20rpx;
color: #ffffff;
font-weight: 600;
}
}
.card-head {
display: flex;
align-items: center;
.head-avatar {
flex-shrink: 0;
width: 104rpx;
height: 104rpx;
border-radius: 50%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
.avatar-img {
width: 100%;
height: 100%;
display: block;
}
.avatar-initial {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
}
}
.head-info {
flex: 1;
min-width: 0;
margin-left: 24rpx;
display: flex;
flex-direction: column;
.head-name {
font-size: 34rpx;
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.head-sub {
font-size: 24rpx;
margin-top: 6rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.card-acts {
margin-top: 24rpx;
display: flex;
flex-wrap: wrap;
.act-btn {
border: 2rpx solid;
border-radius: 999rpx;
padding: 10rpx 28rpx;
margin: 0 16rpx 16rpx 0;
.act-text {
font-size: 24rpx;
font-weight: 500;
}
}
}
.detail-btn {
margin-top: 12rpx;
border-radius: 999rpx;
padding: 16rpx 0;
display: flex;
align-items: center;
justify-content: center;
.detail-text {
font-size: 26rpx;
font-weight: 600;
color: #ffffff;
}
}
}
.self-login,
.self-empty {
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
.login-tip,
.empty-tip {
font-size: 28rpx;
font-weight: 600;
text-align: center;
}
.login-btn {
margin-top: 24rpx;
border-radius: 999rpx;
padding: 14rpx 48rpx;
.login-btn-text {
font-size: 24rpx;
color: #ffffff;
font-weight: 600;
}
}
}
}
</style>

View File

@@ -0,0 +1,301 @@
<template>
<view data-component-name="diy-card-show" class="diy-card-show">
<view v-if="card" class="card-box" :style="boxStyle">
<view class="card-head">
<view class="head-avatar" :style="avatarStyle">
<image v-if="card.avatar" class="avatar-img" :src="$util.img(card.avatar)" mode="aspectFill" />
<text v-else class="avatar-initial">{{ (card.name || '名').substring(0, 1) }}</text>
</view>
<view class="head-info">
<text class="head-name" :style="nameStyle">{{ card.name || '未命名名片' }}</text>
<text v-if="subLine" class="head-sub" :style="infoStyle">{{ subLine }}</text>
</view>
</view>
<view v-if="showRows && card.rows && card.rows.length" class="card-rows">
<view v-for="(row, index) in card.rows" :key="index" class="row-line">
<text class="row-label" :style="labelStyle">{{ row.label }}</text>
<text class="row-value" :style="infoStyle">{{ row.value }}</text>
</view>
</view>
<view v-if="showQuick && card.acts && card.acts.length" class="card-acts">
<view v-for="(act, index) in card.acts" :key="index" class="act-btn" :style="actStyle" @tap.stop="doAct(act)">
<text class="act-text" :style="actTextStyle">{{ act.label }}</text>
</view>
</view>
<view v-if="showDetailBtn" class="detail-btn" :style="detailStyle" @tap.stop="goDetail">
<text class="detail-text">{{ value.detailBtnText || '查看完整名片' }}</text>
</view>
</view>
<view v-else class="card-empty" :style="boxStyle">
<text class="empty-tip" :style="infoStyle">{{ emptyTip }}</text>
</view>
</view>
</template>
<script>
// 数字名片 · 精选名片(装修组件): 单张名片的原生迷你卡
// 数据口径: /card/api/diy/card?card_id=.. 公开摘要(与 wap 公开页同源)
import DiyMinx from './minx.js';
import golbalConfig from '@/common/js/golbalConfig.js';
export default {
name: 'diy-card-show',
props: {
value: { type: Object }
},
mixins: [DiyMinx, golbalConfig],
data() {
return {
card: null
};
},
computed: {
showRows() {
const flag = this.getDiyToggle(['showRows']);
return flag === undefined ? true : flag;
},
showQuick() {
const flag = this.getDiyToggle(['showQuick']);
return flag === undefined ? true : flag;
},
showDetailBtn() {
const flag = this.getDiyToggle(['showDetailBtn']);
return flag === undefined ? true : flag;
},
emptyTip() {
return String((this.value || {}).cardId || '').trim() === '' ? '商家还未选择名片' : '名片不存在或已删除';
},
subLine() {
const c = this.card || {};
return [c.job_title, c.company].filter(Boolean).join(' · ');
},
boxStyle() {
const v = this.value || {};
return this.$util.objToStyle({
background: v.bgColor || '#FFFFFF',
borderRadius: this.px2rpx(v.borderRadius || 16) + 'rpx',
padding: this.px2rpx(v.padding || 16) + 'rpx'
});
},
avatarStyle() {
return this.$util.objToStyle({ background: (this.card || {}).theme_color || '#2F6BFF' });
},
nameStyle() {
return this.$util.objToStyle({ color: (this.value || {}).nameColor || '#1F2329' });
},
infoStyle() {
return this.$util.objToStyle({ color: (this.value || {}).infoColor || '#888888' });
},
labelStyle() {
return this.$util.objToStyle({ color: (this.value || {}).labelColor || '#999999' });
},
actStyle() {
const theme = (this.card || {}).theme_color || '#2F6BFF';
return this.$util.objToStyle({ borderColor: theme });
},
actTextStyle() {
return this.$util.objToStyle({ color: (this.card || {}).theme_color || '#2F6BFF' });
},
detailStyle() {
return this.$util.objToStyle({ background: (this.card || {}).theme_color || '#2F6BFF' });
}
},
watch: {
'value.cardId'() {
this.fetchData();
}
},
mounted() {
this.fetchData();
},
methods: {
px2rpx(v) {
const n = Number(v);
return isNaN(n) ? 0 : Math.round(n * 2);
},
fetchData() {
const cardId = String((this.value || {}).cardId || '').trim();
if (cardId === '') {
this.card = null;
return;
}
this.$api.sendRequest({
url: '/card/api/diy/card',
data: { card_id: cardId },
success: res => {
if (res.code == 0 && res.data && res.data.card) {
this.card = res.data.card;
} else {
this.card = null;
}
}
});
},
doAct(act) {
if (!act || !act.value) return;
if (act.type === 'tel') {
uni.makePhoneCall({ phoneNumber: act.value, fail: () => {} });
} else if (act.type === 'wx') {
uni.setClipboardData({
data: act.value,
success: () => uni.showToast({ title: '微信号已复制', icon: 'none' })
});
} else if (act.type === 'mail') {
// #ifdef H5
window.location.href = 'mailto:' + act.value;
// #endif
// #ifndef H5
uni.setClipboardData({
data: act.value,
success: () => uni.showToast({ title: '邮箱已复制', icon: 'none' })
});
// #endif
} else {
uni.setClipboardData({
data: act.value,
success: () => uni.showToast({ title: '已复制', icon: 'none' })
});
}
},
goDetail() {
if (!this.card || !this.card.card_id) return;
this.$util.redirectTo('/pages_tool/card/detail', { card_id: this.card.card_id });
}
}
};
</script>
<style lang="scss" scoped>
.diy-card-show {
width: 100%;
.card-box {
width: 100%;
box-sizing: border-box;
.card-head {
display: flex;
align-items: center;
.head-avatar {
flex-shrink: 0;
width: 104rpx;
height: 104rpx;
border-radius: 50%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
.avatar-img {
width: 100%;
height: 100%;
display: block;
}
.avatar-initial {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
}
}
.head-info {
flex: 1;
min-width: 0;
margin-left: 24rpx;
display: flex;
flex-direction: column;
.head-name {
font-size: 34rpx;
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.head-sub {
font-size: 24rpx;
margin-top: 6rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.card-rows {
margin-top: 24rpx;
padding-top: 20rpx;
border-top: 2rpx solid #f0f0f0;
.row-line {
display: flex;
line-height: 1.9;
.row-label {
flex-shrink: 0;
font-size: 24rpx;
margin-right: 20rpx;
}
.row-value {
flex: 1;
font-size: 24rpx;
word-break: break-all;
}
}
}
.card-acts {
margin-top: 24rpx;
display: flex;
flex-wrap: wrap;
.act-btn {
border: 2rpx solid;
border-radius: 999rpx;
padding: 10rpx 28rpx;
margin: 0 16rpx 16rpx 0;
.act-text {
font-size: 24rpx;
font-weight: 500;
}
}
}
.detail-btn {
margin-top: 12rpx;
border-radius: 999rpx;
padding: 16rpx 0;
display: flex;
align-items: center;
justify-content: center;
.detail-text {
font-size: 26rpx;
font-weight: 600;
color: #ffffff;
}
}
}
.card-empty {
width: 100%;
box-sizing: border-box;
.empty-tip {
display: block;
text-align: center;
padding: 30rpx 0;
font-size: 24rpx;
}
}
}
</style>

View File

@@ -170,6 +170,22 @@
<!-- 自定义推荐码组件 -->
<diy-recommend-code :value="item"></diy-recommend-code>
</template>
<template v-else-if="item.componentName == 'DiyCardEntry'">
<!-- 数字名片 · 名片入口横幅 -->
<diy-card-entry :value="item"></diy-card-entry>
</template>
<template v-else-if="item.componentName == 'DiyCardList'">
<!-- 数字名片 · 团队名片墙 -->
<diy-card-list :value="item"></diy-card-list>
</template>
<template v-else-if="item.componentName == 'DiyCardShow'">
<!-- 数字名片 · 精选名片 -->
<diy-card-show :value="item"></diy-card-show>
</template>
<template v-else-if="item.componentName == 'DiyCardSelf'">
<!-- 数字名片 · 我的名片(登录态自适应) -->
<diy-card-self :value="item"></diy-card-self>
</template>
<template v-if="item.componentName == 'GoodsBrand'">
<!-- 商品品牌 -->
<diy-goods-brand :value="item"></diy-goods-brand>