-
125README.md
-
BINpublic/cdn/blue-icon.png
-
BINpublic/cdn/blue-marker.png
-
BINpublic/cdn/buildings.png
-
BINpublic/cdn/green-icon.png
-
BINpublic/cdn/green-marker.png
-
262public/cdn/njhl_bg copy.svg
-
176public/cdn/njhl_bg.svg
-
BINpublic/cdn/white-icon.png
-
BINpublic/cdn/white-marker.png
-
BINpublic/cdn/yellow-icon.png
-
BINpublic/cdn/yellow-marker.png
-
BINpublic/favicon.ico
-
BINsrc/assets/images/njhl/air.png
-
BINsrc/assets/images/njhl/bg.png
-
BINsrc/assets/images/njhl/block.png
-
BINsrc/assets/images/njhl/dd.png
-
BINsrc/assets/images/njhl/elec.png
-
BINsrc/assets/images/njhl/gas.png
-
BINsrc/assets/images/njhl/mm.png
-
BINsrc/assets/images/njhl/pop.png
-
BINsrc/assets/images/njhl/pop_0.png
-
BINsrc/assets/images/njhl/pop_1.png
-
BINsrc/assets/images/njhl/pop_2.png
-
BINsrc/assets/images/njhl/steam.png
-
BINsrc/assets/images/njhl/title.png
-
BINsrc/assets/images/njhl/tooltip/airValue.png
-
BINsrc/assets/images/njhl/tooltip/bg.png
-
BINsrc/assets/images/njhl/tooltip/close.png
-
BINsrc/assets/images/njhl/tooltip/electricValue.png
-
BINsrc/assets/images/njhl/tooltip/steamValue.png
-
BINsrc/assets/images/njhl/tooltip/waterValue.png
-
BINsrc/assets/images/njhl/water.png
-
BINsrc/assets/images/njhl/yy.png
-
2src/layout/header/base-header.vue
-
378src/views/dashboard/common/model.ts
-
289src/views/dashboard/common/style.ts
-
110src/views/dashboard/comp/bar.vue
-
117src/views/dashboard/comp/block.vue
-
102src/views/dashboard/comp/pop.vue
-
212src/views/dashboard/comp/preview.vue
-
122src/views/dashboard/comp/tooltip.vue
-
503src/views/dashboard/main.vue
@ -1,125 +0,0 @@ |
|||||
#### 2022-07-22 变更 |
|
||||
``` |
|
||||
1. 物管理-物属性extendData字段判空处理。 |
|
||||
2. 物管理-物计算文案字段以及ui布局调整。 |
|
||||
3. 告警管理页面布局开发。 |
|
||||
4. 中机首页模型更换以及增加动画效果。 |
|
||||
``` |
|
||||
|
|
||||
#### 2022-07-21 变更 |
|
||||
``` |
|
||||
1. 中机首页模型压缩体积。 |
|
||||
2. 中机首页看板设备状态api调整。 |
|
||||
``` |
|
||||
|
|
||||
#### 2022-07-20 变更 |
|
||||
``` |
|
||||
1. 中机首页看板异步加载修复。 |
|
||||
2. 中机 首页看板bug修复。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-19 变更 |
|
||||
``` |
|
||||
1. 中机看板联调及优化。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-18 变更 |
|
||||
``` |
|
||||
1. 中机首页模型标注开发。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-15 变更 |
|
||||
``` |
|
||||
1. 中机首页看板前端界面开发完成,待联调。 |
|
||||
2. 中机设备管理属性新增/编辑弹框。 |
|
||||
3. 系统设置-文件上传对接字段。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-14 变更 |
|
||||
``` |
|
||||
1. 数据集交互优化。 |
|
||||
2. 优化上传图片组件。 |
|
||||
3. 系统设置-文件上传对接字段。 |
|
||||
4. 登录页新增通过接口拿到登录框图片链接。 |
|
||||
5. 设备首页看板界面开发。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-13 变更 |
|
||||
``` |
|
||||
1. 设备控制-协议管理抽屉框标题修改也显示新增的bug。 |
|
||||
2. 消息中心-消息模板类型格式问题修复。 |
|
||||
3. 数据处理-规则链修复自动登录问题。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-12 变更 |
|
||||
``` |
|
||||
1. 设备管理-中机首页模型加载。 |
|
||||
2. 增加退出登录时重置title和icon的功能。 |
|
||||
3. 数据集修复bug 6046 6047 6048 6052 6057。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-11 变更 |
|
||||
``` |
|
||||
1. 设备管理-看板和设置等页面初始化。 |
|
||||
2. 推送设置-提醒人字段在全部推送情况下不为必填项。 |
|
||||
``` |
|
||||
|
|
||||
#### 2022-07-08 变更 |
|
||||
``` |
|
||||
1. 设备控制-计算引擎回显bug修复。 |
|
||||
2. 企业管理-企业管理筛选全部类型下拉无数据的问题。 |
|
||||
3. 设备控制-设备模板描述字段bug。 |
|
||||
4. 设备控制-协议管理表格内容居中。 |
|
||||
5. 设备控制-设备管理-通讯协议调试提示字段放大。 |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
#### 2022-07-07 变更 |
|
||||
``` |
|
||||
1. 缓存设置-修改物页面中点击查询报错修复。 |
|
||||
2. 缓存设置-勾选的属性没有被添加。 |
|
||||
3. 控制模板-指令导入,存在重复指令应无法导入,且导入后提示报错修复。 |
|
||||
4. 租户配置新增表单置空修复。 |
|
||||
5. 物管里-物属性/物标签修改判断页面数据数组的逻辑。 |
|
||||
6. 物管里-物分组/物属性/物标签/组管理优化导入逻辑。 |
|
||||
7. 修改utilService判断对象逻辑。 |
|
||||
8. 完善上传文件代码抛错逻辑。 |
|
||||
9. 配置中心-能源品种对接导入导出。 |
|
||||
10. 配置中心-属性设置对接导入导出。 |
|
||||
11. 新增导入JSON组件传入url并手动上传功能。 |
|
||||
12. 设备控制-设备控制调试页面去掉取消按钮。 |
|
||||
13. 设备控制-设备控制调试表单增计算模块字段加校验。 |
|
||||
14. 隐藏主题设置入口。 |
|
||||
15. 物管理-物属性弹框去掉回车提交事件,避免误操作。 |
|
||||
16. 设备控制-通讯协议布局和设计图不一致的问题。 |
|
||||
``` |
|
||||
#### 2022-07-06 变更 |
|
||||
``` |
|
||||
1. 企业管理-企业分组状态文案修改(正常 => 启用)。 |
|
||||
2. 企业管理-租户账户状态文案修改(正常 => 启用)。 |
|
||||
3. 物管理-物分组弹框打开重置相关数据;切换分页保存table(dataListSelections)所选数据。 |
|
||||
4. 物管理-物分组中el-popover交互修改,支持点击空白处隐藏该组件。 |
|
||||
5. 企业管理-企业账户状态更换为按钮形式。 |
|
||||
6. 企业管理-租户账户状态更换为按钮形式并优化了企业账户按钮的代码。 |
|
||||
7. 设备管理-设备清单添加异常设备数。 |
|
||||
8. 设备清单-设备属性详情图表和列表开发并联调完成。 |
|
||||
9. 物管理-物实体状态时间格式化。 |
|
||||
10. 计算模块api联调更新,设备管理-设备清单属性详情api调整。 |
|
||||
11. 优化并修复租户配置bug。 |
|
||||
12. 通讯协议-新增页面点击保存关闭抽屉。 |
|
||||
13. 通讯协议-调试中不可点击model外关闭 按钮更换字段(测试-订阅 测试-推送 取消-退出调试)。 |
|
||||
14. 设备控制-控制模板描述添加字数限制。 |
|
||||
15. 设备控制-通讯设备描述字段添加字数限制。 |
|
||||
16. 物管里-物管里,数据缓存-物管里去除多余的按钮。 |
|
||||
17. 设备控制-通讯协议点击调试按钮 点击model外不关闭的bug。 |
|
||||
18. 设备控制-控制模板-指令添加描述字段。 |
|
||||
19. 物管理-物关系详情页面按钮替换成图片。 |
|
||||
20. 物管理-选择物名称弹框table物名称字段改为“名称-code”。 |
|
||||
``` |
|
||||
|
After Width: 66 | Height: 74 | Size: 11 KiB |
|
After Width: 18 | Height: 23 | Size: 950 B |
|
After Width: 1368 | Height: 862 | Size: 365 KiB |
|
After Width: 68 | Height: 75 | Size: 10 KiB |
|
After Width: 18 | Height: 23 | Size: 1011 B |
262
public/cdn/njhl_bg copy.svg
File diff suppressed because it is too large
View File
176
public/cdn/njhl_bg.svg
File diff suppressed because it is too large
View File
|
After Width: 67 | Height: 73 | Size: 9.4 KiB |
|
After Width: 18 | Height: 23 | Size: 840 B |
|
After Width: 66 | Height: 73 | Size: 9.6 KiB |
|
After Width: 18 | Height: 23 | Size: 951 B |
|
Before Width: 1024 | Height: 1024 | Size: 36 KiB After Width: 277 | Height: 280 | Size: 27 KiB |
|
After Width: 60 | Height: 59 | Size: 1.1 KiB |
|
After Width: 1309 | Height: 783 | Size: 332 KiB |
|
After Width: 484 | Height: 318 | Size: 3.6 KiB |
|
After Width: 45 | Height: 51 | Size: 1.9 KiB |
|
After Width: 60 | Height: 59 | Size: 1.1 KiB |
|
After Width: 55 | Height: 55 | Size: 2.0 KiB |
|
After Width: 45 | Height: 51 | Size: 2.0 KiB |
|
After Width: 199 | Height: 86 | Size: 711 B |
|
After Width: 41 | Height: 41 | Size: 1.6 KiB |
|
After Width: 41 | Height: 41 | Size: 1.6 KiB |
|
After Width: 40 | Height: 40 | Size: 1.3 KiB |
|
After Width: 60 | Height: 60 | Size: 1.3 KiB |
|
After Width: 1920 | Height: 88 | Size: 13 KiB |
|
After Width: 26 | Height: 26 | Size: 936 B |
|
After Width: 289 | Height: 253 | Size: 8.7 KiB |
|
After Width: 18 | Height: 18 | Size: 445 B |
|
After Width: 26 | Height: 26 | Size: 864 B |
|
After Width: 26 | Height: 26 | Size: 907 B |
|
After Width: 26 | Height: 26 | Size: 874 B |
|
After Width: 60 | Height: 60 | Size: 1.1 KiB |
|
After Width: 45 | Height: 51 | Size: 1.9 KiB |
@ -0,0 +1,378 @@ |
|||||
|
import dateService from '@/service/dateService'; |
||||
|
import utilService from '@/service/utilService'; |
||||
|
import { IObject } from '@/types/interface'; |
||||
|
import { smooth } from '@antv/x6/lib/registry/connector/smooth'; |
||||
|
import moment from 'moment'; |
||||
|
|
||||
|
export const monthEnergyUsageTrend = (data = []): IObject => { |
||||
|
const length = new dateService().getDateCountByMonth()[12]; |
||||
|
const xAxisData = Array.from({ length }, (x, i) => i + 1); |
||||
|
const seriesData = []; |
||||
|
if (utilService.isValidArray(data)) { |
||||
|
for (const day of xAxisData) { |
||||
|
let val; |
||||
|
for (const item of data) { |
||||
|
if (day === +moment(item.date).format('D')) { |
||||
|
val = item.value; |
||||
|
} |
||||
|
} |
||||
|
seriesData.push(val); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
grid: { |
||||
|
bottom: 45, |
||||
|
top: 30, |
||||
|
left: 60, |
||||
|
}, |
||||
|
tooltip: { trigger: 'axis' }, |
||||
|
xAxis: { |
||||
|
name: '(日)', |
||||
|
type: 'category', |
||||
|
data: xAxisData, |
||||
|
axisLine: { lineStyle: { color: '#fff' } }, |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
axisLine: { lineStyle: { color: '#fff' }, show: true }, |
||||
|
splitLine: { lineStyle: { type: 'dashed', color: 'rgba(255,255,255,0.3)' } }, |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
data: seriesData, |
||||
|
type: 'line', |
||||
|
smooth: true, |
||||
|
lineStyle: { color: '#00EFF6', width: 3 }, |
||||
|
areaStyle: { |
||||
|
opacity: 0.8, |
||||
|
color: new window.echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
||||
|
{ |
||||
|
offset: 0, |
||||
|
color: 'rgb(1, 73, 134)', |
||||
|
}, |
||||
|
{ |
||||
|
offset: 1, |
||||
|
color: 'rgba(1, 73, 134, 0.1)', |
||||
|
}, |
||||
|
]), |
||||
|
}, |
||||
|
emphasis: { |
||||
|
focus: 'series', |
||||
|
}, |
||||
|
showSymbol: false, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export const costStatistic = (data = []): IObject => { |
||||
|
//颜色16进制换算rgba,添加透明度
|
||||
|
function hexToRgba(hex, opacity) { |
||||
|
return ( |
||||
|
'rgba(' + |
||||
|
parseInt('0x' + hex.slice(1, 3)) + |
||||
|
',' + |
||||
|
parseInt('0x' + hex.slice(3, 5)) + |
||||
|
',' + |
||||
|
parseInt('0x' + hex.slice(5, 7)) + |
||||
|
',' + |
||||
|
opacity + |
||||
|
')' |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 数据
|
||||
|
const chartdata = [ |
||||
|
{ |
||||
|
name: '电', |
||||
|
value: undefined, |
||||
|
}, |
||||
|
{ |
||||
|
name: '水', |
||||
|
value: undefined, |
||||
|
}, |
||||
|
// {
|
||||
|
// name: "压缩空气",
|
||||
|
// value: undefined
|
||||
|
// },
|
||||
|
{ |
||||
|
name: '蒸汽', |
||||
|
value: undefined, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
if (utilService.isValidArray(data)) { |
||||
|
for (const item of data) { |
||||
|
for (const val of chartdata) { |
||||
|
if (item.name === val.name) { |
||||
|
val.value = item.value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const radius = ['45%', '50%']; |
||||
|
// 颜色系列
|
||||
|
//const color = ["#0084FF", "#37FFC9", "#FFE777", "#19D6FF"];
|
||||
|
const color = ['#0084FF', '#37FFC9', '#FFE777']; |
||||
|
const color1 = []; |
||||
|
const color2 = []; |
||||
|
const color3 = []; |
||||
|
// 设置每层圆环颜色和添加间隔的透明色
|
||||
|
color.forEach((item) => { |
||||
|
color1.push(item, 'transparent'); |
||||
|
color2.push(hexToRgba(item, 0.7), 'transparent'); |
||||
|
color3.push(hexToRgba(item, 0.4), 'transparent'); |
||||
|
}); |
||||
|
const data1 = []; |
||||
|
let sum = 0; |
||||
|
// 根据总值设置间隔值大小
|
||||
|
chartdata.forEach((item) => { |
||||
|
sum += Number(item.value); |
||||
|
}); |
||||
|
// 给每个数据后添加特定的透明的数据形成间隔
|
||||
|
chartdata.forEach((item, index) => { |
||||
|
if (item.value !== 0) { |
||||
|
data1.push(item, { |
||||
|
//name: "",
|
||||
|
value: sum / 70, |
||||
|
labelLine: { |
||||
|
show: false, |
||||
|
lineStyle: { |
||||
|
color: 'transparent', |
||||
|
}, |
||||
|
}, |
||||
|
itemStyle: { |
||||
|
color: 'transparent', |
||||
|
}, |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
// 每层圆环大小
|
||||
|
const radius2 = [ |
||||
|
Number(radius[1].split('%')[0]) + 0 + '%', |
||||
|
Number(radius[1].split('%')[0]) + 4 + '%', |
||||
|
]; |
||||
|
const radius3 = [ |
||||
|
Number(radius[1].split('%')[0]) + 4 + '%', |
||||
|
Number(radius[1].split('%')[0]) + 8 + '%', |
||||
|
]; |
||||
|
|
||||
|
return { |
||||
|
legend: { |
||||
|
data: chartdata.map((v) => ({ name: v.name })), |
||||
|
type: 'scroll', |
||||
|
bottom: 15, |
||||
|
textStyle: { |
||||
|
color: '#fff', |
||||
|
}, |
||||
|
}, |
||||
|
grid: { |
||||
|
top: 0, |
||||
|
bottom: 0, |
||||
|
left: 0, |
||||
|
right: 0, |
||||
|
containLabel: true, |
||||
|
}, |
||||
|
tooltip: { |
||||
|
formatter: (params) => { |
||||
|
if (params.name !== '') { |
||||
|
return params.name + ' : ' + params.value + '\n' + '(' + params.percent + '%)'; |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
series: [ |
||||
|
// 最外层圆环
|
||||
|
{ |
||||
|
type: 'pie', |
||||
|
radius: radius3, |
||||
|
center: ['50%', '45%'], |
||||
|
hoverAnimation: false, |
||||
|
startAngle: 90, |
||||
|
selectedMode: 'single', |
||||
|
selectedOffset: 0, |
||||
|
itemStyle: { |
||||
|
normal: { |
||||
|
color: (params) => { |
||||
|
return color1[params.dataIndex]; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
label: { color: '#fff' }, |
||||
|
labelLine: { |
||||
|
show: true, |
||||
|
length: 15, |
||||
|
length2: 30, |
||||
|
lineStyle: { |
||||
|
color: '#fff', |
||||
|
width: 2, |
||||
|
}, |
||||
|
}, |
||||
|
data: data1, |
||||
|
}, |
||||
|
{ |
||||
|
type: 'pie', |
||||
|
radius: radius2, |
||||
|
center: ['50%', '45%'], |
||||
|
hoverAnimation: false, |
||||
|
startAngle: 90, |
||||
|
selectedMode: 'single', |
||||
|
selectedOffset: 0, |
||||
|
itemStyle: { |
||||
|
normal: { |
||||
|
color: (params) => { |
||||
|
return color2[params.dataIndex]; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
label: { |
||||
|
show: false, |
||||
|
formatter: '{b}' + ' ' + '{c}', |
||||
|
}, |
||||
|
data: data1, |
||||
|
}, |
||||
|
{ |
||||
|
type: 'pie', |
||||
|
radius: radius, |
||||
|
center: ['50%', '45%'], |
||||
|
hoverAnimation: false, |
||||
|
startAngle: 90, |
||||
|
selectedMode: 'single', |
||||
|
selectedOffset: 0, |
||||
|
itemStyle: { |
||||
|
normal: { |
||||
|
color: (params) => { |
||||
|
return color3[params.dataIndex]; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
label: { |
||||
|
show: false, |
||||
|
formatter: '{b}' + ' ' + '{c}', |
||||
|
}, |
||||
|
data: data1, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export const usageRanking = (data = []): IObject => { |
||||
|
let yAxisData = []; |
||||
|
let seriesData = []; |
||||
|
if (utilService.isValidArray(data)) { |
||||
|
data = data.slice(0, 5).sort((a, b) => a.value - b.value); |
||||
|
yAxisData = data.map((v) => v.thingName); |
||||
|
seriesData = data.map((v) => v.value); |
||||
|
} |
||||
|
return { |
||||
|
tooltip: { |
||||
|
trigger: 'axis', |
||||
|
axisPointer: { |
||||
|
type: 'shadow', |
||||
|
}, |
||||
|
}, |
||||
|
grid: { |
||||
|
bottom: 35, |
||||
|
top: 10, |
||||
|
left: 70, |
||||
|
}, |
||||
|
xAxis: { |
||||
|
name: '(万)', |
||||
|
type: 'value', |
||||
|
boundaryGap: [0, 0.01], |
||||
|
axisLine: { lineStyle: { color: '#fff' }, show: true }, |
||||
|
splitLine: { show: false }, |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'category', |
||||
|
axisLine: { lineStyle: { color: '#fff' }, show: true }, |
||||
|
data: yAxisData, |
||||
|
axisLabel: { |
||||
|
//fontSize: 10,
|
||||
|
formatter: (val: string) => { |
||||
|
return val.length > 5 ? `${val.slice(0, 3)}...` : val; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
type: 'bar', |
||||
|
data: seriesData, |
||||
|
barWidth: 16, |
||||
|
itemStyle: { |
||||
|
normal: { |
||||
|
color: '#25DDFF', |
||||
|
barBorderRadius: [10, 10, 10, 10], |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export const elecPayload = (data = []): IObject => { |
||||
|
const length = 24; |
||||
|
const xAxisData = Array.from({ length }, (x, i) => i); |
||||
|
const seriesData = []; |
||||
|
if (utilService.isValidArray(data)) { |
||||
|
for (const day of xAxisData) { |
||||
|
let val; |
||||
|
for (const item of data) { |
||||
|
if ( |
||||
|
typeof item.date === 'string' && |
||||
|
item.date.includes(`${new dateService().addZero(day)}:00:00`) |
||||
|
) { |
||||
|
val = item.value; |
||||
|
} |
||||
|
} |
||||
|
seriesData.push(val); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
grid: { |
||||
|
bottom: 45, |
||||
|
top: 30, |
||||
|
left: 40, |
||||
|
}, |
||||
|
tooltip: { trigger: 'axis' }, |
||||
|
xAxis: { |
||||
|
name: '(时)', |
||||
|
type: 'category', |
||||
|
data: xAxisData, |
||||
|
axisLine: { lineStyle: { color: '#fff' } }, |
||||
|
axisLabel: { fontSize: 10 }, |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
axisLine: { lineStyle: { color: '#fff' }, show: true }, |
||||
|
splitLine: { lineStyle: { type: 'dashed', color: 'rgba(255,255,255,0.3)' } }, |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
data: seriesData, |
||||
|
type: 'line', |
||||
|
smooth: true, |
||||
|
lineStyle: { color: '#449DD4', width: 1 }, |
||||
|
areaStyle: { |
||||
|
opacity: 0.8, |
||||
|
color: new window.echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
||||
|
{ |
||||
|
offset: 0, |
||||
|
color: 'rgb(1, 73, 134)', |
||||
|
}, |
||||
|
{ |
||||
|
offset: 1, |
||||
|
color: 'rgba(1, 73, 134, 0.1)', |
||||
|
}, |
||||
|
]), |
||||
|
}, |
||||
|
emphasis: { |
||||
|
focus: 'series', |
||||
|
}, |
||||
|
showSymbol: false, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}; |
||||
@ -0,0 +1,289 @@ |
|||||
|
import { useFetch } from '@/hooks/fetch'; |
||||
|
import { IObject } from '@/types/interface'; |
||||
|
import moment from 'moment'; |
||||
|
import dragStretchService from '@/service/dragStretchService'; |
||||
|
|
||||
|
export const pathStyle = { |
||||
|
show: 'cursor:pointer;fill:#2a9bdd;stroke:#2a9bdd;stroke-width:0.26458333;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none;fill-opacity:0.38039216', |
||||
|
hide: 'cursor:pointer;opacity: 0;', |
||||
|
}; |
||||
|
|
||||
|
const reset = (state: IObject) => { |
||||
|
if (state.dragStretch) { |
||||
|
state.dragStretch.reset(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const pathMap: IObject = { |
||||
|
path4830: { |
||||
|
data: [ |
||||
|
{ code: 'G06', key: 'A29' }, |
||||
|
{ code: 'B_V0000151_27', key: 'B2' }, |
||||
|
], |
||||
|
}, |
||||
|
path4770: { |
||||
|
data: [ |
||||
|
{ code: 'A_016', key: 'A29' }, |
||||
|
{ code: 'B_V0000151_21', key: 'B2' }, |
||||
|
{ code: 'E_V0000151_5', key: 'E3' }, |
||||
|
{ code: 'D_V0000151_2', key: 'D2' }, |
||||
|
], |
||||
|
}, |
||||
|
path4766: {}, |
||||
|
path7032: { |
||||
|
data: [{ code: 'B_V0000151_11', key: 'B2' }], |
||||
|
}, |
||||
|
path4666: {}, |
||||
|
path3938: {}, |
||||
|
path3936: { |
||||
|
data: [{ code: 'B_V0000151_15', key: 'B2' }], |
||||
|
}, |
||||
|
path3102: { |
||||
|
data: [ |
||||
|
{ code: 'A_009', key: 'A29' }, |
||||
|
{ code: 'B_V0000151_16', key: 'B2' }, |
||||
|
{ code: 'E_V0000151_6', key: 'E3' }, |
||||
|
{ code: 'D_V0000151_4', key: 'D2' }, |
||||
|
], |
||||
|
}, |
||||
|
path3934: { |
||||
|
data: [ |
||||
|
{ code: 'G04', key: 'A29' }, |
||||
|
{ code: 'B_V0000151_23', key: 'B2' }, |
||||
|
], |
||||
|
}, |
||||
|
path3932: { |
||||
|
data: [ |
||||
|
{ code: 'A_019', key: 'A29' }, |
||||
|
{ code: 'E_11004151_1', key: 'E3' }, |
||||
|
], |
||||
|
}, |
||||
|
path3100: { |
||||
|
data: [ |
||||
|
{ code: 'A_010', key: 'A29' }, |
||||
|
{ code: 'B_V0000151_26', key: 'B2' }, |
||||
|
{ code: 'E_V0000151_7', key: 'E3' }, |
||||
|
{ code: 'D_V0000151_3', key: 'D2' }, |
||||
|
], |
||||
|
}, |
||||
|
path7030: { |
||||
|
data: [{ code: 'B_V0000151_12', key: 'B2' }], |
||||
|
}, |
||||
|
path4768: { |
||||
|
data: [ |
||||
|
{ code: 'A_005', key: 'A29' }, |
||||
|
{ code: 'B_V0000151_25', key: 'B2' }, |
||||
|
], |
||||
|
}, |
||||
|
path7028: { |
||||
|
data: [{ code: 'B_V0000151_17', key: 'B2' }], |
||||
|
}, |
||||
|
path6300: { |
||||
|
data: [ |
||||
|
{ code: 'A_021', key: 'A29' }, |
||||
|
{ code: 'E_11004154_1', key: 'E3' }, |
||||
|
], |
||||
|
codes: ['A_021', 'E_11004154_1'], |
||||
|
}, |
||||
|
path6298: { |
||||
|
data: [ |
||||
|
{ code: 'G05', key: 'A29' }, |
||||
|
{ code: 'B_V0000151_19', key: 'B2' }, |
||||
|
], |
||||
|
}, |
||||
|
|
||||
|
path6296: {}, |
||||
|
path6294: { |
||||
|
data: [{ code: 'A_007', key: 'A29' }], |
||||
|
}, |
||||
|
path6292: { |
||||
|
data: [ |
||||
|
{ code: 'B_V0000151_13', key: 'B2' }, |
||||
|
{ code: 'E_11004154_2', key: 'E3' }, |
||||
|
], |
||||
|
}, |
||||
|
path5564: { |
||||
|
data: [{ code: 'A_020', key: 'A29' }], |
||||
|
}, |
||||
|
path5558: {}, |
||||
|
path5562: {}, |
||||
|
}; |
||||
|
|
||||
|
const animateMap: IObject = { |
||||
|
'layer-d-animate': `<animate href="#path7592" attributeName="stroke-dashoffset" dur="15s" to="0" fill="freeze"></animate>
|
||||
|
<animate href="#path7592-3" attributeName="stroke-dashoffset" dur="15s" to="0" fill="freeze"></animate> <animate href="#path9046" attributeName="stroke-dashoffset" begin="0.6s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path9046-1" attributeName="stroke-dashoffset" begin="0.6s" dur="15s" to="0" fill="freeze"></animate><animate href="#path18869" attributeName="stroke-dashoffset" begin="0.5s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path18869-1" attributeName="stroke-dashoffset" begin="0.5s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path9046-5" attributeName="stroke-dashoffset" begin="2s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path9046-1-0" attributeName="stroke-dashoffset" begin="2s" dur="15s" to="0" fill="freeze"></animate><animate href="#path23350-62" attributeName="stroke-dashoffset" begin="1.22s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path23350-6-2" attributeName="stroke-dashoffset" begin="1.22s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path23326" attributeName="stroke-dashoffset" dur="3.8s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path23326-1" attributeName="stroke-dashoffset" dur="3.8s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path23350" attributeName="stroke-dashoffset" begin="1.42s" dur="25s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path23350-6" attributeName="stroke-dashoffset" begin="1.42s" dur="25s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path23374" attributeName="stroke-dashoffset" begin="2.8s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path23374-0" attributeName="stroke-dashoffset" begin="2.8s" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path26736" attributeName="stroke-dashoffset" dur="2s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path26736-9" attributeName="stroke-dashoffset" dur="2s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path28441-0" attributeName="stroke-dashoffset" dur="2s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path28441-8-9" attributeName="stroke-dashoffset" dur="2s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path30063" attributeName="stroke-dashoffset" begin="0.5s" dur="2s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path30063-0" attributeName="stroke-dashoffset" begin="0.5s" dur="2s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path28441" attributeName="stroke-dashoffset" begin="0.5s" dur="2s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#path28441-8-9-2" attributeName="stroke-dashoffset" begin="0.5s" dur="2s" to="0" fill="freeze"></animate> |
||||
|
|
||||
|
<animate href="#path23264" attributeName="stroke-dashoffset" dur="15s" to="0" fill="freeze"></animate><animate href="#path23264-3" attributeName="stroke-dashoffset" dur="15s" to="0" fill="freeze"></animate> |
||||
|
<animate href="#image31036-69" attributeName="display" dur="3.2s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-6" attributeName="display" dur="7.8s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-8" attributeName="display" dur="5s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-3" attributeName="display" dur="5s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-69-9" attributeName="display" dur="2.3s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-69-5" attributeName="display" dur="2.8s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-1" attributeName="display" dur="2s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-5112" attributeName="display" dur="3.4s" from="none" to="block" fill="freeze"></animate> |
||||
|
<animate href="#image31036-5" attributeName="display" dur="2.4s" from="none" to="block" fill="freeze"></animate> |
||||
|
`,
|
||||
|
}; |
||||
|
|
||||
|
const pointerElec = { lineId: 'njhl-svg-elec' }; |
||||
|
const pointerWater = { lineId: 'njhl-svg-water' }; |
||||
|
const pointerGas = { lineId: 'njhl-svg-gas' }; |
||||
|
const pointerSteam = { lineId: 'njhl-svg-steam' }; |
||||
|
|
||||
|
const pointerMap: IObject = { |
||||
|
'image31024-4': pointerElec, |
||||
|
image31024: pointerElec, //电
|
||||
|
image4433: pointerWater, |
||||
|
'image4433-8': pointerWater, |
||||
|
image8135: pointerSteam, |
||||
|
'image8135-9': pointerSteam, |
||||
|
image12904: pointerGas, |
||||
|
}; |
||||
|
|
||||
|
const initToolTip = (state: IObject): any => { |
||||
|
for (const key in pathMap) { |
||||
|
const val = pathMap[key]; |
||||
|
if (!val.data) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
const path = document.getElementById(key); |
||||
|
if (path) { |
||||
|
path.onmouseenter = () => { |
||||
|
path.setAttribute('style', pathStyle.show); |
||||
|
}; |
||||
|
path.onmouseleave = () => { |
||||
|
path.setAttribute('style', pathStyle.hide); |
||||
|
}; |
||||
|
path.onclick = (event: IObject) => { |
||||
|
setToolTipStatus('flex'); |
||||
|
|
||||
|
const { screenX, screenY } = event; |
||||
|
const target = document.querySelector('.njhl-tool-tip'); |
||||
|
|
||||
|
if (target) { |
||||
|
useFetch('/board/build/data', { |
||||
|
method: 'post', |
||||
|
data: { |
||||
|
datas: val.data, |
||||
|
month: moment().format('YYYY-MM'), |
||||
|
}, |
||||
|
cb: (res: any) => { |
||||
|
state.toolTipData = res; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
target.style.left = screenX - 100 + 'px'; |
||||
|
target.style.top = screenY - 100 + 'px'; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const pointerLineMap: IObject = { 'layer-d-animate': ['image31024-4', 'image31024'] }; |
||||
|
|
||||
|
const setPointerLineStatus = (target: HTMLElement, status: string): void => { |
||||
|
if (target) { |
||||
|
target.style.display = status; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
export const setPointerLineStatusAll = (status: string): void => { |
||||
|
for (const key in pointerMap) { |
||||
|
const item = pointerMap[key]; |
||||
|
|
||||
|
const target = document.getElementById(item.lineId) as HTMLElement; |
||||
|
setPointerLineStatus(target, status); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const initLine = (): any => { |
||||
|
// for (const key in pointerLineMap) {
|
||||
|
// const ids = pointerLineMap[key];
|
||||
|
// for (const item of ids) {
|
||||
|
// const pointer = document.getElementById(item);
|
||||
|
// if (pointer) {
|
||||
|
// pointer.onclick = () => {
|
||||
|
// const v = animateMap[key];
|
||||
|
// const target = document.getElementById(key);
|
||||
|
// if (target) {
|
||||
|
// target.innerHTML = v;
|
||||
|
// const center = document.getElementById(".center");
|
||||
|
// if (center) {
|
||||
|
// const content = center.innerHTML;
|
||||
|
// center.innerHTML = "";
|
||||
|
// center.innerHTML = content;
|
||||
|
// }
|
||||
|
// }
|
||||
|
// };
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
setPointerLineStatusAll('none'); |
||||
|
|
||||
|
for (const key in pointerMap) { |
||||
|
const target = document.getElementById(key); |
||||
|
const item = pointerMap[key]; |
||||
|
if (target) { |
||||
|
target.onclick = () => { |
||||
|
setPointerLineStatusAll('none'); |
||||
|
const t = document.getElementById(item.lineId) as HTMLElement; |
||||
|
setPointerLineStatus(t, 'block'); |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const getToolTipCloseElement = (): HTMLElement => { |
||||
|
return document.querySelector('.njhl-tool-tip .title .close'); |
||||
|
}; |
||||
|
|
||||
|
const getToolTipElement = (): HTMLElement => { |
||||
|
return document.querySelector('.njhl-tool-tip'); |
||||
|
}; |
||||
|
|
||||
|
const setToolTipStatus = (status: string): void => { |
||||
|
const target = getToolTipElement(); |
||||
|
if (target) { |
||||
|
target.style.display = status; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const initCloseToolTip = (): void => { |
||||
|
const target = getToolTipCloseElement(); |
||||
|
if (target) { |
||||
|
target.onclick = () => { |
||||
|
setToolTipStatus('none'); |
||||
|
}; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
export const init = (state: IObject, target: HTMLElement): void => { |
||||
|
initToolTip(state); |
||||
|
initLine(); |
||||
|
initCloseToolTip(); |
||||
|
|
||||
|
state.dragStretch = new dragStretchService(target); |
||||
|
}; |
||||
@ -0,0 +1,110 @@ |
|||||
|
<template> |
||||
|
<div class="bar"> |
||||
|
<div :class="['flex-absolute', item.data && item.data.length === 3 ? 'around' : '']"> |
||||
|
<div :class="['item']" v-for="(val, index) in item.data || []" :key="index"> |
||||
|
<img :src="$util.getImg('/src/assets/images/njhl/' + val.icon + '.png')" alt="" /> |
||||
|
|
||||
|
<span class="label">{{ val.label }}</span> |
||||
|
<span class="value">{{ val.value }}</span> |
||||
|
<span class="unit">{{ val.unit }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, reactive, toRefs } from 'vue'; |
||||
|
import { IObject } from '@/types/interface'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
name: 'bar', |
||||
|
props: { |
||||
|
item: { |
||||
|
type: Object, |
||||
|
default: () => ({}), |
||||
|
}, |
||||
|
}, |
||||
|
emits: ['set-val'], |
||||
|
setup() { |
||||
|
const state = reactive({}) as IObject; |
||||
|
|
||||
|
const methods = {}; |
||||
|
|
||||
|
return { |
||||
|
...toRefs(state), |
||||
|
...methods, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
.bar { |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
|
||||
|
> .flex-absolute { |
||||
|
padding: 0 0 6px 0; |
||||
|
// overflow-y: auto; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
height: 100%; |
||||
|
color: #00caff; |
||||
|
&.around { |
||||
|
justify-content: space-around; |
||||
|
.item { |
||||
|
&:not(:last-child) ::after { |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
height: 1px; |
||||
|
left: 0; |
||||
|
bottom: -20px; |
||||
|
content: ''; |
||||
|
background-color: rgba(#70c5ff, 0.1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
> .item { |
||||
|
position: relative; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
width: 394px; |
||||
|
|
||||
|
> img { |
||||
|
margin-right: 16px; |
||||
|
width: 39px; |
||||
|
height: 39px; |
||||
|
} |
||||
|
|
||||
|
> .label { |
||||
|
width: 45%; |
||||
|
font-size: 20px; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
> .value { |
||||
|
width: 20%; |
||||
|
color: #ffd200; |
||||
|
font-family: 'Alibaba PuHuiTi Heavy'; //阿里巴巴 普惠体 |
||||
|
font-size: 24px; |
||||
|
text-align: left; |
||||
|
padding-right: 10px; |
||||
|
color: #00faa8; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
> .unit { |
||||
|
width: 6em; |
||||
|
color: #00e5ff; |
||||
|
font-family: 'Alibaba PuHuiTi Heavy'; //阿里巴巴 普惠体 |
||||
|
font-size: 16px; |
||||
|
text-align: right; |
||||
|
// font-weight: bold; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,117 @@ |
|||||
|
<template> |
||||
|
<div class="block" ref="blockRef"> |
||||
|
<div :class="['title']"> |
||||
|
<span>{{ item.title || '' }}</span> |
||||
|
|
||||
|
<div class="title-right"> |
||||
|
<el-select :model-value="dataForm.code" v-if="item.select" @change="$emit('change-code', $event)"><el-option v-for="(val, key, index) in dataForm.codeMap || {}" :key="index" :label="key" :value="key"></el-option></el-select> |
||||
|
<span class="unit" v-if="item.unit">{{ item.unit }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="main"> |
||||
|
<slot></slot> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { computed, defineComponent, nextTick, onMounted, reactive, toRefs } from 'vue'; |
||||
|
import { IObject } from '@/types/interface'; |
||||
|
import utilService from '@/service/utilService'; |
||||
|
export default defineComponent({ |
||||
|
name: 'block', |
||||
|
props: { item: { type: Object, default: () => ({}) }, dataForm: { type: Object, default: () => ({}) } }, |
||||
|
setup(props) { |
||||
|
const state = reactive({ |
||||
|
blockRef: null, |
||||
|
}); |
||||
|
|
||||
|
return { |
||||
|
...toRefs(state), |
||||
|
}; |
||||
|
}, |
||||
|
emits: ['change-code'], |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
.block { |
||||
|
width: 484px; |
||||
|
height: 318px; |
||||
|
background: url('@/assets/images/njhl/block.png') no-repeat center; |
||||
|
background-size: 100% 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
|
||||
|
> .title { |
||||
|
position: relative; |
||||
|
// height: v-bind("getSizeByType.titleHeight"); |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
padding: 10px 38px; |
||||
|
color: #00e5ff; |
||||
|
|
||||
|
> span { |
||||
|
font-size: 20px; |
||||
|
font-family: Microsoft YaHei; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
> .title-right { |
||||
|
position: absolute; |
||||
|
top: 20px; |
||||
|
right: 20px; |
||||
|
|
||||
|
::v-deep .el-select { |
||||
|
width: 100px; |
||||
|
|
||||
|
.el-input__wrapper { |
||||
|
background: transparent; |
||||
|
padding-right: 20px; |
||||
|
.el-input__inner { |
||||
|
color: #fff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-input__suffix-inner i { |
||||
|
color: #0084ff; |
||||
|
} |
||||
|
|
||||
|
.el-select:hover, |
||||
|
.el-input__wrapper { |
||||
|
box-shadow: 0 0 0 1px #0084ff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.unit { |
||||
|
display: inline-block; |
||||
|
margin-left: 8px; |
||||
|
width: 2em; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
> .dot { |
||||
|
> span { |
||||
|
padding-left: 25px; |
||||
|
} |
||||
|
|
||||
|
&:before { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 50%; |
||||
|
content: ''; |
||||
|
width: 14px; |
||||
|
height: 41px; |
||||
|
transform: translateY(-50%); |
||||
|
background: rgba(#3c8ef5, 0.34); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
> .main { |
||||
|
position: relative; |
||||
|
flex: 1; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,102 @@ |
|||||
|
<template> |
||||
|
<div class="njhl-pop"> |
||||
|
<div class="icon"> |
||||
|
<img :src="getIcon" alt="" /> |
||||
|
</div> |
||||
|
<div class="right"> |
||||
|
<div class="wrap"> |
||||
|
<div class="top">{{ item.label }}</div> |
||||
|
<div class="bottom"> |
||||
|
<div class="wrap"> |
||||
|
<b class="orange">{{ item.value }}</b> |
||||
|
<span>{{ item.unit }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import utilService from '@/service/utilService'; |
||||
|
import { computed, defineComponent } from 'vue'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
name: 'pop', |
||||
|
props: { item: { type: Object, default: () => ({}) }, index: { type: Number } }, |
||||
|
setup(props) { |
||||
|
const getIcon = computed(() => utilService.getImg('/src/assets/images/njhl/pop_' + props.index + '.png')); |
||||
|
|
||||
|
return { |
||||
|
getIcon, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
.njhl-pop { |
||||
|
width: 199px; |
||||
|
height: 86px; |
||||
|
background: url('@/assets/images/njhl/pop.png') no-repeat center; |
||||
|
|
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
color: #fff; |
||||
|
padding: 0 12px; |
||||
|
> .icon { |
||||
|
margin-right: 12px; |
||||
|
img { |
||||
|
width: 41px; |
||||
|
height: 41px; |
||||
|
} |
||||
|
} |
||||
|
> .right { |
||||
|
position: relative; |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
height: 100%; |
||||
|
> .wrap { |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
> .top { |
||||
|
color: #00caff; |
||||
|
font-size: 18px; |
||||
|
margin: 6px 0; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
> .bottom { |
||||
|
flex: 1; |
||||
|
position: relative; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
color: #00faa8; |
||||
|
> .wrap { |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
display: flex; |
||||
|
align-items: baseline; |
||||
|
b { |
||||
|
flex: 1; |
||||
|
font-size: 25px; |
||||
|
margin-right: 7px; |
||||
|
} |
||||
|
span { |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,122 @@ |
|||||
|
<template> |
||||
|
<div class="njhl-tool-tip"> |
||||
|
<div class="title"> |
||||
|
<span>此建筑月用能统计</span> |
||||
|
<div class="close"></div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="content"> |
||||
|
<div class="item" v-for="(item, index) in list" :key="index"> |
||||
|
<div class="left"> |
||||
|
<img :src="$util.getImg('/src/assets/images/njhl/tooltip/' + item.key + '.png')" alt="" /> |
||||
|
<span>{{ item.label }}</span> |
||||
|
</div> |
||||
|
<div class="right">{{ item.value }}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { IObject } from '@/types/interface'; |
||||
|
import { defineComponent, reactive, toRefs, watch } from 'vue'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
props: { data: { type: Object, default: () => ({}) } }, |
||||
|
setup(props) { |
||||
|
const state = reactive({ |
||||
|
list: [ |
||||
|
{ label: '电用量(kWh):', value: '--', key: 'electricValue' }, |
||||
|
{ label: '水用量(t):', value: '--', key: 'waterValue' }, |
||||
|
{ label: '蒸汽用量(t):', value: '--', key: 'steamValue' }, |
||||
|
{ label: '压缩空气(Nm³):', value: '--', key: 'airValue' }, |
||||
|
], |
||||
|
}); |
||||
|
|
||||
|
watch( |
||||
|
() => props.data, |
||||
|
(newVal: IObject) => { |
||||
|
for (const item of state.list) { |
||||
|
item.value = newVal ? newVal[item.key] ?? '--' : '--'; |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
return { |
||||
|
...toRefs(state), |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.njhl-tool-tip { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
width: 289px; |
||||
|
height: 253px; |
||||
|
color: #fff; |
||||
|
background: url('@/assets/images/njhl/tooltip/bg.png') no-repeat center; |
||||
|
background-size: 100% 100%; |
||||
|
transition: all 0.4s; |
||||
|
z-index: 9999; |
||||
|
flex-direction: column; |
||||
|
display: none; |
||||
|
> .title { |
||||
|
position: relative; |
||||
|
color: #34f857; |
||||
|
font-size: 18px; |
||||
|
height: 74px; |
||||
|
line-height: 90px; |
||||
|
font-weight: bold; |
||||
|
padding: 0 16px; |
||||
|
> .close { |
||||
|
cursor: pointer; |
||||
|
position: absolute; |
||||
|
width: 18px; |
||||
|
height: 18px; |
||||
|
top: 33px; |
||||
|
right: 20px; |
||||
|
background: url('@/assets/images/njhl/tooltip/close.png') no-repeat center; |
||||
|
transition: all 0.4s; |
||||
|
&:hover { |
||||
|
transform: scale(1.2); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
> .content { |
||||
|
flex: 1; |
||||
|
padding: 0 16px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
> .item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin: 6px 0; |
||||
|
> .left { |
||||
|
width: 160px; |
||||
|
font-size: 14px; |
||||
|
white-space: nowrap; |
||||
|
> img { |
||||
|
margin-right: 6px; |
||||
|
} |
||||
|
} |
||||
|
> .right { |
||||
|
flex: 1; |
||||
|
text-align: left; |
||||
|
font-weight: bold; |
||||
|
font-size: 18px; |
||||
|
color: #d8e2ff; |
||||
|
line-height: 24px; |
||||
|
text-shadow: 14px 17px 13px rgba(255, 126, 0, 0.06); |
||||
|
background: linear-gradient(0deg, #ff5700 0%, #ffde00 100%); |
||||
|
-webkit-background-clip: text; |
||||
|
-webkit-text-fill-color: transparent; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,503 @@ |
|||||
|
<template> |
||||
|
<div class="borads-index"> |
||||
|
<screen-adapter class="adapter"> |
||||
|
<div class="boards-container"> |
||||
|
<div class="center" title="使用鼠标左键、滚轮实现拖拽、放大缩小。"></div> |
||||
|
<div class="top"> |
||||
|
<div class="title" @click="reset" title="点击此标题将鸟瞰图及管线恢复成初始状态。">南京海陵药业能源管理平台</div> |
||||
|
<div class="time" v-if="timeCount && timeCount.ts > 0"> |
||||
|
<div class="time-left"> |
||||
|
{{ $m(timeCount.ts).format('HH:mm:ss') }} |
||||
|
</div> |
||||
|
<div class="time-right"> |
||||
|
<div>{{ $date.getDay(timeCount.ts) }}</div> |
||||
|
<div> |
||||
|
{{ $m(timeCount.ts).format('YYYY/MM/DD') }} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="pop"> |
||||
|
<pop v-for="(item, index) in pop" :key="index" :item="item" :index="index"></pop> |
||||
|
</div> |
||||
|
<div class="left"> |
||||
|
<block v-for="(item, index) in left" :key="index" :item="item" :data-form="dataForm" @change-code="dataForm.code = $event"> |
||||
|
<component :is="item.comp" :key="index" :item="item" :option="item.option" tip-loop></component> |
||||
|
</block> |
||||
|
</div> |
||||
|
<div class="right"> |
||||
|
<block v-for="(item, index) in right" :key="index" :item="item" :data-form="dataForm" @change-code="dataForm.code = $event"> |
||||
|
<component :is="item.comp" :key="index" :item="item" :option="item.option" tip-loop></component> |
||||
|
</block> |
||||
|
</div> |
||||
|
</div> |
||||
|
<tooltip :data="toolTipData" /> |
||||
|
</screen-adapter> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, reactive, toRefs, onMounted, nextTick, watch, onBeforeUnmount } from 'vue'; |
||||
|
import ScreenAdapter from '@/components/screen-adapter.vue'; |
||||
|
import Block from './comp/block.vue'; |
||||
|
import Bar from './comp/bar.vue'; |
||||
|
import Pop from './comp/pop.vue'; |
||||
|
import timeCountHooks from '@/hooks/time-count'; |
||||
|
import { useFetch } from '@/hooks/fetch'; |
||||
|
import utilService from '@/service/utilService'; |
||||
|
import Chart from '@/components/chart.vue'; |
||||
|
import { costStatistic, elecPayload, monthEnergyUsageTrend, usageRanking } from './common/model'; |
||||
|
import { IObject } from '@/types/interface'; |
||||
|
import moment from 'moment'; |
||||
|
import toolHooks from '@/hooks/tool'; |
||||
|
import { init, setPointerLineStatusAll } from './common/style'; |
||||
|
import Tooltip from './comp/tooltip.vue'; |
||||
|
import switchScreenHooks from '@/hooks/switch-screen'; |
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
ScreenAdapter, |
||||
|
Tooltip, |
||||
|
Block, |
||||
|
Chart, |
||||
|
|
||||
|
Bar, |
||||
|
Pop, |
||||
|
}, |
||||
|
setup() { |
||||
|
const { timeCount } = timeCountHooks(); |
||||
|
const { generateSvg2Dom } = toolHooks(); |
||||
|
|
||||
|
const state = reactive({ |
||||
|
dragStretch: null, |
||||
|
toolTipData: {}, |
||||
|
timer: null, |
||||
|
dataForm: { |
||||
|
code: '电', |
||||
|
codeMap: { 电: 'kWh', 水: 't', 蒸汽: 't', 压缩空气: 'Nm³' }, |
||||
|
}, |
||||
|
timeCount, |
||||
|
pop: [ |
||||
|
{ |
||||
|
key: 'yearCarbon', |
||||
|
icon: '', |
||||
|
label: '年碳排放量', |
||||
|
value: '--', |
||||
|
unit: 'tCO₂', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'monthConsumptionValue', |
||||
|
icon: '', |
||||
|
label: '月综合能耗', |
||||
|
value: '--', |
||||
|
unit: 'tce', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'yearConsumptionValue', |
||||
|
icon: '', |
||||
|
label: '年综合能耗', |
||||
|
value: '--', |
||||
|
unit: 'tce', |
||||
|
}, |
||||
|
], |
||||
|
left: [ |
||||
|
{ |
||||
|
comp: 'bar', |
||||
|
title: '月用能统计', |
||||
|
data: [ |
||||
|
{ |
||||
|
key: 'electricDayValue', |
||||
|
icon: 'elec', |
||||
|
label: '电用量', |
||||
|
value: '', |
||||
|
unit: '万kWh', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'waterDayValue', |
||||
|
icon: 'water', |
||||
|
label: '水用量', |
||||
|
value: '', |
||||
|
unit: 't', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'steamDayValue', |
||||
|
icon: 'steam', |
||||
|
label: '蒸汽用量', |
||||
|
value: '', |
||||
|
unit: 't', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'airDayValue', |
||||
|
icon: 'air', |
||||
|
label: '压缩空气用量', |
||||
|
value: '', |
||||
|
unit: 'Nm³', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'gasValue', |
||||
|
icon: 'gas', |
||||
|
label: '天然气用量', |
||||
|
value: '', |
||||
|
unit: 'Nm³', |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
title: '年用能统计', |
||||
|
comp: 'bar', |
||||
|
data: [ |
||||
|
{ |
||||
|
key: 'electricDayValue', |
||||
|
icon: 'elec', |
||||
|
label: '电用量', |
||||
|
value: '', |
||||
|
unit: '万kWh', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'waterDayValue', |
||||
|
icon: 'water', |
||||
|
label: '水用量', |
||||
|
value: '', |
||||
|
unit: 't', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'steamDayValue', |
||||
|
icon: 'steam', |
||||
|
label: '蒸汽用量', |
||||
|
value: '', |
||||
|
unit: 't', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'airDayValue', |
||||
|
icon: 'air', |
||||
|
label: '压缩空气用量', |
||||
|
value: '', |
||||
|
unit: 'Nm³', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'gasValue', |
||||
|
icon: 'gas', |
||||
|
label: '天然气用量', |
||||
|
value: '', |
||||
|
unit: 'Nm³', |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
title: '当月用能趋势', |
||||
|
comp: 'chart', |
||||
|
option: monthEnergyUsageTrend(), |
||||
|
unit: 'kWh', |
||||
|
select: true, |
||||
|
}, |
||||
|
], |
||||
|
right: [ |
||||
|
{ |
||||
|
comp: 'chart', |
||||
|
title: '能耗费用统计(月)', |
||||
|
option: costStatistic(), |
||||
|
unit: '元', |
||||
|
}, |
||||
|
{ |
||||
|
comp: 'chart', |
||||
|
title: '用能排行(月)', |
||||
|
option: usageRanking(), |
||||
|
unit: 'kWh', |
||||
|
select: true, |
||||
|
}, |
||||
|
{ |
||||
|
comp: 'chart', |
||||
|
title: '当日电力负荷', |
||||
|
option: elecPayload(), |
||||
|
unit: 'kWh', |
||||
|
}, |
||||
|
], |
||||
|
}) as IObject; |
||||
|
|
||||
|
const changeType = (type: string) => { |
||||
|
const c = state.dataForm.code; |
||||
|
const u = state.dataForm.codeMap[c]; |
||||
|
state.left[2].unit = u; |
||||
|
state.right[1].unit = u; |
||||
|
|
||||
|
//当月用能趋势 |
||||
|
useFetch('/board/monthEnergy/analyse', { |
||||
|
data: { |
||||
|
month: moment().format('YYYY-MM'), |
||||
|
type, |
||||
|
}, |
||||
|
cb: (res: any) => { |
||||
|
if (utilService.isValidObject(res) && utilService.isValidArray(res.currentMonthData)) { |
||||
|
const d = res.currentMonthData; |
||||
|
state.left[2].option = monthEnergyUsageTrend(d); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
//用能排行(月) |
||||
|
useFetch('/board/monthEnergy/ranking', { |
||||
|
data: { |
||||
|
day: moment().format('YYYY-MM'), |
||||
|
type, |
||||
|
}, |
||||
|
cb: (res: any) => { |
||||
|
if (utilService.isValidArray(res)) { |
||||
|
state.right[1].option = usageRanking(res); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const fn = () => { |
||||
|
//三个小气泡 |
||||
|
useFetch('/board/carbonAndConsumption', { |
||||
|
cb: (res: any) => { |
||||
|
if (utilService.isValidObject(res)) { |
||||
|
for (const item of state.pop) { |
||||
|
item.value = res[item.key] ?? '--'; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
//月用能统计 |
||||
|
useFetch('/board/eachEnergy', { |
||||
|
cb: (res: any) => { |
||||
|
if (utilService.isValidObject(res)) { |
||||
|
for (const item of state.left[0].data) { |
||||
|
item.value = res[item.key] ?? '--'; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
//年用能统计 |
||||
|
useFetch('/board/eachEnergyYear', { |
||||
|
cb: (res: any) => { |
||||
|
if (utilService.isValidObject(res)) { |
||||
|
for (const item of state.left[1].data) { |
||||
|
item.value = res[item.key] ?? '--'; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
//能耗费用统计 |
||||
|
useFetch('/board/energyCost', { |
||||
|
data: { |
||||
|
day: moment().format('YYYY-MM-DD'), |
||||
|
}, |
||||
|
cb: (res: any) => { |
||||
|
if (utilService.isValidArray(res)) { |
||||
|
state.right[0].option = costStatistic(res); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
//当日电力负荷 |
||||
|
useFetch('/board/qcDayLoad/analyse', { |
||||
|
data: { |
||||
|
day: moment().format('YYYY-MM-DD'), |
||||
|
}, |
||||
|
cb: (res: any) => { |
||||
|
if (utilService.isValidObject(res) && utilService.isValidArray(res.currentMonthData)) { |
||||
|
const d = res.currentMonthData; |
||||
|
state.right[2].option = elecPayload(d); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
changeType(state.dataForm.code); |
||||
|
fn(); |
||||
|
|
||||
|
const reset = () => { |
||||
|
setPointerLineStatusAll('none'); |
||||
|
|
||||
|
state.dragStretch.reset(); |
||||
|
}; |
||||
|
|
||||
|
const methods = { changeType, reset }; |
||||
|
|
||||
|
watch( |
||||
|
() => state.dataForm.code, |
||||
|
(newCode: string) => { |
||||
|
changeType(newCode); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
const getSvg = () => { |
||||
|
debugger; |
||||
|
const target = document.querySelector('.boards-container .center') as HTMLElement; |
||||
|
generateSvg2Dom('/cdn/njhl_bg.svg', target, () => { |
||||
|
target.style.transform = 'scale(1.2)'; |
||||
|
|
||||
|
nextTick(() => { |
||||
|
init(state, target); |
||||
|
// document.getElementById("layer-d-animate").innerHTML = '<animate href="#path23264" attributeName="stroke-dashoffset" dur="15s" to="0" fill="freeze"></animate><animate href="#path23264-3" attributeName="stroke-dashoffset" dur="15s" to="0" fill="freeze"></animate>'; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
getSvg(); |
||||
|
state.timer = setInterval(() => { |
||||
|
changeType(state.dataForm.code); |
||||
|
fn(); |
||||
|
}, 1 * 60 * 1000); |
||||
|
}); |
||||
|
|
||||
|
onBeforeUnmount(() => { |
||||
|
clearInterval(state.timer); |
||||
|
state.timer = null; |
||||
|
}); |
||||
|
|
||||
|
return { ...toRefs(state), ...methods, ...switchScreenHooks({ screen: '1' }) }; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<!-- <style lang="scss"> |
||||
|
.rr-view-ctx-card { |
||||
|
height: 100%; |
||||
|
|
||||
|
.el-card__body { |
||||
|
position: relative; |
||||
|
height: 100%; |
||||
|
} |
||||
|
} |
||||
|
</style> --> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.borads-index { |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
background: #000b40; |
||||
|
|
||||
|
.adapter { |
||||
|
.boards-container { |
||||
|
position: relative; |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
|
||||
|
> .top { |
||||
|
position: relative; |
||||
|
z-index: 2; |
||||
|
height: 88px; |
||||
|
|
||||
|
> .title { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
color: #e2edff; |
||||
|
letter-spacing: 6px; |
||||
|
background: url('@/assets/images/njhl/title.png') no-repeat center; |
||||
|
background-size: 100% 100%; |
||||
|
text-align: center; |
||||
|
font-weight: bold; |
||||
|
font-size: 44px; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
> .time { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 3px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
> .time-left { |
||||
|
position: relative; |
||||
|
font-size: 32px; |
||||
|
margin: 0 60px; |
||||
|
background: linear-gradient(to top, #fff 30%, #3e576f 100%); |
||||
|
-webkit-background-clip: text; |
||||
|
-webkit-text-fill-color: transparent; |
||||
|
font-family: 'Alibaba PuHuiTi Heavy'; //阿里巴巴 普惠体 |
||||
|
|
||||
|
&:after { |
||||
|
position: absolute; |
||||
|
content: ''; |
||||
|
background: #3e576f; |
||||
|
right: -30px; |
||||
|
top: 50%; |
||||
|
width: 1px; |
||||
|
height: 40px; |
||||
|
transform: translate(-50%, -50%); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
> .time-right { |
||||
|
color: rgba(#fff, 0.7); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
> .center { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
width: 1920px; |
||||
|
height: 1080px; |
||||
|
cursor: move; |
||||
|
//background: url("@/assets/images/njhl/bg.png"); |
||||
|
//transform: translate(-50%, -50%); |
||||
|
} |
||||
|
|
||||
|
.icon { |
||||
|
opacity: 0.4; |
||||
|
position: absolute; |
||||
|
top: 8px; |
||||
|
right: 120px; |
||||
|
z-index: 999; |
||||
|
::v-deep svg { |
||||
|
transition: all 80ms; |
||||
|
// opacity: 0.8; |
||||
|
//&:hover { |
||||
|
// width: 35px !important; |
||||
|
// height: 35px !important; |
||||
|
// opacity: 1; |
||||
|
//} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.pop { |
||||
|
position: absolute; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
height: 86px; |
||||
|
left: 50%; |
||||
|
top: 88px; |
||||
|
transform: translate(-50%); |
||||
|
|
||||
|
> * { |
||||
|
margin: 0 40px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.left, |
||||
|
.right { |
||||
|
position: absolute; |
||||
|
top: 88px; |
||||
|
height: calc(100% - 108px); |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.left { |
||||
|
//left: 0; |
||||
|
left: 16px; |
||||
|
} |
||||
|
|
||||
|
.right { |
||||
|
//right: 0; |
||||
|
right: 16px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||