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

布局视频审核,互动数据

parent 953a86b7
......@@ -14,12 +14,14 @@
"@vue-flow/additional-components": "^1.3.3",
"@vue-flow/core": "^1.48.2",
"axios": "^1.18.1",
"echarts": "^6.1.0",
"element-plus": "^2.14.2",
"pinia": "^2.2.0",
"swiper": "^14.0.5",
"three": "^0.185.1",
"v3-cropper": "^1.2.1",
"vue": "^3.5.0",
"vue-echarts": "^8.1.0",
"vue-router": "^4.4.0"
},
"devDependencies": {
......
......@@ -184,6 +184,7 @@ $spacing-values: ();
.hide { display: none; }
.over-auto { overflow: auto; }
.over-scroll { overflow: scroll; }
.over-y-auto { overflow-y: auto;}
.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-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
......@@ -9,7 +9,7 @@
<span>平台 UI 遮挡排查蒙版</span>
<span class="fs-12 color-888 fw-500">预审防遮挡违规</span>
</div>
<div class="bg-eee flex gap-10 mt-10 round-4 p-4">
<div class="bg-47 flex gap-10 mt-10 round-4 p-4">
<div v-for="(item, index) in ptTabs" :key="index" @click="ptIndex = index"
class="round-4 py-4 px-10 pointer"
:class="ptIndex === index ? 'bg-main color-fff' : ''">
......@@ -39,7 +39,7 @@
</div>
</div>
</el-card>
<el-card class="flex-1 round-12">
<el-card class="flex-1 round-12" shadow="hover">
<div class="flex justify-between pb-10" style="border-bottom: 1px solid #eee;">
<div class="flex-items-center">
<div class="w-36 h-36 bg-main round-6"></div>
......@@ -53,77 +53,187 @@
</div>
<el-button type="primary" round>权限监测</el-button>
</div>
<div class="bg-eee flex gap-10 mt-20 round-4 p-4">
<div class="bg-47 flex gap-10 mt-20 round-4 p-4">
<div v-for="(item, index) in ptTabs" :key="index" @click="ptIndex = index"
class="round-4 py-4 px-10 pointer" :class="ptIndex === index ? 'bg-main color-fff' : ''">
class="round-4 py-4 px-10 pointer" :class="ptIndex === index ? 'bg-fff color-main fw-500' : ''">
<span>{{ item.label }}</span>
</div>
</div>
<div class="flex flex-col gap-20 mt-20">
<div class="flex-items-center">
<div class="w-100 color-666">成片区</div>
<div class="flex-1 color-000">
<span>女士内衣</span>
<el-button type="primary" text>修改</el-button>
<section v-if="ptIndex === 0">
<div class="flex flex-col gap-20 mt-20">
<div class="flex-items-center">
<div class="w-100 color-666">成片区</div>
<div class="flex-1 color-000">
<span>女士内衣</span>
<el-button type="primary" text>修改</el-button>
</div>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">视频标题</div>
<div class="flex-1 color-000">
<span>0730-8835-鲁月园-复古耳环动态奢感视频.mp4</span>
<el-button type="primary" text>修改</el-button>
<div class="flex-items-center">
<div class="w-100 color-666">视频标题</div>
<div class="flex-1 color-000">
<span>0730-8835-鲁月园-复古耳环动态奢感视频.mp4</span>
<el-button type="primary" text>修改</el-button>
</div>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">公共标签</div>
<div class="flex-1 color-000">
<el-tag type="success">仙侠穿越</el-tag>
<el-tag type="success">视频卡</el-tag>
<el-tag type="success">隐式陪叫</el-tag>
<el-button type="primary" text>+ 添加公共标签</el-button>
<div class="flex-items-center">
<div class="w-100 color-666">公共标签</div>
<div class="flex-1 color-000">
<el-tag type="success">仙侠穿越</el-tag>
<el-tag type="success">视频卡</el-tag>
<el-tag type="success">隐式陪叫</el-tag>
<el-button type="primary" text>+ 添加公共标签</el-button>
</div>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">个人标签</div>
<div class="flex-1 color-000">
<el-tag type="success">仙侠穿越</el-tag>
<el-tag type="success">视频卡</el-tag>
<el-tag type="success">隐式</el-tag>
<el-button type="primary" text>+ 添加个人标签</el-button>
<div class="flex-items-center">
<div class="w-100 color-666">个人标签</div>
<div class="flex-1 color-000">
<el-tag type="success">仙侠穿越</el-tag>
<el-tag type="success">视频卡</el-tag>
<el-tag type="success">隐式</el-tag>
<el-button type="primary" text>+ 添加个人标签</el-button>
</div>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">关联脚本</div>
<div class="flex-1 color-000">
<el-button type="primary" text>查看脚本(1)</el-button>
<div class="flex-items-center">
<div class="w-100 color-666">关联脚本</div>
<div class="flex-1 color-000">
<el-button type="primary" text>查看脚本(1)</el-button>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">视频状态</div>
<div class="flex-1 color-000">
<el-tag type="warning">待审核</el-tag>
<el-button type="primary" text>修改</el-button>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">视频备注</div>
<div class="flex-1 color-000">
<el-input type="textarea" rows="2" />
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">附件</div>
<div class="flex-1 color-000">
<el-button type="primary" text>+ 添加附件</el-button>
</div>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">视频状态</div>
<div class="flex-1 color-000">
<el-tag type="warning">待审核</el-tag>
<el-button type="primary" text>修改</el-button>
<div style="border-top: 1px solid #eee;" class="pt-16 mt-10">
<el-button type="primary" plain>分享</el-button>
<el-button type="primary" plain>操作记录</el-button>
<el-button type="primary" plain>下载源码视频</el-button>
<el-button type="primary" plain>更多</el-button>
</div>
</section>
<section v-if="ptIndex === 1">
<div class="bg-47 p-4 round-6 mt-20 flex-items-center gap-20">
<el-select placeholder="Select" style="width: 100px;" class="myselect">
<el-option v-for="item in pzOptions" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
<el-radio-group>
<el-radio value="1">只看@我的</el-radio>
<el-radio value="2">只看回复我的</el-radio>
</el-radio-group>
</div>
<div class="h-400 over-y-auto">
<div class="round-12 p-12 backitems mt-10" v-for="(item, index) in 10" :key="index">
<div class="fs-12 flex justify-between items-center">
<span class="round-6 color-main px-8 py-2"
style="background: rgba(var(--main-color), .05);box-shadow: 0 0 0 1px rgba(var(--main-color), .1);">0分2秒54
至 0分3秒68</span>
<div class="px-10 h-24 flex-center color-000 fs-10 round-40" style="background: #eee;">
第一版</div>
</div>
<div class="mt-4 fs-12">这里有点模糊,改一下 @dy4 @lan大声道撒活动大胜靠德卡仕达四大斯柯达</div>
<div class="bg-ef round-6 p-10 mt-10 flex flex-col gap-8">
<div v-for="(notice, indexn) in 2" :key="indexn" class="flex-items-center gap-20">
<div class="fs-12 flex-1 ellipsis">
<span class="fw-500">逢场作戏</span>
<span class="color-666 px-6">回复</span>
<span class="fw-500">天上人间%:</span>
<span class="color-333" title="已修改 @天上人间%杀很大撒大声地等哈啊哈是的">已修改
@天上人间%杀很大撒大声地等哈啊哈是的</span>
</div>
<div class="flex-items-center fs-12 gap-6">
<div class="color-blue">回复</div>
<span class="color-888">08-16 20:18</span>
</div>
</div>
</div>
<div class="flex justify-between items-center mt-10">
<div class="flex-items-center gap-8">
<div class="w-24 h-24 round bg-main hidden">
<img src="@/static/image/huaban.png" class="cover" width="100%" height="100%"
alt="">
</div>
<span class="fw-600 color-main">逢场作戏</span>
<span class="color-888 fs-12">05-23 14:58</span>
</div>
<div>
<el-button size="small" type="primary" class="color-blue" link>回复</el-button>
<el-button size="small" link type="danger">删除</el-button>
<el-button size="small" link>标记完成</el-button>
</div>
</div>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">视频备注</div>
<div class="flex-1 color-000">
<el-input type="textarea" rows="2" />
<div class="round-12 p-12 backitems mt-10 bg-ef">
<div class="fs-12 mb-10">
<span class="round-6 color-main px-8 py-2"
style="background: rgba(var(--main-color), .05);box-shadow: 0 0 0 1px rgba(var(--main-color), .1);">0分2秒54
至 0分3秒68</span>
<span class="ml-10 color-888">(片段批注)</span>
</div>
<div class="flex gap-10">
<el-mention v-model="mention" type="textarea" :rows="2" :maxlength="100" :options="ptTabs"
placeholder="请输入批注信息,输入@..." />
</div>
<div class="flex-items-center justify-between gap-10 mt-10">
<div class="flex-items-center gap-10">
<FileUpload :limit="1" :width="30" title="上传截图附件">
<template #trigger>
<span class="fs-18 lh-18 color-888">+</span>
</template>
</FileUpload>
<span class="fs-12 color-888">上传截图附件</span>
</div>
<div class="flex-items-center gap-10">
<el-checkbox label="同时发送通知" value="Value 1" />
<el-button type="primary" size="small" round>发送</el-button>
</div>
</div>
</div>
<div class="flex-items-center">
<div class="w-100 color-666">附件</div>
<div class="flex-1 color-000">
<el-button type="primary" text>+ 添加附件</el-button>
</section>
<section v-if="ptIndex === 2">
<StackedAreaChart />
<div class="p-12 backitems round-12 mt-10 bg-ef">
<div class="flex-items-center justify-between">
<div>
<div class="pl-12 relative fw-600 title">复盘区</div>
<div class="fs-12 color-888">分析视频在每个帧数的亮点与爆点,支持点击定位跳转播放</div>
</div>
<el-button type="primary" round size="small">+ 添加帧复盘</el-button>
</div>
<div v-for="(item, index) in 3" :key="index" class="bg-fff round-10 p-10 mt-10 flex gap-10">
<div class="w-48 h-48 round-10 bg-000" style="min-width: 48px;"></div>
<div class="flex-1 pt-4">
<div class="flex justify-between">
<div class="flex fs-12 gap-10">
<span class="px-8 py-2 round-4 tag">优质画面</span>
<span class="round-6 color-main px-8 py-2"
style="background: rgba(var(--main-color), .05);box-shadow: 0 0 0 1px rgba(var(--main-color), .1);">0分2秒54</span>
</div>
<span class="fs-12 color-888">2026-06-27 09:40</span>
</div>
<div class="fs-12 mt-4">
纯朴科技:<span class="fw-500 color-000">大萨达撒大花洒等哈还</span>
</div>
</div>
</div>
</div>
</div>
<div style="border-top: 1px solid #eee;" class="pt-16 mt-10">
<el-button type="primary" plain>分享</el-button>
<el-button type="primary" plain>操作记录</el-button>
<el-button type="primary" plain>下载源码视频</el-button>
<el-button type="primary" plain>更多</el-button>
</div>
</section>
</el-card>
</div>
</div>
......@@ -131,9 +241,10 @@
<script setup lang="ts">
import { ref } from 'vue';
import FileUpload from '@/components/Upload/index.vue'
import StackedAreaChart from './components/StackedAreaChart.vue';
const ptIndex = ref(0)
const ptIndex = ref(2)
const ptTabs = ref([
{ label: '抖音样式', value: 0 },
{ label: '抖音橱窗', value: 1 },
......@@ -147,6 +258,14 @@ const jtTabs = ref([
{ label: '9~12s 黄金Hook', desc: '直播间买一赠一' },
{ label: '12~15s 黄金Hook', desc: '点击下方小黄车' },
])
const pzOptions = ref([
{ label: '全部批注', value: 0 },
{ label: '单帧批注', value: 1 },
{ label: '片段批注', value: 2 },
{ label: '字幕批注', value: 3 },
])
const mention = ref('')
</script>
<style scoped lang="scss">
......@@ -160,11 +279,54 @@ const jtTabs = ref([
background-color: rgba(var(--main-color), 1);
color: #fff;
}
.bg-eee {
.bg-47 {
background-color: #f0f4f7;
}
.bg-ef {
background-color: #f9fcfd;
}
.color-blue {
color: #148cfc;
font-weight: bold;
}
.phone {
width: 320px;
}
.tag {
color: #148cfc;
background-color: #f5faff;
box-shadow: 0 0 0 1px #63b4ff;
}
.title {
&::before {
content: '';
position: absolute;
left: 0;
top: 3px;
border-radius: 20px;
height: 16px;
width: 6px;
background-color: rgba(var(--main-color), 1);
}
}
.backitems {
border: 1px solid #eee;
&:hover {
border-color: rgba(var(--main-color), .4);
}
}
:deep(.myselect) {
.el-select__wrapper {
border-radius: 12px;
}
}
</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