mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-20 07:13:51 +02:00
rewrite tables
This commit is contained in:
@@ -38,361 +38,41 @@
|
||||
</div>
|
||||
<el-tabs type="card">
|
||||
<el-tab-pane :label="t('view.player_list.photon.current')">
|
||||
<DataTable v-bind="photonEventTable" style="margin-bottom: 10px">
|
||||
<el-table-column :label="t('table.playerList.date')" prop="created_at" width="130">
|
||||
<template #default="scope">
|
||||
<TooltipWrapper side="right">
|
||||
<template #content>
|
||||
<span>{{ formatDateFilter(scope.row.created_at, 'long') }}</span>
|
||||
</template>
|
||||
<span>{{ formatDateFilter(scope.row.created_at, 'short') }}</span>
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('table.playerList.user')" prop="photonId" width="160">
|
||||
<template #default="scope">
|
||||
<span
|
||||
class="x-link"
|
||||
style="padding-right: 10px"
|
||||
@click="showUserFromPhotonId(scope.row.photonId)"
|
||||
v-text="scope.row.displayName"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('table.playerList.type')" prop="type" width="140"></el-table-column>
|
||||
<el-table-column :label="t('table.playerList.detail')" prop="text">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.type === 'ChangeAvatar'">
|
||||
<span
|
||||
class="x-link"
|
||||
@click="showAvatarDialog(scope.row.avatar.id)"
|
||||
v-text="scope.row.avatar.name"></span>
|
||||
|
||||
<span v-if="!scope.row.inCache" style="color: #aaa"
|
||||
><el-icon><Download /></el-icon> </span
|
||||
>
|
||||
<span v-if="scope.row.avatar.releaseStatus === 'public'" class="avatar-info-public">{{
|
||||
t('dialog.avatar.labels.public')
|
||||
}}</span>
|
||||
<span
|
||||
v-else-if="scope.row.avatar.releaseStatus === 'private'"
|
||||
class="avatar-info-own"
|
||||
>{{ t('dialog.avatar.labels.private') }}</span
|
||||
>
|
||||
</template>
|
||||
<template v-else-if="scope.row.type === 'ChangeStatus'">
|
||||
<template v-if="scope.row.status !== scope.row.previousStatus">
|
||||
<TooltipWrapper side="top">
|
||||
<template #content>
|
||||
<span v-if="scope.row.previousStatus === 'active'">{{
|
||||
t('dialog.user.status.active')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.previousStatus === 'join me'">{{
|
||||
t('dialog.user.status.join_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.previousStatus === 'ask me'">{{
|
||||
t('dialog.user.status.ask_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.previousStatus === 'busy'">{{
|
||||
t('dialog.user.status.busy')
|
||||
}}</span>
|
||||
<span v-else>{{ t('dialog.user.status.offline') }}</span>
|
||||
</template>
|
||||
<i class="x-user-status" :class="statusClass(scope.row.previousStatus)"></i>
|
||||
</TooltipWrapper>
|
||||
<span>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</span>
|
||||
<TooltipWrapper side="top">
|
||||
<template #content>
|
||||
<span v-if="scope.row.status === 'active'">{{
|
||||
t('dialog.user.status.active')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.status === 'join me'">{{
|
||||
t('dialog.user.status.join_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.status === 'ask me'">{{
|
||||
t('dialog.user.status.ask_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.status === 'busy'">{{
|
||||
t('dialog.user.status.busy')
|
||||
}}</span>
|
||||
<span v-else>{{ t('dialog.user.status.offline') }}</span>
|
||||
</template>
|
||||
<i
|
||||
class="x-user-status"
|
||||
:class="statusClass(scope.row.status)"
|
||||
style="margin-right: 5px"></i>
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
<span
|
||||
v-if="scope.row.statusDescription !== scope.row.previousStatusDescription"
|
||||
v-text="scope.row.statusDescription"></span>
|
||||
</template>
|
||||
<template v-else-if="scope.row.type === 'ChangeGroup'">
|
||||
<span
|
||||
v-if="scope.row.previousGroupName"
|
||||
class="x-link"
|
||||
style="margin-right: 5px"
|
||||
@click="showGroupDialog(scope.row.previousGroupId)"
|
||||
v-text="scope.row.previousGroupName"></span>
|
||||
<span
|
||||
v-else
|
||||
class="x-link"
|
||||
style="margin-right: 5px"
|
||||
@click="showGroupDialog(scope.row.previousGroupId)"
|
||||
v-text="scope.row.previousGroupId"></span>
|
||||
<span>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</span>
|
||||
<span
|
||||
v-if="scope.row.groupName"
|
||||
class="x-link"
|
||||
style="margin-left: 5px"
|
||||
@click="showGroupDialog(scope.row.groupId)"
|
||||
v-text="scope.row.groupName"></span>
|
||||
<span
|
||||
v-else
|
||||
class="x-link"
|
||||
style="margin-left: 5px"
|
||||
@click="showGroupDialog(scope.row.groupId)"
|
||||
v-text="scope.row.groupId"></span>
|
||||
</template>
|
||||
<span
|
||||
v-else-if="scope.row.type === 'PortalSpawn'"
|
||||
class="x-link"
|
||||
@click="showWorldDialog(scope.row.location, scope.row.shortName)">
|
||||
<Location
|
||||
:location="scope.row.location"
|
||||
:hint="scope.row.worldName"
|
||||
:grouphint="scope.row.groupName"
|
||||
:link="false" />
|
||||
</span>
|
||||
<span v-else-if="scope.row.type === 'ChatBoxMessage'" v-text="scope.row.text"></span>
|
||||
<span v-else-if="scope.row.type === 'OnPlayerJoined'">
|
||||
<span v-if="scope.row.platform === 'Desktop'" style="color: var(--el-color-primary)"
|
||||
>Desktop </span
|
||||
>
|
||||
<span v-else-if="scope.row.platform === 'VR'" style="color: var(--el-color-primary)"
|
||||
>VR </span
|
||||
>
|
||||
<span v-else-if="scope.row.platform === 'Quest'" style="color: var(--el-color-success)"
|
||||
>Android </span
|
||||
>
|
||||
<span
|
||||
class="x-link"
|
||||
@click="showAvatarDialog(scope.row.avatar.id)"
|
||||
v-text="scope.row.avatar.name"></span>
|
||||
|
||||
<span v-if="!scope.row.inCache" style="color: #aaa"
|
||||
><el-icon><Download /></el-icon> </span
|
||||
>
|
||||
<span v-if="scope.row.avatar.releaseStatus === 'public'" class="avatar-info-public">{{
|
||||
t('dialog.avatar.labels.public')
|
||||
}}</span>
|
||||
<span
|
||||
v-else-if="scope.row.avatar.releaseStatus === 'private'"
|
||||
class="avatar-info-own"
|
||||
>{{ t('dialog.avatar.labels.private') }}</span
|
||||
>
|
||||
</span>
|
||||
<span v-else-if="scope.row.type === 'SpawnEmoji'">
|
||||
<span v-if="scope.row.imageUrl">
|
||||
<TooltipWrapper side="right">
|
||||
<template #content>
|
||||
<img
|
||||
:src="scope.row.imageUrl"
|
||||
class="friends-list-avatar"
|
||||
style="height: 500px; cursor: pointer"
|
||||
@click="showFullscreenImageDialog(scope.row.imageUrl)"
|
||||
loading="lazy" />
|
||||
</template>
|
||||
<span v-text="scope.row.fileId"></span>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
<span v-else v-text="scope.row.text"></span>
|
||||
</span>
|
||||
<span
|
||||
v-else-if="scope.row.color === 'yellow'"
|
||||
style="color: yellow"
|
||||
v-text="scope.row.text"></span>
|
||||
<span v-else v-text="scope.row.text"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</DataTable>
|
||||
<DataTableLayout
|
||||
class="min-w-0 w-full"
|
||||
:table="currentTable"
|
||||
:loading="false"
|
||||
:table-style="tableStyle"
|
||||
:page-sizes="pageSizes"
|
||||
:total-items="currentTotal"
|
||||
:on-page-size-change="handleCurrentPageSizeChange"
|
||||
style="margin-bottom: 10px" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="t('view.player_list.photon.previous')">
|
||||
<DataTable v-bind="photonEventTablePrevious" style="margin-bottom: 10px">
|
||||
<el-table-column :label="t('table.playerList.date')" prop="created_at" width="130">
|
||||
<template #default="scope">
|
||||
<TooltipWrapper side="right">
|
||||
<template #content>
|
||||
<span>{{ formatDateFilter(scope.row.created_at, 'long') }}</span>
|
||||
</template>
|
||||
<span>{{ formatDateFilter(scope.row.created_at, 'short') }}</span>
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('table.playerList.user')" prop="photonId" width="160">
|
||||
<template #default="scope">
|
||||
<span
|
||||
class="x-link"
|
||||
style="padding-right: 10px"
|
||||
@click="lookupUser(scope.row)"
|
||||
v-text="scope.row.displayName"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('table.playerList.type')" prop="type" width="140"></el-table-column>
|
||||
<el-table-column :label="t('table.playerList.detail')" prop="text">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.type === 'ChangeAvatar'">
|
||||
<span
|
||||
class="x-link"
|
||||
@click="showAvatarDialog(scope.row.avatar.id)"
|
||||
v-text="scope.row.avatar.name"></span>
|
||||
|
||||
<span v-if="!scope.row.inCache" style="color: #aaa"
|
||||
><el-icon><Download /></el-icon> </span
|
||||
>
|
||||
<span v-if="scope.row.avatar.releaseStatus === 'public'" class="avatar-info-public">{{
|
||||
t('dialog.avatar.labels.public')
|
||||
}}</span>
|
||||
<span
|
||||
v-else-if="scope.row.avatar.releaseStatus === 'private'"
|
||||
class="avatar-info-own"
|
||||
>{{ t('dialog.avatar.labels.private') }}</span
|
||||
>
|
||||
<template
|
||||
v-if="
|
||||
scope.row.avatar.description &&
|
||||
scope.row.avatar.name !== scope.row.avatar.description
|
||||
">
|
||||
| - {{ scope.row.avatar.description }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="scope.row.type === 'ChangeStatus'">
|
||||
<template v-if="scope.row.status !== scope.row.previousStatus">
|
||||
<TooltipWrapper side="top">
|
||||
<template #content>
|
||||
<span v-if="scope.row.previousStatus === 'active'">{{
|
||||
t('dialog.user.status.active')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.previousStatus === 'join me'">{{
|
||||
t('dialog.user.status.join_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.previousStatus === 'ask me'">{{
|
||||
t('dialog.user.status.ask_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.previousStatus === 'busy'">{{
|
||||
t('dialog.user.status.busy')
|
||||
}}</span>
|
||||
<span v-else>{{ t('dialog.user.status.offline') }}</span>
|
||||
</template>
|
||||
<i class="x-user-status" :class="statusClass(scope.row.previousStatus)"></i>
|
||||
</TooltipWrapper>
|
||||
<span>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</span>
|
||||
<TooltipWrapper side="top">
|
||||
<template #content>
|
||||
<span v-if="scope.row.status === 'active'">{{
|
||||
t('dialog.user.status.active')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.status === 'join me'">{{
|
||||
t('dialog.user.status.join_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.status === 'ask me'">{{
|
||||
t('dialog.user.status.ask_me')
|
||||
}}</span>
|
||||
<span v-else-if="scope.row.status === 'busy'">{{
|
||||
t('dialog.user.status.busy')
|
||||
}}</span>
|
||||
<span v-else>{{ t('dialog.user.status.offline') }}</span>
|
||||
</template>
|
||||
<i
|
||||
class="x-user-status"
|
||||
:class="statusClass(scope.row.status)"
|
||||
style="margin-right: 5px"></i>
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
<span
|
||||
v-if="scope.row.statusDescription !== scope.row.previousStatusDescription"
|
||||
v-text="scope.row.statusDescription"></span>
|
||||
</template>
|
||||
<template v-else-if="scope.row.type === 'ChangeGroup'">
|
||||
<span
|
||||
v-if="scope.row.previousGroupName"
|
||||
class="x-link"
|
||||
style="margin-right: 5px"
|
||||
@click="showGroupDialog(scope.row.previousGroupId)"
|
||||
v-text="scope.row.previousGroupName"></span>
|
||||
<span
|
||||
v-else
|
||||
class="x-link"
|
||||
style="margin-right: 5px"
|
||||
@click="showGroupDialog(scope.row.previousGroupId)"
|
||||
v-text="scope.row.previousGroupId"></span>
|
||||
<span>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</span>
|
||||
<span
|
||||
v-if="scope.row.groupName"
|
||||
class="x-link"
|
||||
style="margin-left: 5px"
|
||||
@click="showGroupDialog(scope.row.groupId)"
|
||||
v-text="scope.row.groupName"></span>
|
||||
<span
|
||||
v-else
|
||||
class="x-link"
|
||||
style="margin-left: 5px"
|
||||
@click="showGroupDialog(scope.row.groupId)"
|
||||
v-text="scope.row.groupId"></span>
|
||||
</template>
|
||||
<span
|
||||
v-else-if="scope.row.type === 'PortalSpawn'"
|
||||
class="x-link"
|
||||
@click="showWorldDialog(scope.row.location, scope.row.shortName)">
|
||||
<Location
|
||||
:location="scope.row.location"
|
||||
:hint="scope.row.worldName"
|
||||
:grouphint="scope.row.groupName"
|
||||
:link="false" />
|
||||
</span>
|
||||
<span v-else-if="scope.row.type === 'ChatBoxMessage'" v-text="scope.row.text"></span>
|
||||
<span v-else-if="scope.row.type === 'SpawnEmoji'">
|
||||
<span v-if="scope.row.imageUrl">
|
||||
<TooltipWrapper side="right">
|
||||
<template #content>
|
||||
<img
|
||||
:src="scope.row.imageUrl"
|
||||
class="friends-list-avatar"
|
||||
style="height: 500px; cursor: pointer"
|
||||
@click="showFullscreenImageDialog(scope.row.imageUrl)"
|
||||
loading="lazy" />
|
||||
</template>
|
||||
<span v-text="scope.row.fileId"></span>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
<span v-else v-text="scope.row.text"></span>
|
||||
</span>
|
||||
<span
|
||||
v-else-if="scope.row.color === 'yellow'"
|
||||
style="color: yellow"
|
||||
v-text="scope.row.text"></span>
|
||||
<span v-else v-text="scope.row.text"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</DataTable>
|
||||
<DataTableLayout
|
||||
class="min-w-0 w-full"
|
||||
:table="previousTable"
|
||||
:loading="false"
|
||||
:table-style="tableStyle"
|
||||
:page-sizes="pageSizes"
|
||||
:total-items="previousTotal"
|
||||
:on-page-size-change="handlePreviousPageSizeChange"
|
||||
style="margin-bottom: 10px" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ArrowRight, Download } from '@element-plus/icons-vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DataTableLayout } from '@/components/ui/data-table';
|
||||
import { InputGroupField } from '@/components/ui/input-group';
|
||||
import { localeIncludes } from '@/shared/utils';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useSearchStore } from '@/stores';
|
||||
import { useVrcxVueTable } from '@/lib/table/useVrcxVueTable';
|
||||
|
||||
import {
|
||||
useAvatarStore,
|
||||
@@ -404,7 +84,7 @@
|
||||
useWorldStore
|
||||
} from '../../../stores';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../components/ui/select';
|
||||
import { formatDateFilter, statusClass } from '../../../shared/utils';
|
||||
import { createColumns } from './photonEventColumns.jsx';
|
||||
import { photonEventTableTypeFilterList } from '../../../shared/constants/photon';
|
||||
|
||||
const emit = defineEmits(['show-chatbox-blacklist']);
|
||||
@@ -420,6 +100,8 @@
|
||||
} = storeToRefs(photonStore);
|
||||
const { photonEventTableFilterChange, showUserFromPhotonId } = photonStore;
|
||||
|
||||
const { stringComparer } = storeToRefs(useSearchStore());
|
||||
|
||||
const { lookupUser } = useUserStore();
|
||||
const { showAvatarDialog } = useAvatarStore();
|
||||
const { showWorldDialog } = useWorldStore();
|
||||
@@ -427,6 +109,104 @@
|
||||
const { showFullscreenImageDialog } = useGalleryStore();
|
||||
const { ipcEnabled } = storeToRefs(useVrcxStore());
|
||||
|
||||
const pageSizes = [10, 25, 50, 100];
|
||||
const tableStyle = { maxHeight: '320px' };
|
||||
|
||||
const q = computed(() =>
|
||||
String(photonEventTableFilter.value ?? '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
);
|
||||
const typeFilterSet = computed(() => new Set(photonEventTableTypeFilter.value ?? []));
|
||||
|
||||
const filterRows = (rows) => {
|
||||
const query = q.value;
|
||||
const types = typeFilterSet.value;
|
||||
const comparer = stringComparer.value;
|
||||
const src = Array.isArray(rows) ? rows : [];
|
||||
|
||||
return src.filter((row) => {
|
||||
if (types.size && !types.has(row?.type)) return false;
|
||||
if (!query) return true;
|
||||
|
||||
return (
|
||||
localeIncludes(row?.displayName ?? '', query, comparer) ||
|
||||
localeIncludes(row?.text ?? '', query, comparer)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const currentRawRows = computed(() =>
|
||||
Array.isArray(photonEventTable.value?.data) ? photonEventTable.value.data.slice() : []
|
||||
);
|
||||
const previousRawRows = computed(() =>
|
||||
Array.isArray(photonEventTablePrevious.value?.data) ? photonEventTablePrevious.value.data.slice() : []
|
||||
);
|
||||
|
||||
const currentRows = computed(() => filterRows(currentRawRows.value));
|
||||
const previousRows = computed(() => filterRows(previousRawRows.value));
|
||||
|
||||
const currentTotal = computed(() => currentRows.value.length);
|
||||
const previousTotal = computed(() => previousRows.value.length);
|
||||
|
||||
const currentPageSize = ref(photonEventTable.value?.pageSize ?? 10);
|
||||
const previousPageSize = ref(photonEventTablePrevious.value?.pageSize ?? 10);
|
||||
|
||||
const currentColumns = computed(() =>
|
||||
createColumns({
|
||||
isPrevious: false,
|
||||
onShowUser: (row) => showUserFromPhotonId(row?.photonId),
|
||||
onShowAvatar: showAvatarDialog,
|
||||
onShowGroup: showGroupDialog,
|
||||
onShowWorld: showWorldDialog,
|
||||
onShowImage: showFullscreenImageDialog
|
||||
})
|
||||
);
|
||||
|
||||
const previousColumns = computed(() =>
|
||||
createColumns({
|
||||
isPrevious: true,
|
||||
onShowUser: (row) => lookupUser(row),
|
||||
onShowAvatar: showAvatarDialog,
|
||||
onShowGroup: showGroupDialog,
|
||||
onShowWorld: showWorldDialog,
|
||||
onShowImage: showFullscreenImageDialog
|
||||
})
|
||||
);
|
||||
|
||||
const { table: currentTable } = useVrcxVueTable({
|
||||
persistKey: 'photonEventTable:current',
|
||||
data: currentRows,
|
||||
columns: currentColumns.value,
|
||||
getRowId: (row) => `${row?.photonId ?? ''}:${row?.created_at ?? ''}:${row?.type ?? ''}`,
|
||||
initialSorting: [{ id: 'created_at', desc: true }],
|
||||
initialPagination: { pageIndex: 0, pageSize: currentPageSize.value }
|
||||
});
|
||||
|
||||
const { table: previousTable } = useVrcxVueTable({
|
||||
persistKey: 'photonEventTable:previous',
|
||||
data: previousRows,
|
||||
columns: previousColumns.value,
|
||||
getRowId: (row) => `${row?.photonId ?? ''}:${row?.created_at ?? ''}:${row?.type ?? ''}`,
|
||||
initialSorting: [{ id: 'created_at', desc: true }],
|
||||
initialPagination: { pageIndex: 0, pageSize: previousPageSize.value }
|
||||
});
|
||||
|
||||
const handleCurrentPageSizeChange = (size) => {
|
||||
currentPageSize.value = size;
|
||||
};
|
||||
const handlePreviousPageSizeChange = (size) => {
|
||||
previousPageSize.value = size;
|
||||
};
|
||||
|
||||
watch(currentColumns, (next) => {
|
||||
currentTable.setOptions((prev) => ({ ...prev, columns: next }));
|
||||
});
|
||||
|
||||
watch(previousColumns, (next) => {
|
||||
previousTable.setOptions((prev) => ({ ...prev, columns: next }));
|
||||
});
|
||||
|
||||
function emitShowChatboxBlacklist() {
|
||||
emit('show-chatbox-blacklist');
|
||||
}
|
||||
|
||||
313
src/views/PlayerList/components/photonEventColumns.jsx
Normal file
313
src/views/PlayerList/components/photonEventColumns.jsx
Normal file
@@ -0,0 +1,313 @@
|
||||
import { ArrowRight, Download } from '@element-plus/icons-vue';
|
||||
|
||||
import Location from '@/components/Location.vue';
|
||||
import { TooltipWrapper } from '@/components/ui/tooltip';
|
||||
import { i18n } from '@/plugin';
|
||||
import { formatDateFilter, statusClass } from '@/shared/utils';
|
||||
|
||||
const { t } = i18n.global;
|
||||
|
||||
const statusLabel = (key) => {
|
||||
if (key === 'active') return t('dialog.user.status.active');
|
||||
if (key === 'join me') return t('dialog.user.status.join_me');
|
||||
if (key === 'ask me') return t('dialog.user.status.ask_me');
|
||||
if (key === 'busy') return t('dialog.user.status.busy');
|
||||
return t('dialog.user.status.offline');
|
||||
};
|
||||
|
||||
const avatarStatusLabel = (status) => {
|
||||
if (status === 'public') return t('dialog.avatar.labels.public');
|
||||
if (status === 'private') return t('dialog.avatar.labels.private');
|
||||
return '';
|
||||
};
|
||||
|
||||
const avatarStatusClass = (status) => {
|
||||
if (status === 'public') return 'avatar-info-public';
|
||||
if (status === 'private') return 'avatar-info-own';
|
||||
return null;
|
||||
};
|
||||
|
||||
function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, onShowUser, onShowImage }) {
|
||||
const r = row;
|
||||
if (!r) return null;
|
||||
|
||||
if (r.type === 'ChangeAvatar') {
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
class="x-link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onShowAvatar?.(r.avatar?.id);
|
||||
}}
|
||||
>
|
||||
{r.avatar?.name}
|
||||
</span>
|
||||
|
||||
{!r.inCache ? (
|
||||
<span style="color: #aaa">
|
||||
<el-icon>
|
||||
<Download />
|
||||
</el-icon>
|
||||
|
||||
</span>
|
||||
) : null}
|
||||
{r.avatar?.releaseStatus ? (
|
||||
<span class={avatarStatusClass(r.avatar.releaseStatus)}>
|
||||
{avatarStatusLabel(r.avatar.releaseStatus)}
|
||||
</span>
|
||||
) : null}
|
||||
{isPrevious &&
|
||||
r.avatar?.description &&
|
||||
r.avatar?.name !== r.avatar?.description ? (
|
||||
<>
|
||||
{' | - '}
|
||||
{r.avatar.description}
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (r.type === 'ChangeStatus') {
|
||||
return (
|
||||
<>
|
||||
{r.status !== r.previousStatus ? (
|
||||
<>
|
||||
<TooltipWrapper
|
||||
side="top"
|
||||
v-slots={{
|
||||
content: () => (
|
||||
<span>{statusLabel(r.previousStatus)}</span>
|
||||
)
|
||||
}}
|
||||
>
|
||||
<i
|
||||
class={[
|
||||
'x-user-status',
|
||||
statusClass(r.previousStatus)
|
||||
]}
|
||||
></i>
|
||||
</TooltipWrapper>
|
||||
<span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</span>
|
||||
<TooltipWrapper
|
||||
side="top"
|
||||
v-slots={{
|
||||
content: () => (
|
||||
<span>{statusLabel(r.status)}</span>
|
||||
)
|
||||
}}
|
||||
>
|
||||
<i
|
||||
class={['x-user-status', statusClass(r.status)]}
|
||||
style="margin-right: 5px"
|
||||
></i>
|
||||
</TooltipWrapper>
|
||||
</>
|
||||
) : null}
|
||||
{r.statusDescription !== r.previousStatusDescription ? (
|
||||
<span>{r.statusDescription}</span>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (r.type === 'ChangeGroup') {
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
class="x-link"
|
||||
style="margin-right: 5px"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onShowGroup?.(r.previousGroupId);
|
||||
}}
|
||||
>
|
||||
{r.previousGroupName || r.previousGroupId}
|
||||
</span>
|
||||
<span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</span>
|
||||
<span
|
||||
class="x-link"
|
||||
style="margin-left: 5px"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onShowGroup?.(r.groupId);
|
||||
}}
|
||||
>
|
||||
{r.groupName || r.groupId}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (r.type === 'PortalSpawn') {
|
||||
return (
|
||||
<span
|
||||
class="x-link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onShowWorld?.(r.location, r.shortName);
|
||||
}}
|
||||
>
|
||||
<Location
|
||||
location={r.location}
|
||||
hint={r.worldName}
|
||||
grouphint={r.groupName}
|
||||
link={false}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (r.type === 'ChatBoxMessage') {
|
||||
return <span>{r.text}</span>;
|
||||
}
|
||||
|
||||
if (r.type === 'OnPlayerJoined') {
|
||||
return (
|
||||
<>
|
||||
{r.platform === 'Desktop' ? (
|
||||
<span style="color: var(--el-color-primary)">
|
||||
Desktop
|
||||
</span>
|
||||
) : r.platform === 'VR' ? (
|
||||
<span style="color: var(--el-color-primary)">VR </span>
|
||||
) : r.platform === 'Quest' ? (
|
||||
<span style="color: var(--el-color-success)">
|
||||
Android
|
||||
</span>
|
||||
) : null}
|
||||
|
||||
<span
|
||||
class="x-link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onShowAvatar?.(r.avatar?.id);
|
||||
}}
|
||||
>
|
||||
{r.avatar?.name}
|
||||
</span>
|
||||
|
||||
{!r.inCache ? (
|
||||
<span style="color: #aaa">
|
||||
<el-icon>
|
||||
<Download />
|
||||
</el-icon>
|
||||
|
||||
</span>
|
||||
) : null}
|
||||
{r.avatar?.releaseStatus ? (
|
||||
<span class={avatarStatusClass(r.avatar.releaseStatus)}>
|
||||
{avatarStatusLabel(r.avatar.releaseStatus)}
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (r.type === 'SpawnEmoji') {
|
||||
return r.imageUrl ? (
|
||||
<TooltipWrapper
|
||||
side="right"
|
||||
v-slots={{
|
||||
content: () => (
|
||||
<img
|
||||
src={r.imageUrl}
|
||||
class="friends-list-avatar"
|
||||
style="height: 500px; cursor: pointer"
|
||||
loading="lazy"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onShowImage?.(r.imageUrl);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
>
|
||||
<span>{r.fileId}</span>
|
||||
</TooltipWrapper>
|
||||
) : (
|
||||
<span>{r.text}</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (r.color === 'yellow') {
|
||||
return <span style="color: yellow">{r.text}</span>;
|
||||
}
|
||||
|
||||
return <span>{r.text}</span>;
|
||||
}
|
||||
|
||||
export const createColumns = ({ isPrevious, onShowUser, onShowAvatar, onShowGroup, onShowWorld, onShowImage }) => [
|
||||
{
|
||||
id: 'created_at',
|
||||
accessorFn: (row) => (row?.created_at ? Date.parse(row.created_at) : 0),
|
||||
header: () => t('table.playerList.date'),
|
||||
size: 130,
|
||||
cell: ({ row }) => (
|
||||
<TooltipWrapper
|
||||
side="right"
|
||||
v-slots={{
|
||||
content: () => (
|
||||
<span>
|
||||
{formatDateFilter(row.original?.created_at, 'long')}
|
||||
</span>
|
||||
)
|
||||
}}
|
||||
>
|
||||
<span>{formatDateFilter(row.original?.created_at, 'short')}</span>
|
||||
</TooltipWrapper>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'user',
|
||||
header: () => t('table.playerList.user'),
|
||||
size: 160,
|
||||
enableSorting: false,
|
||||
cell: ({ row }) => (
|
||||
<span
|
||||
class="x-link"
|
||||
style="padding-right: 10px"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onShowUser?.(row.original);
|
||||
}}
|
||||
>
|
||||
{row.original?.displayName}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
accessorKey: 'type',
|
||||
header: () => t('table.playerList.type'),
|
||||
size: 140
|
||||
},
|
||||
{
|
||||
id: 'detail',
|
||||
accessorKey: 'text',
|
||||
header: () => t('table.playerList.detail'),
|
||||
enableSorting: false,
|
||||
meta: {
|
||||
stretch: true
|
||||
},
|
||||
cell: ({ row }) => (
|
||||
<DetailCell
|
||||
row={row.original}
|
||||
isPrevious={!!isPrevious}
|
||||
onShowAvatar={onShowAvatar}
|
||||
onShowGroup={onShowGroup}
|
||||
onShowWorld={onShowWorld}
|
||||
onShowImage={onShowImage}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
Reference in New Issue
Block a user