Files
aiot-platform-ui/apps/web-antd/src/views/ops/area-security/modules/staff-card.vue
2026-03-15 16:58:26 +08:00

180 lines
3.6 KiB
Vue

<script setup lang="ts">
import type { AreaSecurityUserDisplay } from '../data';
import { computed } from 'vue';
import { Button, Card, Tag } from 'ant-design-vue';
import { BIND_TYPE_MAP } from '../data';
const props = defineProps<{
item: AreaSecurityUserDisplay;
}>();
const emit = defineEmits<{
(e: 'goSource', item: AreaSecurityUserDisplay): void;
(e: 'unbind', item: AreaSecurityUserDisplay): void;
}>();
const isDirect = computed(() => props.item.bindType === 'DIRECT');
const bindMeta = computed(() => BIND_TYPE_MAP[props.item.bindType]);
</script>
<template>
<Card
class="staff-card"
:class="{ 'staff-card--inherited': !isDirect }"
hoverable
:body-style="{ padding: '0' }"
>
<div class="staff-card__body">
<!-- Header -->
<div class="staff-card__header">
<span class="staff-card__name" :title="item.userName">
{{ item.userName || '--' }}
</span>
<Tag :color="bindMeta.color" class="staff-card__tag">
{{ bindMeta.label }}
</Tag>
</div>
<!-- Info -->
<div class="staff-card__info">
<div v-if="item.createTime" class="staff-card__info-row">
<span class="staff-card__info-label">绑定时间</span>
<span class="staff-card__info-value">{{ item.createTime }}</span>
</div>
<div
v-if="!isDirect && item.sourceAreaName"
class="staff-card__info-row"
>
<span class="staff-card__info-label">来源区域</span>
<span class="staff-card__info-value staff-card__source">
{{ item.sourceAreaName }}
</span>
</div>
</div>
<!-- Actions -->
<div class="staff-card__footer">
<Tag v-if="!item.enabled" color="error">已停用</Tag>
<Button
v-if="isDirect"
size="small"
danger
@click="emit('unbind', item)"
>
解除绑定
</Button>
<Button
v-else
size="small"
type="link"
class="staff-card__go-source"
@click="emit('goSource', item)"
>
去源区域查看
</Button>
</div>
</div>
</Card>
</template>
<style scoped lang="scss">
.staff-card {
overflow: hidden;
border-radius: 8px;
transition: all 0.3s ease;
&:hover {
box-shadow: 0 4px 16px rgb(0 0 0 / 8%);
transform: translateY(-2px);
}
&--inherited {
border-style: dashed;
opacity: 0.75;
}
&__body {
padding: 16px;
}
&__header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
&__name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
font-size: 15px;
font-weight: 600;
color: #262626;
white-space: nowrap;
}
&__tag {
flex-shrink: 0;
margin-right: 0;
}
&__info {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 10px;
font-size: 13px;
}
&__info-row {
display: flex;
gap: 8px;
align-items: center;
}
&__info-label {
flex-shrink: 0;
color: #8c8c8c;
}
&__info-value {
overflow: hidden;
text-overflow: ellipsis;
color: #595959;
white-space: nowrap;
}
&__source {
color: #1677ff;
}
&__footer {
display: flex;
gap: 8px;
align-items: center;
}
&__go-source {
padding-left: 0;
}
}
html.dark {
.staff-card__name {
color: rgb(255 255 255 / 85%);
}
.staff-card__info-label {
color: rgb(255 255 255 / 45%);
}
.staff-card__info-value {
color: rgb(255 255 255 / 65%);
}
}
</style>