From 83a6c36d5784ac554c6f52fad4cb507fdf83fe42 Mon Sep 17 00:00:00 2001 From: Megghy Date: Fri, 26 Sep 2025 23:10:09 +0800 Subject: [PATCH] feat: enhance DefaultIndexTemplate with ordered links and UI improvements - Added computed property to order links based on user settings or default order. - Updated UI to display ordered links dynamically. - Improved text display for UID and adjusted button styles for better UX. - Modified TypeScript configuration to include 'jszip' type definitions. --- bun.lockb | Bin 319996 -> 324042 bytes package.json | 2 + src/api/api-models.ts | 6 + src/components.d.ts | 1 + .../manage/tools/ToolDynamicNineGrid.vue | 608 --------- src/router/manage.ts | 2 +- src/views/manage/HistoryView.vue | 573 ++++---- src/views/manage/SettingsManageView.vue | 171 ++- src/views/manage/ToolsManageView.vue | 4 +- .../manage/tools/DynamicNineGridGenerator.vue | 499 ------- .../manage/tools/DynamicNineGridView.vue | 15 - .../manage/tools/ToolDynamicNineGrid.vue | 543 +++++--- src/views/open_live/LiveRequest.vue | 4 +- src/views/open_live/OpenLottery.vue | 1152 +++++++++++++++-- .../indexTemplate/DefaultIndexTemplate.vue | 69 +- tsconfig.json | 2 +- 16 files changed, 1787 insertions(+), 1864 deletions(-) delete mode 100644 src/components/manage/tools/ToolDynamicNineGrid.vue delete mode 100644 src/views/manage/tools/DynamicNineGridGenerator.vue delete mode 100644 src/views/manage/tools/DynamicNineGridView.vue diff --git a/bun.lockb b/bun.lockb index 7f28d9838a86f8f5c7f0a0a859565d8cf7eb51b9..82e9e99d1f2ff4f1d69013bba26e6cab3e8879ff 100644 GIT binary patch delta 45118 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 ShMAfj!ef{AUL5{djsFL&c1&{s diff --git a/package.json b/package.json index 18f72b2..c8135a4 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "file-saver": "^2.0.5", "grapheme-splitter": "^1.0.4", "html2canvas": "^1.4.1", + "jszip": "^3.10.1", "idb-keyval": "^6.2.2", "linqts": "^2.0.0", "lodash": "^4.17.21", @@ -81,6 +82,7 @@ "devDependencies": { "@types/bun": "^1.2.16", "@types/file-saver": "^2.0.7", + "@types/jszip": "^3.10.6", "@types/uuid": "^10.0.0", "@vicons/ionicons5": "^0.13.0", "@vitejs/plugin-vue-jsx": "^4.2.0", diff --git a/src/api/api-models.ts b/src/api/api-models.ts index 0465d48..17da721 100644 --- a/src/api/api-models.ts +++ b/src/api/api-models.ts @@ -143,6 +143,11 @@ export interface Setting_Index { videos: string[] notification: string links: { [key: string]: string } + /** + * 自定义链接顺序(存储链接名称的有序数组) + * 旧数据无此字段时在前端初始化为 Object.keys(links) + */ + linkOrder?: string[] } export interface Setting_LiveRequest { orderPrefix: string @@ -824,6 +829,7 @@ export interface ResponseUserIndexModel { notification: string videos: VideoCollectVideo[] links: { [key: string]: string } + linkOrder?: string[] } // 签到排行信息 diff --git a/src/components.d.ts b/src/components.d.ts index ff637fb..32b6e3c 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -31,6 +31,7 @@ declare module 'vue' { NIcon: typeof import('naive-ui')['NIcon'] NImage: typeof import('naive-ui')['NImage'] NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel'] + NInputNumber: typeof import('naive-ui')['NInputNumber'] NModal: typeof import('naive-ui')['NModal'] NPopconfirm: typeof import('naive-ui')['NPopconfirm'] NScrollbar: typeof import('naive-ui')['NScrollbar'] diff --git a/src/components/manage/tools/ToolDynamicNineGrid.vue b/src/components/manage/tools/ToolDynamicNineGrid.vue deleted file mode 100644 index 53046a4..0000000 --- a/src/components/manage/tools/ToolDynamicNineGrid.vue +++ /dev/null @@ -1,608 +0,0 @@ - - - - - diff --git a/src/router/manage.ts b/src/router/manage.ts index 32bd13f..bc49b4a 100644 --- a/src/router/manage.ts +++ b/src/router/manage.ts @@ -225,7 +225,7 @@ export default //管理页面 { path: 'tools/dynamic-nine-grid', name: 'ManageToolDynamicNineGrid', - component: () => import('@/components/manage/tools/ToolDynamicNineGrid.vue'), + component: () => import('@/views/manage/tools/ToolDynamicNineGrid.vue'), meta: { title: '动态九图生成器', parent: 'manage-tools-dashboard' // 指向工具箱仪表盘 diff --git a/src/views/manage/HistoryView.vue b/src/views/manage/HistoryView.vue index e2d6016..37ab023 100644 --- a/src/views/manage/HistoryView.vue +++ b/src/views/manage/HistoryView.vue @@ -15,8 +15,8 @@ import { } from 'echarts/components' import { use } from 'echarts/core' import { CanvasRenderer } from 'echarts/renderers' -import { NAlert, NButton, NCard, NDivider, NIcon, NSpace, NSpin, NText, NTime, NTooltip, useMessage } from 'naive-ui' -import { computed, onMounted, ref } from 'vue' +import { NAlert, NButton, NCard, NDatePicker, NDivider, NIcon, NSpace, NSpin, NText, NTime, NTooltip, useMessage } from 'naive-ui' +import { computed, onMounted, ref, watch } from 'vue' import VChart from 'vue-echarts' @@ -88,6 +88,26 @@ const isLoading = ref(true) const statisticStartDate = new Date(2023, 10, 4) const statisticStartDateTime = statisticStartDate.getTime() +// 日期范围选择(毫秒时间戳区间) +const dateRange = ref<[number, number] | null>(null) +const dateShortcuts: Record [number, number])> = { + '最近7天': () => { + const end = endOfDay(new Date()).getTime() + const start = startOfDay(addDays(new Date(), -6)).getTime() + return [start, end] as [number, number] + }, + '最近30天': () => { + const end = endOfDay(new Date()).getTime() + const start = startOfDay(addDays(new Date(), -29)).getTime() + return [start, end] as [number, number] + }, + '最近90天': () => { + const end = endOfDay(new Date()).getTime() + const start = startOfDay(addDays(new Date(), -89)).getTime() + return [start, end] as [number, number] + }, +} + // 响应式图表高度 const chartHeight = computed(() => { // 可以根据窗口大小动态调整图表高度 @@ -150,103 +170,99 @@ function getBaseChartOptions() { } } +/** + * 生成每日时间序列数据的通用函数 + * @param historyData 原始历史记录 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param initialTimeIndex 起始索引 + * @param initialCount 初始计数值 + */ +function generateTimeSeries( + historyData: HistoryRecordModel[], + startTime: Date, + endTime: Date, + initialTimeIndex: number, + initialCount: number +) { + const timeSeries: { time: Date; count: number; change: boolean; exist: boolean }[] = [] + let lastDayCount = initialCount + let lastTimeIndex = initialTimeIndex + let currentTime = startTime + + while (currentTime <= endTime) { + const dayEndTime = endOfDay(currentTime).getTime() + let dayExist = false + + while (true) { + const data = historyData[lastTimeIndex] + if (!data) { + break + } + + if ((historyData[lastTimeIndex + 1]?.time ?? Number.MAX_VALUE) > dayEndTime) { + const changed = data.count !== lastDayCount + lastDayCount = data.count + dayExist = true + break + } + lastTimeIndex++ + } + + timeSeries.push({ + time: currentTime, + count: lastDayCount, + change: lastDayCount !== (timeSeries[timeSeries.length - 1]?.count ?? initialCount), + exist: dayExist, + }) + + currentTime = addDays(currentTime, 1) + } + + return timeSeries +} + /** * 处理粉丝历史数据并生成图表选项 */ function processFansChartOptions() { if (!fansHistory.value || fansHistory.value.length === 0) return - // 确定开始时间 - let startTime = new Date(accountInfo.value?.createAt ?? Date.now()) - startTime = startTime < statisticStartDate ? statisticStartDate : startTime - startTime = startOfDay(startTime) - const endTime = new Date() + let startTimeBase = new Date(accountInfo.value?.createAt ?? Date.now()) + startTimeBase = startTimeBase < statisticStartDate ? statisticStartDate : startTimeBase + const startTime = startOfDay(dateRange.value ? new Date(dateRange.value[0]) : startTimeBase) + const endTime = dateRange.value ? new Date(dateRange.value[1]) : new Date() - // 用于存储完整的时间序列数据 - const completeTimeSeries: { time: Date; count: number; change: boolean, exist: boolean }[] = [] - // 用于存储粉丝增量数据 - const fansIncreacement: { time: Date; count: number }[] = [] - - // 查找统计开始时间之后的第一个数据点 - let lastFansTimeIndex = fansHistory.value.length > 0 - ? fansHistory.value[0].time >= statisticStartDateTime - ? 0 - : fansHistory.value.findIndex((entry) => entry.time >= statisticStartDateTime) - : -1 - let lastDayCount = lastFansTimeIndex >= 0 ? fansHistory.value[lastFansTimeIndex].count : 0 - - // 生成完整的天序列数据 - let currentTime = startTime - while (currentTime <= endTime) { - const dayEndTime = endOfDay(currentTime).getTime() - while (true) { - const data = fansHistory.value[lastFansTimeIndex] - if (!data) { - completeTimeSeries.push({ - time: currentTime, - count: lastDayCount, - change: false, - exist: false, - }) - break - } - // 如果下一个数据的时间大于当前天的结束时间 - if ((fansHistory.value[lastFansTimeIndex + 1]?.time ?? Number.MAX_VALUE) > dayEndTime) { - const changed = data.count !== lastDayCount - lastDayCount = data.count - - completeTimeSeries.push({ - time: currentTime, - count: lastDayCount, - change: changed, - exist: true, - }) - break - } - - lastFansTimeIndex++ - } - - currentTime = addDays(currentTime, 1) // 移动到下一天 + if (startTime > endTime) { + fansOption.value = { ...getBaseChartOptions(), series: [] } // Simplified empty state + return } - // 计算粉丝增量数据 - let previousDayCount = completeTimeSeries[0].count - completeTimeSeries.forEach((entry, index, array) => { - if (index === 0 || !isSameDay(entry.time, array[index - 1].time)) { - if (index > 0) { - const dailyIncrement = entry.count - previousDayCount - fansIncreacement.push({ - time: startOfDay(array[index - 1].time), - count: dailyIncrement, - }) - } - previousDayCount = entry.count - } else if (index === array.length - 1) { + const initialIndex = fansHistory.value.findIndex((entry) => entry.time >= statisticStartDateTime) + const initialCount = initialIndex >= 0 ? fansHistory.value[initialIndex].count : 0 + + const completeTimeSeries = generateTimeSeries(fansHistory.value, startTime, endTime, initialIndex, initialCount) + + const fansIncreacement: { time: Date; count: number }[] = [] + let previousDayCount = completeTimeSeries[0]?.count ?? 0 + completeTimeSeries.forEach((entry, index) => { + if (index > 0) { const dailyIncrement = entry.count - previousDayCount - fansIncreacement.push({ - time: startOfDay(entry.time), - count: dailyIncrement, - }) + fansIncreacement.push({ time: startOfDay(entry.time), count: dailyIncrement }) } + previousDayCount = entry.count }) - // 准备图表数据 const chartData = { xAxisData: completeTimeSeries.map((entry) => format(entry.time, 'yyyy-MM-dd')), - hourlyCounts: completeTimeSeries.map((entry) => entry.count), - dailyIncrements: fansIncreacement.map((entry) => ({ - date: format(entry.time, 'yyyy-MM-dd'), - count: entry.count, - })), + seriesData: completeTimeSeries.map((entry) => entry.count), + incrementData: fansIncreacement.map((entry) => entry.count), } - // 生成图表配置 - const baseOptions = getBaseChartOptions() fansOption.value = { - ...baseOptions, + ...getBaseChartOptions(), tooltip: { - ...baseOptions.tooltip, + ...getBaseChartOptions().tooltip, formatter: (param: any) => { const name = param[0].name + '
' let str = '' @@ -260,54 +276,22 @@ function processFansChartOptions() { }, }, yAxis: [ - { - type: 'value', - name: '粉丝数', - }, - { - type: 'value', - name: '每日增量', - }, + { type: 'value', name: '粉丝数', min: 'dataMin' }, + { type: 'value', name: '每日增量' }, ], xAxis: [ - { - type: 'category', - axisTick: { - alignWithLabel: true, - }, - axisLine: { - onZero: false, - lineStyle: { - color: '#5470C6', - }, - }, - data: chartData.xAxisData, - }, - { - type: 'category', - axisTick: { - alignWithLabel: true, - }, - axisLine: { - onZero: false, - lineStyle: { - color: '#EE6666', - }, - }, - data: fansIncreacement.map((f) => format(f.time, 'yyyy-MM-dd')), - }, + { type: 'category', data: chartData.xAxisData }, + { type: 'category', data: chartData.xAxisData.slice(1) }, // Align increments ], series: [ { name: '粉丝数', type: 'line', - emphasis: { - focus: 'series', - }, - data: chartData.hourlyCounts, + data: chartData.seriesData, itemStyle: { - color: function (data: any) { - return completeTimeSeries[data.dataIndex].change ? '#18a058' : '#5470C6' + color: (data: any) => { + const item = completeTimeSeries[data.dataIndex] + return !item.exist ? '#cccccc' : item.change ? '#18a058' : '#5470C6' }, }, }, @@ -316,15 +300,8 @@ function processFansChartOptions() { type: 'bar', yAxisIndex: 1, xAxisIndex: 1, - emphasis: { - focus: 'series', - }, - data: chartData.dailyIncrements.map((f) => f.count), - itemStyle: { - color: function (params: any) { - return params.value < 0 ? '#FF4D4F' : '#3398DB' // 负数时红色,正数时默认颜色 - }, - }, + data: chartData.incrementData, + itemStyle: { color: (params: any) => (params.value < 0 ? '#FF4D4F' : '#3398DB') }, }, ], } @@ -336,120 +313,143 @@ function processFansChartOptions() { function processGuardsChartOptions() { if (!guardHistory.value || guardHistory.value.length === 0) return - // 确定开始时间 - let startTime = new Date(accountInfo.value?.createAt ?? Date.now()) - startTime = startTime < statisticStartDate ? statisticStartDate : startTime - startTime = startOfDay(startTime) - const endTime = new Date() + let startTimeBase = new Date(accountInfo.value?.createAt ?? Date.now()) + startTimeBase = startTimeBase < statisticStartDate ? statisticStartDate : startTimeBase + const startTime = startOfDay(dateRange.value ? new Date(dateRange.value[0]) : startTimeBase) + const endTime = dateRange.value ? new Date(dateRange.value[1]) : new Date() - // 生成完整的舰长天序列 - const completeGuardTimeSeries: { time: Date; count: number }[] = [] - let currentGuardTime = startTime - let lastGuardTimeIndex = 0 - let lastDayGuardCount = 0 - - while (currentGuardTime <= endTime) { - const dayEndTime = endOfDay(currentGuardTime).getTime() - while (true) { - const data = guardHistory.value[lastGuardTimeIndex] - if (!data) { - completeGuardTimeSeries.push({ - time: currentGuardTime, - count: lastDayGuardCount, - }) - break - } - - if ((guardHistory.value[lastGuardTimeIndex + 1]?.time ?? Number.MAX_VALUE) > dayEndTime) { - lastDayGuardCount = data.count - completeGuardTimeSeries.push({ - time: currentGuardTime, - count: lastDayGuardCount, - }) - break - } - - lastGuardTimeIndex++ - } - - currentGuardTime = addDays(currentGuardTime, 1) // 移动到下一天 + if (startTime > endTime) { + guardsOption.value = { ...getBaseChartOptions(), series: [] } // Simplified empty state + return } - // 计算守护增量数据 - const guardsIncreacement: { time: number; count: number; timeString: string }[] = [] - const guards: { time: number; count: number; timeString: string }[] = [] + const initialIndex = guardHistory.value.findIndex((entry) => entry.time >= startTime.getTime()) + const initialCount = initialIndex >= 0 ? guardHistory.value[initialIndex].count : 0 - let lastDayGuards = 0 - let lastDay = 0 + const completeTimeSeries = generateTimeSeries(guardHistory.value, startTime, endTime, initialIndex, initialCount) - completeGuardTimeSeries.forEach((g) => { - if (!isSameDay(g.time, new Date(lastDay * 1000))) { - guardsIncreacement.push({ - time: lastDayGuards, - count: lastDay === 0 ? 0 : g.count - lastDayGuards, - timeString: format(g.time, 'yyyy-MM-dd'), - }) - guards.push({ - time: g.time.getTime() / 1000, - count: g.count, - timeString: format(g.time, 'yyyy-MM-dd'), - }) - lastDay = g.time.getTime() / 1000 - lastDayGuards = g.count + const guardIncrements: number[] = [] + let previousDayCount = completeTimeSeries[0]?.count ?? 0 + completeTimeSeries.forEach((entry, index) => { + if (index > 0) { + guardIncrements.push(entry.count - previousDayCount) } + previousDayCount = entry.count }) - // 生成图表配置 - const baseOptions = getBaseChartOptions() + const xAxisData = completeTimeSeries.map((entry) => format(entry.time, 'yyyy-MM-dd')) + guardsOption.value = { - ...baseOptions, + ...getBaseChartOptions(), yAxis: [ - { - type: 'value', - }, - { - type: 'value', - }, + { type: 'value', name: '舰长数', min: 'dataMin' }, + { type: 'value', name: '日增' }, ], xAxis: [ - { - type: 'category', - axisTick: { - alignWithLabel: true, - }, - axisLine: { - onZero: false, - lineStyle: { - color: '#EE6666', - }, - }, - data: guardsIncreacement.map((f) => f.timeString), - }, + { type: 'category', data: xAxisData }, + { type: 'category', data: xAxisData.slice(1) }, ], series: [ { name: '舰长数', type: 'line', step: 'middle', - emphasis: { - focus: 'series', + data: completeTimeSeries.map(item => item.count), + itemStyle: { + color: (data: any) => completeTimeSeries[data.dataIndex].exist ? '#5470C6' : '#cccccc', }, - data: guards.map((f) => f.count), }, { name: '日增', type: 'bar', yAxisIndex: 1, - emphasis: { - focus: 'series', - }, - data: guardsIncreacement.map((f) => f.count), + xAxisIndex: 1, + data: guardIncrements, + itemStyle: { color: (params: any) => (params.value < 0 ? '#FF4D4F' : '#3398DB') }, + }, + ], + } +} + +/** + * 处理投稿数据并生成图表选项的通用函数 + * @param {('views' | 'likes')} dataType - 要处理的数据类型 ('views' 或 'likes') + * @param {string} title - 图表主标题 + */ +function processUpstatChartOptions(dataType: 'views' | 'likes', title: string) { + if (!upstatHistory.value || upstatHistory.value.length === 0) { + return { + ...getBaseChartOptions(), + xAxis: [{ type: 'category', data: [] }], + yAxis: [{ type: 'value' }, { type: 'value' }], + series: [ + { name: title, type: 'line', data: [] }, + { name: '日增', type: 'bar', data: [], yAxisIndex: 1 }, + ], + } + } + + const rangeStart = dateRange.value ? dateRange.value[0] : -Infinity + const rangeEnd = dateRange.value ? dateRange.value[1] : Infinity + const filtered = upstatHistory.value.filter((u) => u.time >= rangeStart && u.time <= rangeEnd) + + if (filtered.length === 0) { + return { + ...getBaseChartOptions(), + xAxis: [{ type: 'category', data: [] }], + yAxis: [{ type: 'value' }, { type: 'value' }], + series: [ + { name: title, type: 'line', data: [] }, + { name: '日增', type: 'bar', data: [], yAxisIndex: 1 }, + ], + } + } + + const increments: { time: number; value: number }[] = [] + let lastValue = filtered[0].stats[dataType] + + filtered.forEach((u) => { + const currentValue = u.stats[dataType] + increments.push({ + time: u.time, + value: currentValue - lastValue, + }) + lastValue = currentValue + }) + + return { + ...getBaseChartOptions(), + yAxis: [ + { type: 'value', min: 'dataMin' }, + { type: 'value' }, + ], + xAxis: [ + { + type: 'category', + axisTick: { alignWithLabel: true }, + axisLine: { onZero: false, lineStyle: { color: '#EE6666' } }, + data: filtered.map((f) => format(f.time, 'yyyy-MM-dd')), + }, + ], + series: [ + { + name: title, + type: 'line', + emphasis: { focus: 'series' }, + data: filtered.map((f) => f.stats[dataType]), itemStyle: { - color: function (params: any) { - return params.value < 0 ? '#FF4D4F' : '#3398DB' + color: function (data: any) { + return increments[data.dataIndex].value !== 0 ? '#5470C6' : '#cccccc' }, }, }, + { + name: '日增', + type: 'bar', + yAxisIndex: 1, + emphasis: { focus: 'series' }, + data: increments.map((f) => f.value), + }, ], } } @@ -458,134 +458,14 @@ function processGuardsChartOptions() { * 处理播放量历史数据并生成图表选项 */ function processUpstatViewChartOptions() { - if (!upstatHistory.value || upstatHistory.value.length === 0) return - - // 计算播放量增量数据 - const upstatViewIncreace: { time: number; value: number }[] = [] - let lastUpstatView = upstatHistory.value[0].stats.views - - upstatHistory.value.forEach((u) => { - upstatViewIncreace.push({ - time: u.time, - value: u.stats.views - lastUpstatView, - }) - lastUpstatView = u.stats.views - }) - - // 生成图表配置 - const baseOptions = getBaseChartOptions() - upstatViewOption.value = { - ...baseOptions, - yAxis: [ - { - type: 'value', - }, - { - type: 'value', - }, - ], - xAxis: [ - { - type: 'category', - axisTick: { - alignWithLabel: true, - }, - axisLine: { - onZero: false, - lineStyle: { - color: '#EE6666', - }, - }, - data: upstatHistory.value.map((f) => format(f.time, 'yyyy-MM-dd')), - }, - ], - series: [ - { - name: '播放数', - type: 'line', - emphasis: { - focus: 'series', - }, - data: upstatHistory.value.map((f) => f.stats.views), - }, - { - name: '日增', - type: 'bar', - yAxisIndex: 1, - emphasis: { - focus: 'series', - }, - data: upstatViewIncreace.map((f) => f.value), - }, - ], - } + upstatViewOption.value = processUpstatChartOptions('views', '播放数') } /** * 处理点赞量历史数据并生成图表选项 */ function processUpstatLikeChartOptions() { - if (!upstatHistory.value || upstatHistory.value.length === 0) return - - // 计算点赞量增量数据 - const upstatLikeIncreace: { time: number; value: number }[] = [] - let lastUpstatLike = upstatHistory.value[0].stats.likes - - upstatHistory.value.forEach((u) => { - upstatLikeIncreace.push({ - time: u.time, - value: u.stats.likes - lastUpstatLike, - }) - lastUpstatLike = u.stats.likes - }) - - // 生成图表配置 - const baseOptions = getBaseChartOptions() - upstatLikeOption.value = { - ...baseOptions, - yAxis: [ - { - type: 'value', - }, - { - type: 'value', - }, - ], - xAxis: [ - { - type: 'category', - axisTick: { - alignWithLabel: true, - }, - axisLine: { - onZero: false, - lineStyle: { - color: '#EE6666', - }, - }, - data: upstatHistory.value.map((f) => format(f.time, 'yyyy-MM-dd')), - }, - ], - series: [ - { - name: '点赞数', - type: 'line', - emphasis: { - focus: 'series', - }, - data: upstatHistory.value.map((f) => f.stats.likes), - }, - { - name: '日增', - type: 'bar', - yAxisIndex: 1, - emphasis: { - focus: 'series', - }, - data: upstatLikeIncreace.map((f) => f.value), - }, - ], - } + upstatLikeOption.value = processUpstatChartOptions('likes', '点赞数') } /** @@ -605,6 +485,14 @@ onMounted(async () => { isLoading.value = false } }) + +// 选择日期范围后,自动刷新图表 +watch( + () => dateRange.value, + () => { + if (!isLoading.value) processAllChartOptions() + } +)