Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
bb76d85f
提交
bb76d85f
authored
3月 07, 2026
作者:
coderBryanFu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat:新增概览页时间线日历热力图功能
上级
bb99a95a
隐藏空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
575 行增加
和
64 行删除
+575
-64
index.vue
src/components/devStyle/components/index.vue
+11
-12
textStyle.vue
src/components/devStyle/components/textStyle.vue
+1
-1
main.js
src/main.js
+1
-0
CalendarHeatmap copy.vue
...ponents/allGovernment/components/CalendarHeatmap copy.vue
+447
-0
CalendarHeatmap.vue
...s/components/allGovernment/components/CalendarHeatmap.vue
+115
-51
没有找到文件。
src/components/devStyle/components/index.vue
浏览文件 @
bb76d85f
<
script
setup
lang=
"ts"
>
import
"@/styles/container.scss"
import
TextStyle
from
'./textStyle.vue'
;
import
ConstStyle
from
'./constStyle.vue'
;
import
{
ElScrollbar
,
ElSpace
}
from
"element-plus"
;
</
script
>
<
template
>
<el-scrollbar>
<div
class=
"common-page"
>
<el-space
direction=
"vertical"
alignment=
"flex-start"
>
<div
class=
"text-title-0-show"
>
开发样式
</div>
<div
class=
"text-title-1-show"
>
样式变量
</div>
<
const-style></const-style
>
<
ConstStyle
/
>
<div
class=
"text-title-1-show"
>
文字样式
</div>
<
text-style></text-style
>
<
TextStyle
/
>
</el-space>
</div>
</el-scrollbar>
</
template
>
\ No newline at end of file
</
template
>
<
script
setup
>
import
"@/styles/container.scss"
import
TextStyle
from
'./textStyle.vue'
;
import
ConstStyle
from
'./constStyle.vue'
;
</
script
>
\ No newline at end of file
src/components/devStyle/components/textStyle.vue
浏览文件 @
bb76d85f
<
template
>
<table
style=
"width: 1
00%
; border-collapse: collapse; border: 1px solid #ebeef5;"
>
<table
style=
"width: 1
600px
; border-collapse: collapse; border: 1px solid #ebeef5;"
>
<!-- 表头 -->
<thead>
<tr
class=
"text-title-2"
>
...
...
src/main.js
浏览文件 @
bb76d85f
...
...
@@ -8,6 +8,7 @@ import { withFallbackImage } from "./utils";
import
"./styles/scrollbar.css"
;
import
"./styles/elui.css"
;
import
"./styles/main.css"
;
import
"./styles/common.scss"
import
'@/assets/fonts/font.css'
import
zhCn
from
'element-plus/dist/locale/zh-cn.mjs'
...
...
src/views/ZMOverView/components/fourSuppress/components/allGovernment/components/CalendarHeatmap copy.vue
0 → 100644
浏览文件 @
bb76d85f
<
template
>
<div
style=
"position: relative;"
>
<div
ref=
"chartRef"
style=
"height: 620px; width: 1640px"
@
click=
"handleClick"
></div>
<div
v-show=
"tooltipVisible"
class=
"custom-tooltip background-as-card"
:style=
"
{ left: mouseX + 'px', top: mouseY + 'px' }">
<div
class=
"tooltip-header flex-display"
>
<div
class=
"tooltip-header-left text-title-3-bold"
>
{{
currentDate
}}
</div>
<div
class=
"tooltip-header-right text-title-3-show"
>
{{
`${'3个部门'
}
/${'3项举措'
}
`
}}
<
/div
>
<
/div
>
<
div
class
=
"tooltip-main"
>
<
div
class
=
"tooltip-main-item"
v
-
for
=
"item, index in currentDetailList"
:
key
=
"index"
>
<
div
class
=
"item-header flex-display"
>
<
div
class
=
"item-header-left flex-display"
>
<
div
class
=
"logo"
>
<
img
style
=
"width:100%; height: 100%"
:
src
=
"item.orgLogoUrl"
alt
=
"logo"
>
<
/div
>
<
div
class
=
"name text-bold"
>
{{
item
.
orgName
}}
<
/div
>
<
div
class
=
"status"
>
<
div
class
=
"status-on text-tip-2"
v
-
if
=
"item.stauts === 2"
>
{{
'已落实'
}}
<
/div
>
<
div
class
=
"status-off text-tip-2"
v
-
else
>
{{
'未落实'
}}
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"item-header-right flex-display"
>
<
AreaTag
v
-
for
=
"tag, idx in item.techDomainList.slice(0, 3)"
:
key
=
"idx"
:
tagName
=
"tag"
><
/AreaTag
>
<
/div
>
<
/div
>
<
div
class
=
"item-content text-compact"
>
{{
item
.
name
}}
<
/div
>
<
div
class
=
"item-footer"
><
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/template
>
<
script
setup
>
import
{
ref
,
onMounted
,
onBeforeUnmount
,
watch
,
computed
}
from
'vue'
;
import
*
as
echarts
from
'echarts/core'
;
import
{
CustomChart
}
from
'echarts/charts'
;
import
{
TitleComponent
,
TooltipComponent
,
CalendarComponent
}
from
'echarts/components'
;
import
{
CanvasRenderer
}
from
'echarts/renderers'
;
import
dayjs
from
'dayjs'
;
import
'dayjs/locale/zh-cn'
;
dayjs
.
locale
(
'zh-cn'
);
const
props
=
defineProps
(
{
timelineData
:
{
type
:
Array
,
default
:
[]
}
}
);
echarts
.
use
([
CustomChart
,
TitleComponent
,
TooltipComponent
,
CalendarComponent
,
CanvasRenderer
,
]);
const
chartRef
=
ref
(
null
);
let
chartInstance
=
null
;
// 弹窗控制
const
tooltipVisible
=
ref
(
false
)
const
mouseX
=
ref
(
0
)
const
mouseY
=
ref
(
0
)
const
currentDate
=
ref
(
''
)
const
currentDetailList
=
ref
([])
// // 鼠标移动,记录位置
const
handleMouseMove
=
(
e
)
=>
{
mouseX
.
value
=
e
.
clientX
+
20
mouseY
.
value
=
e
.
clientY
+
20
}
const
handleClick
=
(
e
)
=>
{
mouseX
.
value
=
e
.
clientX
-
160
mouseY
.
value
=
e
.
clientY
+
50
}
// 计算展示的月份 获取今天在内的之后的三个月的月份
const
startDate
=
dayjs
();
console
.
log
(
'startDate'
,
startDate
);
const
months
=
[
0
,
1
,
2
].
map
(
offset
=>
startDate
.
add
(
offset
,
'month'
));
// 生成日历数据
function
buildDataMap
(
arr
)
{
const
map
=
new
Map
();
const
stats
=
months
.
map
(()
=>
({
total
:
0
,
resolved
:
0
}
));
// 按日期聚合
arr
.
forEach
(
item
=>
{
const
date
=
item
.
endDate
;
if
(
!
map
.
has
(
date
))
{
map
.
set
(
date
,
{
date
,
count
:
0
,
resolved
:
0
,
logos
:
[],
status
:
'empty'
,
raw
:
[],
}
);
}
const
d
=
map
.
get
(
date
);
d
.
count
+=
1
;
if
(
item
.
status
===
2
)
d
.
resolved
+=
1
;
if
(
d
.
logos
.
length
<
3
&&
item
.
orgLogoUrl
)
d
.
logos
.
push
(
item
.
orgLogoUrl
);
d
.
status
=
'has_events'
;
d
.
raw
.
push
(
item
);
}
);
// 统计每月
months
.
forEach
((
month
,
idx
)
=>
{
const
daysInMonth
=
month
.
daysInMonth
();
for
(
let
i
=
1
;
i
<=
daysInMonth
;
i
++
)
{
const
dateStr
=
month
.
date
(
i
).
format
(
'YYYY-MM-DD'
);
const
d
=
map
.
get
(
dateStr
);
if
(
d
)
{
stats
[
idx
].
total
+=
d
.
count
;
stats
[
idx
].
resolved
+=
d
.
resolved
;
}
else
{
map
.
set
(
dateStr
,
{
date
:
dateStr
,
count
:
0
,
resolved
:
0
,
logos
:
[],
status
:
'empty'
,
raw
:
[],
}
);
}
}
}
);
return
{
dataMap
:
map
,
monthStats
:
stats
}
;
}
console
.
log
(
'timelineData'
,
props
.
timelineData
);
const
{
dataMap
,
monthStats
}
=
buildDataMap
(
props
.
timelineData
);
function
getOption
()
{
const
calendarWidthPercent
=
30
;
const
gapPercent
=
(
95
-
(
calendarWidthPercent
*
3
))
/
4
;
const
calendars
=
months
.
map
((
month
,
index
)
=>
({
top
:
40
,
left
:
`${gapPercent + index * (calendarWidthPercent + gapPercent)
}
%`
,
width
:
`${calendarWidthPercent
}
%`
,
range
:
month
.
format
(
'YYYY-MM'
),
cellSize
:
[
'auto'
,
82
],
splitLine
:
{
show
:
true
,
lineStyle
:
{
color
:
'#fff'
,
width
:
4
}
}
,
itemStyle
:
{
color
:
'#f0f9ff'
,
borderColor
:
'#fff'
,
borderWidth
:
4
}
,
yearLabel
:
{
show
:
false
}
,
monthLabel
:
{
show
:
false
}
,
dayLabel
:
{
show
:
false
}
,
}
));
const
titles
=
months
.
map
((
month
,
index
)
=>
({
text
:
`{month|${month.format('M月')
}}
{stats|共 ${monthStats[index].total
}
项, 已落实 ${monthStats[index].resolved
}
项
}
`
,
left
:
`${gapPercent + index * (calendarWidthPercent + gapPercent)
}
%`
,
top
:
10
,
textStyle
:
{
rich
:
{
month
:
{
fontSize
:
18
,
fontWeight
:
'bold'
,
color
:
'rgb(5, 95, 194)'
,
fontFamily
:
'Source Han Sans CN'
}
,
stats
:
{
fontSize
:
18
,
color
:
'rgb(5, 95, 194)'
,
fontWeight
:
'bold'
,
fontFamily
:
'Source Han Sans CN'
}
}
}
}
));
const
series
=
months
.
map
((
month
,
index
)
=>
{
const
monthData
=
[];
const
daysInMonth
=
month
.
daysInMonth
();
for
(
let
i
=
1
;
i
<=
daysInMonth
;
i
++
)
{
const
dateStr
=
month
.
date
(
i
).
format
(
'YYYY-MM-DD'
);
const
item
=
dataMap
.
get
(
dateStr
);
monthData
.
push
([
dateStr
,
item
]);
}
// console.log('monthData', monthData);
return
{
type
:
'custom'
,
coordinateSystem
:
'calendar'
,
calendarIndex
:
index
,
data
:
monthData
,
renderItem
:
(
params
,
api
)
=>
{
const
cellPoint
=
api
.
coord
([
api
.
value
(
0
),
0
]);
const
cellWidth
=
params
.
coordSys
.
cellWidth
;
const
cellHeight
=
params
.
coordSys
.
cellHeight
;
const
dataIndex
=
params
.
dataIndex
;
const
rawDataItem
=
monthData
[
dataIndex
];
const
item
=
rawDataItem
[
1
];
if
(
!
item
)
return
;
const
x
=
cellPoint
[
0
]
-
cellWidth
/
2
;
const
y
=
cellPoint
[
1
]
-
cellHeight
/
2
;
const
groupChildren
=
[];
const
bgColor
=
item
.
status
===
'has_events'
?
'#bfdbfe'
:
'#f0f9ff'
;
groupChildren
.
push
({
type
:
'rect'
,
shape
:
{
x
,
y
,
width
:
cellWidth
,
height
:
cellHeight
}
,
style
:
{
fill
:
bgColor
,
stroke
:
'#fff'
,
lineWidth
:
1
}
,
}
);
if
(
item
.
status
===
'has_events'
)
{
const
iconSize
=
20
;
const
iconGap
=
-
5
;
const
maxIcons
=
3
;
const
displayLogos
=
item
.
logos
.
slice
(
0
,
maxIcons
);
const
iconsY
=
y
+
8
;
const
iconsX
=
x
+
8
;
displayLogos
.
forEach
((
logo
,
idx
)
=>
{
groupChildren
.
push
({
type
:
'image'
,
style
:
{
image
:
logo
,
x
:
iconsX
+
idx
*
(
iconSize
+
iconGap
),
y
:
iconsY
,
width
:
iconSize
,
height
:
iconSize
,
}
,
}
);
}
);
groupChildren
.
push
({
type
:
'text'
,
style
:
{
text
:
`${item.count
}
项`
,
x
:
x
+
8
,
y
:
y
+
cellHeight
-
12
,
textAlign
:
'left'
,
textVerticalAlign
:
'bottom'
,
fontSize
:
18
,
fontFamily
:
'Source Han Sans CN'
// fontWeight: 'bold',
}
,
}
);
}
else
{
const
d
=
dayjs
(
item
.
date
);
groupChildren
.
push
({
type
:
'text'
,
style
:
{
text
:
d
.
format
(
'YYYY年'
),
x
:
x
+
cellWidth
/
2
,
y
:
y
+
cellHeight
/
2
-
8
,
textAlign
:
'center'
,
textVerticalAlign
:
'bottom'
,
fontSize
:
10
,
// fill: '#93c5fd',
fill
:
'rgb(185, 220, 255)'
,
fontFamily
:
'Source Han Sans CN'
}
,
}
);
groupChildren
.
push
({
type
:
'text'
,
style
:
{
text
:
d
.
format
(
'MM月DD日'
),
x
:
x
+
cellWidth
/
2
,
y
:
y
+
cellHeight
/
2
+
4
,
textAlign
:
'center'
,
textVerticalAlign
:
'top'
,
fontSize
:
12
,
// fontWeight: 'bold',
fill
:
'#rgb(185, 220, 255)'
,
fontFamily
:
'Source Han Sans CN'
}
,
}
);
}
return
{
type
:
'group'
,
children
:
groupChildren
,
}
;
}
,
}
;
}
);
// const visualMap =
{
// min: 0, // 数据最小值
// max: 10, // 数据最大值,根据你的实际数据范围调整
// calculable: true, // 是否显示拖拽手柄
// orient: 'horizontal', // 图例方向
// left: 'center', // 图例位置
// inRange:
{
// // 颜色数组:从左(浅)到右(深)代表数值从小到大
// color: ['rgb(231, 243, 255)', 'rgb(137, 193, 255)'] // 示例:从白色到深蓝色
//
}
//
}
return
{
tooltip
:
{
show
:
false
}
,
title
:
titles
,
calendar
:
calendars
,
// visualMap: visualMap,
series
:
series
,
}
;
}
onMounted
(()
=>
{
if
(
chartRef
.
value
)
{
chartInstance
=
echarts
.
init
(
chartRef
.
value
,
undefined
,
{
renderer
:
'canvas'
}
);
chartInstance
.
setOption
(
getOption
());
window
.
addEventListener
(
'resize'
,
resizeChart
);
chartInstance
.
on
(
'click'
,
(
params
)
=>
{
console
.
log
(
'params'
,
params
);
if
(
Array
.
isArray
(
params
.
data
)
&&
params
.
data
.
length
>=
2
)
{
const
date
=
params
.
data
[
0
]
// const list = dataMap.get(date)?.raw || []
const
list
=
params
.
data
[
1
].
raw
if
(
list
.
length
>
0
)
{
currentDate
.
value
=
date
currentDetailList
.
value
=
list
tooltipVisible
.
value
=
true
}
else
{
tooltipVisible
.
value
=
false
}
}
}
);
// chartInstance.on('mouseout', () =>
{
// tooltipVisible.value = false
//
}
);
}
}
);
function
resizeChart
()
{
if
(
chartInstance
)
{
chartInstance
.
resize
();
}
}
onBeforeUnmount
(()
=>
{
window
.
removeEventListener
(
'resize'
,
resizeChart
);
if
(
chartInstance
)
{
chartInstance
.
dispose
();
chartInstance
=
null
;
}
}
);
<
/script
>
<
style
scoped
>
.
custom
-
tooltip
{
position
:
absolute
;
/* 使用 fixed 相对于视口定位 */
/* pointer-events: none; */
/* 让鼠标事件穿透到图表,避免闪烁 */
z
-
index
:
1000
;
width
:
670
px
;
background
:
rgb
(
255
,
255
,
255
);
}
.
tooltip
-
header
{
height
:
50
px
;
box
-
sizing
:
border
-
box
;
padding
:
13
px
24
px
;
justify
-
content
:
space
-
between
;
border
-
bottom
:
1
px
solid
rgb
(
234
,
236
,
238
);
}
.
tooltip
-
main
{
padding
:
0
24
px
10
px
;
}
.
tooltip
-
main
-
item
{
width
:
622
px
;
height
:
144
px
;
border
-
bottom
:
1
px
solid
rgb
(
234
,
236
,
238
);
}
.
item
-
header
{
height
:
46
px
;
justify
-
content
:
space
-
between
;
align
-
items
:
center
;
}
.
item
-
header
-
left
{
gap
:
8
px
;
align
-
items
:
center
;
}
.
logo
{
width
:
24
px
;
height
:
24
px
;
}
.
status
-
on
{
height
:
23
px
;
padding
:
0
8
px
;
color
:
rgb
(
33
,
129
,
57
);
background
:
rgba
(
33
,
129
,
57
,
0.1
);
}
.
status
-
off
{
height
:
23
px
;
padding
:
0
8
px
;
color
:
rgb
(
206
,
79
,
81
);
background
:
rgba
(
206
,
79
,
81
,
0.1
);
}
.
item
-
content
{
height
:
48
px
;
display
:
-
webkit
-
box
;
-
webkit
-
line
-
clamp
:
2
;
/* 限制显示2行 */
-
webkit
-
box
-
orient
:
vertical
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
word
-
break
:
break
-
word
;
/* 可选:防止单词被截断 */
}
.
item
-
header
-
right
{
gap
:
8
px
;
}
<
/style
>
src/views/ZMOverView/components/fourSuppress/components/allGovernment/components/CalendarHeatmap.vue
浏览文件 @
bb76d85f
<
template
>
<div
style=
"position: relative;"
>
<div
ref=
"chartRef"
style=
"height: 620px; width: 1640px"
@
mousemove=
"handleMouseMove"
></div>
<div
v-show=
"tooltipVisible"
class=
"custom-tooltip background-as-card"
:style=
"
{ left: mouseX + 'px', top: mouseY + 'px' }">
<div
class=
"tooltip-header flex-display"
>
<div
class=
"tooltip-header-left text-title-3-bold"
>
{{
currentDate
}}
</div>
<div
class=
"tooltip-header-right text-title-3-show"
>
{{
`${'3个部门'
}
/${'3项举措'
}
`
}}
<
/div
>
<div
ref=
"chartRef"
style=
"height: 620px; width: 1640px"
@
click=
"handleClick"
></div>
<div
v-show=
"tooltipVisible"
class=
"custom-tooltip background-as-card"
:style=
"
{ left: mouseX + 'px', top: mouseY + 'px', cursor: dragging ? 'move' : 'default' }"
@mousedown="startDrag"
>
<div
class=
"tooltip-header flex-display"
@
mousedown
.
stop=
"startDrag"
style=
"cursor: move;"
>
<div
class=
"tooltip-header-left text-title-3-bold"
>
{{
currentDate
}}
</div>
<div
class=
"tooltip-header-right text-title-3-show"
>
{{
`${'3个部门'
}
/${'3项举措'
}
`
}}
<
/div
>
<
/div
>
<
div
class
=
"tooltip-main"
>
<
div
class
=
"tooltip-main-item"
v
-
for
=
"item, index in currentDetailList"
:
key
=
"index"
>
<
div
class
=
"item-header flex-display"
>
<
div
class
=
"item-header-left flex-display"
>
<
div
class
=
"logo"
>
<
img
style
=
"width:100%; height: 100%"
:
src
=
"item.orgLogoUrl"
alt
=
"logo"
>
<
/div
>
<
div
class
=
"name text-bold"
>
{{
item
.
orgName
}}
<
/div
>
<
div
class
=
"status"
>
<
div
class
=
"status-on text-tip-2"
v
-
if
=
"item.stauts === 2"
>
{{
'已落实'
}}
<
/div
>
<
div
class
=
"status-off text-tip-2"
v
-
else
>
{{
'未落实'
}}
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"item-header-right flex-display"
>
<
AreaTag
v
-
for
=
"tag, idx in item.techDomainList.slice(0,3)"
:
key
=
"idx"
:
tagName
=
"tag"
><
/AreaTag
>
<
/div
>
<
div
class
=
"tooltip-main-item"
v
-
for
=
"item, index in currentDetailList"
:
key
=
"index"
>
<
div
class
=
"item-header flex-display"
>
<
div
class
=
"item-header-left flex-display"
>
<
div
class
=
"logo"
>
<
img
style
=
"width:100%; height: 100%"
:
src
=
"item.orgLogoUrl"
alt
=
"logo"
>
<
/div
>
<
div
class
=
"item-content text-compact"
>
{{
item
.
name
}}
<
/div
>
<
div
class
=
"item-footer"
><
/div
>
<
div
class
=
"name text-bold"
>
{{
item
.
orgName
}}
<
/div
>
<
div
class
=
"status"
>
<
div
class
=
"status-on text-tip-2"
v
-
if
=
"item.stauts === 2"
>
{{
'已落实'
}}
<
/div
>
<
div
class
=
"status-off text-tip-2"
v
-
else
>
{{
'未落实'
}}
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"item-header-right flex-display"
>
<
AreaTag
v
-
for
=
"tag, idx in item.techDomainList.slice(0, 3)"
:
key
=
"idx"
:
tagName
=
"tag"
><
/AreaTag
>
<
/div
>
<
/div
>
<
div
class
=
"item-content text-compact"
>
{{
item
.
name
}}
<
/div
>
<
div
class
=
"item-footer"
><
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/template
>
...
...
@@ -53,6 +60,32 @@ const props = defineProps(
}
);
const
dragging
=
ref
(
false
);
let
dragOffsetX
=
0
;
let
dragOffsetY
=
0
;
const
startDrag
=
(
e
)
=>
{
dragging
.
value
=
true
;
dragOffsetX
=
e
.
clientX
-
mouseX
.
value
;
dragOffsetY
=
e
.
clientY
-
mouseY
.
value
;
document
.
addEventListener
(
'mousemove'
,
onDrag
);
document
.
addEventListener
(
'mouseup'
,
stopDrag
);
}
const
onDrag
=
(
e
)
=>
{
if
(
dragging
.
value
)
{
mouseX
.
value
=
e
.
clientX
-
dragOffsetX
;
mouseY
.
value
=
e
.
clientY
-
dragOffsetY
;
}
}
const
stopDrag
=
()
=>
{
dragging
.
value
=
false
;
document
.
removeEventListener
(
'mousemove'
,
onDrag
);
document
.
removeEventListener
(
'mouseup'
,
stopDrag
);
}
echarts
.
use
([
CustomChart
,
...
...
@@ -72,10 +105,18 @@ const mouseY = ref(0)
const
currentDate
=
ref
(
''
)
const
currentDetailList
=
ref
([])
// 鼠标移动,记录位置
//
//
鼠标移动,记录位置
const
handleMouseMove
=
(
e
)
=>
{
mouseX
.
value
=
e
.
clientX
+
20
mouseY
.
value
=
e
.
clientY
+
20
mouseY
.
value
=
e
.
clientY
-
20
}
const
handleClick
=
(
e
)
=>
{
// mouseX.value = e.clientX - 160
// mouseY.value = e.clientY - 120
mouseX
.
value
=
e
.
clientX
+
10
mouseY
.
value
=
e
.
clientY
-
100
}
// 计算展示的月份 获取今天在内的之后的三个月的月份
...
...
@@ -141,12 +182,27 @@ console.log('timelineData', props.timelineData);
const
{
dataMap
,
monthStats
}
=
buildDataMap
(
props
.
timelineData
);
function
getOption
()
{
const
calendarWidthPercent
=
30
;
const
gapPercent
=
(
95
-
(
calendarWidthPercent
*
3
))
/
4
;
// 计算所有天的最大 count
let
maxCount
=
0
;
dataMap
.
forEach
(
item
=>
{
if
(
item
.
count
>
maxCount
)
maxCount
=
item
.
count
;
}
);
// 颜色插值函数
function
getColorByCount
(
count
)
{
// rgb(231,243,255) -> rgb(137,193,255)
const
start
=
[
231
,
243
,
255
];
const
end
=
[
137
,
193
,
255
];
if
(
maxCount
===
0
)
return
`rgb(${start.join(',')
}
)`
;
const
ratio
=
Math
.
min
(
count
/
maxCount
,
1
);
const
rgb
=
start
.
map
((
s
,
i
)
=>
Math
.
round
(
s
+
(
end
[
i
]
-
s
)
*
ratio
));
return
`rgb(${rgb.join(',')
}
)`
;
}
const
calendars
=
months
.
map
((
month
,
index
)
=>
({
top
:
40
,
left
:
`${gapPercent + index * (calendarWidthPercent + gapPercent)
}
%`
,
...
...
@@ -167,14 +223,16 @@ function getOption() {
textStyle
:
{
rich
:
{
month
:
{
fontSize
:
24
,
fontSize
:
18
,
fontWeight
:
'bold'
,
color
:
'#1e3a8a'
,
color
:
'rgb(5, 95, 194)'
,
fontFamily
:
'Source Han Sans CN'
}
,
stats
:
{
fontSize
:
1
4
,
color
:
'
#1e40af
'
,
fontSize
:
1
8
,
color
:
'
rgb(5, 95, 194)
'
,
fontWeight
:
'bold'
,
fontFamily
:
'Source Han Sans CN'
}
}
}
...
...
@@ -189,9 +247,6 @@ function getOption() {
monthData
.
push
([
dateStr
,
item
]);
}
// console.log('monthData', monthData);
return
{
type
:
'custom'
,
coordinateSystem
:
'calendar'
,
...
...
@@ -210,14 +265,17 @@ function getOption() {
const
y
=
cellPoint
[
1
]
-
cellHeight
/
2
;
const
groupChildren
=
[];
const
bgColor
=
item
.
status
===
'has_events'
?
'#bfdbfe'
:
'#f0f9ff'
;
// 动态颜色
const
bgColor
=
item
.
status
===
'has_events'
?
getColorByCount
(
item
.
count
)
:
'#f0f9ff'
;
groupChildren
.
push
({
type
:
'rect'
,
shape
:
{
x
,
y
,
width
:
cellWidth
,
height
:
cellHeight
}
,
style
:
{
fill
:
bgColor
,
stroke
:
'#
efefe
f'
,
stroke
:
'#
ff
f'
,
lineWidth
:
1
}
,
}
);
...
...
@@ -252,7 +310,7 @@ function getOption() {
textAlign
:
'left'
,
textVerticalAlign
:
'bottom'
,
fontSize
:
18
,
font
Weight
:
'bold'
,
font
Family
:
'Source Han Sans CN'
}
,
}
);
}
else
{
...
...
@@ -266,7 +324,8 @@ function getOption() {
textAlign
:
'center'
,
textVerticalAlign
:
'bottom'
,
fontSize
:
10
,
fill
:
'#93c5fd'
,
fill
:
'rgb(185, 220, 255)'
,
fontFamily
:
'Source Han Sans CN'
}
,
}
);
groupChildren
.
push
({
...
...
@@ -278,8 +337,8 @@ function getOption() {
textAlign
:
'center'
,
textVerticalAlign
:
'top'
,
fontSize
:
12
,
f
ontWeight
:
'bold
'
,
f
ill
:
'#93c5fd'
,
f
ill
:
'rgb(185, 220, 255)
'
,
f
ontFamily
:
'Source Han Sans CN'
}
,
}
);
}
...
...
@@ -292,7 +351,6 @@ function getOption() {
}
;
}
);
return
{
tooltip
:
{
show
:
false
}
,
title
:
titles
,
...
...
@@ -307,7 +365,7 @@ onMounted(() => {
chartInstance
.
setOption
(
getOption
());
window
.
addEventListener
(
'resize'
,
resizeChart
);
chartInstance
.
on
(
'
mouseover
'
,
(
params
)
=>
{
chartInstance
.
on
(
'
click
'
,
(
params
)
=>
{
console
.
log
(
'params'
,
params
);
if
(
Array
.
isArray
(
params
.
data
)
&&
params
.
data
.
length
>=
2
)
{
...
...
@@ -318,13 +376,15 @@ onMounted(() => {
currentDate
.
value
=
date
currentDetailList
.
value
=
list
tooltipVisible
.
value
=
true
}
else
{
tooltipVisible
.
value
=
false
}
}
}
);
chartInstance
.
on
(
'mouseout'
,
()
=>
{
tooltipVisible
.
value
=
false
}
);
//
chartInstance.on('mouseout', () =>
{
//
tooltipVisible.value = false
//
}
);
}
}
);
...
...
@@ -347,11 +407,12 @@ onBeforeUnmount(() => {
.
custom
-
tooltip
{
position
:
fixed
;
/* 使用 fixed 相对于视口定位 */
pointer
-
events
:
none
;
/* pointer-events: none; */
/* 让鼠标事件穿透到图表,避免闪烁 */
z
-
index
:
1000
;
width
:
670
px
;
background
:
rgb
(
255
,
255
,
255
);
}
.
tooltip
-
header
{
...
...
@@ -404,16 +465,19 @@ onBeforeUnmount(() => {
background
:
rgba
(
206
,
79
,
81
,
0.1
);
}
.
item
-
content
{
.
item
-
content
{
height
:
48
px
;
display
:
-
webkit
-
box
;
-
webkit
-
line
-
clamp
:
2
;
/* 限制显示2行 */
-
webkit
-
line
-
clamp
:
2
;
/* 限制显示2行 */
-
webkit
-
box
-
orient
:
vertical
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
word
-
break
:
break
-
word
;
/* 可选:防止单词被截断 */
word
-
break
:
break
-
word
;
/* 可选:防止单词被截断 */
}
.
item
-
header
-
right
{
.
item
-
header
-
right
{
gap
:
8
px
;
}
<
/style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论