Files
xk-admin/apps/web-antd/src/components/promoter/PromoterInfoCard.vue
李琦 d93e465d3c
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
1. 特色方功能迭代(固定价格),固定价格目前统一使用药品id(-102),后期会考虑新增特色方的时候自动添加一个特色方药品
2. 退款的时候可以退回分成
2026-07-09 15:45:39 +08:00

239 lines
4.8 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.
<script setup lang="ts">
import { computed } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Avatar } from 'ant-design-vue';
import { resolveAvatarUrl } from '#/views/system/store-input/utils/inputUser';
import SensitiveText from '#/components/sensitive-text/SensitiveText.vue';
import PromoterDetailModal from './PromoterDetailModal.vue';
export type PromoterAdminLike = {
id?: number;
nick_name?: string;
avatar?: string;
phone?: string;
code?: string;
role_name?: string;
};
const props = withDefaults(
defineProps<{
admin?: PromoterAdminLike | null;
size?: 'compact' | 'trigger';
clickable?: boolean;
showClear?: boolean;
disabled?: boolean;
}>(),
{
admin: null,
size: 'compact',
clickable: true,
showClear: false,
disabled: false,
},
);
const emits = defineEmits<{
clear: [];
}>();
const [DetailModal, detailModalApi] = useVbenModal({
connectedComponent: PromoterDetailModal,
});
const displayName = computed(
() => props.admin?.nick_name?.trim() || props.admin?.phone?.trim() || '-',
);
const avatarUrl = computed(() => resolveAvatarUrl(props.admin?.avatar));
const canOpenDetail = computed(
() =>
props.clickable &&
!props.disabled &&
!!(props.admin?.id || props.admin?.code),
);
function openDetail() {
if (!canOpenDetail.value) return;
detailModalApi.setData({
id: props.admin?.id,
code: props.admin?.code,
});
detailModalApi.open();
}
function onClear(e: Event) {
e.stopPropagation();
emits('clear');
}
</script>
<template>
<div>
<DetailModal />
<div
v-if="admin"
class="promoter-info-card"
:class="[
`promoter-info-card--${size}`,
{
'promoter-info-card--clickable': canOpenDetail,
'promoter-info-card--disabled': disabled,
},
]"
@click="openDetail"
>
<Avatar v-if="avatarUrl" :src="avatarUrl" :size="size === 'trigger' ? 36 : 28" />
<Avatar v-else :size="size === 'trigger' ? 36 : 28">
{{ displayName.charAt(0) }}
</Avatar>
<div class="promoter-info-card__meta">
<div class="promoter-info-card__name">{{ displayName }}</div>
<div v-if="size === 'trigger' && admin.code" class="promoter-info-card__sub">
业务码:{{ admin.code }}
</div>
<div v-else-if="admin.phone" class="promoter-info-card__sub">
<SensitiveText :record="admin" field="phone" :show-eye="false" />
</div>
</div>
<span
v-if="showClear && !disabled"
class="promoter-info-card__clear"
@click="onClear"
>
×
</span>
</div>
<span v-else class="promoter-info-card__empty">-</span>
</div>
</template>
<style scoped lang="scss">
.promoter-info-card {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.promoter-info-card--compact {
padding: 2px 0;
}
.promoter-info-card--trigger {
width: 100%;
padding: 8px 12px;
border: 1px solid #e5e6eb;
border-radius: 8px;
background: #fafafa;
transition:
border-color 0.2s,
background-color 0.2s;
}
.promoter-info-card--clickable.promoter-info-card--trigger {
cursor: pointer;
}
.promoter-info-card--clickable.promoter-info-card--trigger:hover {
border-color: #165dff;
background: #f2f7ff;
}
.promoter-info-card--clickable.promoter-info-card--compact {
cursor: pointer;
}
.promoter-info-card--clickable.promoter-info-card--compact:hover {
opacity: 0.85;
}
.promoter-info-card--disabled {
cursor: not-allowed;
opacity: 0.65;
}
.promoter-info-card__meta {
min-width: 0;
flex: 1;
}
.promoter-info-card__name {
font-size: 14px;
font-weight: 500;
color: #1d2129;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.promoter-info-card--compact .promoter-info-card__name {
font-size: 13px;
font-weight: 400;
}
.promoter-info-card__sub {
font-size: 12px;
color: #86909c;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.promoter-info-card--compact .promoter-info-card__sub {
font-size: 11px;
}
.promoter-info-card__clear {
flex-shrink: 0;
cursor: pointer;
color: #86909c;
font-size: 16px;
line-height: 1;
padding: 0 4px;
}
.promoter-info-card__clear:hover {
color: #1d2129;
}
.promoter-info-card__empty {
color: #86909c;
}
.dark {
.promoter-info-card--trigger {
background: #1f2937;
border-color: #374151;
}
.promoter-info-card--clickable.promoter-info-card--trigger:hover {
background: #374151;
border-color: #60a5fa;
}
.promoter-info-card__name {
color: #f3f4f6;
}
.promoter-info-card__sub,
.promoter-info-card__empty {
color: #9ca3af;
}
.promoter-info-card__clear {
color: #9ca3af;
}
.promoter-info-card__clear:hover {
color: #f3f4f6;
}
}
</style>