rewrite tables

This commit is contained in:
pa
2026-01-13 17:49:38 +09:00
committed by Natsumi
parent 7649390939
commit 6e3aa44710
7 changed files with 746 additions and 435 deletions

View File

@@ -222,6 +222,7 @@
const { t } = useI18n();
const router = useRouter();
const route = useRoute();
const { showGalleryPage } = useGalleryStore();
const { friends } = storeToRefs(useFriendStore());
@@ -239,11 +240,7 @@
const isExportFriendsListDialogVisible = ref(false);
const isExportAvatarsListDialogVisible = ref(false);
const isEditInviteMessagesDialogVisible = ref(false);
const isToolsTabVisible = computed(() => {
const route = useRoute();
if (!route) return false;
return route.name === 'tools';
});
const isToolsTabVisible = computed(() => route.name === 'tools');
const showGroupCalendarDialog = () => {
isGroupCalendarDialogVisible.value = true;

View File

@@ -18,13 +18,20 @@
<Button
size="sm"
class="mr-2"
variant="outline"
:disabled="loading"
style="margin-top: 10px"
@click="updateNoteExportDialog">
{{ t('dialog.note_export.refresh') }}
</Button>
<Button size="sm" variant="outline" :disabled="loading" style="margin-top: 10px" @click="exportNoteExport">
<Button
size="sm"
class="mr-2"
variant="outline"
:disabled="loading"
style="margin-top: 10px"
@click="exportNoteExport">
{{ t('dialog.note_export.export') }}
</Button>
<Button v-if="loading" size="sm" variant="outline" style="margin-top: 10px" @click="cancelNoteExport">
@@ -45,60 +52,29 @@
<pre style="white-space: pre-wrap; font-size: 12px" v-text="errors"></pre>
</template>
<DataTable :loading="loading" v-bind="noteExportTable" style="margin-top: 10px">
<el-table-column :label="t('table.import.image')" width="70" prop="currentAvatarThumbnailImageUrl">
<template #default="{ row }">
<el-popover placement="right" :width="500" trigger="hover">
<template #reference>
<img :src="userImage(row.ref)" class="friends-list-avatar" loading="lazy" />
</template>
<img
:src="userImageFull(row.ref)"
:class="['friends-list-avatar', 'x-popover-image']"
style="cursor: pointer"
loading="lazy"
@click="showFullscreenImageDialog(userImageFull(row.ref))" />
</el-popover>
</template>
</el-table-column>
<el-table-column :label="t('table.import.name')" width="170" prop="name">
<template #default="{ row }">
<span class="x-link" @click="showUserDialog(row.id)" v-text="row.name"></span>
</template>
</el-table-column>
<el-table-column :label="t('table.import.note')" prop="memo">
<template #default="{ row }">
<InputGroupTextareaField
v-model="row.memo"
:maxlength="256"
:rows="2"
input-class="min-h-0 py-1 resize-none"
show-count />
</template>
</el-table-column>
<el-table-column :label="t('table.import.skip_export')" width="90" align="right">
<template #default="{ row }">
<Button size="sm" variant="ghost" @click="removeFromNoteExportTable(row)"></Button>
</template>
</el-table-column>
</DataTable>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:show-pagination="false"
style="margin-top: 10px" />
</el-dialog>
</template>
<script setup>
import { ref, watch } from 'vue';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group';
import { DataTableLayout } from '@/components/ui/data-table';
import { Loading } from '@element-plus/icons-vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { removeFromArray, userImage, userImageFull } from '../../../shared/utils';
import { useFriendStore, useGalleryStore, useUserStore } from '../../../stores';
import { createColumns } from './noteExportColumns.jsx';
import { miscRequest } from '../../../api';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
import * as workerTimers from 'worker-timers';
@@ -123,6 +99,29 @@
layout: 'table'
});
const tableStyle = { maxHeight: '500px' };
const rows = computed(() => (Array.isArray(noteExportTable.value?.data) ? noteExportTable.value.data.slice() : []));
const columns = computed(() =>
createColumns({
userImage,
userImageFull,
onShowFullscreenImage: showFullscreenImageDialog,
onShowUser: showUserDialog,
onRemove: removeFromNoteExportTable
})
);
const { table } = useVrcxVueTable({
persistKey: 'noteExportDialog',
data: rows,
columns: columns.value,
getRowId: (row) => String(row?.id ?? ''),
enablePagination: false,
enableSorting: false
});
const progress = ref(0);
const progressTotal = ref(0);
const loading = ref(false);

View File

@@ -0,0 +1,119 @@
import { Trash2 } from 'lucide-vue-next';
import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group';
import { i18n } from '@/plugin';
const { t } = i18n.global;
export const createColumns = ({ userImage, userImageFull, onShowFullscreenImage, onShowUser, onRemove }) => [
{
id: 'image',
header: () => t('table.import.image'),
enableSorting: false,
size: 70,
cell: ({ row }) => {
const original = row.original;
const ref = original?.ref;
const thumb = userImage?.(ref);
const full = userImageFull?.(ref);
return (
<el-popover
placement="right"
width={500}
trigger="hover"
v-slots={{
reference: () => (
<img
src={thumb}
class="friends-list-avatar"
loading="lazy"
/>
)
}}
>
<img
src={full}
class={['friends-list-avatar', 'x-popover-image']}
style="cursor: pointer"
loading="lazy"
onClick={(e) => {
e.stopPropagation();
if (full) {
onShowFullscreenImage?.(full);
}
}}
/>
</el-popover>
);
}
},
{
id: 'name',
header: () => t('table.import.name'),
size: 170,
cell: ({ row }) => {
const original = row.original;
return (
<span
class="x-link"
onClick={(e) => {
e.stopPropagation();
onShowUser?.(original?.id);
}}
>
{original?.name}
</span>
);
}
},
{
id: 'memo',
accessorKey: 'memo',
header: () => t('table.import.note'),
enableSorting: false,
meta: {
stretch: true
},
cell: ({ row }) => {
const original = row.original;
return (
<InputGroupTextareaField
modelValue={original?.memo ?? ''}
onUpdate:modelValue={(value) => {
original.memo = value;
}}
maxlength={256}
rows={2}
input-class="min-h-0 py-1 resize-none"
show-count
/>
);
}
},
{
id: 'skip',
header: () => t('table.import.skip_export'),
size: 90,
enableSorting: false,
meta: {
tdClass: 'text-right'
},
cell: ({ row }) => {
const original = row.original;
return (
<Button
size="icon-sm"
variant="ghost"
onClick={(e) => {
e.stopPropagation();
onRemove?.(original);
}}
>
<Trash2 />
</Button>
);
}
}
];