diff --git a/src/api/log/index.ts b/src/api/log/index.ts index a289a24..65ea77d 100644 --- a/src/api/log/index.ts +++ b/src/api/log/index.ts @@ -9,6 +9,7 @@ import { baseUrlHost } from '../baseUrlHost'; * @method getlogList 获取日志列表 * @method getaiabilityList 获取统计AI能力列表 * @method getbaseUserList 获取统计基础信息列表 + * @method getaiabilityConsumeList 获取统计AI能力消费钻石列表 */ export function logApi() { @@ -33,5 +34,12 @@ export function logApi() { method: 'get', }); }, + getaiabilityConsumeList: (params:object) => { + return request({ + url: baseUrlHost + '/acLog/AiAbilityConsume', + method: 'get', + params, + }); + }, }; } diff --git a/src/views/log/index.vue b/src/views/log/index.vue index 737de79..bdd2938 100644 --- a/src/views/log/index.vue +++ b/src/views/log/index.vue @@ -175,14 +175,14 @@ getTableData(); \ No newline at end of file diff --git a/src/views/statistics/index.vue b/src/views/statistics/index.vue index 8dc0306..7ca4b75 100644 --- a/src/views/statistics/index.vue +++ b/src/views/statistics/index.vue @@ -5,7 +5,7 @@ :xs="24" :sm="12" :md="12" - :lg="8" + :lg="6" :xl="6" v-for="(v, k) in state.homeOne" :key="k" @@ -25,32 +25,125 @@ - - -
- -
+
+
+ +
-
+ + + + + +
+
+
+ +
+ +
+ + + + +
+
+
+
+ + +
+ +
+ +
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
+ +
@@ -61,15 +154,15 @@ import { storeToRefs } from 'pinia'; import { useThemeConfig } from '/@/stores/themeConfig'; import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; import { logApi } from '/@/api/log'; +import { ElMessage } from 'element-plus'; const logapi = logApi(); // 定义变量内容 +// const centerDialogVisible = ref(false) const homeLineRef = ref(); const homePieRef = ref(); const homeBarRef = ref(); -const dateRange = ref(''); -const defaultTime1 = new Date(2000, 1, 1, 0, 0, 0) // '12:00:00' const storesTagsViewRoutes = useTagsViewRoutes(); const storesThemeConfig = useThemeConfig(); const { themeConfig } = storeToRefs(storesThemeConfig); @@ -202,21 +295,30 @@ const getList = async() =>{ { num1: data.userTodayCount, // num2: "42.32", // 示例百分比变化值 - num3: "今日用户数", + num3: "今天新增用户数", color1: '#6690F9', color2: '--next-color-success-lighter', color3: '--el-color-success', num4: "iconfont icon-ditu", }, { - num1: data.homeviewCount, + num1: data.homeviewTodayCount, // num2: "17.32", // 示例百分比变化值 - num3: "首页浏览数", + num3: "今日首页浏览数", color1: '#6690F9', color2: '--next-color-warning-lighter', color3: '--el-color-warning', num4: "iconfont icon-zaosheng", }, + { + num1: data.homeviewCount, + // num2: '-10.01', + num3: '首页总浏览数', + num4: 'fa fa-github-alt', + color1: '#FF6462', + color2: '--next-color-danger-lighter', + color3: '--el-color-danger', + }, ]; } }catch(error){ @@ -224,88 +326,6 @@ const getList = async() =>{ } }; -// 折线图 -const initLineChart = () => { - if (!state.global.dispose.some((b: any) => b === state.global.homeChartOne)) state.global.homeChartOne.dispose(); - state.global.homeChartOne = markRaw(echarts.init(homeLineRef.value, state.charts.theme)); - const option = { - backgroundColor: state.charts.bgColor, - title: { - text: '政策补贴额度', - x: 'left', - textStyle: { fontSize: '15', color: state.charts.color }, - }, - grid: { top: 70, right: 20, bottom: 30, left: 30 }, - tooltip: { trigger: 'axis' }, - legend: { data: ['预购队列', '最新成交价'], right: 0 }, - xAxis: { - data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], - }, - yAxis: [ - { - type: 'value', - name: '价格', - splitLine: { show: true, lineStyle: { type: 'dashed', color: '#f5f5f5' } }, - }, - ], - series: [ - { - name: '预购队列', - type: 'line', - symbolSize: 6, - symbol: 'circle', - smooth: true, - data: [0, 41.1, 30.4, 65.1, 53.3, 53.3, 53.3, 41.1, 30.4, 65.1, 53.3, 10], - lineStyle: { color: '#fe9a8b' }, - itemStyle: { color: '#fe9a8b', borderColor: '#fe9a8b' }, - areaStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: '#fe9a8bb3' }, - { offset: 1, color: '#fe9a8b03' }, - ]), - }, - }, - { - name: '最新成交价', - type: 'line', - symbolSize: 6, - symbol: 'circle', - smooth: true, - data: [0, 24.1, 7.2, 15.5, 42.4, 42.4, 42.4, 24.1, 7.2, 15.5, 42.4, 0], - lineStyle: { color: '#9E87FF' }, - itemStyle: { color: '#9E87FF', borderColor: '#9E87FF' }, - areaStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: '#9E87FFb3' }, - { offset: 1, color: '#9E87FF03' }, - ]), - }, - emphasis: { - itemStyle: { - color: { - type: 'radial', - x: 0.5, - y: 0.5, - r: 0.5, - colorStops: [ - { offset: 0, color: '#9E87FF' }, - { offset: 0.4, color: '#9E87FF' }, - { offset: 0.5, color: '#fff' }, - { offset: 0.7, color: '#fff' }, - { offset: 0.8, color: '#fff' }, - { offset: 1, color: '#fff' }, - ], - }, - borderColor: '#9E87FF', - borderWidth: 2, - }, - }, - }, - ], - }; - state.global.homeChartOne.setOption(option); - state.myCharts.push(state.global.homeChartOne); -}; // 饼图 const initPieChart = () => { if (!state.global.dispose.some((b: any) => b === state.global.homeChartTwo)) state.global.homeChartTwo.dispose(); @@ -392,93 +412,368 @@ const initPieChart = () => { state.myCharts.push(state.global.homeChartTwo); }; -//获取柱状图的数据 -const fetchChartData = async (start?: string, end?: string) => { - try { - const params = start && end ? { start, end } : {}; // 参数 - const response = await logapi.getabilityList(params); // 调用接口获取数据 - if (response && response.data) { - initBarChart(response.data); // 调用图表初始化函数并传入数据 - } - } catch (error) { - console.error('获取柱状图数据失败:', error); - } +//获取当天的具体时间 +const setDefaultDateBar = ( + type:number +): string => { + let t = ''; + let date = new Date(); + let dateMap = { + year: date.getFullYear(), + month: date.getMonth() + 1, + day: date.getDate(), + }; + + let month = dateMap.month >= 10 ? dateMap.month : "0" + dateMap.month + let day = dateMap.day >= 10 ? dateMap.day : "0" + dateMap.day + //当天默认初始时间 00:00:00 + if (type === 0) { + t = date.getFullYear() + "-" + month + "-" + day + ' '+ '00' + ':'+ '00' +':'+ '00'; + } + + //当天默认初始时间 23:59:59 + if (type === 1) { + const date = new Date(); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0') + const minutes = String(date.getMinutes()).padStart(2, '0') + const second = String(date.getSeconds()).padStart(2,'0') + t = `${year}-${month}-${day} ${hours}:${minutes}:${second}`; + } + return t; }; -// 处理日期范围变化 -const handleDateChange = () => { - if (dateRange.value.length === 2) { - const [start, end] = dateRange.value; // 已是 yyyy-MM-dd HH:mm:ss 格式 - fetchChartData(start, end); // 将选择后的日期范围传递给图表数据接口 - } else { - fetchChartData(); // 日期范围清空时的操作 +const setDefaultDateLine = ( + type: number +): string => { + const date = new Date(); + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + + let startDate = new Date(year, date.getMonth(), date.getDate()); + let endDate = new Date(year, date.getMonth(), date.getDate()); + + // 调整日期以周的时间段 + if (type === 0) { + startDate.setDate(startDate.getDate() - 6); // 起始是从今天往前开始的前7天 + } + + if (type === 1) { + endDate = date; // 终止是今天的当前时刻 + } + + const formattedStartDate = [ + startDate.getFullYear(), + (startDate.getMonth() + 1).toString().padStart(2, '0'), + startDate.getDate().toString().padStart(2, '0') + ].join('-') + ' 00:00:00'; + + const formattedEndDate = [ + endDate.getFullYear(), + (endDate.getMonth() + 1).toString().padStart(2, '0'), + endDate.getDate().toString().padStart(2, '0') + ].join('-') + ` ${endDate.getHours().toString().padStart(2, '0')}:${endDate.getMinutes().toString().padStart(2, '0')}:${endDate.getSeconds().toString().padStart(2, '0')}`; + + return type === 0 ? formattedStartDate : formattedEndDate; +}; + +const dateRangeBar = ref([setDefaultDateBar(0), setDefaultDateBar(1)]); + +const dateRangeLine = ref([setDefaultDateLine(0), setDefaultDateLine(1)]); +console.log(111111111111111,dateRangeLine.value); + +//AI能力使用数据 +const AIabliltyData = ref([]); + +//AI钻石消费数据 +const lineChartData = ref([]); + +//处理AI能力统计移动端日期范围变化 +const handleDateBar = () => { + const [start, end] = dateRangeBar.value; + fetchBarMobile(start, end); +}; + +//移动端AI能力数据获取 +const fetchBarMobile = async( start?: string, end?: string ) => { + try{ + const params = start && end ? { start, end } : {}; // 参数 + const response = await logapi.getabilityList(params); + if(response?.success){ + AIabliltyData.value = response.data; + console.log('AI能力使用数据',AIabliltyData.value); + } + }catch(error){ + console.error('获取AI能力使用失败',error); + } +}; + +//处理禁用日期 +const datePickerOptions = ref({ + disabledDate: (time: Date):boolean => false, // 默认不禁用任何日期 +}); + +//处理AI消费钻石移动端日期范围变化 +const handleDateLine = () => { + const [start] = dateRangeLine.value; + console.log([start],44444); + + if (start) { + const startDate = new Date(start); + const minDate = new Date(startDate); + minDate.setDate(startDate.getDate() - 2); // 设置最小允许日期为开始日期前两天 + console.log(minDate,'zuixiao'); + + const maxDate = new Date(startDate); + + maxDate.setDate(startDate.getDate() + 2); // 设置最大允许日期为开始日期后两天 + console.log(maxDate,'zuida'); + // 更新禁用日期的配置 + datePickerOptions.value = { + disabledDate: (time: Date):boolean => { + return time < minDate || time > maxDate; + } + }; + } + fetchLineMobile(start, dateRangeLine.value[1]); +}; + +//移动端AI消费钻石数据获取 +const fetchLineMobile = async( start?: string, end?: string ) => { + try{ + const params = start && end ? {start, end} : {};//参数 + const response = await logapi.getaiabilityConsumeList(params); + // console.log(22222222222,response.value); + if(response?.success){ + lineChartData.value = response.data; + console.log('AI消费钻石数据',lineChartData.value); + } + }catch(error){ + console.error('获取AI消费钻石数据失败:',error) + } +} + + +// 处理柱状图日期范围变化 +const handleDateChangeBar = () => { + const [start, end] = dateRangeBar.value; // 已是 yyyy-MM-dd HH:mm:ss 格式 + fetchBarChartData(start, end); // 将选择后的日期范围传递给柱状图图表数据接口 +}; + +// 处理折线图日期范围变化 +const handleDateChangeLine = () => { + const [start] = dateRangeLine.value; + console.log([start],44444); + + if (start) { + const startDate = new Date(start); + const minDate = new Date(startDate); + minDate.setDate(startDate.getDate() - 2); // 设置最小允许日期为开始日期前两天 + console.log(minDate,'zuixiao'); + + const maxDate = new Date(startDate); + + maxDate.setDate(startDate.getDate() + 2); // 设置最大允许日期为开始日期后两天 + console.log(maxDate,'zuida'); + // 更新禁用日期的配置 + datePickerOptions.value = { + disabledDate: (time: Date):boolean => { + return time < minDate || time > maxDate; + } + }; + } + fetchLineCharData(start, dateRangeLine.value[1]); +}; + +//获取柱状图的数据 +const fetchBarChartData = async (start?: string, end?: string) => { + try { + const params = start && end ? { start, end } : {}; // 参数 + const response = await logapi.getabilityList(params); // 调用接口获取数据 + if (response && response.data) { + initBarChart(response.data); // 调用图表初始化函数并传入数据 } + } catch (error) { + console.error('获取柱状图数据失败:', error); + } +}; + +//获取折线图的数据 +const fetchLineCharData = async (start?: string,end?: string) => { + try{ + const params = start && end ? {start, end} : {};//参数 + const response = await logapi.getaiabilityConsumeList(params); + // console.log(22222222222,response.value); + + if(response && response.data){ + lineChartData.value = response.data; + console.log('折线图数据',lineChartData.value); + initLineChart(response.data); + } + }catch(error){ + console.error('获取折线图数据失败:',error) + } }; // 柱状图 -const initBarChart = (data:any = []) => { - if (!state.global.dispose.some((b) => b === state.global.homeCharThree)) - state.global.homeCharThree.dispose(); +const initBarChart = (data: any = []) => { + console.log('Chart Data:', data); // Debug: Log the data + + if (state.global.homeCharThree) { + state.global.homeCharThree.clear(); // 正常清理而非 dispose, 以防止图表被卸载 + } else { + state.global.homeCharThree = markRaw(echarts.init(homeBarRef.value, state.charts.theme)); + } - state.global.homeCharThree = markRaw(echarts.init(homeBarRef.value, state.charts.theme)); + // 数据不为空,正常渲染逻辑 + if (data && data.length > 0) { + // console.log(333333333333); + + const abilities = data.map((item) => item.ability); + const successNums = data.map((item) => item.successnNum); + const failNums = data.map((item) => item.failNum); - const abilities = data.length ? data.map((item) => item.ability) : ['无数据']; - const numbers = data.length ? data.map((item) => item.num) : [0]; - - const option = { - backgroundColor: state.charts.bgColor, - title: { - text: 'AI能力使用统计', - x: 'left', - textStyle: { fontSize: '15', color: state.charts.color }, - }, - tooltip: { trigger: 'axis' }, - grid: { top: 100, right: 30, bottom: 100, left: 50 }, - xAxis: [ - { - type: 'category', - data: abilities, - axisTick: { show: false }, - axisLabel: { - color: state.charts.color, - interval: 0, - rotate: 30, - }, - axisLine: { - lineStyle: { color: state.charts.color }, - }, - }, - ], - yAxis: [ - { - type: 'value', - name: '使用次数', - nameTextStyle: { padding: [0, 0, 10, 0] }, - splitLine: { show: true, lineStyle: { type: 'dashed', color: '#f5f5f5' } }, - axisLine: { show: false }, - axisTick: { show: false }, - axisLabel: { color: state.charts.color, formatter: '{value}' }, - }, - ], - series: [ - { - name: '使用次数', - type: data.length ? 'bar' : 'line', // 无数据时显示为一条线 - barWidth: '40%', - itemStyle: { - color: data.length ? new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(108,80,243,0.8)' }, - { offset: 1, color: 'rgba(108,80,243,0.3)' }, - ]) : undefined, // 符合bar和line样式 - borderRadius: [5, 5, 0, 0], - }, - data: numbers, - }, - ], - }; + const option = { + backgroundColor: state.charts.bgColor, + title: { + text: 'AI能力使用统计', + x: 'left', + textStyle: { fontSize: '15', color: state.charts.color }, + }, + tooltip: { trigger: 'axis' }, + grid: { top: 100, right: 30, bottom: 100, left: 50 }, + xAxis: [ + { + type: 'category', + data: abilities, + axisTick: { show: false }, + axisLabel: { + color: state.charts.color, + interval: 0, + rotate: 30, + }, + axisLine: { + lineStyle: { color: state.charts.color }, + }, + }, + ], + yAxis: [ + { + type: 'value', + name: '使用次数', + nameTextStyle: { padding: [0, 0, 10, 0] }, + splitLine: { show: true, lineStyle: { type: 'dashed', color: '#f5f5f5' } }, + axisLine: { show: false }, + axisTick: { show: false }, + axisLabel: { color: state.charts.color, formatter: '{value}' }, + }, + ], + series: [ + { + name: '成功使用次数', + type: 'bar', + barWidth: '40%', + itemStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: 'rgba(108,80,243,0.8)' }, + { offset: 1, color: 'rgba(108,80,243,0.3)' }, + ]), + borderRadius: [5, 5, 0, 0], + }, + data: successNums, + label:{ + show:true, + position:'top' + } + }, + { + name: '失败使用次数', + type: 'bar', + barWidth: '40%', + itemStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: 'rgba(23,145,239,0.8)' }, + { offset: 1, color: 'rgba(23,145,239,0.3)' }, + ]), + borderRadius: [5, 5, 0, 0], + }, + data: failNums, + label:{ + show:true, + position:'top' + } + }, + ], + }; state.global.homeCharThree.setOption(option); - state.myCharts.push(state.global.homeCharThree); + } else { + console.warn('没有图表数据'); + } + state.myCharts.push(state.global.homeCharThree); }; + +// 折线图 +const initLineChart = (data: any = []) => { + console.log('LineChart Data:',data); + + if (!state.global.dispose.some((b: any) => b === state.global.homeChartOne)) state.global.homeChartOne.dispose(); + state.global.homeChartOne = markRaw(echarts.init(homeLineRef.value, state.charts.theme)); + + const consume = data.map((item) => item.consume); + const time = data.map((item) => item.time); + + + const option = { + backgroundColor: state.charts.bgColor, + title: { + text: 'AI能力消费钻石数', + x: 'left', + textStyle: { fontSize: '15', color: state.charts.color }, + }, + grid: { top: 70, right: 20, bottom: 100, left: 30 }, + tooltip: { trigger: 'axis' }, + legend: { data: ['消费钻石数'], right: 0 }, + xAxis: { + data: time, + axisTick: { show: false }, + }, + yAxis: [ + { + type: 'value', + name: '钻石数量', + splitLine: { show: true, lineStyle: { type: 'dashed', color: '#f5f5f5' } }, + }, + ], + series: [ + { + name: '消费钻石数', + type: 'line', + symbolSize: 6, + symbol: 'circle', + smooth: true, + data: consume, + label:{ + show:true, + position:'top' + }, + lineStyle: { color: '#fe9a8b' }, + itemStyle: { color: '#fe9a8b', borderColor: '#fe9a8b' }, + areaStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#fe9a8bb3' }, + { offset: 1, color: '#fe9a8b03' }, + ]), + }, + }, + ], + }; + state.global.homeChartOne.setOption(option); + state.myCharts.push(state.global.homeChartOne); +}; + // 批量设置 echarts resize const initEchartsResizeFun = () => { nextTick(() => { @@ -493,11 +788,50 @@ const initEchartsResizeFun = () => { const initEchartsResize = () => { window.addEventListener('resize', initEchartsResizeFun); }; + +// 检测是否是手机设备 +const isMobile = /Mobi|Android|iP(hone|od|ad)|BlackBerry|IEMobile|Kindle|Silk-Accelerated|Opera Mini|webOS/i.test(navigator.userAgent); + // 页面加载时 onMounted(() => { - initEchartsResize(); getList(); - fetchChartData(); // 初始加载无参数调用 + initEchartsResize(); // 初始加载无参数调用 + // formattedDate(); + if (isMobile) { + console.log('Mobile device detected'); + // ElMessage.success('Mobile device detected'); + // 在此处可以初始化移动端相关逻辑 + fetchBarMobile(setDefaultDateBar(0), setDefaultDateBar(1)) + fetchLineMobile(setDefaultDateLine(0), setDefaultDateLine(1)) + } else { + console.log('Desktop device detected'); + // 在此处可以初始化PC端相关逻辑 + // 监听 pinia 中是否开启深色主题 + watch( + () => themeConfig.value.isIsDark, + (isIsDark) => { + nextTick(() => { + state.charts.theme = isIsDark ? 'dark' : ''; + state.charts.bgColor = isIsDark ? 'transparent' : ''; + state.charts.color = isIsDark ? '#dadada' : '#303133'; + setTimeout(async() => { + await fetchBarChartData(setDefaultDateBar(0), setDefaultDateBar(1)); + }, 500); + setTimeout(() => { + initPieChart(); + }, 800); + setTimeout(async() => { + await fetchLineCharData(setDefaultDateLine(0), setDefaultDateLine(1)) + // initLineChart(); + }, 1200); + }); + }, + { + deep: true, + immediate: true, + } + ); + } }); // 由于页面缓存原因,keep-alive onActivated(() => { @@ -510,30 +844,7 @@ watch( initEchartsResizeFun(); } ); -// 监听 pinia 中是否开启深色主题 -watch( - () => themeConfig.value.isIsDark, - (isIsDark) => { - nextTick(() => { - state.charts.theme = isIsDark ? 'dark' : ''; - state.charts.bgColor = isIsDark ? 'transparent' : ''; - state.charts.color = isIsDark ? '#dadada' : '#303133'; - setTimeout(() => { - initLineChart(); - }, 500); - setTimeout(() => { - initPieChart(); - }, 700); - setTimeout(() => { - initBarChart(); - }, 1000); - }); - }, - { - deep: true, - immediate: true, - } -); + \ No newline at end of file