fix: 群详情成员分页并与后端能力对齐
This commit is contained in:
@@ -10,10 +10,12 @@ import {
|
||||
NModal,
|
||||
NScrollbar,
|
||||
NSpace,
|
||||
NText,
|
||||
useDialog,
|
||||
} from "naive-ui";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import LoadFailed from "@/components/LoadFailed.vue";
|
||||
import HelpTip from "@/components/HelpTip.vue";
|
||||
import {
|
||||
addGroupMembers,
|
||||
createGroup,
|
||||
@@ -40,11 +42,14 @@ const pageSize = ref(50);
|
||||
const query = ref("");
|
||||
|
||||
const createOpen = ref(false);
|
||||
const createForm = reactive({ id: "", name: "", owner_id: "", member_ids: "" });
|
||||
const createForm = reactive({ name: "", owner_id: "", member_ids: "" });
|
||||
const createLoading = ref(false);
|
||||
|
||||
const detailOpen = ref(false);
|
||||
const detailId = ref("");
|
||||
const detail = ref<GroupDetail | null>(null);
|
||||
const memberPage = ref(1);
|
||||
const memberPageSize = ref(50);
|
||||
const renameName = ref("");
|
||||
const addMembers = ref("");
|
||||
|
||||
@@ -137,13 +142,38 @@ const memberColumns = computed<DataTableColumns<GroupMember>>(() => [
|
||||
},
|
||||
]);
|
||||
|
||||
async function openDetail(id: string) {
|
||||
detail.value = await getGroup(id);
|
||||
async function loadDetail(id: string) {
|
||||
const cursor = memberPage.value > 1 ? String((memberPage.value - 1) * memberPageSize.value) : "";
|
||||
detail.value = await getGroup(id, cursor, memberPageSize.value);
|
||||
renameName.value = detail.value.name;
|
||||
}
|
||||
|
||||
async function openDetail(id: string) {
|
||||
detailId.value = id;
|
||||
memberPage.value = 1;
|
||||
addMembers.value = "";
|
||||
await loadDetail(id);
|
||||
detailOpen.value = true;
|
||||
}
|
||||
|
||||
function failLabel(code: string): string {
|
||||
switch (code) {
|
||||
case "not_found":
|
||||
case "invalid_target":
|
||||
return "端不存在";
|
||||
case "endpoint_disabled":
|
||||
return "端已停用";
|
||||
case "group_full":
|
||||
return "群已满";
|
||||
default:
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
function formatFailed(failed: { id: string; code: string }[]): string {
|
||||
return failed.map((f) => `${f.id}(${failLabel(f.code)})`).join("、");
|
||||
}
|
||||
|
||||
async function submitCreate() {
|
||||
if (!createForm.name.trim() || !createForm.owner_id.trim()) {
|
||||
message.error("名称与群主必填");
|
||||
@@ -156,14 +186,13 @@ async function submitCreate() {
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
const res = await createGroup({
|
||||
id: createForm.id.trim() || undefined,
|
||||
name: createForm.name.trim(),
|
||||
owner_id: createForm.owner_id.trim(),
|
||||
member_ids,
|
||||
});
|
||||
createOpen.value = false;
|
||||
if (res.failed.length) {
|
||||
message.warning(`已创建,部分成员失败:${res.failed.map((f) => f.id).join(", ")}`);
|
||||
message.warning(`已创建,部分成员失败:${formatFailed(res.failed)}`);
|
||||
} else {
|
||||
message.success("已创建");
|
||||
}
|
||||
@@ -191,7 +220,7 @@ async function onRename() {
|
||||
if (!detail.value) return;
|
||||
await renameGroup(detail.value.id, renameName.value.trim());
|
||||
message.success("已改名");
|
||||
await openDetail(detail.value.id);
|
||||
await loadDetail(detail.value.id);
|
||||
await load();
|
||||
}
|
||||
|
||||
@@ -204,28 +233,44 @@ async function onAddMembers() {
|
||||
if (!ids.length) return;
|
||||
const res = await addGroupMembers(detail.value.id, ids);
|
||||
if (res.failed.length) {
|
||||
message.warning(`部分失败:${res.failed.map((f) => f.id).join(", ")}`);
|
||||
message.warning(`部分失败:${formatFailed(res.failed)}`);
|
||||
} else {
|
||||
message.success("已加人");
|
||||
}
|
||||
await openDetail(detail.value.id);
|
||||
await loadDetail(detail.value.id);
|
||||
await load();
|
||||
}
|
||||
|
||||
async function onRemove(endpointId: string) {
|
||||
if (!detail.value) return;
|
||||
await removeGroupMember(detail.value.id, endpointId);
|
||||
message.success("已移除");
|
||||
await openDetail(detail.value.id);
|
||||
await load();
|
||||
dialog.warning({
|
||||
title: "移除成员",
|
||||
content: `确定将 ${endpointId} 移出本群?`,
|
||||
positiveText: "移除",
|
||||
negativeText: "取消",
|
||||
onPositiveClick: async () => {
|
||||
await removeGroupMember(detail.value!.id, endpointId);
|
||||
message.success("已移除");
|
||||
await loadDetail(detail.value!.id);
|
||||
await load();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function onTransfer(endpointId: string) {
|
||||
if (!detail.value) return;
|
||||
await transferGroup(detail.value.id, endpointId);
|
||||
message.success("已转让群主");
|
||||
await openDetail(detail.value.id);
|
||||
await load();
|
||||
dialog.warning({
|
||||
title: "转让群主",
|
||||
content: `确定将群主转让给 ${endpointId}?`,
|
||||
positiveText: "转让",
|
||||
negativeText: "取消",
|
||||
onPositiveClick: async () => {
|
||||
await transferGroup(detail.value!.id, endpointId);
|
||||
message.success("已转让群主");
|
||||
await loadDetail(detail.value!.id);
|
||||
await load();
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -237,7 +282,7 @@ async function onTransfer(endpointId: string) {
|
||||
type="primary"
|
||||
data-testid="group-create-open"
|
||||
@click="
|
||||
Object.assign(createForm, { id: '', name: '', owner_id: '', member_ids: '' });
|
||||
Object.assign(createForm, { name: '', owner_id: '', member_ids: '' });
|
||||
createOpen = true;
|
||||
"
|
||||
>
|
||||
@@ -249,7 +294,7 @@ async function onTransfer(endpointId: string) {
|
||||
<LoadFailed v-if="loadError" :description="loadError" @retry="load" />
|
||||
<template v-else>
|
||||
<n-space style="margin-bottom: 12px">
|
||||
<n-input v-model:value="query" placeholder="名称/编号" style="width: 200px" @keyup.enter="page = 1; load()" />
|
||||
<n-input v-model:value="query" placeholder="群名称" style="width: 200px" data-testid="group-query" @keyup.enter="page = 1; load()" />
|
||||
<n-button @click="page = 1; load()">查询</n-button>
|
||||
</n-space>
|
||||
<n-data-table
|
||||
@@ -275,8 +320,12 @@ async function onTransfer(endpointId: string) {
|
||||
<n-modal v-model:show="createOpen" preset="card" title="新建群" style="width: 480px">
|
||||
<n-scrollbar style="max-height: 320px">
|
||||
<n-form label-placement="left" label-width="90" :show-feedback="false">
|
||||
<n-form-item label="编号">
|
||||
<n-input v-model:value="createForm.id" placeholder="留空则生成" data-testid="group-id" />
|
||||
<n-form-item>
|
||||
<template #label>
|
||||
编号
|
||||
<HelpTip>由服务器生成,后台不能自定。</HelpTip>
|
||||
</template>
|
||||
<n-text depth="3">创建后自动分配</n-text>
|
||||
</n-form-item>
|
||||
<n-form-item label="名称">
|
||||
<n-input v-model:value="createForm.name" data-testid="group-name" />
|
||||
@@ -323,7 +372,23 @@ async function onTransfer(endpointId: string) {
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-data-table :columns="memberColumns" :data="detail.members" :row-key="(r: GroupMember) => r.id" size="small" />
|
||||
<n-data-table
|
||||
remote
|
||||
:columns="memberColumns"
|
||||
:data="detail.members"
|
||||
:row-key="(r: GroupMember) => r.id"
|
||||
size="small"
|
||||
:max-height="280"
|
||||
:pagination="{
|
||||
page: memberPage,
|
||||
pageSize: memberPageSize,
|
||||
itemCount: detail.member_total ?? detail.members.length,
|
||||
onChange: (p: number) => {
|
||||
memberPage = p;
|
||||
loadDetail(detailId);
|
||||
},
|
||||
}"
|
||||
/>
|
||||
</n-scrollbar>
|
||||
<template #footer>
|
||||
<n-space justify="end">
|
||||
|
||||
Reference in New Issue
Block a user