feat: add user dropdown selector component

pull/3445/head
Ryan Wang 2022-09-06 19:48:12 +08:00
parent 811f998a45
commit 6b1b6db751
8 changed files with 106 additions and 108 deletions

View File

@ -0,0 +1,85 @@
<script lang="ts" setup>
import type { User } from "@halo-dev/api-client";
import { useUserFetch } from "@/modules/system/users/composables/use-user";
import { IconCheckboxCircle } from "@halo-dev/components";
const props = withDefaults(
defineProps<{
selected?: User;
}>(),
{
selected: undefined,
}
);
const emit = defineEmits<{
(event: "update:selected", user?: User): void;
(event: "select", user?: User): void;
}>();
const { users, handleFetchUsers } = useUserFetch();
const handleSelect = (user: User) => {
if (props.selected && user.metadata.name === props.selected.metadata.name) {
emit("update:selected", undefined);
emit("select", undefined);
return;
}
emit("update:selected", user);
emit("select", user);
};
function onDropdownShow() {
handleFetchUsers();
}
</script>
<template>
<FloatingDropdown @show="onDropdownShow">
<slot />
<template #popper>
<div class="h-96 w-80">
<div class="bg-white p-4">
<!--TODO: Auto Focus-->
<FormKit placeholder="输入关键词搜索" type="text"></FormKit>
</div>
<div class="mt-2">
<ul class="divide-y divide-gray-200" role="list">
<li
v-for="(user, index) in users"
:key="index"
v-close-popper
class="cursor-pointer hover:bg-gray-50"
:class="{
'bg-gray-100': selected?.metadata.name === user.metadata.name,
}"
@click="handleSelect(user)"
>
<div class="flex items-center space-x-4 px-4 py-3">
<div class="flex-shrink-0">
<img
:alt="user.spec.displayName"
:src="user.spec.avatar"
class="h-10 w-10 rounded"
/>
</div>
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-medium text-gray-900">
{{ user.spec.displayName }}
</p>
<p class="truncate text-sm text-gray-500">
@{{ user.metadata.name }}
</p>
</div>
<div v-if="selected?.metadata.name === user.metadata.name">
<IconCheckboxCircle class="text-primary" />
</div>
</div>
</li>
</ul>
</div>
</div>
</template>
</FloatingDropdown>
</template>

View File

