Files
lucky_shop/pages_tool/card/detail.vue

222 lines
5.0 KiB
Vue

<template>
<view class="card-detail">
<!-- 名片头部 -->
<view class="detail-head" v-if="relation">
<view class="head-avatar">
<text>{{ avatarText(relation.name) }}</text>
</view>
<view class="head-info">
<view class="head-name">{{ relation.name || '未命名名片' }}</view>
<view class="head-sub" v-if="relation.job_title || relation.company">
{{ [relation.job_title, relation.company].filter(Boolean).join(' · ') }}
</view>
</view>
</view>
<!-- 字段列表 -->
<view class="detail-fields" v-if="fieldRows.length > 0">
<view v-for="(row, index) in fieldRows" :key="index" class="field-row">
<view class="field-label">{{ row.label }}</view>
<view class="field-value">{{ row.value }}</view>
<view class="field-action" v-if="row.action"
@tap="row.action.type === 'call' ? callPhone(row.value) : copyText2(row.value)">
{{ row.action.text }}
</view>
</view>
</view>
<!-- 加载中 -->
<view class="detail-loading" v-if="isLoading">加载中…</view>
<!-- 不存在 / 无权查看 -->
<ns-empty v-if="!isLoading && !relation" isIndex="false"
:text="errorMsg || '卡片不存在或已被删除'"></ns-empty>
</view>
</template>
<script>
export default {
data() {
return {
cardId: '',
relation: null,
source: null,
shareList: [],
isLoading: true,
errorMsg: ''
};
},
computed: {
fieldRows() {
const r = this.relation;
if (!r) return [];
const rows = [];
const push = (label, value, action) => {
if (value !== undefined && value !== null && String(value).trim() !== '') {
rows.push({ label, value: String(value), action: action || null });
}
};
push('手机', r.mobile, { type: 'call', text: '拨打' });
push('电话', r.phone, { type: 'call', text: '拨打' });
push('邮箱', r.email, { type: 'copy', text: '复制' });
push('微信', r.wechat, { type: 'copy', text: '复制' });
push('网站', r.website);
push('地址', [r.country, r.province, r.city, r.address].filter(Boolean).join(' '));
push('邮编', r.postal_code);
push('Telegram', r.telegram);
push('Messenger', r.messenger);
return rows;
}
},
onLoad(options) {
this.cardId = decodeURIComponent(options.card_id || '');
this.loadDetail();
},
methods: {
avatarText(name) {
return (name || '?').trim().charAt(0).toUpperCase();
},
loadDetail() {
if (!this.cardId) {
this.isLoading = false;
this.errorMsg = '缺少名片编号';
return;
}
this.isLoading = true;
this.$api.sendRequest({
url: '/card/api/card/detail',
data: { card_id: this.cardId },
success: res => {
this.isLoading = false;
if (res.code == 0) {
const data = res.data || {};
this.relation = data.relation || null;
this.source = data.source || null;
this.shareList = data.share_list || [];
} else {
// 后端对"不存在"与"非本人名下"同一报错口径,不区分展示
this.errorMsg = res.message || '卡片不存在或已被删除';
this.relation = null;
}
},
fail: () => {
this.isLoading = false;
this.errorMsg = '网络异常,请稍后重试';
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
}
});
},
callPhone(mobile) {
if (!mobile) return;
uni.makePhoneCall({ phoneNumber: mobile });
},
copyText2(text) {
uni.setClipboardData({
data: text,
success: () => {
uni.showToast({ title: '已复制', icon: 'success' });
}
});
}
}
};
</script>
<style lang="scss" scoped>
.card-detail {
min-height: 100vh;
background-color: #f6f7f9;
padding-bottom: 60rpx;
box-sizing: border-box;
}
.detail-head {
display: flex;
align-items: center;
padding: 48rpx 32rpx;
background: linear-gradient(135deg, var(--main-color, #0054a5), var(--main-color-shallow, #3a7bc8));
color: #ffffff;
.head-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.25);
font-size: 52rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-right: 28rpx;
}
.head-info {
min-width: 0;
.head-name {
font-size: 40rpx;
font-weight: 600;
}
.head-sub {
font-size: 26rpx;
opacity: 0.85;
margin-top: 12rpx;
}
}
}
.detail-fields {
margin: 24rpx;
background-color: #ffffff;
border-radius: 16rpx;
overflow: hidden;
.field-row {
display: flex;
align-items: center;
padding: 28rpx 24rpx;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.field-label {
width: 140rpx;
font-size: 28rpx;
color: #999;
flex-shrink: 0;
}
.field-value {
flex: 1;
font-size: 28rpx;
color: #333;
word-break: break-all;
}
.field-action {
margin-left: 20rpx;
flex-shrink: 0;
font-size: 24rpx;
color: var(--main-color, #0054a5);
border: 1rpx solid var(--main-color, #0054a5);
border-radius: 28rpx;
padding: 6rpx 24rpx;
}
}
}
.detail-loading {
text-align: center;
color: #999;
font-size: 26rpx;
padding: 120rpx 0;
}
</style>