Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mengchangaigc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
姚珂
mengchangaigc
Commits
f02c366d
Commit
f02c366d
authored
Aug 15, 2026
by
黄同智
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
布局视频审核,互动数据
parent
953a86b7
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
319 additions
and
0 deletions
+319
-0
package.json
apps/web-vue/package.json
+2
-0
common.scss
apps/web-vue/public/styles/common.scss
+1
-0
StackedAreaChart.vue
...e/src/views/resource/clip/components/StackedAreaChart.vue
+316
-0
detail.vue
apps/web-vue/src/views/resource/clip/detail.vue
+0
-0
No files found.
apps/web-vue/package.json
View file @
f02c366d
...
@@ -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"
:
{
...
...
apps/web-vue/public/styles/common.scss
View file @
f02c366d
...
@@ -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
;
}
...
...
apps/web-vue/src/views/resource/clip/components/StackedAreaChart.vue
0 → 100644
View file @
f02c366d
<
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
apps/web-vue/src/views/resource/clip/detail.vue
View file @
f02c366d
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment