Commit 4810befc authored by nick zheng's avatar nick zheng

feat: 整体数据分析

parent 2dc5a72e
import { request } from '@/utils/request'
/**
* @query channels 渠道列表
* @returns 平台积分使用情况
*/
export function fetchGetPlatformPointUsage<T>(channels: string[]) {
return request.post<T>(`/dataStatisticsRest/platformPointUsage.json?channels=${channels}`)
}
/**
* @param { channel: 渠道列表 timeRange: { rangType: 类型, startTime: 开始时间, endTime: 结束时间 } }
* @returns 平台积分使用趋势
*/
export function fetchGetPlatformPointTrend<T>(payload: {
channel: string[]
timeRange: { rangType: string; startTime: string; endTime: string }
}) {
return request.post<T>('/dataStatisticsRest/platformPointTrend.json', payload)
}
/**
* @query channels 渠道列表
* @returns 平台应用使用情况
*/
export function fetchGetPlatformAgentUsage<T>(channels: string[]) {
return request.post<T>(`/dataStatisticsRest/platformAgentUsage.json?channels=${channels}`)
}
/**
* @params { timeRange: { rangType: 类型, startTime: 开始时间, endTime: 结束时间 } }
* @returns 平台应用使用明细
*/
export function fetchGetPlatformAgentUsageDetail<T>(payload: {
timeRange: {
rangType: 'month' | 'week' | 'customize'
startTime: string
endTime: string
}
pagingInfo: {
pageNo: number
pageSize: number
}
}) {
return request.post<T>('/dataStatisticsRest/platformAgentUsageDetail.json', payload)
}
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { RangType } from './type.d'
const emit = defineEmits<{
updateSearchList: [currentTime: RangType, startTime: string, endTime: string]
}>()
const { t } = useI18n()
const currentTime = ref(RangType.week)
const selectDateRange = ref<[string, string]>(['', ''])
const rangTypeOptionList = [
{
label: t('common_module.last_week'),
value: RangType.week,
},
{
label: t('common_module.last_month'),
value: RangType.month,
},
{
label: t('common_module.custom'),
value: RangType.customize,
},
]
const disableSelectDate = (ts: number, type: 'start' | 'end', range: [number, number] | null) => {
if (type === 'start' && range !== null) {
return range[1] - ts >= 86400000 * 365 || ts > Date.now()
}
if (type === 'end' && range !== null) {
return ts - range[0] >= 86400000 * 365 || ts > Date.now()
}
return ts > Date.now()
}
onMounted(() => {
emit('updateSearchList', currentTime.value, '', '')
})
function handleUpdateRangType(rangType: string) {
if (rangType !== RangType.customize) {
selectDateRange.value = ['', '']
emit('updateSearchList', currentTime.value, '', '')
}
}
function handleUpdateDateRange(_value: [number, number], formattedValue: [string, string]) {
if (formattedValue[0] && formattedValue[1]) {
selectDateRange.value = formattedValue
emit('updateSearchList', currentTime.value, selectDateRange.value[0], selectDateRange.value[1])
}
}
</script>
<template>
<div class="flex gap-3">
<n-select
v-model:value="currentTime"
:options="rangTypeOptionList"
class="w-[124px]! time-range-select"
@update:value="handleUpdateRangType"
/>
<n-date-picker
v-show="currentTime === 'customize'"
type="daterange"
:is-date-disabled="disableSelectDate"
clearable
class="w-[250px]! customize-date-picker"
@update:value="handleUpdateDateRange"
/>
</div>
</template>
<style scoped lang="scss">
:deep(.time-range-select .n-base-selection),
:deep(.customize-date-picker.n-date-picker .n-input) {
--n-height: 36px !important;
}
</style>
export enum RangType {
week = 'week',
month = 'month',
customize = 'customize',
}
......@@ -40,6 +40,11 @@ const menuOptions = computed<MenuOption[]>(() => {
key: 'ApplicationsSquare',
icon: () => h('i', { class: 'iconfont icon-square' }),
},
{
label: () => h('div', {}, t('router_title_module.data_statistic')),
key: 'Statistic',
icon: () => h('i', { class: 'iconfont icon-statistics' }),
},
],
},
]
......
......@@ -185,6 +185,7 @@ router_title_module:
application_square: 'Application square'
personal_settings: 'Personal settings'
order_manage: 'Order Management'
data_statistic: 'Data statistic'
login_module:
app_welcome_words: 'Hi, welcome to Model Link'
......@@ -610,5 +611,26 @@ analysis_module:
usage_channel: 'Usage channel'
index: 'Index'
agent_square: 'Agent square'
api: 'Api'
api: 'API'
link_share: 'Link share'
statistic_module:
data_statistic: 'Data statistic'
point_statistic: 'Point statistic'
agent_statistic: 'Agent statistic'
platform_point_usage: 'Platform point usage'
platform_point_trend: 'Platform point trend'
today_usage: 'Today usage'
current_week_usage: 'Current week usage'
current_month_usage: 'Current month usage'
current_year_usage: 'Current year usage'
create_agent_count: 'Create agent count'
usage_agent_count: 'Usage agent count'
unpublish_agent_count: 'Unpublish agent count'
published_agent_count: 'Published agent count'
platform_agent_usage_detail: 'Platform agent usage detail'
agent_title: 'Agent title'
agent_status: 'Agent status'
owner: 'Owner'
usage_count: 'Usage count'
last_usage_time: 'Last usage time'
......@@ -184,6 +184,7 @@ router_title_module:
application_square: '应用广场'
personal_settings: '个人设置'
order_manage: '订单管理'
data_statistic: '数据统计'
login_module:
app_welcome_words: 'Hi, 欢迎使用Model Link'
......@@ -608,5 +609,28 @@ analysis_module:
usage_channel: '使用渠道'
index: '首页'
agent_square: '应用广场'
api: 'api调用'
api: 'API调用'
link_share: '网页链接'
statistic_module:
data_statistic: '数据统计'
point_statistic: '积分统计'
agent_statistic: '应用统计'
platform_point_usage: '平台积分使用情况'
platform_point_trend: '平台积分使用趋势'
today_usage: '今日消耗积分'
current_week_usage: '本周消耗积分'
current_month_usage: '本月消耗积分'
current_year_usage: '本年消耗积分'
create_agent_count: '创建的应用'
usage_agent_count: '创建的应用'
unpublish_agent_count: '未发布的应用'
published_agent_count: '已发布的应用'
platform_agent_usage_detail: '各应用使用明细表'
agent_title: '应用标题'
agent_status: '应用状态'
owner: '开发者'
usage_count: '使用次数'
last_usage_time: '最后一次使用时间'
......@@ -184,6 +184,7 @@ router_title_module:
application_square: '應用廣場'
personal_settings: '個人設置'
order_manage: '訂單管理'
data_statistic: '數據統計'
login_module:
app_welcome_words: 'Hi, 歡迎使用Model Link'
......@@ -608,5 +609,26 @@ analysis_module:
usage_channel: '使用渠道'
index: '首頁'
agent_square: '應用廣場'
api: 'api調用'
api: 'API調用'
link_share: '網頁鏈接'
statistic_module:
data_statistic: '數據統計'
point_statistic: '積分統計'
agent_statistic: '應用統計'
platform_point_usage: '平台積分使用情況'
platform_point_trend: '平台積分使用趨勢'
today_usage: '今日消耗積分'
current_week_usage: '本週消耗積分'
current_month_usage: '本月消耗積分'
current_year_usage: '本年消耗積分'
create_agent_count: '創建的應用'
usage_agent_count: '創建的應用'
unpublish_agent_count: '未發佈的應用'
published_agent_count: '已發佈的應用'
platform_agent_usage_detail: '各應用使用明細表'
agent_title: '應用標題'
agent_status: '應用狀態'
owner: '開發者'
usage_count: '使用次數'
last_usage_time: '最後一次使用時間'
import { type RouteRecordRaw } from 'vue-router'
import Layout from '@/layout/index.vue'
export default [
{
path: '/statistic-layout',
name: 'StatisticLayout',
meta: {
rank: 1001,
title: '',
},
component: Layout,
redirect: '/statistic',
children: [
{
path: '/statistic',
name: 'Statistic',
meta: {
rank: 1001,
title: 'router_title_module.data_statistic',
},
component: () => import('@/views/statistics/statistics.vue'),
redirect: '/statistic/point-statistic',
children: [
{
path: '/statistic/point-statistic',
name: 'PointStatistic',
meta: {
rank: 1001,
title: 'router_title_module.data_statistic',
belong: 'Statistic',
},
component: () => import('@/views/statistics/point-statistic/point-static.vue'),
},
{
path: '/statistic/agent-statistic',
name: 'AgentStatistic',
meta: {
rank: 1001,
title: 'router_title_module.data_statistic',
belong: 'Statistic',
},
component: () => import('@/views/statistics/agent-statistic/agent-statistic.vue'),
},
],
},
],
},
] as RouteRecordRaw[]
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import ContentTitle from '../components/content-title.vue'
import { IPlatformAgentUsage, IPlatformAgentUsageDetailItem } from '../type'
import { createPlatformAgentUsageDetail } from './columns'
import CustomPagination from '@/components/custom-pagination/custom-pagination.vue'
import { fetchGetPlatformAgentUsage, fetchGetPlatformAgentUsageDetail } from '@/apis/statistic'
import { ChannelType } from '@/enums/channel'
import { usePagination } from '@/composables/usePagination'
import useTableScrollY from '@/composables/useTableScrollY'
import DataSelectSearch from '@/components/date-select-search/data-select-search.vue'
import { RangType } from '@/components/date-select-search/type.d'
const { t } = useI18n()
const { pageContentWrapRef, tableContentY } = useTableScrollY(46 + 124 + 28 + 36 + 20 + 48 + 28 + 40)
const { paginationData, handlePageNoChange, handlePageSizeChange } = usePagination()
const platformAgentUsage = ref<IPlatformAgentUsage>({
createCount: 0,
usageCount: 0,
unPublishCount: 0,
publishCount: 0,
})
const currentTime = ref<RangType>(RangType.week)
const selectDateRange = ref<[string, string]>(['', ''])
const platformAgentUsageDetailLoading = ref(false)
const platformAgentUsageDetailColumns = createPlatformAgentUsageDetail()
const platformAgentUsageDetailData = ref<IPlatformAgentUsageDetailItem[]>([])
watch([() => paginationData.pageNo, () => paginationData.pageSize], () => {
handleGetPlatformAgentUsageDetail(currentTime.value, selectDateRange.value[0], selectDateRange.value[1])
})
onMounted(() => {
handleGetPlatformAgentUsage()
})
async function handleGetPlatformAgentUsage() {
const channels = [
ChannelType.api,
ChannelType.index,
ChannelType.link_share,
ChannelType.mall,
ChannelType.preview,
ChannelType.multi_preview,
]
const res = await fetchGetPlatformAgentUsage<IPlatformAgentUsage>(channels)
if (res.code === 0) {
platformAgentUsage.value = res.data
}
}
async function handleGetPlatformAgentUsageDetail(rangType: RangType, startTime: string, endTime: string) {
currentTime.value = rangType
selectDateRange.value = [startTime, endTime]
platformAgentUsageDetailLoading.value = true
const res = await fetchGetPlatformAgentUsageDetail<IPlatformAgentUsageDetailItem[]>({
timeRange: {
rangType,
startTime,
endTime,
},
pagingInfo: paginationData,
})
if (res.code === 0) {
platformAgentUsageDetailData.value = res.data
paginationData.totalRows = res.pagingInfo?.totalRows || 0
paginationData.totalPages = res.pagingInfo?.totalPages || 0
platformAgentUsageDetailLoading.value = false
}
}
</script>
<template>
<div ref="pageContentWrapRef" class="mx-6 h-full rounded-[10px] bg-white pt-[46px]">
<div class="text-font-color mb-7 flex w-full justify-around gap-2 px-[34px]">
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-create_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformAgentUsage.createCount" />
</div>
<span class="mt-3">{{ t('statistic_module.create_agent_count') }}</span>
</div>
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-usage_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformAgentUsage.usageCount" />
</div>
<span class="mt-3">{{ t('statistic_module.usage_agent_count') }}</span>
</div>
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-unpublish_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformAgentUsage.unPublishCount" />
</div>
<span class="mt-3">{{ t('statistic_module.unpublish_agent_count') }}</span>
</div>
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-publish_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformAgentUsage.publishCount" />
</div>
<span class="mt-3">{{ t('statistic_module.published_agent_count') }}</span>
</div>
</div>
<div class="mx-[34px] flex items-start justify-between">
<ContentTitle :title="t('statistic_module.platform_agent_usage_detail')" />
<DataSelectSearch @update-search-list="handleGetPlatformAgentUsageDetail" />
</div>
<div class="mx-[34px] mt-5 flex flex-1 flex-col">
<div :style="{ height: tableContentY + 48 + 'px' }">
<n-data-table
:columns="platformAgentUsageDetailColumns"
:bordered="false"
:bottom-bordered="false"
:max-height="tableContentY"
:loading="platformAgentUsageDetailLoading"
:data="platformAgentUsageDetailData"
:scroll-x="1505"
>
<template #empty>
<div class="flex items-center justify-center" :style="{ height: tableContentY + 'px' }">
<div class="flex flex-col items-center justify-center">
<div class="bg-px-empty_list-png mb-5 h-[68px] w-[68px]" />
<p class="select-none text-[#84868c]">{{ t('common_module.empty_data') }}</p>
</div>
</div>
</template>
</n-data-table>
</div>
<div v-show="tableContentY > 0" class="mt-5 flex justify-end">
<CustomPagination
:paging-info="paginationData"
@update-page-no="handlePageNoChange"
@update-page-size="handlePageSizeChange"
/>
</div>
</div>
</div>
</template>
import i18n from '@/locales'
import { IPlatformAgentUsageDetailItem } from '../type'
import { formatDateTime } from '@/utils/date-formatter'
const t = i18n.global.t
export function createPlatformAgentUsageDetail() {
return [
{
title: () => <span>{t('statistic_module.agent_title')}</span>,
key: 'agentTitle',
align: 'left',
width: '369px',
ellipsis: {
tooltip: true,
},
render(row: IPlatformAgentUsageDetailItem) {
return row.agentTitle || '--'
},
},
{
title: () => <span>{t('analysis_module.consume_points')}</span>,
key: 'totalPoint',
align: 'left',
width: '188px',
ellipsis: {
tooltip: true,
},
render(row: IPlatformAgentUsageDetailItem) {
return row.totalPoint.toFixed(1) || '--'
},
},
{
title: () => <span>{t('statistic_module.agent_status')}</span>,
key: 'publishStatus',
align: 'left',
width: '160px',
ellipsis: {
tooltip: true,
},
render(row: IPlatformAgentUsageDetailItem) {
return row.publishStatus === 'Y' ? t('common_module.published') : t('common_module.unpublished')
},
},
{
title: () => <span>{t('statistic_module.owner')}</span>,
key: 'owner',
align: 'left',
width: '236px',
ellipsis: {
tooltip: true,
},
render(row: IPlatformAgentUsageDetailItem) {
return row.owner || '--'
},
},
{
title: () => <span>{t('statistic_module.usage_count')}</span>,
key: 'usageCount',
align: 'left',
width: '200px',
ellipsis: {
tooltip: true,
},
render(row: IPlatformAgentUsageDetailItem) {
return row.usageCount || '--'
},
},
{
title: () => <span>{t('statistic_module.last_usage_time')}</span>,
key: 'lastUsageTime',
align: 'left',
width: '360px',
ellipsis: {
tooltip: true,
},
render(row: IPlatformAgentUsageDetailItem) {
return row.lastUsageTime ? formatDateTime(row.lastUsageTime) : '--'
},
},
]
}
<script setup lang="ts">
interface Props {
title: string
}
defineProps<Props>()
</script>
<template>
<div class="flex items-start">
<span class="bg-theme-color mr-[5px] mt-1.5 inline-block h-[14px] w-1 flex-shrink-0 rounded-sm" />
<span class="text-[16px]">{{ title }}</span>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import ContentTitle from '../../components/content-title.vue'
import { IPlatformPointUsage } from '../../type'
import { fetchGetPlatformPointUsage } from '@/apis/statistic'
interface Props {
channel: string[]
}
const { t } = useI18n()
const props = defineProps<Props>()
const platformPointUsage = ref<IPlatformPointUsage>({
today: 0,
week: 0,
month: 0,
year: 0,
})
watch(
() => props.channel,
() => {
handleGetPlatformPointUsage()
},
)
async function handleGetPlatformPointUsage() {
const res = await fetchGetPlatformPointUsage<IPlatformPointUsage>(props.channel)
if (res.code === 0) {
platformPointUsage.value = res.data
}
}
</script>
<template>
<div class="w-full rounded-[20px] bg-white py-5">
<ContentTitle :title="t('statistic_module.platform_point_usage')" class="ml-[34px]" />
<div class="text-font-color mt-6.5 mb-2.5 flex w-full justify-around gap-2 px-[34px]">
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-today_point_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformPointUsage.today" :precision="1" />
</div>
<span class="mt-3">{{ t('statistic_module.today_usage') }}</span>
</div>
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-week_point_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformPointUsage.week" :precision="1" />
</div>
<span class="mt-3">{{ t('statistic_module.current_week_usage') }}</span>
</div>
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-month_point_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformPointUsage.month" :precision="1" />
</div>
<span class="mt-3">{{ t('statistic_module.current_month_usage') }}</span>
</div>
<div
class="relative flex h-[124px] max-w-[312px] flex-1 flex-col justify-center rounded-[10px] bg-[#F8F9FB] px-10"
>
<div class="bg-px-statistics-year_point_icon-png absolute bottom-0 right-0 h-[93px] w-[90px]" />
<div class="font-600 text-[30px]">
<n-number-animation :from="0" :to="platformPointUsage.year" :precision="1" />
</div>
<span class="mt-3">{{ t('statistic_module.current_year_usage') }}</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, useTemplateRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import ContentTitle from '../../components/content-title.vue'
import { IPlatformPointTrendItem } from '../../type'
import { type EChartsOption } from '@/utils/echarts'
import CustomEchart from '@/components/custom-echart/custom-echart.vue'
import DataSelectSearch from '@/components/date-select-search/data-select-search.vue'
import { RangType } from '@/components/date-select-search/type.d'
import { ChannelText, ChannelType } from '@/enums/channel'
import { fetchGetPlatformPointTrend } from '@/apis/statistic'
interface Props {
channel: string[]
}
const { t } = useI18n()
const props = defineProps<Props>()
const pointUsageTrendRef = useTemplateRef<InstanceType<typeof CustomEchart> | null>('pointUsageTrendRef')
const currentTime = ref<RangType>(RangType.week)
const selectDateRange = ref<[string, string]>(['', ''])
const defaultEchartOption: EChartsOption = {
legend: {
top: '36px',
},
tooltip: {
trigger: 'axis',
textStyle: {
fontWeight: 'normal',
},
},
xAxis: { type: 'category' },
yAxis: { gridIndex: 0 },
grid: { top: '100px', left: '110px', right: '70px', bottom: '40px' },
color: ['#e94540', '#6ea2ff', '#ba68ff', '#ff61c1', '#2db70e', '#eda030'],
series: [
{
type: 'line',
smooth: true,
seriesLayoutBy: 'row',
emphasis: { focus: 'series' },
},
{
type: 'line',
smooth: true,
seriesLayoutBy: 'row',
emphasis: { focus: 'series' },
},
{
type: 'line',
smooth: true,
seriesLayoutBy: 'row',
emphasis: { focus: 'series' },
},
{
type: 'line',
smooth: true,
seriesLayoutBy: 'row',
emphasis: { focus: 'series' },
},
{
type: 'line',
smooth: true,
seriesLayoutBy: 'row',
emphasis: { focus: 'series' },
},
{
type: 'line',
smooth: true,
seriesLayoutBy: 'row',
emphasis: { focus: 'series' },
},
],
}
const pointUsageTrendEchartsOption = reactive<EChartsOption>({ ...defaultEchartOption })
watch(
() => props.channel,
() => {
handleGetPlatformPointTrend(currentTime.value, selectDateRange.value[0], selectDateRange.value[1])
},
)
async function handleGetPlatformPointTrend(rangType: RangType, startTime: string, endTime: string) {
if (!props.channel.length) {
return
}
currentTime.value = rangType
selectDateRange.value = [startTime, endTime]
pointUsageTrendRef.value?.echartShowLoading()
const res = await fetchGetPlatformPointTrend<IPlatformPointTrendItem[]>({
channel: props.channel,
timeRange: {
rangType,
startTime,
endTime,
},
})
if (res.code === 0) {
const dataSourceSort = handleDataSourceSort(res.data)
const dateList = [...new Set(dataSourceSort.flatMap((item) => item.pointUsages.map((usage) => usage.date)))].sort()
const dataSource: [string[], ...[string, ...number[]][]] = [['product', ...dateList]]
dataSourceSort.forEach((item) => {
const row: [string, ...number[]] = [t(ChannelText[item.channel])]
dateList.forEach((date) => {
const count = item.pointUsages.find((usage) => usage.date === date)?.count || 0
row.push(count)
})
dataSource.push(row)
})
pointUsageTrendEchartsOption.dataset = {
source: dataSource,
}
pointUsageTrendRef.value?.echartHideLoading()
}
}
function handleDataSourceSort(dataSource: IPlatformPointTrendItem[]) {
const channelSortMap = {
[ChannelType.preview]: 1,
[ChannelType.multi_preview]: 2,
[ChannelType.mall]: 3,
[ChannelType.index]: 4,
[ChannelType.link_share]: 5,
[ChannelType.api]: 6,
}
return dataSource.sort((a, b) => channelSortMap[a.channel] - channelSortMap[b.channel])
}
</script>
<template>
<div class="relative h-[455px] w-full rounded-[20px] bg-white py-5">
<div class="absolute left-0 right-0 z-10">
<div class="mx-[34px] flex items-start justify-between">
<ContentTitle :title="t('statistic_module.platform_point_trend')" />
<DataSelectSearch @update-search-list="handleGetPlatformPointTrend" />
</div>
</div>
<div class="h-full w-full">
<CustomEchart ref="pointUsageTrendRef" :option="pointUsageTrendEchartsOption" />
</div>
</div>
</template>
<script setup lang="ts">
import { computed, h, onMounted, readonly, ref } from 'vue'
import { NTag, TreeSelectOption } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import PointUsagePanel from './components/point-usage-panel.vue'
import PointUsageTrend from './components/point-usage-trend.vue'
import { ChannelType } from '@/enums/channel'
import { useSystemLanguageStore } from '@/store/modules/system-language'
const { t } = useI18n()
const systemLanguageStore = useSystemLanguageStore()
const channelOptionList = [
{
label: t('analysis_module.agent_debug'),
key: 'agent_preview',
children: [
{
label: t('analysis_module.debug'),
key: ChannelType.preview,
},
{
label: t('analysis_module.multi_debug'),
key: ChannelType.multi_preview,
},
],
},
{
label: t('analysis_module.usage_channel'),
key: 'usage_channel',
children: [
{
label: t('analysis_module.index'),
key: ChannelType.index,
},
{
label: t('analysis_module.agent_square'),
key: ChannelType.mall,
},
{
label: t('analysis_module.link_share'),
key: ChannelType.link_share,
},
{
label: t('analysis_module.api'),
key: ChannelType.api,
},
],
},
]
const channelGroupList = readonly(channelOptionList.map((channelItem) => channelItem.key))
const allChannelList = handleGetAllChannelList(channelOptionList)
const selectChannelList = ref<string[]>([])
onMounted(() => {
selectChannelList.value = allChannelList
})
const isEnLanguage = computed(() => {
return systemLanguageStore.currentLanguageInfo.key === 'en'
})
function handleUpdateChannelList(channelList: string[]) {
if (channelList.length === 0) {
selectChannelList.value = allChannelList
return
}
selectChannelList.value = channelList
}
function handleRenderChannelLabel({ option }: { option: TreeSelectOption }) {
return h('span', { style: { marginRight: '24px' } }, { default: () => option.label as string })
}
function handleRenderSelectChannel({ option }: { option: TreeSelectOption }) {
if (
selectChannelList.value.length === allChannelList.length &&
selectChannelList.value.every((item) => allChannelList.includes(item))
) {
return option.key === allChannelList?.[0]
? h('span', { class: 'mb-[3px]' }, t('analysis_module.all_channels'))
: null
}
return h(NTag, { class: 'mb-[3px] px-[10px]!' }, { default: () => option.label as string })
}
function handleGetAllChannelList(options: TreeSelectOption[]) {
let channelList: string[] = []
function recurseChannelList(channels: TreeSelectOption[]) {
if (Array.isArray(channels)) {
channels.forEach((channel) => {
if (!channel.children || channel.children.length === 0) {
channelList.push(channel.key as string)
} else {
recurseChannelList(channel.children)
}
})
}
}
recurseChannelList(options)
return channelList
}
</script>
<template>
<div class="flex h-full w-full flex-col overflow-y-auto overflow-x-hidden px-6">
<div class="flex justify-end pr-[34px]">
<div class="max-w-[300px]" :class="isEnLanguage ? 'min-w-[124px]' : 'min-w-[154px]'">
<n-tree-select
v-model:value="selectChannelList"
multiple
cascade
checkable
check-strategy="child"
placement="bottom-end"
max-tag-count="responsive"
class="tree-tag"
:options="channelOptionList"
:menu-props="{ style: { marginTop: '6px', borderRadius: '5px' } }"
:consistent-menu-width="false"
:ellipsis-tag-popover-props="{ show: false }"
:default-expanded-keys="channelGroupList"
:render-label="handleRenderChannelLabel"
:render-tag="handleRenderSelectChannel"
@update:value="handleUpdateChannelList"
>
</n-tree-select>
</div>
</div>
<div class="mt-5 flex flex-1 flex-col gap-5">
<PointUsagePanel :channel="selectChannelList" />
<PointUsageTrend :channel="selectChannelList" />
</div>
</div>
</template>
<style scoped lang="scss">
@include custom-scrollbar(6px);
:deep(.tree-tag .n-base-selection) {
--n-height: 36px !important;
--n-color: #f3f5f8 !important;
--n-color-active: #f3f5f8 !important;
--n-border: 1px solid #ccc !important;
.n-base-selection-tag-wrapper .n-tag {
margin-right: 10px !important;
background: #fff !important;
border-radius: 5px !important;
--n-border: none !important;
}
.n-base-selection-tag-wrapper {
padding: 0;
}
}
</style>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
const { t } = useI18n()
const currentRoute = useRoute()
const router = useRouter()
const routerNameValue = ref(currentRoute.name)
const statisticModuleList = [
{
routeName: 'PointStatistic',
label: 'statistic_module.point_statistic',
},
{
routeName: 'AgentStatistic',
label: 'statistic_module.agent_statistic',
},
]
watch(
() => currentRoute.fullPath,
() => {
routerNameValue.value = currentRoute.name
},
)
function handleChangeRoute(routeName: string) {
router.replace({ name: routeName })
}
</script>
<template>
<div class="m-auto flex h-full max-w-[1669px] flex-col pb-2 pt-1">
<div class="flex flex-col px-6">
<div class="mb-5 flex items-center">
<img src="@/assets/images/statistics/statistics-icon.png" />
<p class="ml-[5px] text-lg">{{ t('statistic_module.data_statistic') }}</p>
</div>
<ul class="mb-5 flex">
<li
v-for="statisticModuleItem in statisticModuleList"
:key="statisticModuleItem.routeName"
class="rounded-theme hover:bg-theme-color ml-2.5 h-8 cursor-pointer select-none px-[14px] leading-8 transition-colors duration-300 first:ml-0 hover:text-white"
:class="[
routerNameValue === statisticModuleItem.routeName
? 'bg-theme-color text-white'
: 'text-gray-font-color border-transparent',
]"
@click="handleChangeRoute(statisticModuleItem.routeName)"
>
{{ t(statisticModuleItem.label) }}
</li>
</ul>
</div>
<div class="h-full overflow-hidden">
<RouterView v-slot="{ Component }">
<Transition appear name="fade-slide" mode="out-in">
<Component :is="Component" />
</Transition>
</RouterView>
</div>
</div>
</template>
<style lang="scss" scoped>
.fade-slide-leave-active,
.fade-slide-enter-active {
transition: all 0.3s;
}
.fade-slide-enter-from {
opacity: 0;
transform: translateX(-30px);
}
.fade-slide-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
import { ChannelType } from '@/enums/channel'
export interface IPlatformPointUsage {
today: number
week: number
month: number
year: number
}
export interface IPlatformPointTrendItem {
channel: ChannelType
pointUsages: {
date: string
count: number
}[]
}
export interface IPlatformAgentUsage {
createCount: number
usageCount: number
unPublishCount: number
publishCount: number
}
export interface IPlatformAgentUsageDetailItem {
agentTitle: string
owner: string
publishStatus: 'Y' | 'N'
totalPoint: number
usageCount: number
lastUsageTime: Date
}
......@@ -191,6 +191,7 @@ declare namespace I18n {
application_square: string
personal_settings: string
order_manage: string
data_statistic: string
}
login_module: {
......@@ -629,5 +630,27 @@ declare namespace I18n {
api: string
link_share: string
}
statistic_module: {
data_statistic: string
point_statistic: string
agent_statistic: string
platform_point_usage: string
platform_point_trend: string
today_usage: string
current_week_usage: string
current_month_usage: string
current_year_usage: string
create_agent_count: string
usage_agent_count: string
unpublish_agent_count: string
published_agent_count: string
platform_agent_usage_detail: string
agent_title: string
agent_status: string
owner: string
usage_count: string
last_usage_time: string
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment