Files
platforms/frontend/platform_admin/src/views/resource/ResourceAccountSummary.vue

207 lines
5.0 KiB
Vue
Raw Normal View History

<!--
功能展示账户类资源的头像用户名唯一标识和创建时间摘要
版本v1.1.0
-->
<template>
<a-card class="account-card" :bordered="false">
<div class="account-summary" :class="{ 'account-summary-text': !avatarEnabled }">
<div v-if="avatarEnabled" class="avatar-column">
<button
class="avatar-button"
type="button"
:disabled="mode === 'detail' || !avatarEnabled"
:aria-label="mode === 'detail' || !avatarEnabled ? '账户头像' : '选择账户头像'"
@click="chooseAvatar"
>
<a-avatar :size="120" class="account-avatar">
<img :src="avatarUrl" alt="账户头像" />
</a-avatar>
<span v-if="mode !== 'detail' && avatarEnabled" class="camera-badge"><icon-camera /></span>
</button>
<input
ref="avatarInput"
class="avatar-input"
type="file"
accept="image/jpeg,image/png"
@change="onAvatarSelected"
/>
<span v-if="mode !== 'detail' && avatarEnabled" class="avatar-help">JPG/PNG最大 2 MB</span>
<a-button v-if="mode !== 'detail' && avatarEnabled && canClear" type="text" size="mini" @click="emit('clear-avatar')">
恢复默认头像
</a-button>
</div>
<div class="identity-summary">
<h2>{{ summaryTitle }}</h2>
<dl>
<div>
<dt>用户名</dt>
<dd>{{ String(record.username ?? '保存后确定') }}</dd>
</div>
<div>
<dt>唯一标识</dt>
<dd class="identity-value">{{ String(record.identity ?? '保存后生成') }}</dd>
</div>
<div>
<dt>创建时间</dt>
<dd>{{ displayRawValue('created_at', record.created_at) }}</dd>
</div>
</dl>
</div>
</div>
</a-card>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { IconCamera } from '@arco-design/web-vue/es/icon';
import { displayRawValue } from '@/api/resource-display';
import type { ResourceRow, RecordPageMode } from '@/api/resource-page-rules';
const props = defineProps<{
mode: RecordPageMode;
title: string;
record: ResourceRow;
avatarUrl: string;
avatarEnabled: boolean;
canClear: boolean;
}>();
const emit = defineEmits<{
'select-avatar': [file: File];
'clear-avatar': [];
}>();
const avatarInput = ref<HTMLInputElement>();
const summaryTitle = computed(() =>
String(
props.record.name ??
props.record.display_name ??
props.record.real_name ??
props.record.username ??
(props.mode === 'create' ? `新建${props.title}` : props.title),
),
);
function chooseAvatar() {
if (props.mode !== 'detail' && props.avatarEnabled)
avatarInput.value?.click();
}
function onAvatarSelected(event: Event) {
const input = event.target as HTMLInputElement;
const file = input.files?.[0];
if (file) emit('select-avatar', file);
input.value = '';
}
</script>
<style scoped lang="less">
.account-card {
border-radius: 10px;
}
.account-summary {
display: grid;
grid-template-columns: 180px minmax(360px, 500px);
justify-content: center;
align-items: center;
gap: 44px;
min-height: 168px;
padding: 18px 32px;
}
.account-summary-text {
grid-template-columns: minmax(420px, 720px);
justify-content: start;
min-height: 116px;
padding: 14px 32px;
}
.account-summary-text .identity-summary {
width: 100%;
}
.avatar-column {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.avatar-button {
position: relative;
padding: 0;
background: transparent;
border: 0;
cursor: pointer;
}
.avatar-button:disabled {
cursor: default;
}
.account-avatar {
background: var(--color-fill-3);
}
.account-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.camera-badge {
position: absolute;
right: 2px;
bottom: 2px;
display: grid;
width: 34px;
height: 34px;
place-items: center;
color: rgb(var(--primary-6));
background: var(--color-bg-2);
border: 3px solid var(--color-bg-2);
border-radius: 50%;
box-shadow: 0 2px 8px rgb(0 0 0 / 10%);
}
.avatar-input {
display: none;
}
.avatar-help {
color: var(--color-text-3);
font-size: 12px;
}
.identity-summary h2 {
margin: 0 0 14px;
color: var(--color-text-1);
font-size: 20px;
}
.identity-summary dl,
.identity-summary dd {
margin: 0;
}
.identity-summary dl > div {
display: grid;
grid-template-columns: 92px minmax(0, 1fr);
align-items: center;
min-height: 38px;
}
.identity-summary dt {
color: var(--color-text-3);
text-align: right;
}
.identity-summary dd {
color: var(--color-text-1);
font-size: 15px;
}
.identity-value {
color: rgb(var(--primary-6)) !important;
word-break: break-all;
}
@media (max-width: 760px) {
.account-summary {
grid-template-columns: 1fr;
gap: 20px;
padding: 20px 8px;
}
.identity-summary {
width: min(100%, 440px);
margin: 0 auto;
}
.account-summary-text {
grid-template-columns: 1fr;
min-height: auto;
padding: 14px 8px;
}
}
</style>