up功能基本完成

This commit is contained in:
2026-04-23 22:52:55 +08:00
parent 78b70d4fec
commit 1b1ec7f64d
9 changed files with 467 additions and 228 deletions
@@ -41,6 +41,7 @@ const container = ref(null)
const photos = ref([])
const parentChain = ref([])
const containerDepth = ref(0)
const canModifyContainer = ref(false)
const loadingDetail = ref(true)
const notFound = ref(false)
@@ -134,6 +135,7 @@ async function fetchContainer() {
photos.value = data.photos ?? []
parentChain.value = data.parent_chain ?? []
containerDepth.value = data.depth ?? 0
canModifyContainer.value = data.canModifyContainer === true
} else {
notFound.value = true
}
@@ -328,6 +330,7 @@ onMounted(async () => {
</div>
<div class="flex gap-2">
<button
v-if="canModifyContainer"
class="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-dk-muted dark:bg-dk-base dark:text-white dark:hover:bg-dk-muted"
@click="openEdit"
>
@@ -335,7 +338,7 @@ onMounted(async () => {
{{ t('warehouse.edit') }}
</button>
<button
v-if="container.ChildCount === 0 && container.ItemCount === 0"
v-if="canModifyContainer && container.ChildCount === 0 && container.ItemCount === 0"
class="inline-flex items-center gap-1.5 rounded-lg border border-red-300 bg-white px-3 py-1.5 text-sm font-medium text-red-600 transition-colors hover:bg-red-50 dark:border-red-900 dark:bg-dk-base dark:text-red-400 dark:hover:bg-red-900/20"
@click="confirmDelete"
>
@@ -378,7 +381,14 @@ onMounted(async () => {
<!-- 元信息 -->
<div class="flex flex-wrap gap-x-6 gap-y-1 text-xs text-gray-400 dark:text-gray-500">
<span>{{ t('warehouse.created_by') }}: {{ usersStore.getUsernameFromUserID(container.CreatorID) }}</span>
<span class="flex items-center gap-1">
<span>{{ t('warehouse.created_by') }}:</span>
<img
:src="usersStore.getAvatarUrlFromUserID(container.CreatorID)"
class="w-4 h-4 rounded-full object-cover"
/>
{{ usersStore.getUsernameFromUserID(container.CreatorID) }}
</span>
<span>{{ t('warehouse.created_at') }}: {{ fmtTs(container.CreatedAt) }}</span>
<span>{{ t('warehouse.child_containers') }}: {{ container.ChildCount }}</span>
<span>{{ t('warehouse.items') }}: {{ container.ItemCount }}</span>
@@ -418,12 +428,13 @@ onMounted(async () => {
<th class="px-5 py-3 font-medium w-24 text-center">{{ t('warehouse.child_containers') }}</th>
<th class="px-5 py-3 font-medium w-24 text-center">{{ t('warehouse.items') }}</th>
<th class="px-5 py-3 font-medium whitespace-nowrap">{{ t('warehouse.created_at') }}</th>
<th class="px-5 py-3 font-medium">{{ t('warehouse.created_by') }}</th>
<th class="px-5 py-3 font-medium w-24 text-right">{{ t('warehouse.actions') }}</th>
</tr>
</thead>
<tbody>
<tr v-if="loadingSub">
<td colspan="5" class="px-5 py-8 text-center">
<td colspan="6" class="px-5 py-8 text-center">
<svg class="mx-auto h-5 w-5 animate-spin text-gray-400" viewBox="0 0 24 24" fill="none">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z" />
@@ -431,7 +442,7 @@ onMounted(async () => {
</td>
</tr>
<tr v-else-if="subContainers.length === 0">
<td colspan="5" class="px-5 py-8 text-center text-gray-400 dark:text-gray-500">
<td colspan="6" class="px-5 py-8 text-center text-gray-400 dark:text-gray-500">
{{ t('warehouse.no_containers') }}
</td>
</tr>
@@ -459,6 +470,15 @@ onMounted(async () => {
</span>
</td>
<td class="px-5 py-3 text-xs text-gray-400 dark:text-gray-500 whitespace-nowrap">{{ fmtTs(c.CreatedAt) }}</td>
<td class="px-5 py-3">
<div class="flex items-center gap-1.5">
<img
:src="usersStore.getAvatarUrlFromUserID(c.CreatorID)"
class="w-5 h-5 rounded-full object-cover flex-shrink-0"
/>
<span class="truncate text-gray-600 dark:text-gray-400">{{ usersStore.getUsernameFromUserID(c.CreatorID) }}</span>
</div>
</td>
<td class="px-5 py-3 text-right">
<button
class="text-xs text-blue-500 hover:underline"
@@ -534,12 +554,13 @@ onMounted(async () => {
<th class="px-5 py-3 font-medium">{{ t('warehouse.serial_number') }}</th>
<th class="px-5 py-3 font-medium w-20 text-center">{{ t('warehouse.quantity') }}</th>
<th class="px-5 py-3 font-medium whitespace-nowrap">{{ t('warehouse.created_at') }}</th>
<th class="px-5 py-3 font-medium">{{ t('warehouse.created_by') }}</th>
<th class="px-5 py-3 font-medium w-20 text-right">{{ t('warehouse.actions') }}</th>
</tr>
</thead>
<tbody>
<tr v-if="loadingItems">
<td colspan="5" class="px-5 py-8 text-center">
<td colspan="6" class="px-5 py-8 text-center">
<svg class="mx-auto h-5 w-5 animate-spin text-gray-400" viewBox="0 0 24 24" fill="none">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z" />
@@ -547,7 +568,7 @@ onMounted(async () => {
</td>
</tr>
<tr v-else-if="items.length === 0">
<td colspan="5" class="px-5 py-8 text-center text-gray-400 dark:text-gray-500">
<td colspan="6" class="px-5 py-8 text-center text-gray-400 dark:text-gray-500">
{{ t('warehouse.no_items') }}
</td>
</tr>
@@ -567,6 +588,15 @@ onMounted(async () => {
<td class="px-5 py-3 text-xs text-gray-500 dark:text-gray-400 max-w-[140px] truncate">{{ item.serial_number || '—' }}</td>
<td class="px-5 py-3 text-center text-sm">{{ item.Quantity }}</td>
<td class="px-5 py-3 text-xs text-gray-400 dark:text-gray-500 whitespace-nowrap">{{ fmtTs(item.CreatedAt) }}</td>
<td class="px-5 py-3">
<div class="flex items-center gap-1.5">
<img
:src="usersStore.getAvatarUrlFromUserID(item.CreatorID)"
class="w-5 h-5 rounded-full object-cover flex-shrink-0"
/>
<span class="truncate text-gray-600 dark:text-gray-400">{{ usersStore.getUsernameFromUserID(item.CreatorID) }}</span>
</div>
</td>
<td class="px-5 py-3 text-right">
<button
class="text-xs text-blue-500 hover:underline"
@@ -727,7 +757,6 @@ onMounted(async () => {
:confirm-text="t('warehouse.delete')"
:cancel-text="t('message.cancel')"
danger
:confirm-loading="deleting"
@confirm="doDelete"
/>
</template>