feat(user-management): 添加用户状态过滤功能和优化数字讲师管理界面
This commit is contained in:
@@ -55,6 +55,7 @@ const selectedColumns = ref([...columns.filter(row => {
|
||||
})])
|
||||
const page = ref(1)
|
||||
const pageCount = ref(15)
|
||||
const state_filter = ref<'verified' | 'unverified'>('verified')
|
||||
const is_verified = ref(true)
|
||||
const viewingUser = ref<UserSchema | null>(null)
|
||||
const isSlideOpen = computed({
|
||||
@@ -63,6 +64,7 @@ const isSlideOpen = computed({
|
||||
})
|
||||
|
||||
watch([is_verified, pageCount], () => page.value = 1)
|
||||
watch(state_filter, () => is_verified.value = state_filter.value === 'verified')
|
||||
|
||||
const {
|
||||
data: usersData,
|
||||
@@ -281,10 +283,10 @@ const setUserStatus = (uid: number, is_verified: boolean) => {
|
||||
|
||||
<div class="flex gap-1.5 items-center">
|
||||
<USelectMenu
|
||||
v-model="is_verified"
|
||||
v-model="state_filter"
|
||||
:options="[
|
||||
{label: '正常账号', value: true, icon: 'tabler:user-check'},
|
||||
{label: '停用账号', value: false, icon: 'tabler:user-cancel'},
|
||||
{label: '正常账号', value: 'verified', icon: 'tabler:user-check'},
|
||||
{label: '停用账号', value: 'unverified', icon: 'tabler:user-cancel'},
|
||||
]"
|
||||
:ui-menu="{width: 'w-fit', option: {size: 'text-xs', icon: {base: 'w-4 h-4'}}}"
|
||||
size="xs"
|
||||
|
||||
@@ -9,6 +9,7 @@ const pagination = reactive({
|
||||
|
||||
const {
|
||||
data: userAvatarList,
|
||||
status: userAvatarStatus,
|
||||
} = useAsyncData(
|
||||
'user-digital-human',
|
||||
() => useFetchWrapped<req.gen.DigitalHumanList & AuthedRequest, BaseResponse<PagedData<DigitalHumanItem>>>(
|
||||
@@ -25,47 +26,79 @@ const {
|
||||
watch: [pagination],
|
||||
},
|
||||
)
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'avatar',
|
||||
label: '图片',
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '名称',
|
||||
},
|
||||
{
|
||||
key: 'model_id',
|
||||
label: 'ID',
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
label: '备注',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full">
|
||||
<div class="p-4 pb-0">
|
||||
<BubbleTitle title="数字讲师管理" subtitle="Avatars">
|
||||
<template #action>
|
||||
<UButton :icon="data_layout === 'grid' ? 'tabler:layout-list' : 'tabler:layout-grid'" variant="ghost"
|
||||
@click="data_layout = data_layout === 'grid' ? 'list' : 'grid'" />
|
||||
</template>
|
||||
</BubbleTitle>
|
||||
<GradientDivider />
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div v-if="data_layout === 'grid'" class="grid grid-cols-7 gap-4">
|
||||
<div v-for="(avatar, k) in userAvatarList?.data.items" :key="avatar.model_id || k"
|
||||
class="relative rounded-lg shadow overflow-hidden w-full aspect-[9/16]">
|
||||
<NuxtImg :src="avatar.avatar" class="w-full h-full object-cover" />
|
||||
<div class="absolute inset-x-0 bottom-0 p-2 bg-gradient-to-t from-black/50 to-transparent">
|
||||
<UBadge color="white" variant="solid" icon="tabler:user-screen">{{ avatar.name }}</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
<LoginNeededContent>
|
||||
<div class="h-full">
|
||||
<div class="p-4 pb-0">
|
||||
<BubbleTitle title="数字讲师管理" subtitle="Avatars">
|
||||
<template #action>
|
||||
<UButton :icon="data_layout === 'grid' ? 'tabler:layout-list' : 'tabler:layout-grid'" variant="soft"
|
||||
color="gray" @click="data_layout = data_layout === 'grid' ? 'list' : 'grid'"
|
||||
:label="data_layout === 'grid' ? '列表视图' : '宫格视图'" />
|
||||
</template>
|
||||
</BubbleTitle>
|
||||
<GradientDivider />
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="p-4">
|
||||
<div v-if="data_layout === 'grid'" class="grid grid-cols-7 gap-4">
|
||||
<div v-for="(avatar, k) in userAvatarList?.data.items" :key="avatar.model_id || k"
|
||||
class="flex items-center gap-4 p-4 bg-white dark:bg-neutral-800 rounded-lg shadow">
|
||||
<NuxtImg :src="avatar.avatar" class="w-16 h-16 rounded-lg" />
|
||||
<div class="flex flex-col gap-1">
|
||||
<UBadge color="gray" variant="solid" icon="tabler:user-screen">{{ avatar.name }}</UBadge>
|
||||
<UBadge color="gray" variant="solid" icon="tabler:user-screen">{{ avatar.model_id }}</UBadge>
|
||||
class="relative rounded-lg shadow overflow-hidden w-full aspect-[9/16]">
|
||||
<NuxtImg :src="avatar.avatar" class="w-full h-full object-cover" />
|
||||
<div class="absolute inset-x-0 bottom-0 p-2 bg-gradient-to-t from-black/50 to-transparent">
|
||||
<UBadge color="white" variant="solid" icon="tabler:user-screen">{{ avatar.name }}</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4">
|
||||
<UPagination v-model="pagination.page" :max="9" :page-count="pagination.pageSize"
|
||||
:total="userAvatarList?.data.total || 0" />
|
||||
<div v-else>
|
||||
<div class="flex flex-col gap-4">
|
||||
<pre>{{ userAvatarList?.data.items }}</pre>
|
||||
<UTable :rows="userAvatarList?.data.items" :columns="columns" :loading="userAvatarStatus === 'pending'"
|
||||
:progress="{ color: 'amber', animation: 'carousel' }" class="border dark:border-neutral-800 rounded-md">
|
||||
<template #avatar-data="{ row }">
|
||||
<NuxtImg :src="row.avatar" class="h-16 aspect-[9/16] rounded-lg" />
|
||||
</template>
|
||||
<template #actions-data="{ row }">
|
||||
<div class="flex gap-2">
|
||||
<UButton color="gray" icon="tabler:download" label="下载图片" variant="soft" size="xs" @click="() => {
|
||||
const { download } = useDownload(row.avatar, `数字人_${row.name}.png`)
|
||||
download()
|
||||
}" />
|
||||
</div>
|
||||
</template>
|
||||
</UTable>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4">
|
||||
<UPagination v-model="pagination.page" :max="9" :page-count="pagination.pageSize"
|
||||
:total="userAvatarList?.data.total || 0" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LoginNeededContent>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
Reference in New Issue
Block a user