@ -19,12 +19,12 @@ import {
IconFolder,
} from "@halo-dev/components";
import LazyImage from "@/components/image/LazyImage.vue";
import UserDropdownSelector from "@/components/dropdown-selector/UserDropdownSelector.vue";
import AttachmentDetailModal from "./components/AttachmentDetailModal.vue";
import AttachmentUploadModal from "./components/AttachmentUploadModal.vue";
import AttachmentPoliciesModal from "./components/AttachmentPoliciesModal.vue";
import AttachmentGroupList from "./components/AttachmentGroupList.vue";
import { onMounted, ref } from "vue";
import { useUserFetch } from "@/modules/system/users/composables/use-user";
import type { Attachment, Group, Policy, User } from "@halo-dev/api-client";
import { formatDatetime } from "@/utils/date";
import prettyBytes from "pretty-bytes";
@ -43,7 +43,6 @@ const uploadVisible = ref(false);
const detailVisible = ref(false);
const selectVisible = ref(false);
const { users } = useUserFetch();
const { policies } = useFetchAttachmentPolicy({ fetchOnMounted: true });
const { groups, handleFetchGroups } = useFetchAttachmentGroup({
fetchOnMounted: true,
@ -345,7 +344,10 @@ onMounted(() => {
</div>
</template>
</FloatingDropdown>
<FloatingDropdown>
<UserDropdownSelector
v-model:selected="selectedUser"
@select="handleSelectUser"
>
<div
class="flex cursor-pointer select-none items-center text-sm text-gray-700 hover:text-black"
>
@ -354,56 +356,7 @@ onMounted(() => {
<IconArrowDown />
</span>
</div>
<template #popper>
<div class="h-96 w-80">
<div class="bg-white p-4">
<!--TODO: Auto Focus-->
<FormKit
placeholder="输入关键词搜索"
type="text"
></FormKit>
</div>
<div class="mt-2">
<ul class="divide-y divide-gray-200" role="list">
<li
v-for="(user, index) in users"
:key="index"
v-close-popper
class="cursor-pointer hover:bg-gray-50"
:class="{
'bg-gray-100':
selectedUser?.metadata.name ===
user.metadata.name,
}"
@click="handleSelectUser(user)"
>
<div
class="flex items-center space-x-4 px-4 py-3"
>
<div class="flex-shrink-0">
<img
:alt="user.spec.displayName"
:src="user.spec.avatar"
class="h-10 w-10 rounded"
/>
</div>
<div class="min-w-0 flex-1">
<p
class="truncate text-sm font-medium text-gray-900"
>
{{ user.spec.displayName }}
</p>
<p class="truncate text-sm text-gray-500">
@{{ user.metadata.name }}
</p>
</div>
</div>
</li>
</ul>
</div>
</div>
</template>
</FloatingDropdown>
</UserDropdownSelector>
<FloatingDropdown>
<div
class="flex cursor-pointer select-none items-center text-sm text-gray-700 hover:text-black"

View File

@ -42,7 +42,7 @@ const pagesRef = ref([
const activeId = ref("functional");
const checkAll = ref(false);
const { users } = useUserFetch();
const { users } = useUserFetch({ fetchOnMounted: true });
const pagesPublicState = ref<PagesPublicState>({
functionalPages: [],

View File

@ -16,15 +16,14 @@ import {
VPageHeader,
VPagination,
VSpace,
VTag,
} from "@halo-dev/components";
import UserDropdownSelector from "@/components/dropdown-selector/UserDropdownSelector.vue";
import PostSettingModal from "./components/PostSettingModal.vue";
import PostTag from "../posts/tags/components/PostTag.vue";
import { onMounted, ref, watch, watchEffect } from "vue";
import type { ListedPostList, Post, PostRequest } from "@halo-dev/api-client";
import { apiClient } from "@halo-dev/admin-shared";
import { formatDatetime } from "@/utils/date";
import { useUserFetch } from "@/modules/system/users/composables/use-user";
import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category";
import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag";
import cloneDeep from "lodash.clonedeep";
@ -53,7 +52,6 @@ const selectedPostWithContent = ref<PostRequest | null>(null);
const checkedAll = ref(false);
const selectedPostNames = ref<string[]>([]);
const { users } = useUserFetch();
const { categories } = usePostCategory({ fetchOnMounted: true });
const { tags } = usePostTag({ fetchOnMounted: true });
const dialog = useDialog();
@ -525,7 +523,7 @@ function handlePhaseFilterItemChange(filterItem: FilterItem) {
</div>
</template>
</FloatingDropdown>
<FloatingDropdown>
<UserDropdownSelector>
<div
class="flex cursor-pointer select-none items-center text-sm text-gray-700 hover:text-black"
>
@ -534,51 +532,7 @@ function handlePhaseFilterItemChange(filterItem: FilterItem) {
<IconArrowDown />
</span>
</div>
<template #popper>
<div class="h-96 w-80">
<div class="bg-white p-4">
<!--TODO: Auto Focus-->
<FormKit
placeholder="输入关键词搜索"
type="text"
></FormKit>
</div>
<div class="mt-2">
<ul class="divide-y divide-gray-200" role="list">
<li
v-for="(user, index) in users"
:key="index"
v-close-popper
class="cursor-pointer hover:bg-gray-50"
>
<div class="flex items-center space-x-4 px-4 py-3">
<div class="flex-shrink-0">
<img
:alt="user.spec.displayName"
:src="user.spec.avatar"
class="h-10 w-10 rounded"
/>
</div>
<div class="min-w-0 flex-1">
<p
class="truncate text-sm font-medium text-gray-900"
>
{{ user.spec.displayName }}
</p>
<p class="truncate text-sm text-gray-500">
@{{ user.metadata.name }}
</p>
</div>
<div>
<VTag>{{ index + 1 }} </VTag>
</div>
</div>
</li>
</ul>
</div>
</div>
</template>
</FloatingDropdown>
</UserDropdownSelector>
<FloatingDropdown>
<div
class="flex cursor-pointer select-none items-center text-sm text-gray-700 hover:text-black"

View File

@ -2,7 +2,7 @@
import { VCard } from "@halo-dev/components";
import { useUserFetch } from "@/modules/system/users/composables/use-user";
const { users } = useUserFetch();
const { users } = useUserFetch({ fetchOnMounted: true });
</script>
<template>
<VCard

View File

@ -1,7 +1,7 @@
<script lang="ts" name="UserStatsWidget" setup>
import { VCard } from "@halo-dev/components";
import { useUserFetch } from "@/modules/system/users/composables/use-user";
const { users } = useUserFetch();
const { users } = useUserFetch({ fetchOnMounted: true });
</script>
<template>
<VCard class="h-full">

View File

@ -28,7 +28,7 @@ const { roleTemplateGroups, handleRoleTemplateSelect, selectedRoleTemplates } =
const { formState, saving, handleCreateOrUpdate } = useRoleForm();
const { users } = useUserFetch();
const { users } = useUserFetch({ fetchOnMounted: true });
watch(
() => selectedRoleTemplates.value,

View File

@ -9,7 +9,11 @@ interface useUserFetchReturn {
handleFetchUsers: () => void;
}
export function useUserFetch(): useUserFetchReturn {
export function useUserFetch(options?: {
fetchOnMounted: boolean;
}): useUserFetchReturn {
const { fetchOnMounted } = options || {};
const users = ref<User[]>([] as User[]);
const loading = ref(false);
@ -25,7 +29,9 @@ export function useUserFetch(): useUserFetchReturn {
}
};
onMounted(handleFetchUsers);
onMounted(() => {
fetchOnMounted && handleFetchUsers();
});
return {
users,