From fba9dc4932e27cfcdf4af12cab6665f29252ec16 Mon Sep 17 00:00:00 2001 From: Innei Date: Mon, 12 Feb 2024 11:16:24 +0800 Subject: [PATCH] feat: support reading duartion Signed-off-by: Innei --- .../analyze/components/guest-activity.tsx | 301 ++++++++++++++---- 1 file changed, 236 insertions(+), 65 deletions(-) diff --git a/src/views/analyze/components/guest-activity.tsx b/src/views/analyze/components/guest-activity.tsx index db463bf53..b33144460 100644 --- a/src/views/analyze/components/guest-activity.tsx +++ b/src/views/analyze/components/guest-activity.tsx @@ -1,6 +1,14 @@ -import { NButton } from 'naive-ui' +import { NButton, NTabPane, NTabs } from 'naive-ui' +import { defineComponent, onBeforeMount, ref, shallowRef, watch } from 'vue' import { useRoute } from 'vue-router' -import type { PaginateResult } from '@mx-space/api-client' +import type { + NoteModel, + PageModel, + PaginateResult, + PostModel, + RecentlyModel, +} from '@mx-space/api-client' +import type { TableColumns } from 'naive-ui/es/data-table/src/interface' import { IpInfoPopover } from '~/components/ip-info' import { Table } from '~/components/table' @@ -17,19 +25,68 @@ interface ActivityItem { enum ActivityType { Like, + ReadDuration, } -const ActivityType2Copy = ['点赞'] +type WithObjects = { + objects: { + posts: PostModel[] + notes: NoteModel[] + pages: PageModel[] + recentlies: RecentlyModel[] + } +} & T + +type ObjectsCollection = { + posts: Record + notes: Record + pages: Record + recentlies: Record + + all: Record +} + +const refObjectCollectionRef = shallowRef({ + posts: {}, + notes: {}, + pages: {}, + recentlies: {}, + + all: {}, +} as ObjectsCollection) + +const mapDataToCollection = ( + type: keyof ObjectsCollection, + data: WithObjects<{}>['objects'], +) => { + const collection = refObjectCollectionRef.value[type] + for (const list in data[type]) { + const item = data[type][list] + collection[item.id] = item + refObjectCollectionRef.value.all[item.id] = item + } +} export const GuestActivity = defineComponent({ setup() { + const tabValue = ref(ActivityType.Like) + const { data, pager, fetchDataFn } = useDataTableFetch( (list, pager) => async (page, size) => { RESTManager.api.activity - .get>({ params: { page, size } }) + .get>>({ + params: { page, size, type: tabValue.value }, + }) .then((res) => { list.value = res.data pager.value = res.pagination + + if (res.objects) { + mapDataToCollection('posts', res.objects) + mapDataToCollection('notes', res.objects) + mapDataToCollection('pages', res.objects) + mapDataToCollection('recentlies', res.objects) + } }) }, ) @@ -45,70 +102,184 @@ export const GuestActivity = defineComponent({ }, ) + const tabPanelMapping = { + [ActivityType.Like]: LikeTableColumns, + [ActivityType.ReadDuration]: ReadDurationTableColumns, + } + return () => { return ( - {ActivityType2Copy[row.type]}, - width: 120, - }, - - { - title: '引用', - key: 'payload.ref', - render: (row) => { - switch (row.type) { - case ActivityType.Like: - return ( - { - RESTManager.api - .helper('url-builder')(row.payload.id) - .get<{ data: string }>() - .then(({ data: url }) => { - window.open(url) - }) - }} - > - {row.ref.title} - - ) - } - return null - }, - width: 350, - ellipsis: { - tooltip: true, - }, - }, - { - title: '时间', - key: 'created', - render: (row) => , - }, - { - title: 'IP', - key: 'payload.ip', - render: (row) => ( - {row.payload.ip}} - /> - ), - }, - ]} - /> + <> + { + tabValue.value = value + fetchDataFn() + }} + value={tabValue.value} + > + +
+ + +
+ + + +
+ ) } }, }) + +const baseColumns = [ + { + title: '时间', + key: 'created', + render: (row) => , + }, + { + title: 'IP', + key: 'payload.ip', + render: (row) => ( + {row.payload.ip}} + /> + ), + }, +] + +const LikeTableColumns: TableColumns<{ + id: string + created: string + payload: any + type: number + ref?: any +}> = [ + { + title: '类型', + key: 'type', + render: () => 点赞, + width: 120, + }, + + { + title: '引用', + key: 'payload.ref', + render: (row) => { + return ( + { + RESTManager.api + .helper('url-builder')(row.payload.id) + .get<{ data: string }>() + .then(({ data: url }) => { + window.open(url) + }) + }} + > + {row.ref.title} + + ) + }, + width: 350, + ellipsis: { + tooltip: true, + }, + }, + ...baseColumns, +] + +const ReadDurationTableColumns: TableColumns = [ + { + title: '类型', + key: 'type', + render: () => 阅读记录, + width: 120, + }, + { + title: '引用', + key: 'payload.ref', + render: (row) => { + const ref = refObjectCollectionRef.value.all[row.refId] + + if (!ref) return '未知' + + return ( + { + RESTManager.api + .helper('url-builder')(ref.id) + .get<{ data: string }>() + .then(({ data: url }) => { + window.open(url) + }) + }} + > + {(ref as any).title} + + ) + }, + width: 350, + ellipsis: { + tooltip: true, + }, + }, + { + title: '阅读时长', + key: 'payload.duration', + width: 150, + render: (row) => { + return ( + + {(row.payload.operationTime - row.payload.connectedAt) / 1000} 秒 + + ) + }, + }, + + { + title: '连接时间', + key: 'payload.connectedAt', + render: (row) => , + }, + { + title: '更新时间', + key: 'payload.updatedAt', + render: (row) => , + }, + { + title: '最后的位置', + key: 'payload.position', + }, + ...baseColumns, +] + +interface ActivityReadDurationType { + id: string + type: number + payload: RoomPayload + created: string + refId: string +} +interface RoomPayload { + connectedAt: number + operationTime: number + updatedAt: number + position: number + roomName: string + ip: string +}