Commit f02c366d authored by 黄同智's avatar 黄同智

布局视频审核,互动数据

parent 953a86b7
...@@ -14,12 +14,14 @@ ...@@ -14,12 +14,14 @@
"@vue-flow/additional-components": "^1.3.3", "@vue-flow/additional-components": "^1.3.3",
"@vue-flow/core": "^1.48.2", "@vue-flow/core": "^1.48.2",
"axios": "^1.18.1", "axios": "^1.18.1",
"echarts": "^6.1.0",
"element-plus": "^2.14.2", "element-plus": "^2.14.2",
"pinia": "^2.2.0", "pinia": "^2.2.0",
"swiper": "^14.0.5", "swiper": "^14.0.5",
"three": "^0.185.1", "three": "^0.185.1",
"v3-cropper": "^1.2.1", "v3-cropper": "^1.2.1",
"vue": "^3.5.0", "vue": "^3.5.0",
"vue-echarts": "^8.1.0",
"vue-router": "^4.4.0" "vue-router": "^4.4.0"
}, },
"devDependencies": { "devDependencies": {
......
...@@ -184,6 +184,7 @@ $spacing-values: (); ...@@ -184,6 +184,7 @@ $spacing-values: ();
.hide { display: none; } .hide { display: none; }
.over-auto { overflow: auto; } .over-auto { overflow: auto; }
.over-scroll { overflow: scroll; } .over-scroll { overflow: scroll; }
.over-y-auto { overflow-y: auto;}
.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ellipsis-2 { overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 2;line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box; } .ellipsis-2 { overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 2;line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box; }
.ellipsis-3 { overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; display: -webkit-box; } .ellipsis-3 { overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; display: -webkit-box; }
......
<template>
<div class="data-card round-12 p-12 mt-20">
<!-- 1. 顶部控制栏 -->
<div class=" flex-items-center justify-between mb-10 flex-wrap">
<div class="left-actions flex-items-center gap-16">
<!-- 平台切换标签组 -->
<div class="platform-tabs flex gap-10 p-4 round-8 fs-12">
<div class="tab-item py-4 px-10 color-666 pointer round-6" v-for="(item, index) in ptOptions"
:key="index" @click="dataType = item.value" :class="dataType === item.value ? 'active' : ''">
巨量引擎
</div>
</div>
<!-- 数据筛选下拉 -->
<el-select v-model="dataType2" placeholder="选择数据" class="data-select" size="small">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in ptOptions2"
:key="index" />
</el-select>
</div>
<!-- 右侧指标选择(圆点+下拉) -->
<div class="right-actions flex-items-center gap-16">
<div class="flex-items-center gap-6">
<span class="dot purple"></span>
<el-select v-model="metric1" size="small" class="metric-select">
<el-option label="点击数" value="clicks" />
<el-option label="展示数" value="views" />
</el-select>
</div>
<div class="metric-item">
<span class="dot green"></span>
<el-select v-model="metric2" size="small" class="metric-select">
<el-option label="流失数" value="loss" />
<el-option label="转化数" value="conversion" />
</el-select>
</div>
</div>
</div>
<!-- 2. 图表区域 -->
<div class="chart-container">
<!-- 使用你上一轮写的 v-chart,传入配置 -->
<v-chart class="chart" :option="chartOption" autoresize />
</div>
<!-- 3. 底部信息说明 -->
<div class="mt-10 pt-10 text-center fs-12 footer-info">
<div class="color-888">
(数据来源:根据巨星接口实时查询,近一个月视频素材的互动流失数据)
</div>
<div class="red-text fw-500">
互动数据目前仅有 【标准推广】,【全域推广】需要巨量引擎官方开放API后接入
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import VChart from 'vue-echarts';
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart } from 'echarts/charts';
import { TitleComponent, TooltipComponent, LegendComponent, GridComponent } from 'echarts/components';
// 注册 ECharts 组件
use([CanvasRenderer, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent]);
// 数据状态
const dataType = ref(0);
const dataType2 = ref(0);
const metric1 = ref('clicks');
const metric2 = ref('loss');
// 模拟数据生成 (0-80秒)
const timeData = Array.from({ length: 81 }, (_, i) => `${i}s`);
const clicksData = timeData.map((_, i) => Math.round(9000 * Math.exp(-i / 30) + 200 * Math.sin(i / 5)));
const lossData = timeData.map((_, i) => Math.round(1800000 * Math.exp(-i / 35) + 50000 * Math.cos(i / 8)));
const ptOptions = ref([
{ label: '巨量引擎', value: 0 },
{ label: '腾讯ADQ', value: 1 },
{ label: 'TikTok', value: 2 },
])
const ptOptions2 = ref([
{ label: '全部抖音互动数据', value: 0 },
{ label: '千川直播间推广账户', value: 1 },
{ label: '巨量星图素材互动', value: 2 },
{ label: '全域计划推广汇总', value: 3 },
])
// 图表配置
const chartOption = computed(() => ({
tooltip: {
trigger: 'axis',
backgroundColor: '#fff',
borderColor: '#eee',
borderWidth: 1,
padding: [12, 16],
formatter: function (params: any) {
// 自定义 Tooltip 样式,匹配图片效果
let res = `<div style="font-weight:bold;margin-bottom:8px;">${params[0].axisValue}</div>`;
params.forEach((p: any) => {
const color = p.color === '#7b68ee' ? '#7b68ee' : '#3ecf8e';
const name = p.seriesName;
const val = p.value.toLocaleString();
res += `<div style="display:flex;justify-content:space-between;gap:20px;margin:4px 0;">
<span><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${color};margin-right:6px;"></span>${name}</span>
<span style="font-weight:bold;">${val} 次</span>
</div>`;
});
return res;
}
},
legend: {
data: ['点击数', '流失数'],
right: 20,
top: 10,
icon: 'circle',
itemWidth: 10,
itemHeight: 10,
},
grid: {
left: '3%',
right: '8%',
bottom: '5%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: timeData,
axisLine: { lineStyle: { color: '#eee' } },
axisLabel: { fontSize: 11, color: '#999' }
},
yAxis: [
{
type: 'value',
name: '',
min: 0,
max: 10000,
splitLine: { lineStyle: { type: 'dashed', color: '#eee' } },
axisLabel: {
formatter: (v: number) => v >= 10000 ? `${v / 10000}w` : v
}
},
{
type: 'value',
name: '',
min: 0,
max: 1800000,
splitLine: { show: false },
axisLabel: {
formatter: (v: number) => v >= 10000 ? `${v / 10000}w` : v
}
}
],
series: [
{
name: '点击数',
type: 'line',
yAxisIndex: 0,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 3, color: '#7b68ee' },
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(123, 104, 238, 0.4)' },
{ offset: 1, color: 'rgba(123, 104, 238, 0.01)' }
]
}
},
data: clicksData
},
{
name: '流失数',
type: 'line',
yAxisIndex: 1,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 3, color: '#3ecf8e' },
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(62, 207, 142, 0.4)' },
{ offset: 1, color: 'rgba(62, 207, 142, 0.01)' }
]
}
},
data: lossData
}
]
}));
</script>
<style scoped lang="scss">
.data-card {
border: 1px solid #eee;
&:hover {
border-color: rgba(var(--main-color), .4);
}
}
.left-actions {
.platform-tabs {
background: #f5f7fa;
.tab-item {
transition: all 0.2s;
&:hover {
color: #333;
}
&.active {
background: rgba(var(--main-color));
color: #fff;
font-weight: 500;
}
}
}
.data-select {
width: 160px;
:deep(.el-input__wrapper) {
box-shadow: none;
background: #f5f7fa;
border-radius: 6px;
}
}
}
.right-actions {
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
&.purple {
background: #7b68ee;
}
&.green {
background: #3ecf8e;
}
}
.metric-select {
width: 90px;
:deep(.el-input__wrapper) {
box-shadow: none;
background: transparent;
padding: 0 8px 0 0;
}
:deep(.el-input__inner) {
color: #333;
font-weight: 500;
}
}
}
/* --- 图表区域 --- */
.chart-container {
width: 100%;
height: 200px;
margin-top: 10px;
position: relative;
.chart {
width: 100%;
height: 100%;
}
}
/* --- 底部说明文字 --- */
.footer-info {
border-top: 1px solid #f5f5f5;
.red-text {
color: #ff5744;
margin-top: 4px;
}
}
/* 响应式调整 */
@media screen and (max-width: 768px) {
.header-bar {
flex-direction: column;
align-items: flex-start;
}
.right-actions {
width: 100%;
justify-content: flex-start;
}
.chart-container {
height: 250px;
}
}
</style>
\ No newline at end of file
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