15 changed files with 1489 additions and 688 deletions
-
BINsrc/assets/images/page4_03-b.png
-
BINsrc/assets/images/pageOne-1-b.png
-
BINsrc/assets/images/pageOne-2-b.png
-
4src/assets/json/lib.json
-
13src/assets/styles/font-some.css
-
220src/assets/styles/index.scss
-
473src/components/echart/todayCircle.vue
-
491src/components/echart/yearCircle.vue
-
2src/main.js
-
14src/views/index.vue
-
536src/views/map/index.vue
-
172src/views/pageFive/index.vue
-
133src/views/pageFour/index.vue
-
3src/views/pageOne/index.vue
-
116src/views/pageThree/index.vue
|
After Width: 1835 | Height: 1201 | Size: 69 KiB |
|
After Width: 267 | Height: 128 | Size: 25 KiB |
|
After Width: 267 | Height: 128 | Size: 28 KiB |
@ -1,4 +1,4 @@ |
|||
{ |
|||
"大湾城市书房":[114.664064,30.478882], |
|||
"张家湾城市书房":[114.635376,30.532215] |
|||
"葛店城市书房·大湾分馆":[114.664064,30.478882], |
|||
"葛店城市书房·张家湾分馆":[114.635376,30.532215] |
|||
} |
|||
@ -1,274 +1,311 @@ |
|||
<template> |
|||
<div style="height: calc(100% - 200px); display: flex; align-items: center; justify-content: flex-start;"> |
|||
<div id="todayType" style="width:400px; height: 230px" /> |
|||
<!-- 1. 样式抽离到class,提升可读性和维护性 --> |
|||
<div class="chart-container"> |
|||
<div ref="todayTypeRef" class="today-type-chart" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import centerImg from '@/assets/images/circle-bg.png' |
|||
|
|||
export default { |
|||
name: 'TodayTypePieChart', // 3. 增加组件名,便于调试和复用 |
|||
props: { |
|||
todayAllNum: { |
|||
type: Object, |
|||
require: true, |
|||
default: function() { |
|||
return {} |
|||
} |
|||
required: true, // 4. 修正拼写错误 require -> required |
|||
default: () => ({}) // 5. 简化默认值写法 |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
myChart: null, |
|||
initDebounceTimer: null |
|||
} |
|||
}, |
|||
watch: { |
|||
'todayAllNum': { |
|||
todayAllNum: { |
|||
handler(val) { |
|||
setTimeout(() => { |
|||
this.initTodayCircle() |
|||
}, 100) |
|||
if (!val) return |
|||
|
|||
clearTimeout(this.initDebounceTimer) |
|||
this.initDebounceTimer = setTimeout(() => { |
|||
this.$nextTick(() => { |
|||
this.initTodayCircle() |
|||
}) |
|||
}, 300) |
|||
}, |
|||
immediate: true, |
|||
deep: true |
|||
} |
|||
}, |
|||
created() { |
|||
}, |
|||
beforeDestroy() { |
|||
}, |
|||
mounted() { |
|||
this.initTodayCircle() |
|||
}, |
|||
beforeDestroy() { |
|||
this.destroyChart() |
|||
}, |
|||
methods: { |
|||
/** |
|||
* 9. 销毁图表实例和定时器(抽离通用逻辑) |
|||
*/ |
|||
destroyChart() { |
|||
clearTimeout(this.initDebounceTimer) |
|||
if (this.myChart) { |
|||
this.myChart.dispose() |
|||
this.myChart = null |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 10. 计算数组value总和(抽离为独立方法,提升可读性) |
|||
* @param {Array} arr - 数据数组 |
|||
* @returns {Number} 总和 |
|||
*/ |
|||
calculateTotal(arr) { |
|||
if (!Array.isArray(arr) || arr.length === 0) return 0 |
|||
return arr.reduce((total, item) => total + (item.value || 0), 0) |
|||
}, |
|||
|
|||
/** |
|||
* 11. 构建图例格式化文本(抽离独立方法) |
|||
* @param {String} name - 图例名称 |
|||
* @param {Array} data - 图表数据 |
|||
* @returns {Array|String} 格式化后的文本 |
|||
*/ |
|||
formatLegendName(name, data) { |
|||
const total = this.calculateTotal(data) |
|||
const targetItem = data.find(item => item.name === name) |
|||
|
|||
if (!targetItem) return name |
|||
|
|||
const percentage = total > 0 ? `${((targetItem.value / total) * 100).toFixed(0)}%` : '0%' |
|||
return [`{name|${name}}`, `{num|${percentage}}`] |
|||
}, |
|||
|
|||
/** |
|||
* 初始化今日类型饼图 |
|||
*/ |
|||
initTodayCircle() { |
|||
const optionData = [ |
|||
// 12. 使用ref替代getElementById,更符合Vue规范 |
|||
const chartDom = this.$refs.todayTypeRef |
|||
if (!chartDom) { |
|||
console.warn('图表容器未找到') |
|||
return |
|||
} |
|||
|
|||
// 13. 数据处理抽离,提升代码可读性 |
|||
const chartData = [ |
|||
{ value: this.todayAllNum.headerLib || 0, name: '大湾' }, |
|||
{ value: this.todayAllNum.branchLib || 0, name: '张家湾' } |
|||
] |
|||
const myChart = this.$echarts.init(document.getElementById('todayType')) |
|||
|
|||
function arrCount(arr) { |
|||
let count = 0 |
|||
arr.forEach(item => { |
|||
count = count + item.value |
|||
}) |
|||
return count |
|||
// 14. 销毁旧实例,避免内存泄漏 |
|||
if (this.myChart) { |
|||
this.myChart.dispose() |
|||
} |
|||
var centerImg = require('@/assets/images/circle-bg.png') |
|||
const option = { |
|||
baseOption: { |
|||
tooltip: { |
|||
show: false, |
|||
trigger: 'item', |
|||
position: 'bottom', |
|||
textStyle: { |
|||
color: '#EEF6FF', |
|||
fontSize: '18' |
|||
} |
|||
// backgroundColor: 'rgba(74, 144, 226, 0.84)', |
|||
// formatter: (params) => { |
|||
// return `<div>${params.seriesName} <br> ${params.data.name}:${this.$parent.formatter(params.data.value)} (${params.percent}%)</div>` |
|||
// } |
|||
}, |
|||
legend: { |
|||
orient: 'vertical', |
|||
right: 40, |
|||
top: 55, |
|||
// textStyle: { |
|||
// color: '#EEF6FF', |
|||
// padding: [20, 0, 18, 4], |
|||
// fontSize: '14' |
|||
// }, |
|||
itemWidth: 10, |
|||
itemHeight: 10, |
|||
icon: 'circle', |
|||
selectedMode: false, |
|||
data: ['大湾', '张家湾'], |
|||
formatter: (name) => { |
|||
// `${name} ${((flag.value / count).toFixed(2)) * 100 + '%'}` |
|||
const count = arrCount(optionData) |
|||
if (optionData) { |
|||
const flag = optionData?.find(item => name === item.name) |
|||
if (flag) { |
|||
const percentage = count > 0 ? ((flag.value / count) * 100).toFixed(0) + '%' : '0%' |
|||
return [`{name|${name}}`, `{num|${percentage}}`] |
|||
} |
|||
} |
|||
return name |
|||
}, |
|||
textStyle: { |
|||
rich: { |
|||
name: { |
|||
fontSize: 18, |
|||
color: '#EEF6FF', |
|||
padding: [20, 0, 20, 4], |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
}, |
|||
num: { |
|||
fontSize: 20, |
|||
fontWeight: 600, |
|||
padding: [20, 0, 20, 15], |
|||
color: '#4C90FF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
|
|||
// 初始化图表 |
|||
this.myChart = this.$echarts.init(chartDom) |
|||
|
|||
// 15. 抽离option配置,拆分基础配置和媒体查询配置,提升可维护性 |
|||
const baseOption = { |
|||
tooltip: { |
|||
show: false, |
|||
trigger: 'item', |
|||
position: 'bottom', |
|||
textStyle: { |
|||
color: '#EEF6FF', |
|||
fontSize: 18 |
|||
} |
|||
}, |
|||
legend: { |
|||
orient: 'vertical', |
|||
right: 40, |
|||
top: 55, |
|||
itemWidth: 10, |
|||
itemHeight: 10, |
|||
icon: 'circle', |
|||
selectedMode: false, |
|||
data: ['大湾', '张家湾'], |
|||
formatter: (name) => this.formatLegendName(name, chartData), |
|||
textStyle: { |
|||
rich: { |
|||
name: { |
|||
fontSize: 18, |
|||
color: '#EEF6FF', |
|||
padding: [20, 0, 20, 4], |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
}, |
|||
num: { |
|||
fontSize: 24, |
|||
fontWeight: 600, |
|||
padding: [20, 0, 20, 15], |
|||
color: '#4C90FF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
} |
|||
}, |
|||
// 中心图片配置(关键代码) |
|||
graphic: [ |
|||
{ |
|||
type: 'image', |
|||
id: 'logo', |
|||
left: '8.5%', // 调整图片位置 |
|||
top: '22%', // 调整图片位置 |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, // 旋转 |
|||
origin: [64.5, 32.5], // 中心点 |
|||
scale: [1.0, 1.0], // 缩放 |
|||
// 设置图片样式 |
|||
style: { |
|||
image: centerImg, |
|||
width: 132, |
|||
height: 131, |
|||
opacity: 1 |
|||
} |
|||
} |
|||
}, |
|||
graphic: [ |
|||
{ |
|||
type: 'image', |
|||
id: 'logo', |
|||
left: '8.5%', |
|||
top: '22%', |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, |
|||
origin: [64.5, 32.5], |
|||
scale: [1.0, 1.0], |
|||
style: { |
|||
image: centerImg, |
|||
width: 132, |
|||
height: 131, |
|||
opacity: 1 |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
name: '今日累计借阅', |
|||
type: 'pie', |
|||
left: '-50%', |
|||
radius: ['60%', '70%'], |
|||
avoidLabelOverlap: false, |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
name: '今日累计借阅', |
|||
type: 'pie', |
|||
left: '-50%', |
|||
radius: ['60%', '70%'], |
|||
avoidLabelOverlap: false, |
|||
label: { |
|||
show: false, |
|||
position: 'center' |
|||
}, |
|||
labelLine: { |
|||
show: true |
|||
}, |
|||
itemStyle: { |
|||
borderWidth: 2, |
|||
borderColor: 'rgba(16,16,21,0.4)' |
|||
}, |
|||
emphasis: { |
|||
label: { |
|||
show: false, |
|||
position: 'center' |
|||
}, |
|||
labelLine: { |
|||
show: true |
|||
}, |
|||
itemStyle: { |
|||
borderWidth: 2, |
|||
borderColor: 'rgba(16,16,21,0.4)' |
|||
}, |
|||
emphasis: { |
|||
label: { |
|||
show: true, |
|||
// 自定义文字显示,函数默认params接受当前指向所有属性 |
|||
formatter: function(params) { |
|||
const { value, name } = params |
|||
return [ |
|||
`{c| ${value}}`, |
|||
`{b| ${name}}` |
|||
].join('\n') // 换行 |
|||
show: true, |
|||
formatter: ({ value, name }) => [ // 16. 解构赋值简化代码 |
|||
`{c| ${value}}`, |
|||
`{b| ${name}}` |
|||
].join('\n'), |
|||
rich: { |
|||
c: { |
|||
fontSize: 24, |
|||
fontWeight: 600, |
|||
color: '#317FFF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular', |
|||
lineHeight: 34 |
|||
}, |
|||
rich: { |
|||
c: { |
|||
fontSize: 24, |
|||
fontWeight: 600, |
|||
color: '#317FFF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular', |
|||
lineHeight: 34 |
|||
}, |
|||
b: { |
|||
fontSize: 18, |
|||
color: '#fff', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
b: { |
|||
fontSize: 18, |
|||
color: '#fff', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
} |
|||
}, |
|||
color: ['#317FFF', '#31DFFF'], |
|||
data: optionData |
|||
} |
|||
] |
|||
}, |
|||
media: [ |
|||
{ |
|||
query: { |
|||
maxWidth: 317 |
|||
} |
|||
}, |
|||
option: { |
|||
legend: { |
|||
right: 30, |
|||
top: 'center', |
|||
textStyle: { |
|||
rich: { |
|||
name: { |
|||
fontSize: 14 |
|||
}, |
|||
num: { |
|||
fontSize: 16 |
|||
} |
|||
} |
|||
color: ['#FFD14F', '#317FFF'], |
|||
data: chartData |
|||
} |
|||
] |
|||
} |
|||
|
|||
const mediaOption = [ |
|||
{ |
|||
query: { maxWidth: 317 }, |
|||
option: { |
|||
legend: { |
|||
right: 30, |
|||
top: 'center', |
|||
textStyle: { |
|||
rich: { |
|||
name: { fontSize: 14 }, |
|||
num: { fontSize: 16 } |
|||
} |
|||
}, |
|||
// 中心图片配置(关键代码) |
|||
graphic: [ |
|||
{ |
|||
left: '8%', // 调整图片位置 |
|||
top: '26%', // 调整图片位置 |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, // 旋转 |
|||
origin: [64.5, 32.5], // 中心点 |
|||
scale: [1.0, 1.0], // 缩放 |
|||
// 设置图片样式 |
|||
style: { |
|||
image: centerImg, |
|||
width: 110, |
|||
height: 110, |
|||
opacity: 1 |
|||
} |
|||
} |
|||
}, |
|||
graphic: [ |
|||
{ |
|||
left: '8%', |
|||
top: '26%', |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, |
|||
origin: [64.5, 32.5], |
|||
scale: [1.0, 1.0], |
|||
style: { |
|||
image: centerImg, |
|||
width: 110, |
|||
height: 110, |
|||
opacity: 1 |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
type: 'pie', |
|||
radius: ['50%', '55%'], |
|||
emphasis: { |
|||
label: { |
|||
rich: { |
|||
c: { |
|||
fontSize: 22, |
|||
lineHeight: 28 |
|||
}, |
|||
b: { |
|||
fontSize: 16 |
|||
} |
|||
} |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
type: 'pie', |
|||
radius: ['50%', '55%'], |
|||
emphasis: { |
|||
label: { |
|||
rich: { |
|||
c: { fontSize: 22, lineHeight: 28 }, |
|||
b: { fontSize: 16 } |
|||
} |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
myChart.setOption(option) |
|||
// // 然后可以通过定时器来旋转背景图 |
|||
// var step = 0 |
|||
// setInterval(function() { |
|||
// // 每秒旋转1度 |
|||
// myChart.setOption({ |
|||
// graphic: { |
|||
// id: 'logo', |
|||
// style: { |
|||
// transform: 'rotate(' + (step++ % 360) + 'deg)' // 持续旋转 |
|||
// } |
|||
// } |
|||
// }) |
|||
// }, 1000) |
|||
} |
|||
] |
|||
|
|||
// 合并配置并设置 |
|||
const option = { baseOption, media: mediaOption } |
|||
this.myChart.setOption(option) |
|||
|
|||
// 自动轮播tooltip |
|||
this.$LoopShowTooltip(this.myChart, baseOption, { loopSeries: true, interval: 4000 }) |
|||
|
|||
this.$LoopShowTooltip(myChart, option.baseOption, { loopSeries: true, interval: 4000 }) |
|||
// 17. 监听窗口大小变化,自适应图表 |
|||
window.addEventListener('resize', this.handleResize) |
|||
}, |
|||
|
|||
/** |
|||
* 18. 窗口大小变化时重绘图表 |
|||
*/ |
|||
handleResize() { |
|||
if (this.myChart) { |
|||
this.myChart.resize() |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// 19. 移除无用的created钩子 |
|||
beforeUnmount() { |
|||
// 20. 移除resize监听,避免内存泄漏 |
|||
window.removeEventListener('resize', this.handleResize) |
|||
this.destroyChart() |
|||
} |
|||
} |
|||
|
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
<style lang="scss" scoped> // 21. 添加scoped,避免样式污染 |
|||
@import "~@/assets/styles/index.scss"; |
|||
@import "~@/assets/styles/font-some.css"; |
|||
|
|||
// 22. 样式抽离,便于维护和修改 |
|||
.chart-container { |
|||
height: calc(100% - 200px); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
|
|||
.today-type-chart { |
|||
width: 400px; |
|||
height: 230px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,289 +1,312 @@ |
|||
<template> |
|||
<div style="height: calc(100% - 200px); display: flex; align-items: center; justify-content: flex-start;"> |
|||
<div id="modelType" style="width:400px; height: 230px" /> |
|||
<!-- 1. 内联样式抽离为class,提升可读性和维护性 --> |
|||
<div class="year-chart-container"> |
|||
<!-- 2. 使用ref替代getElementById,符合Vue规范 --> |
|||
<div ref="modelTypeRef" class="model-type-chart" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
// 3. 图片引入改为ES6 import规范,替代require |
|||
import centerImg from '@/assets/images/circle-bg.png' |
|||
|
|||
export default { |
|||
name: 'YearTypePieChart', // 4. 增加组件名,便于调试和复用 |
|||
props: { |
|||
yearAllNum: { |
|||
type: Object, |
|||
require: true, |
|||
default: function() { |
|||
return {} |
|||
} |
|||
required: true, // 5. 修正拼写错误 require -> required |
|||
default: () => ({}) // 6. 简化默认值写法 |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
myChart: null, // 7. 存储图表实例,便于销毁和重绘 |
|||
resizeTimer: null // 8. 防抖定时器,优化resize性能 |
|||
} |
|||
}, |
|||
watch: { |
|||
'yearAllNum': { |
|||
yearAllNum: { |
|||
handler(val) { |
|||
setTimeout(() => { |
|||
this.initYearCircle() |
|||
// 9. 空值保护:值为空时直接返回,避免无效执行 |
|||
if (!val) return |
|||
|
|||
// 10. 防抖处理,避免频繁触发图表初始化 |
|||
clearTimeout(this.initDebounceTimer) |
|||
this.initDebounceTimer = setTimeout(() => { |
|||
this.$nextTick(() => { |
|||
this.initYearCircle() |
|||
}) |
|||
}, 100) |
|||
}, |
|||
immediate: true, |
|||
deep: true |
|||
} |
|||
}, |
|||
created() { |
|||
}, |
|||
beforeDestroy() { |
|||
}, |
|||
mounted() { |
|||
// 11. 初始化图表 |
|||
this.initYearCircle() |
|||
// 12. 监听窗口大小变化,实现图表自适应 |
|||
window.addEventListener('resize', this.handleResize) |
|||
}, |
|||
beforeUnmount() { |
|||
// 13. 组件销毁时清理资源,避免内存泄漏 |
|||
window.removeEventListener('resize', this.handleResize) |
|||
this.destroyChart() |
|||
clearTimeout(this.initDebounceTimer) |
|||
}, |
|||
methods: { |
|||
/** |
|||
* 14. 销毁图表实例(抽离通用逻辑) |
|||
*/ |
|||
destroyChart() { |
|||
if (this.myChart) { |
|||
this.myChart.dispose() |
|||
this.myChart = null |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 15. 计算数组value总和(抽离独立方法,提升可读性) |
|||
* @param {Array} arr - 数据数组 |
|||
* @returns {Number} 总和 |
|||
*/ |
|||
calculateTotal(arr) { |
|||
if (!Array.isArray(arr) || arr.length === 0) return 0 |
|||
return arr.reduce((total, item) => total + (item.value || 0), 0) |
|||
}, |
|||
|
|||
/** |
|||
* 16. 构建图例格式化文本(抽离独立方法) |
|||
* @param {String} name - 图例名称 |
|||
* @param {Array} data - 图表数据 |
|||
* @returns {Array|String} 格式化后的文本 |
|||
*/ |
|||
formatLegendName(name, data) { |
|||
const total = this.calculateTotal(data) |
|||
const targetItem = data.find(item => item.name === name) |
|||
|
|||
if (!targetItem) return name |
|||
|
|||
const percentage = total > 0 ? `${((targetItem.value / total) * 100).toFixed(0)}%` : '0%' |
|||
return [`{name|${name}}`, `{num|${percentage}}`] |
|||
}, |
|||
|
|||
/** |
|||
* 初始化本年类型饼图 |
|||
*/ |
|||
initYearCircle() { |
|||
const optionData = [ |
|||
// 17. 获取图表容器DOM,增加判空保护 |
|||
const chartDom = this.$refs.modelTypeRef |
|||
if (!chartDom) { |
|||
console.warn('图表容器未找到,初始化失败') |
|||
return |
|||
} |
|||
|
|||
// 18. 数据处理抽离,提升代码可读性 |
|||
const chartData = [ |
|||
{ value: this.yearAllNum.headerLib || 0, name: '大湾' }, |
|||
{ value: this.yearAllNum.branchLib || 0, name: '张家湾' } |
|||
] |
|||
const myChart = this.$echarts.init(document.getElementById('modelType')) |
|||
|
|||
function arrCount(arr) { |
|||
let count = 0 |
|||
arr.forEach(item => { |
|||
count = count + item.value |
|||
}) |
|||
return count |
|||
} |
|||
var centerImg = require('@/assets/images/circle-bg.png') |
|||
const option = { |
|||
baseOption: { |
|||
tooltip: { |
|||
show: false, |
|||
trigger: 'item', |
|||
position: 'bottom', |
|||
textStyle: { |
|||
color: '#EEF6FF', |
|||
fontSize: '18' |
|||
} |
|||
// backgroundColor: 'rgba(74, 144, 226, 0.84)', |
|||
// formatter: (params) => { |
|||
// return `<div>${params.seriesName} <br> ${params.data.name}:${this.$parent.formatter(params.data.value)} (${params.percent}%)</div>` |
|||
// } |
|||
}, |
|||
legend: { |
|||
orient: 'vertical', |
|||
right: 40, |
|||
top: 55, |
|||
// textStyle: { |
|||
// color: '#EEF6FF', |
|||
// padding: [20, 0, 18, 4], |
|||
// fontSize: '14' |
|||
// }, |
|||
itemWidth: 10, |
|||
itemHeight: 10, |
|||
icon: 'circle', |
|||
selectedMode: false, |
|||
data: ['大湾', '张家湾'], |
|||
formatter: (name) => { |
|||
// `${name} ${((flag.value / count).toFixed(2)) * 100 + '%'}` |
|||
const count = arrCount(optionData) |
|||
if (optionData) { |
|||
const flag = optionData?.find(item => name === item.name) |
|||
if (flag) { |
|||
const percentage = count > 0 ? ((flag.value / count) * 100).toFixed(0) + '%' : '0%' |
|||
return [`{name|${name}}`, `{num|${percentage}}`] |
|||
} |
|||
} |
|||
return name |
|||
}, |
|||
textStyle: { |
|||
rich: { |
|||
name: { |
|||
fontSize: 18, |
|||
color: '#EEF6FF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular', |
|||
padding: [20, 0, 20, 4] |
|||
}, |
|||
num: { |
|||
fontSize: 20, |
|||
fontWeight: 600, |
|||
padding: [20, 0, 20, 15], |
|||
color: '#4C90FF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
} |
|||
} |
|||
// formatter: function(name) { |
|||
// let tarValue |
|||
// const count = arrCount(optionData) |
|||
// for (let i = 0; i < optionData.length; i++) { |
|||
// if (data[i].name === name) { |
|||
// tarValue = data[i].value |
|||
// } |
|||
// } |
|||
// 19. 先销毁旧实例,避免多实例叠加 |
|||
this.destroyChart() |
|||
|
|||
// 20. 初始化图表实例 |
|||
this.myChart = this.$echarts.init(chartDom) |
|||
|
|||
// return [`{name|${name}}`, `{num|${((tarValue / count).toFixed(2)) * 100 + '%'}}`].join('\n') |
|||
// } |
|||
}, |
|||
// 中心图片配置(关键代码) |
|||
graphic: [ |
|||
{ |
|||
type: 'image', |
|||
id: 'logo', |
|||
left: '8.5%', // 调整图片位置 |
|||
top: '22%', // 调整图片位置 |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, // 旋转 |
|||
origin: [64.5, 32.5], // 中心点 |
|||
scale: [1.0, 1.0], // 缩放 |
|||
// 设置图片样式 |
|||
style: { |
|||
image: centerImg, |
|||
width: 132, |
|||
height: 131, |
|||
opacity: 1 |
|||
// 21. 拆分option配置,降低函数复杂度 |
|||
const baseOption = { |
|||
tooltip: { |
|||
show: false, |
|||
trigger: 'item', |
|||
position: 'bottom', |
|||
textStyle: { |
|||
color: '#EEF6FF', |
|||
fontSize: 18 |
|||
} |
|||
}, |
|||
legend: { |
|||
orient: 'vertical', |
|||
right: 40, |
|||
top: 55, |
|||
itemWidth: 10, |
|||
itemHeight: 10, |
|||
icon: 'circle', |
|||
selectedMode: false, |
|||
data: ['大湾', '张家湾'], |
|||
formatter: (name) => this.formatLegendName(name, chartData), |
|||
textStyle: { |
|||
rich: { |
|||
name: { |
|||
fontSize: 18, |
|||
color: '#EEF6FF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular', |
|||
padding: [20, 0, 20, 4] |
|||
}, |
|||
num: { |
|||
fontSize: 24, |
|||
fontWeight: 600, |
|||
padding: [20, 0, 20, 15], |
|||
color: '#4C90FF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
name: '本年累计借阅', |
|||
type: 'pie', |
|||
left: '-50%', |
|||
radius: ['60%', '70%'], |
|||
avoidLabelOverlap: false, |
|||
} |
|||
}, |
|||
graphic: [ |
|||
{ |
|||
type: 'image', |
|||
id: 'logo', |
|||
left: '8.5%', |
|||
top: '22%', |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, |
|||
origin: [64.5, 32.5], |
|||
scale: [1.0, 1.0], |
|||
style: { |
|||
image: centerImg, |
|||
width: 132, |
|||
height: 131, |
|||
opacity: 1 |
|||
} |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
name: '本年累计借阅', |
|||
type: 'pie', |
|||
left: '-50%', |
|||
radius: ['60%', '70%'], |
|||
avoidLabelOverlap: false, |
|||
label: { |
|||
show: false, |
|||
position: 'center' |
|||
}, |
|||
labelLine: { |
|||
show: true |
|||
}, |
|||
itemStyle: { |
|||
borderWidth: 2, |
|||
borderColor: 'rgba(16,16,21,0.4)' |
|||
}, |
|||
emphasis: { |
|||
label: { |
|||
show: false, |
|||
position: 'center' |
|||
}, |
|||
labelLine: { |
|||
show: true |
|||
}, |
|||
itemStyle: { |
|||
borderWidth: 2, |
|||
borderColor: 'rgba(16,16,21,0.4)' |
|||
}, |
|||
emphasis: { |
|||
label: { |
|||
show: true, |
|||
// 自定义文字显示,函数默认params接受当前指向所有属性 |
|||
formatter: function(params) { |
|||
const { value, name } = params |
|||
return [ |
|||
`{c| ${value}}`, |
|||
`{b| ${name}}` |
|||
].join('\n') // 换行 |
|||
show: true, |
|||
// 22. 解构赋值简化代码 |
|||
formatter: ({ value, name }) => [ |
|||
`{c| ${value}}`, |
|||
`{b| ${name}}` |
|||
].join('\n'), |
|||
rich: { |
|||
c: { |
|||
fontSize: 24, |
|||
fontWeight: 600, |
|||
color: '#317FFF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular', |
|||
lineHeight: 34 |
|||
}, |
|||
rich: { |
|||
c: { |
|||
fontSize: 24, |
|||
fontWeight: 600, |
|||
color: '#317FFF', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular', |
|||
// color: { |
|||
// type: 'linear', |
|||
// x: 0, |
|||
// y: 0, |
|||
// x2: 0, |
|||
// y2: 1, |
|||
// colorStops: [ |
|||
// { |
|||
// offset: 0, |
|||
// color: 'red' // 0% 处的颜色 |
|||
// }, |
|||
// { |
|||
// offset: 1, |
|||
// color: 'yellow' // 100% 处的颜色 |
|||
// } |
|||
// ], |
|||
// globalCoord: false // 缺省为 false |
|||
// }, |
|||
lineHeight: 34 |
|||
}, |
|||
b: { |
|||
fontSize: 18, |
|||
color: '#fff', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
b: { |
|||
fontSize: 18, |
|||
color: '#fff', |
|||
fontFamily: 'DingTalk_JinBuTi_Regular' |
|||
} |
|||
} |
|||
}, |
|||
color: ['#317FFF', '#31DFFF'], |
|||
data: optionData |
|||
} |
|||
] |
|||
}, |
|||
media: [ |
|||
{ |
|||
query: { |
|||
maxWidth: 317 |
|||
} |
|||
}, |
|||
option: { |
|||
legend: { |
|||
right: 30, |
|||
top: 'center', |
|||
textStyle: { |
|||
rich: { |
|||
name: { |
|||
fontSize: 14 |
|||
}, |
|||
num: { |
|||
fontSize: 16 |
|||
} |
|||
} |
|||
color: ['#FFD14F', '#317FFF'], |
|||
data: chartData |
|||
} |
|||
] |
|||
} |
|||
|
|||
const mediaOption = [ |
|||
{ |
|||
query: { maxWidth: 317 }, |
|||
option: { |
|||
legend: { |
|||
right: 30, |
|||
top: 'center', |
|||
textStyle: { |
|||
rich: { |
|||
name: { fontSize: 14 }, |
|||
num: { fontSize: 16 } |
|||
} |
|||
}, |
|||
// 中心图片配置(关键代码) |
|||
graphic: [ |
|||
{ |
|||
left: '8%', // 调整图片位置 |
|||
top: '26%', // 调整图片位置 |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, // 旋转 |
|||
origin: [64.5, 32.5], // 中心点 |
|||
scale: [1.0, 1.0], // 缩放 |
|||
// 设置图片样式 |
|||
style: { |
|||
image: centerImg, |
|||
width: 110, |
|||
height: 110, |
|||
opacity: 1 |
|||
} |
|||
} |
|||
}, |
|||
graphic: [ |
|||
{ |
|||
left: '8%', |
|||
top: '26%', |
|||
z: -10, |
|||
bounding: 'raw', |
|||
rotation: 0, |
|||
origin: [64.5, 32.5], |
|||
scale: [1.0, 1.0], |
|||
style: { |
|||
image: centerImg, |
|||
width: 110, |
|||
height: 110, |
|||
opacity: 1 |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
type: 'pie', |
|||
radius: ['50%', '55%'], |
|||
emphasis: { |
|||
label: { |
|||
rich: { |
|||
c: { |
|||
fontSize: 22, |
|||
lineHeight: 28 |
|||
}, |
|||
b: { |
|||
fontSize: 16 |
|||
} |
|||
} |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
type: 'pie', |
|||
radius: ['50%', '55%'], |
|||
emphasis: { |
|||
label: { |
|||
rich: { |
|||
c: { fontSize: 22, lineHeight: 28 }, |
|||
b: { fontSize: 16 } |
|||
} |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
myChart.setOption(option) |
|||
this.$LoopShowTooltip(myChart, option.baseOption, { loopSeries: true, interval: 4000 }) |
|||
} |
|||
] |
|||
|
|||
// 23. 合并配置并设置 |
|||
const option = { baseOption, media: mediaOption } |
|||
this.myChart.setOption(option) |
|||
|
|||
// 自动轮播tooltip |
|||
this.$LoopShowTooltip(this.myChart, baseOption, { loopSeries: true, interval: 4000 }) |
|||
}, |
|||
|
|||
/** |
|||
* 24. 窗口大小变化时防抖重绘图表 |
|||
*/ |
|||
handleResize() { |
|||
clearTimeout(this.resizeTimer) |
|||
this.resizeTimer = setTimeout(() => { |
|||
if (this.myChart) { |
|||
this.myChart.resize() |
|||
} |
|||
}, 100) |
|||
} |
|||
} |
|||
} |
|||
|
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
<style lang="scss" scoped> // 25. 添加scoped,避免样式污染全局 |
|||
@import "~@/assets/styles/index.scss"; |
|||
@import "~@/assets/styles/font-some.css"; |
|||
|
|||
// 26. 样式抽离,便于维护 |
|||
.year-chart-container { |
|||
height: calc(100% - 200px); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
|
|||
.model-type-chart { |
|||
width: 400px; |
|||
height: 230px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,172 @@ |
|||
<template> |
|||
<div class="page-wrapper" style="padding: 0 !important; z-index: 9999;"> |
|||
<el-carousel |
|||
ref="carousel" |
|||
indicator-position="none" |
|||
:autoplay="false" |
|||
:autoplay-hover-pause="true" |
|||
@setActiveItem="setActiveItem" |
|||
@change="carouselChange" |
|||
> |
|||
<div v-if="slideData && slideData.length > 0"> |
|||
<el-carousel-item v-for="(item, index) in slideData" :key="index"> |
|||
<video |
|||
ref="videos" |
|||
class="tsgz-video" |
|||
width="100%" |
|||
height="100%" |
|||
controls |
|||
preload="auto" |
|||
:src="item.cover" |
|||
:poster="poster" |
|||
autoplay |
|||
type="video/mp4" |
|||
muted |
|||
@ended="playNextVideo(index)" |
|||
@loadedmetadata="playVideo" |
|||
> |
|||
您的浏览器不支持 video 标签。 |
|||
</video> |
|||
</el-carousel-item> |
|||
</div> |
|||
<el-empty |
|||
v-else |
|||
description="暂无视频" |
|||
style="height: 100vh" |
|||
:image-size="100" |
|||
image="" |
|||
/> |
|||
</el-carousel> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { FetchTotalResource } from '@/api/library' |
|||
export default { |
|||
name: 'PageFive', |
|||
components: { |
|||
}, |
|||
data() { |
|||
return { |
|||
poster: require('@/assets/images/poster.png'), |
|||
videoIndex: 0, |
|||
slideData: [] |
|||
} |
|||
}, |
|||
computed: { |
|||
}, |
|||
beforeDestroy() { |
|||
this.destroy() |
|||
}, |
|||
created() { |
|||
}, |
|||
activated() { |
|||
this.getVideoResource() |
|||
this.load() |
|||
}, |
|||
deactivated() { |
|||
this.destroy() |
|||
}, |
|||
mounted() { |
|||
}, |
|||
methods: { |
|||
load() { |
|||
const videos = this.$refs.videos |
|||
if (videos) { |
|||
videos[this.videoIndex].load() |
|||
videos[this.videoIndex].currentTime = localStorage.getItem('videoCurrentTime') ? localStorage.getItem('videoCurrentTime') : 0 |
|||
} |
|||
}, |
|||
destroy() { |
|||
localStorage.setItem('videoIndex', this.videoIndex) |
|||
localStorage.setItem('videoCurrentTime', this.$refs.videos[this.videoIndex].currentTime) |
|||
this.$refs.videos[this.videoIndex].pause() |
|||
}, |
|||
// 视频资源 |
|||
getVideoResource() { |
|||
FetchTotalResource().then(res => { |
|||
const result = JSON.parse(res.data) |
|||
const linkSrc = process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API |
|||
this.slideData = result.map((item, index) => { |
|||
if (item.filePath) { |
|||
item.cover = linkSrc + '/downloadFile' + item.filePath |
|||
} else { |
|||
item.cover = null |
|||
} |
|||
return item |
|||
}) |
|||
// 下次进入页面时优先缓存的部分 |
|||
if (localStorage.getItem('videoIndex')) { |
|||
this.videoIndex = parseInt(localStorage.getItem('videoIndex')) |
|||
this.$nextTick(() => { |
|||
this.$refs.carousel.setActiveItem(this.videoIndex) |
|||
const videos = this.$refs.videos |
|||
const nextVideo = videos[this.videoIndex] |
|||
videos.forEach((video) => { |
|||
video.pause() |
|||
video.currentTime = 0 |
|||
}) |
|||
setTimeout(() => { |
|||
nextVideo.currentTime = localStorage.getItem('videoCurrentTime') ? localStorage.getItem('videoCurrentTime') : 0 |
|||
nextVideo.play() |
|||
}, 2000) |
|||
}) |
|||
} |
|||
}).catch(error => { |
|||
console.error('Error', error) |
|||
}) |
|||
}, |
|||
playVideo() { |
|||
this.$refs.videos[this.videoIndex].play().catch(error => { |
|||
console.error(error) |
|||
}) |
|||
}, |
|||
setActiveItem(index) { |
|||
this.$refs.carousel.setActiveItem(index) |
|||
}, |
|||
carouselChange(index) { |
|||
const videos = this.$refs.videos |
|||
this.videoIndex = index |
|||
videos.forEach((video) => { |
|||
video.currentTime = 0 // 将视频回到起始时间 |
|||
video.pause() // 暂停视频播放 |
|||
}) |
|||
videos[index].play() |
|||
}, |
|||
playNextVideo(index) { |
|||
const videos = this.$refs.videos |
|||
let nextIndex = index |
|||
this.videoIndex = nextIndex |
|||
if (index < this.slideData.length - 1) { |
|||
nextIndex = nextIndex + 1 |
|||
} else { |
|||
nextIndex = 0 |
|||
} |
|||
const carousel = this.$refs.carousel |
|||
carousel.setActiveItem(nextIndex) |
|||
const nextVideo = videos[nextIndex] |
|||
videos.forEach((video) => { |
|||
video.pause() |
|||
video.currentTime = 0 |
|||
}) |
|||
setTimeout(() => { |
|||
nextVideo.play() |
|||
}, 1000) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
@import "~@/assets/styles/index.scss"; |
|||
.el-carousel { |
|||
margin-top: 0 !important; |
|||
} |
|||
::v-deep .el-carousel__container{ |
|||
height: 100vh !important; |
|||
} |
|||
video { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue