313 lines
7.7 KiB
Vue
313 lines
7.7 KiB
Vue
<template>
|
||
<view v-if="card" class="business-card" @click="handleClick">
|
||
<image class="card-bg" :src="cardBg"></image>
|
||
<view class="card-header">
|
||
<view class="avatar">
|
||
<image :src="card.avatar || '/static/card/avatar.png'" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="info">
|
||
<text class="name">{{ card.externalName || card.anotherName || '' }}</text>
|
||
<text v-if="card.hospitalInfo" class="hospital">{{ card.hospitalInfo.name || '' }}</text>
|
||
<view class="title-tags">
|
||
<text class="title-tag department" v-if="card.deptName">{{ card.deptName }}</text>
|
||
<text class="title-tag position" v-if="card.title">{{ card.title }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="contact-section">
|
||
<view class="contact-info">
|
||
<!-- <view class="contact-item" v-if="card.externalContact">
|
||
<image class="contact-icon" src="/static/card/address.png" mode="aspectFit"></image>
|
||
<text class="contact-text">{{ accountInfo.address }}</text>
|
||
</view> -->
|
||
<view v-if="card.externalContact" class="contact-item">
|
||
<image class="contact-icon" src="/static/card/phone.png" mode="aspectFit"></image>
|
||
<text class="contact-text">{{ card.externalContact || '' }}</text>
|
||
</view>
|
||
<view v-if="card.externalEmail" class="contact-item">
|
||
<image class="contact-icon" src="/static/card/email.png" mode="aspectFit"></image>
|
||
<text class="contact-text">{{ card.externalEmail || '' }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, onMounted, ref } from "vue";
|
||
import { onShow } from '@dcloudio/uni-app'
|
||
// import { useCardStore } from "@/stores/card";
|
||
// import { useAccountStore } from "@/stores/account";
|
||
// import { getDeptStaffDepartments } from "@/api/dept";
|
||
|
||
const props = defineProps({
|
||
card: {
|
||
type: [Object, null],
|
||
default: null
|
||
},
|
||
// 点击事件处理函数
|
||
onClick: {
|
||
type: Function,
|
||
default: null,
|
||
},
|
||
// 背景图片路径
|
||
cardBg: {
|
||
type: String,
|
||
default: "/static/card/card-bg2.png",
|
||
},
|
||
// 显示模式:'doctor' 医生模式(使用 cardStore 的可见性设置),'patient' 患者模式(直接显示)
|
||
mode: {
|
||
type: String,
|
||
default: "doctor",
|
||
validator: (value) => ["doctor", "patient"].includes(value),
|
||
},
|
||
// 自定义账户信息(如果提供,则使用自定义数据而不是 store)
|
||
customAccountInfo: {
|
||
type: Object,
|
||
default: null,
|
||
},
|
||
// 自定义机构信息(如果提供,则使用自定义数据而不是 store)
|
||
customInstitutionInfo: {
|
||
type: Object,
|
||
default: null,
|
||
},
|
||
// 自定义医生名片状态(如果提供,则使用自定义数据而不是 store)
|
||
customDoctorCardStatus: {
|
||
type: Object,
|
||
default: null,
|
||
},
|
||
});
|
||
|
||
const emit = defineEmits(["click"]);
|
||
|
||
const cardStore = ref({});
|
||
const accountStore = ref({});
|
||
|
||
// 获取账户信息(优先使用自定义数据)
|
||
const accountInfo = computed(() => {
|
||
if (props.customAccountInfo) {
|
||
return props.customAccountInfo;
|
||
}
|
||
return accountStore.getAccountInfo || {};
|
||
});
|
||
|
||
// 部门显示名称(优先使用接口 getDeptStaffDepartments 返回的结果)
|
||
const deptDisplayName = ref("");
|
||
|
||
const displayDeptName = computed(() => {
|
||
// 优先展示接口返回的部门字符串,否则回退账户里的 deptName
|
||
return deptDisplayName.value || accountInfo.value.deptName || "";
|
||
});
|
||
|
||
// 获取机构信息(优先使用自定义数据)
|
||
const institutionInfo = computed(() => {
|
||
if (props.customInstitutionInfo) {
|
||
return props.customInstitutionInfo;
|
||
}
|
||
return accountStore.getInstitutionInfo || {};
|
||
});
|
||
|
||
// 获取医生名片状态(优先使用自定义数据)
|
||
const doctorCardStatus = computed(() => {
|
||
if (props.customDoctorCardStatus) {
|
||
return props.customDoctorCardStatus;
|
||
}
|
||
return accountStore.getDoctorCardStatus || { hasDoctorCard: false };
|
||
});
|
||
|
||
// 根据模式决定是否显示部门名称
|
||
const shouldShowDeptName = computed(() => {
|
||
if (props.mode === "patient") {
|
||
return true; // 患者模式直接显示
|
||
}
|
||
return cardStore.deptNameVisible; // 医生模式使用 cardStore 设置
|
||
});
|
||
|
||
// 根据模式决定是否显示职位
|
||
const shouldShowPosition = computed(() => {
|
||
if (props.mode === "patient") {
|
||
return true; // 患者模式直接显示
|
||
}
|
||
return cardStore.positionVisible; // 医生模式使用 cardStore 设置
|
||
});
|
||
|
||
// 根据模式决定是否显示电话
|
||
const shouldShowPhone = computed(() => {
|
||
if (props.mode === "patient") {
|
||
return true; // 患者模式直接显示
|
||
}
|
||
return cardStore.phoneVisible; // 医生模式使用 cardStore 设置
|
||
});
|
||
|
||
// 根据模式决定是否显示邮箱
|
||
const shouldShowEmail = computed(() => {
|
||
if (props.mode === "patient") {
|
||
return true; // 患者模式直接显示
|
||
}
|
||
return cardStore.emailVisible; // 医生模式使用 cardStore 设置
|
||
});
|
||
|
||
// 根据模式决定是否显示地址
|
||
const shouldShowAddress = computed(() => {
|
||
if (props.mode === "patient") {
|
||
return true; // 患者模式直接显示
|
||
}
|
||
return cardStore.addressVisible; // 医生模式使用 cardStore 设置
|
||
});
|
||
|
||
// 处理点击事件
|
||
const handleClick = () => {
|
||
if (props.onClick) {
|
||
props.onClick();
|
||
}
|
||
emit("click");
|
||
};
|
||
|
||
// 组件挂载后,通过工号 staffId 调用 getDeptStaffDepartments 获取部门显示信息
|
||
onShow(async () => {
|
||
try {
|
||
const staffId = accountInfo.value.staffId;
|
||
if (!staffId) return;
|
||
|
||
const res = await getDeptStaffDepartments({ staffId });
|
||
if (res && res.success && Array.isArray(res.data) && res.data.length > 0) {
|
||
// 后端返回的是部门名称数组,例如 ["人力资源部/人事培训科/人事培训科"]
|
||
deptDisplayName.value = res.data.join("、");
|
||
}
|
||
} catch (error) {
|
||
console.error("获取部门显示信息失败:", error);
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
/* 名片展示区域 */
|
||
.business-card {
|
||
position: relative;
|
||
overflow: visible;
|
||
border-bottom-left-radius: 16rpx;
|
||
border-bottom-right-radius: 16rpx;
|
||
font-size: 0;
|
||
}
|
||
|
||
.card-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 0;
|
||
display: block;
|
||
}
|
||
|
||
.card-header {
|
||
position: relative;
|
||
padding: 36rpx 40rpx 10rpx 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 36rpx;
|
||
}
|
||
|
||
.contact-section {
|
||
position: relative;
|
||
z-index: 1;
|
||
padding: 0 40rpx 56rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.avatar {
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
display: flex;
|
||
border-radius: 50%;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 60rpx;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
|
||
flex-shrink: 0;
|
||
margin-right: 30rpx;
|
||
align-self: center;
|
||
|
||
image {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 50%;
|
||
}
|
||
}
|
||
|
||
.info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
|
||
.name {
|
||
display: block;
|
||
font-size: 36rpx;
|
||
font-weight: 500;
|
||
margin-bottom: 6rpx;
|
||
color: #222;
|
||
}
|
||
|
||
.hospital {
|
||
display: block;
|
||
font-size: 26rpx;
|
||
margin-bottom: 8rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.title-tags {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.title-tag {
|
||
font-size: 24rpx;
|
||
font-weight: 400;
|
||
padding: 0 16rpx;
|
||
flex-shrink: 0;
|
||
border-radius: 28rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.title-tag.department {
|
||
color: #ff8b00;
|
||
border: 1rpx solid #ff8b00;
|
||
}
|
||
|
||
.title-tag.position {
|
||
color: #de4f27;
|
||
border: 0.5px solid #de4f27;
|
||
}
|
||
|
||
.contact-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10rpx;
|
||
align-items: flex-start;
|
||
flex: 1;
|
||
}
|
||
|
||
.contact-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
}
|
||
|
||
.contact-icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
}
|
||
|
||
.contact-text {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
</style>
|