108 lines
4.1 KiB
Vue
108 lines
4.1 KiB
Vue
<template>
|
||
<div class="space-y-6">
|
||
<section class="page-header">
|
||
<div>
|
||
<p class="page-kicker">My Assets</p>
|
||
<h2 class="page-title">我的资产</h2>
|
||
</div>
|
||
<div class="page-meta-grid">
|
||
<div class="page-meta">
|
||
<p class="page-meta__label">未归还</p>
|
||
<p class="page-meta__value">{{ assets.length }}</p>
|
||
</div>
|
||
<div class="page-meta">
|
||
<p class="page-meta__label">员工绑定</p>
|
||
<p class="page-meta__value text-base">{{ personLabel }}</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section v-if="loading" class="card empty-state">正在加载本人资产...</section>
|
||
<section v-else-if="errorText" class="card">
|
||
<p class="text-sm text-status-error">{{ errorText }}</p>
|
||
</section>
|
||
<section v-else-if="assets.length === 0" class="card empty-state">当前没有未归还资产。</section>
|
||
|
||
<section v-else class="grid gap-4 lg:grid-cols-2">
|
||
<article v-for="record in assets" :key="record.borrow_record_id" class="card">
|
||
<div class="flex items-start justify-between gap-4">
|
||
<div class="min-w-0">
|
||
<p class="text-base font-semibold text-text-primary">{{ record.equipment.equipment_name }}</p>
|
||
<p class="mt-1 font-mono text-xs text-text-tertiary">{{ record.equipment.equipment_code }}</p>
|
||
</div>
|
||
<span class="badge badge-warning">使用中</span>
|
||
</div>
|
||
|
||
<div class="mt-4 grid gap-3 sm:grid-cols-2">
|
||
<div class="panel">
|
||
<p class="mobile-card__label">借出时间</p>
|
||
<p class="mt-1 text-sm text-text-primary">{{ formatDateTime(record.borrow_time) }}</p>
|
||
</div>
|
||
<div class="panel">
|
||
<p class="mobile-card__label">预计归还</p>
|
||
<p class="mt-1 text-sm text-text-primary">{{ getReturnLabel(record) }}</p>
|
||
</div>
|
||
<div class="panel sm:col-span-2">
|
||
<p class="mobile-card__label">存放位置</p>
|
||
<p class="mt-1 text-sm text-text-primary">{{ record.equipment.storageLocation?.name || '-' }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="record.children?.length" class="mt-4 border-t border-border pt-4">
|
||
<h3 class="section-title">随借配件</h3>
|
||
<div class="mt-3 space-y-2">
|
||
<div v-for="child in record.children" :key="child.id" class="panel flex items-center justify-between gap-3">
|
||
<div class="min-w-0">
|
||
<p class="truncate text-sm text-text-primary">{{ child.equipment_name }}</p>
|
||
<p class="mt-1 font-mono text-xs text-text-tertiary">{{ child.equipment_code }}</p>
|
||
</div>
|
||
<span class="text-xs text-text-secondary">{{ child.equipment_type }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</section>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, onMounted, ref } from 'vue'
|
||
import { getMyAssets, type MyAssetRecord } from '@/api/myAssets'
|
||
import type { BoundPersonSummary } from '@/types'
|
||
import { formatDateTime } from '@/utils/format'
|
||
|
||
const loading = ref(false)
|
||
const errorText = ref('')
|
||
const person = ref<BoundPersonSummary | null>(null)
|
||
const assets = ref<MyAssetRecord[]>([])
|
||
|
||
const personLabel = computed(() => {
|
||
if (!person.value) return '未绑定'
|
||
if (person.value.nickname && person.value.nickname !== person.value.real_name) {
|
||
return `${person.value.nickname}(${person.value.real_name})`
|
||
}
|
||
return person.value.nickname || person.value.real_name
|
||
})
|
||
|
||
const getReturnLabel = (record: MyAssetRecord) => {
|
||
if (record.is_long_term) return '长期使用'
|
||
return record.expected_return_time ? formatDateTime(record.expected_return_time) : '未设置'
|
||
}
|
||
|
||
const loadAssets = async () => {
|
||
loading.value = true
|
||
errorText.value = ''
|
||
try {
|
||
const response = await getMyAssets()
|
||
person.value = response.data?.person || null
|
||
assets.value = response.data?.assets || []
|
||
} catch (error: any) {
|
||
errorText.value = error?.message || '本人资产加载失败'
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(loadAssets)
|
||
</script>
|