feat: 名片页面开发
@ -240,6 +240,13 @@
|
|||||||
"navigationBarTitleText": "添加好友",
|
"navigationBarTitleText": "添加好友",
|
||||||
"disableScroll": true
|
"disableScroll": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "business-card",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "个人名片",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1990
pages/team/business-card.vue
Normal file
312
pages/team/components/BusinessCard.vue
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
<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>
|
||||||
@ -96,7 +96,6 @@ const teammate = computed(() => {
|
|||||||
|
|
||||||
const friendlyMember = computed(() => {
|
const friendlyMember = computed(() => {
|
||||||
const friendlyMembers = team.value && Array.isArray(team.value.friendlyMembers) ? team.value.friendlyMembers : [];
|
const friendlyMembers = team.value && Array.isArray(team.value.friendlyMembers) ? team.value.friendlyMembers : [];
|
||||||
debugger
|
|
||||||
return friendlyMembers.reduce((data, item) => {
|
return friendlyMembers.reduce((data, item) => {
|
||||||
data[item] = true;
|
data[item] = true;
|
||||||
return data
|
return data
|
||||||
|
|||||||
BIN
static/card/avatar.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
static/card/card-bg2.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
static/card/edit-card.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/card/email.png
Normal file
|
After Width: | Height: | Size: 886 B |
1
static/card/email.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1781663573063" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11885" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M838.954667 234.666667H170.666667c-3.626667 0-7.168 0.448-10.56 1.322666l323.690666 323.669334a21.333333 21.333333 0 0 0 30.165334 0L838.954667 234.666667z m46.144 14.186666l-260.693334 260.693334 262.933334 262.912c5.44-7.168 8.661333-16.106667 8.661333-25.792V277.333333c0-10.944-4.117333-20.906667-10.88-28.48zM843.861333 789.333333l-249.6-249.621333-50.133333 50.133333a64 64 0 0 1-90.517333 0l-50.112-50.133333L156.373333 786.88c4.48 1.578667 9.28 2.453333 14.314667 2.453333h673.194667zM128.661333 754.218667L373.333333 509.525333 129.578667 265.813333A42.709333 42.709333 0 0 0 128 277.333333v469.333334c0 2.56 0.213333 5.098667 0.661333 7.552zM170.666667 192h682.666666a85.333333 85.333333 0 0 1 85.333334 85.333333v469.333334a85.333333 85.333333 0 0 1-85.333334 85.333333H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333333V277.333333a85.333333 85.333333 0 0 1 85.333334-85.333333z" fill="#ffffff" p-id="11886"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
static/card/gwBack.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
static/card/gwIcon.png
Normal file
|
After Width: | Height: | Size: 866 B |
BIN
static/card/gzhBack.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
static/card/jzfwBack.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
static/card/jzfwIcon.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
static/card/phone.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
static/card/sphBack.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
1
static/card/telephone.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1781663513850" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10787" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M731.9 631.3c15.5-30.6 46.8-71.9-20-96.3-66.8-24.4-74.7 1-90.8 32.6-11.2 22.1-65.1 1.6-113.7-22.4-48.6-24-97.5-54.2-86.3-76.3 16.1-31.6 32-53-27.8-91.1-59.9-38.1-74.8 11.3-90.3 41.9-18 35.3 40.4 125.4 171.6 190.2 131.1 64.6 239.3 56.6 257.3 21.4z m0 0" p-id="10788" fill="#ffffff"></path><path d="M511 959c-60.4 0-119-11.8-174.2-35.2-53.3-22.5-101.2-54.8-142.3-95.9-41.1-41.1-73.4-89-95.9-142.3-23.3-55.2-35.2-113.8-35.2-174.2 0-60.4 11.8-119 35.2-174.2 22.5-53.3 54.8-101.2 95.9-142.3 41.1-41.1 89-73.4 142.3-95.9C391.9 75.7 450.6 63.8 511 63.8c60.4 0 119 11.8 174.2 35.2 53.3 22.5 101.2 54.8 142.3 95.9 41.1 41.1 73.4 89 95.9 142.3 23.3 55.2 35.2 113.8 35.2 174.2 0 60.4-11.8 119-35.2 174.2-22.5 53.3-54.8 101.2-95.9 142.3-41.1 41.1-89 73.4-142.3 95.9C630 947.1 571.4 959 511 959z m0-851.3c-222.6 0-403.7 181.1-403.7 403.7S288.4 915.1 511 915.1 914.7 734 914.7 511.4 733.6 107.7 511 107.7z" fill="#ffffff" p-id="10789"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -15,7 +15,8 @@ const urlsConfig = {
|
|||||||
getTeamMemberAvatarsAndName: "getTeamMemberAvatarsAndName",
|
getTeamMemberAvatarsAndName: "getTeamMemberAvatarsAndName",
|
||||||
getMiniAppHomeStats: "getMiniAppHomeStats",
|
getMiniAppHomeStats: "getMiniAppHomeStats",
|
||||||
getResponsiblePerson: 'getTeamResponsiblePerson',
|
getResponsiblePerson: 'getTeamResponsiblePerson',
|
||||||
relateWxappTeamByExternalUserId: 'relateWxappTeamByExternalUserId'
|
relateWxappTeamByExternalUserId: 'relateWxappTeamByExternalUserId',
|
||||||
|
getBusinessCard: 'getBusinessCard'
|
||||||
},
|
},
|
||||||
|
|
||||||
knowledgeBase: {
|
knowledgeBase: {
|
||||||
|
|||||||