Files
lucky_shop/components-diy/diy-card-list.vue
ZF sun d0fe005c4a 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 分发分支
2026-10-21 09:13:56 +08:00

231 lines
5.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>