wenlele
2 years ago
119 changed files with 29705 additions and 0 deletions
@ -0,0 +1,19 @@ |
|||
{ |
|||
"presets": [ |
|||
"@babel/preset-react", |
|||
"@babel/preset-env" |
|||
|
|||
], |
|||
"plugins": [ |
|||
"@babel/plugin-proposal-class-properties", |
|||
"@babel/plugin-proposal-object-rest-spread", |
|||
["import", { |
|||
"libraryName": "antd", |
|||
"libraryDirectory": "es" |
|||
|
|||
}] |
|||
], |
|||
"env": { |
|||
"development": {} |
|||
} |
|||
} |
@ -0,0 +1,23 @@ |
|||
{ |
|||
"version": "0.2.0", |
|||
"configurations": [ |
|||
{ |
|||
"name": "Server", |
|||
"type": "node", |
|||
"request": "launch", |
|||
"program": "${workspaceRoot}/server.js", |
|||
"args": [ |
|||
"-u http://127.0.0.1:4000", |
|||
//阿里OSS |
|||
"--aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw", |
|||
"--aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv", |
|||
"--aliOssBucket test-c371", |
|||
"--aliOssRegion oss-cn-hangzhou", |
|||
], |
|||
"outputCapture": "std", |
|||
"env": { |
|||
"NODE_ENV": "development" |
|||
} |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,4 @@ |
|||
// 将设置放入此文件中以覆盖默认值和用户设置。 |
|||
{ |
|||
"editor.fontSize": 16, |
|||
} |
@ -0,0 +1,21 @@ |
|||
FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2 |
|||
|
|||
COPY . /var/app |
|||
|
|||
WORKDIR /var/app |
|||
|
|||
EXPOSE 8080 |
|||
|
|||
RUN npm cache clean -f |
|||
|
|||
RUN npm install --registry http://10.8.30.22:7000 --legacy-peer-deps |
|||
RUN npm run build |
|||
RUN rm -rf client/src |
|||
RUN rm -rf node_modules |
|||
|
|||
RUN npm install --production --registry http://10.8.30.22:7000 |
|||
#RUN npm cache clean -f && npm install --production --force --registry http://10.8.30.22:7000 |
|||
|
|||
CMD ["-u", "http://localhost:8088"] |
|||
|
|||
ENTRYPOINT [ "node", "server.js" ] |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,370 @@ |
|||
*{margin: 0;padding: 0;list-style: none;} |
|||
/* |
|||
KISSY CSS Reset |
|||
理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。 |
|||
2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。 |
|||
3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。 |
|||
特色:1. 适应中文;2. 基于最新主流浏览器。 |
|||
维护:玉伯<lifesinger@gmail.com>, 正淳<ragecarrier@gmail.com> |
|||
*/ |
|||
|
|||
/** 清除内外边距 **/ |
|||
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */ |
|||
dl, dt, dd, ul, ol, li, /* list elements 列表元素 */ |
|||
pre, /* text formatting elements 文本格式元素 */ |
|||
form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */ |
|||
th, td /* table elements 表格元素 */ { |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
/** 设置默认字体 **/ |
|||
body, |
|||
button, input, select, textarea /* for ie */ { |
|||
font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif; |
|||
} |
|||
h1, h2, h3, h4, h5, h6 { font-size: 100%; } |
|||
address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */ |
|||
code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */ |
|||
small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */ |
|||
|
|||
/** 重置列表元素 **/ |
|||
ul, ol { list-style: none; } |
|||
|
|||
/** 重置文本格式元素 **/ |
|||
a { text-decoration: none; } |
|||
a:hover { text-decoration: underline; } |
|||
|
|||
|
|||
/** 重置表单元素 **/ |
|||
legend { color: #000; } /* for ie6 */ |
|||
fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */ |
|||
button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */ |
|||
/* 注:optgroup 无法扶正 */ |
|||
|
|||
/** 重置表格元素 **/ |
|||
table { border-collapse: collapse; border-spacing: 0; } |
|||
|
|||
/* 清除浮动 */ |
|||
.ks-clear:after, .clear:after { |
|||
content: '\20'; |
|||
display: block; |
|||
height: 0; |
|||
clear: both; |
|||
} |
|||
.ks-clear, .clear { |
|||
*zoom: 1; |
|||
} |
|||
|
|||
.main { |
|||
padding: 30px 100px; |
|||
width: 960px; |
|||
margin: 0 auto; |
|||
} |
|||
.main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;} |
|||
|
|||
.helps{margin-top:40px;} |
|||
.helps pre{ |
|||
padding:20px; |
|||
margin:10px 0; |
|||
border:solid 1px #e7e1cd; |
|||
background-color: #fffdef; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.icon_lists{ |
|||
width: 100% !important; |
|||
|
|||
} |
|||
|
|||
.icon_lists li{ |
|||
float:left; |
|||
width: 100px; |
|||
height:180px; |
|||
text-align: center; |
|||
list-style: none !important; |
|||
} |
|||
.icon_lists .icon{ |
|||
font-size: 42px; |
|||
line-height: 100px; |
|||
margin: 10px 0; |
|||
color:#333; |
|||
-webkit-transition: font-size 0.25s ease-out 0s; |
|||
-moz-transition: font-size 0.25s ease-out 0s; |
|||
transition: font-size 0.25s ease-out 0s; |
|||
|
|||
} |
|||
.icon_lists .icon:hover{ |
|||
font-size: 100px; |
|||
} |
|||
|
|||
|
|||
|
|||
.markdown { |
|||
color: #666; |
|||
font-size: 14px; |
|||
line-height: 1.8; |
|||
} |
|||
|
|||
.highlight { |
|||
line-height: 1.5; |
|||
} |
|||
|
|||
.markdown img { |
|||
vertical-align: middle; |
|||
max-width: 100%; |
|||
} |
|||
|
|||
.markdown h1 { |
|||
color: #404040; |
|||
font-weight: 500; |
|||
line-height: 40px; |
|||
margin-bottom: 24px; |
|||
} |
|||
|
|||
.markdown h2, |
|||
.markdown h3, |
|||
.markdown h4, |
|||
.markdown h5, |
|||
.markdown h6 { |
|||
color: #404040; |
|||
margin: 1.6em 0 0.6em 0; |
|||
font-weight: 500; |
|||
clear: both; |
|||
} |
|||
|
|||
.markdown h1 { |
|||
font-size: 28px; |
|||
} |
|||
|
|||
.markdown h2 { |
|||
font-size: 22px; |
|||
} |
|||
|
|||
.markdown h3 { |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.markdown h4 { |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.markdown h5 { |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.markdown h6 { |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.markdown hr { |
|||
height: 1px; |
|||
border: 0; |
|||
background: #e9e9e9; |
|||
margin: 16px 0; |
|||
clear: both; |
|||
} |
|||
|
|||
.markdown p, |
|||
.markdown pre { |
|||
margin: 1em 0; |
|||
} |
|||
|
|||
.markdown > p, |
|||
.markdown > blockquote, |
|||
.markdown > .highlight, |
|||
.markdown > ol, |
|||
.markdown > ul { |
|||
width: 80%; |
|||
} |
|||
|
|||
.markdown ul > li { |
|||
list-style: circle; |
|||
} |
|||
|
|||
.markdown > ul li, |
|||
.markdown blockquote ul > li { |
|||
margin-left: 20px; |
|||
padding-left: 4px; |
|||
} |
|||
|
|||
.markdown > ul li p, |
|||
.markdown > ol li p { |
|||
margin: 0.6em 0; |
|||
} |
|||
|
|||
.markdown ol > li { |
|||
list-style: decimal; |
|||
} |
|||
|
|||
.markdown > ol li, |
|||
.markdown blockquote ol > li { |
|||
margin-left: 20px; |
|||
padding-left: 4px; |
|||
} |
|||
|
|||
.markdown code { |
|||
margin: 0 3px; |
|||
padding: 0 5px; |
|||
background: #eee; |
|||
border-radius: 3px; |
|||
} |
|||
|
|||
.markdown pre { |
|||
border-radius: 6px; |
|||
background: #f7f7f7; |
|||
padding: 20px; |
|||
} |
|||
|
|||
.markdown pre code { |
|||
border: none; |
|||
background: #f7f7f7; |
|||
margin: 0; |
|||
} |
|||
|
|||
.markdown strong, |
|||
.markdown b { |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.markdown > table { |
|||
border-collapse: collapse; |
|||
border-spacing: 0px; |
|||
empty-cells: show; |
|||
border: 1px solid #e9e9e9; |
|||
width: 95%; |
|||
margin-bottom: 24px; |
|||
} |
|||
|
|||
.markdown > table th { |
|||
white-space: nowrap; |
|||
color: #333; |
|||
font-weight: 600; |
|||
|
|||
} |
|||
|
|||
.markdown > table th, |
|||
.markdown > table td { |
|||
border: 1px solid #e9e9e9; |
|||
padding: 8px 16px; |
|||
text-align: left; |
|||
} |
|||
|
|||
.markdown > table th { |
|||
background: #F7F7F7; |
|||
} |
|||
|
|||
.markdown blockquote { |
|||
font-size: 90%; |
|||
color: #999; |
|||
border-left: 4px solid #e9e9e9; |
|||
padding-left: 0.8em; |
|||
margin: 1em 0; |
|||
font-style: italic; |
|||
} |
|||
|
|||
.markdown blockquote p { |
|||
margin: 0; |
|||
} |
|||
|
|||
.markdown .anchor { |
|||
opacity: 0; |
|||
transition: opacity 0.3s ease; |
|||
margin-left: 8px; |
|||
} |
|||
|
|||
.markdown .waiting { |
|||
color: #ccc; |
|||
} |
|||
|
|||
.markdown h1:hover .anchor, |
|||
.markdown h2:hover .anchor, |
|||
.markdown h3:hover .anchor, |
|||
.markdown h4:hover .anchor, |
|||
.markdown h5:hover .anchor, |
|||
.markdown h6:hover .anchor { |
|||
opacity: 1; |
|||
display: inline-block; |
|||
} |
|||
|
|||
.markdown > br, |
|||
.markdown > p > br { |
|||
clear: both; |
|||
} |
|||
|
|||
|
|||
.hljs { |
|||
display: block; |
|||
background: white; |
|||
padding: 0.5em; |
|||
color: #333333; |
|||
overflow-x: auto; |
|||
} |
|||
|
|||
.hljs-comment, |
|||
.hljs-meta { |
|||
color: #969896; |
|||
} |
|||
|
|||
.hljs-string, |
|||
.hljs-variable, |
|||
.hljs-template-variable, |
|||
.hljs-strong, |
|||
.hljs-emphasis, |
|||
.hljs-quote { |
|||
color: #df5000; |
|||
} |
|||
|
|||
.hljs-keyword, |
|||
.hljs-selector-tag, |
|||
.hljs-type { |
|||
color: #a71d5d; |
|||
} |
|||
|
|||
.hljs-literal, |
|||
.hljs-symbol, |
|||
.hljs-bullet, |
|||
.hljs-attribute { |
|||
color: #0086b3; |
|||
} |
|||
|
|||
.hljs-section, |
|||
.hljs-name { |
|||
color: #63a35c; |
|||
} |
|||
|
|||
.hljs-tag { |
|||
color: #333333; |
|||
} |
|||
|
|||
.hljs-title, |
|||
.hljs-attr, |
|||
.hljs-selector-id, |
|||
.hljs-selector-class, |
|||
.hljs-selector-attr, |
|||
.hljs-selector-pseudo { |
|||
color: #795da3; |
|||
} |
|||
|
|||
.hljs-addition { |
|||
color: #55a532; |
|||
background-color: #eaffea; |
|||
} |
|||
|
|||
.hljs-deletion { |
|||
color: #bd2c00; |
|||
background-color: #ffecec; |
|||
} |
|||
|
|||
.hljs-link { |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
pre{ |
|||
background: #fff; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,514 @@ |
|||
|
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"/> |
|||
<title>IconFont</title> |
|||
<link rel="stylesheet" href="demo.css"> |
|||
<link rel="stylesheet" href="iconfont.css"> |
|||
</head> |
|||
<body> |
|||
<div class="main markdown"> |
|||
<h1>IconFont 图标</h1> |
|||
<ul class="icon_lists clear"> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-liuliang"></i> |
|||
<div class="name">流量</div> |
|||
<div class="fontclass">.icon-liuliang</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-iconfontditie"></i> |
|||
<div class="name">轻轨</div> |
|||
<div class="fontclass">.icon-iconfontditie</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-fengsu3"></i> |
|||
<div class="name">风速3</div> |
|||
<div class="fontclass">.icon-fengsu3</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-calendar"></i> |
|||
<div class="name">calendar</div> |
|||
<div class="fontclass">.icon-calendar</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-box"></i> |
|||
<div class="name">box</div> |
|||
<div class="fontclass">.icon-box</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shenheshibai"></i> |
|||
<div class="name">审核失败</div> |
|||
<div class="fontclass">.icon-shenheshibai</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-slope"></i> |
|||
<div class="name">边坡</div> |
|||
<div class="fontclass">.icon-slope</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-icon2"></i> |
|||
<div class="name">公路</div> |
|||
<div class="fontclass">.icon-icon2</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-gnsscaidian"></i> |
|||
<div class="name">GNSS采点</div> |
|||
<div class="fontclass">.icon-gnsscaidian</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-chuanganqishebei"></i> |
|||
<div class="name">传感器设备</div> |
|||
<div class="fontclass">.icon-chuanganqishebei</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-dianliuchuanganqi"></i> |
|||
<div class="name">电流传感器</div> |
|||
<div class="fontclass">.icon-dianliuchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-dianyachuanganqi"></i> |
|||
<div class="name">电压传感器</div> |
|||
<div class="fontclass">.icon-dianyachuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-wenduchuanganqi"></i> |
|||
<div class="name">温度传感器</div> |
|||
<div class="fontclass">.icon-wenduchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-xinjian"></i> |
|||
<div class="name">新建</div> |
|||
<div class="fontclass">.icon-xinjian</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-handong"></i> |
|||
<div class="name">涵洞</div> |
|||
<div class="fontclass">.icon-handong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-guanwanggongcheng"></i> |
|||
<div class="name">管网工程</div> |
|||
<div class="fontclass">.icon-guanwanggongcheng</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shenhe"></i> |
|||
<div class="name">审核</div> |
|||
<div class="fontclass">.icon-shenhe</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-zhihuishequ"></i> |
|||
<div class="name">智慧城市</div> |
|||
<div class="fontclass">.icon-zhihuishequ</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-bianpoweiyi"></i> |
|||
<div class="name">边坡位移</div> |
|||
<div class="fontclass">.icon-bianpoweiyi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-jianzhu"></i> |
|||
<div class="name">建筑</div> |
|||
<div class="fontclass">.icon-jianzhu</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-chuguan"></i> |
|||
<div class="name">储罐</div> |
|||
<div class="fontclass">.icon-chuguan</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-suidao"></i> |
|||
<div class="name">隧道</div> |
|||
<div class="fontclass">.icon-suidao</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-data"></i> |
|||
<div class="name">data</div> |
|||
<div class="fontclass">.icon-data</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-kuangshankaicai"></i> |
|||
<div class="name">矿山开采</div> |
|||
<div class="fontclass">.icon-kuangshankaicai</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-wangluo"></i> |
|||
<div class="name">网络</div> |
|||
<div class="fontclass">.icon-wangluo</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-jiankong"></i> |
|||
<div class="name">监控</div> |
|||
<div class="fontclass">.icon-jiankong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-dashuju"></i> |
|||
<div class="name">大数据</div> |
|||
<div class="fontclass">.icon-dashuju</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shuju"></i> |
|||
<div class="name">数据库</div> |
|||
<div class="fontclass">.icon-shuju</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shenhechenggong"></i> |
|||
<div class="name">审核成功</div> |
|||
<div class="fontclass">.icon-shenhechenggong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-jiankong1"></i> |
|||
<div class="name">监控</div> |
|||
<div class="fontclass">.icon-jiankong1</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-wangluoxitong"></i> |
|||
<div class="name">网络系统</div> |
|||
<div class="fontclass">.icon-wangluoxitong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-dingwei"></i> |
|||
<div class="name">定位</div> |
|||
<div class="fontclass">.icon-dingwei</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-xitongyunzhuanqingkuang"></i> |
|||
<div class="name">系统运转情况</div> |
|||
<div class="fontclass">.icon-xitongyunzhuanqingkuang</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-chakan"></i> |
|||
<div class="name">查看</div> |
|||
<div class="fontclass">.icon-chakan</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-lianjie"></i> |
|||
<div class="name">链接</div> |
|||
<div class="fontclass">.icon-lianjie</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shujudaochu-01"></i> |
|||
<div class="name">数据导出-01</div> |
|||
<div class="fontclass">.icon-shujudaochu-01</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-xitongzhuangtai"></i> |
|||
<div class="name">系统状态</div> |
|||
<div class="fontclass">.icon-xitongzhuangtai</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-xiaofeimingxidan"></i> |
|||
<div class="name">消费明细单</div> |
|||
<div class="fontclass">.icon-xiaofeimingxidan</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-SQLshenhe"></i> |
|||
<div class="name">SQL审核</div> |
|||
<div class="fontclass">.icon-SQLshenhe</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-aislogo"></i> |
|||
<div class="name">aislogo</div> |
|||
<div class="fontclass">.icon-aislogo</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-qiao"></i> |
|||
<div class="name">桥</div> |
|||
<div class="fontclass">.icon-qiao</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-tashiqizhongji"></i> |
|||
<div class="name">塔式起重机</div> |
|||
<div class="fontclass">.icon-tashiqizhongji</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-dwggeshi"></i> |
|||
<div class="name">dwg格式</div> |
|||
<div class="fontclass">.icon-dwggeshi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-luyouqi"></i> |
|||
<div class="name">路由器</div> |
|||
<div class="fontclass">.icon-luyouqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-anzhuangshigong-xianxing"></i> |
|||
<div class="name">244安装、施工-线性</div> |
|||
<div class="fontclass">.icon-anzhuangshigong-xianxing</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shaixuanguolv"></i> |
|||
<div class="name">245筛选过滤</div> |
|||
<div class="fontclass">.icon-shaixuanguolv</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-anzhuangshigong"></i> |
|||
<div class="name">244安装、施工</div> |
|||
<div class="fontclass">.icon-anzhuangshigong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-tiaoxingtu-xianxing"></i> |
|||
<div class="name">408条形图-线性</div> |
|||
<div class="fontclass">.icon-tiaoxingtu-xianxing</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-zhexiantu-xianxing"></i> |
|||
<div class="name">409折线图-线性</div> |
|||
<div class="fontclass">.icon-zhexiantu-xianxing</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-tieta"></i> |
|||
<div class="name">铁塔</div> |
|||
<div class="fontclass">.icon-tieta</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_wendangtxt"></i> |
|||
<div class="name">800格式_文档txt</div> |
|||
<div class="fontclass">.icon-geshi_wendangtxt</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_wendangdoc"></i> |
|||
<div class="name">801格式_文档doc</div> |
|||
<div class="fontclass">.icon-geshi_wendangdoc</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_wendangpdf"></i> |
|||
<div class="name">807格式_文档pdf</div> |
|||
<div class="fontclass">.icon-geshi_wendangpdf</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_wendangxls"></i> |
|||
<div class="name">803格式_文档xls</div> |
|||
<div class="fontclass">.icon-geshi_wendangxls</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_tongyongwendang"></i> |
|||
<div class="name">819格式_通用文档</div> |
|||
<div class="fontclass">.icon-geshi_tongyongwendang</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_shipinmp"></i> |
|||
<div class="name">840格式_视频mp4</div> |
|||
<div class="fontclass">.icon-geshi_shipinmp</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_tupianjpg"></i> |
|||
<div class="name">860格式_图片jpg</div> |
|||
<div class="fontclass">.icon-geshi_tupianjpg</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-geshi_tupianpng"></i> |
|||
<div class="name">865格式_图片png</div> |
|||
<div class="fontclass">.icon-geshi_tupianpng</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-guangzhaochuanganqi"></i> |
|||
<div class="name">光照传感器</div> |
|||
<div class="fontclass">.icon-guangzhaochuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-building"></i> |
|||
<div class="name">建筑</div> |
|||
<div class="fontclass">.icon-building</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-yanwuchuanganqi"></i> |
|||
<div class="name">烟雾传感器</div> |
|||
<div class="fontclass">.icon-yanwuchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shizheng"></i> |
|||
<div class="name">市政</div> |
|||
<div class="fontclass">.icon-shizheng</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-chuanganqi"></i> |
|||
<div class="name">传感器</div> |
|||
<div class="fontclass">.icon-chuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-WSD"></i> |
|||
<div class="name">温湿度传感器</div> |
|||
<div class="fontclass">.icon-WSD</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-yalichuanganqi"></i> |
|||
<div class="name">压力传感器</div> |
|||
<div class="fontclass">.icon-yalichuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-yinglichuanganqi"></i> |
|||
<div class="name">应力传感器</div> |
|||
<div class="fontclass">.icon-yinglichuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-chenjiangchuanganqi"></i> |
|||
<div class="name">沉降传感器</div> |
|||
<div class="fontclass">.icon-chenjiangchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-yalichuanganqi1"></i> |
|||
<div class="name">压力传感器</div> |
|||
<div class="fontclass">.icon-yalichuanganqi1</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-YWC"></i> |
|||
<div class="name">液位传感器</div> |
|||
<div class="fontclass">.icon-YWC</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-computer"></i> |
|||
<div class="name">computer</div> |
|||
<div class="fontclass">.icon-computer</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-empty"></i> |
|||
<div class="name">empty</div> |
|||
<div class="fontclass">.icon-empty</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-offline"></i> |
|||
<div class="name">offline</div> |
|||
<div class="fontclass">.icon-offline</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-daba"></i> |
|||
<div class="name">大坝</div> |
|||
<div class="fontclass">.icon-daba</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shenbuweiyi"></i> |
|||
<div class="name">深部位移</div> |
|||
<div class="fontclass">.icon-shenbuweiyi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-maosuochuanganqi"></i> |
|||
<div class="name">锚索传感器</div> |
|||
<div class="fontclass">.icon-maosuochuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-yuliangchuanganqi"></i> |
|||
<div class="name">雨量传感器</div> |
|||
<div class="fontclass">.icon-yuliangchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-weiyiji"></i> |
|||
<div class="name">位移计</div> |
|||
<div class="fontclass">.icon-weiyiji</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-qixiangzhan_"></i> |
|||
<div class="name">气象站_1</div> |
|||
<div class="fontclass">.icon-qixiangzhan_</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc icon-shenjikeng"></i> |
|||
<div class="name">深基坑</div> |
|||
<div class="fontclass">.icon-shenjikeng</div> |
|||
</li> |
|||
|
|||
</ul> |
|||
|
|||
<h2 id="font-class-">font-class引用</h2> |
|||
<hr> |
|||
|
|||
<p>font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。</p> |
|||
<p>与unicode使用方式相比,具有如下特点:</p> |
|||
<ul> |
|||
<li>兼容性良好,支持ie8+,及所有现代浏览器。</li> |
|||
<li>相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。</li> |
|||
<li>因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。</li> |
|||
<li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li> |
|||
</ul> |
|||
<p>使用步骤如下:</p> |
|||
<h3 id="-fontclass-">第一步:引入项目下面生成的fontclass代码:</h3> |
|||
|
|||
|
|||
<pre><code class="lang-js hljs javascript"><span class="hljs-comment"><link rel="stylesheet" type="text/css" href="./iconfont.css"></span></code></pre> |
|||
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3> |
|||
<pre><code class="lang-css hljs"><<span class="hljs-selector-tag">i</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">sc</span> <span class="hljs-selector-tag">icon-xxx</span>"></<span class="hljs-selector-tag">i</span>></code></pre> |
|||
<blockquote> |
|||
<p>"sc"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p> |
|||
</blockquote> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,695 @@ |
|||
|
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"/> |
|||
<title>IconFont</title> |
|||
<link rel="stylesheet" href="demo.css"> |
|||
<script src="iconfont.js"></script> |
|||
|
|||
<style type="text/css"> |
|||
.icon { |
|||
/* 通过设置 font-size 来改变图标大小 */ |
|||
width: 1em; height: 1em; |
|||
/* 图标和文字相邻时,垂直对齐 */ |
|||
vertical-align: -0.15em; |
|||
/* 通过设置 color 来改变 SVG 的颜色/fill */ |
|||
fill: currentColor; |
|||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 |
|||
normalize.css 中也包含这行 */ |
|||
overflow: hidden; |
|||
} |
|||
|
|||
</style> |
|||
</head> |
|||
<body> |
|||
<div class="main markdown"> |
|||
<h1>IconFont 图标</h1> |
|||
<ul class="icon_lists clear"> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-liuliang"></use> |
|||
</svg> |
|||
<div class="name">流量</div> |
|||
<div class="fontclass">#icon-liuliang</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-iconfontditie"></use> |
|||
</svg> |
|||
<div class="name">轻轨</div> |
|||
<div class="fontclass">#icon-iconfontditie</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-fengsu3"></use> |
|||
</svg> |
|||
<div class="name">风速3</div> |
|||
<div class="fontclass">#icon-fengsu3</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-calendar"></use> |
|||
</svg> |
|||
<div class="name">calendar</div> |
|||
<div class="fontclass">#icon-calendar</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-box"></use> |
|||
</svg> |
|||
<div class="name">box</div> |
|||
<div class="fontclass">#icon-box</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shenheshibai"></use> |
|||
</svg> |
|||
<div class="name">审核失败</div> |
|||
<div class="fontclass">#icon-shenheshibai</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-slope"></use> |
|||
</svg> |
|||
<div class="name">边坡</div> |
|||
<div class="fontclass">#icon-slope</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-icon2"></use> |
|||
</svg> |
|||
<div class="name">公路</div> |
|||
<div class="fontclass">#icon-icon2</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-gnsscaidian"></use> |
|||
</svg> |
|||
<div class="name">GNSS采点</div> |
|||
<div class="fontclass">#icon-gnsscaidian</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-chuanganqishebei"></use> |
|||
</svg> |
|||
<div class="name">传感器设备</div> |
|||
<div class="fontclass">#icon-chuanganqishebei</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-dianliuchuanganqi"></use> |
|||
</svg> |
|||
<div class="name">电流传感器</div> |
|||
<div class="fontclass">#icon-dianliuchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-dianyachuanganqi"></use> |
|||
</svg> |
|||
<div class="name">电压传感器</div> |
|||
<div class="fontclass">#icon-dianyachuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-wenduchuanganqi"></use> |
|||
</svg> |
|||
<div class="name">温度传感器</div> |
|||
<div class="fontclass">#icon-wenduchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-xinjian"></use> |
|||
</svg> |
|||
<div class="name">新建</div> |
|||
<div class="fontclass">#icon-xinjian</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-handong"></use> |
|||
</svg> |
|||
<div class="name">涵洞</div> |
|||
<div class="fontclass">#icon-handong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-guanwanggongcheng"></use> |
|||
</svg> |
|||
<div class="name">管网工程</div> |
|||
<div class="fontclass">#icon-guanwanggongcheng</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shenhe"></use> |
|||
</svg> |
|||
<div class="name">审核</div> |
|||
<div class="fontclass">#icon-shenhe</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-zhihuishequ"></use> |
|||
</svg> |
|||
<div class="name">智慧城市</div> |
|||
<div class="fontclass">#icon-zhihuishequ</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-bianpoweiyi"></use> |
|||
</svg> |
|||
<div class="name">边坡位移</div> |
|||
<div class="fontclass">#icon-bianpoweiyi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-jianzhu"></use> |
|||
</svg> |
|||
<div class="name">建筑</div> |
|||
<div class="fontclass">#icon-jianzhu</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-chuguan"></use> |
|||
</svg> |
|||
<div class="name">储罐</div> |
|||
<div class="fontclass">#icon-chuguan</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-suidao"></use> |
|||
</svg> |
|||
<div class="name">隧道</div> |
|||
<div class="fontclass">#icon-suidao</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-data"></use> |
|||
</svg> |
|||
<div class="name">data</div> |
|||
<div class="fontclass">#icon-data</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-kuangshankaicai"></use> |
|||
</svg> |
|||
<div class="name">矿山开采</div> |
|||
<div class="fontclass">#icon-kuangshankaicai</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-wangluo"></use> |
|||
</svg> |
|||
<div class="name">网络</div> |
|||
<div class="fontclass">#icon-wangluo</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-jiankong"></use> |
|||
</svg> |
|||
<div class="name">监控</div> |
|||
<div class="fontclass">#icon-jiankong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-dashuju"></use> |
|||
</svg> |
|||
<div class="name">大数据</div> |
|||
<div class="fontclass">#icon-dashuju</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shuju"></use> |
|||
</svg> |
|||
<div class="name">数据库</div> |
|||
<div class="fontclass">#icon-shuju</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shenhechenggong"></use> |
|||
</svg> |
|||
<div class="name">审核成功</div> |
|||
<div class="fontclass">#icon-shenhechenggong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-jiankong1"></use> |
|||
</svg> |
|||
<div class="name">监控</div> |
|||
<div class="fontclass">#icon-jiankong1</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-wangluoxitong"></use> |
|||
</svg> |
|||
<div class="name">网络系统</div> |
|||
<div class="fontclass">#icon-wangluoxitong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-dingwei"></use> |
|||
</svg> |
|||
<div class="name">定位</div> |
|||
<div class="fontclass">#icon-dingwei</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-xitongyunzhuanqingkuang"></use> |
|||
</svg> |
|||
<div class="name">系统运转情况</div> |
|||
<div class="fontclass">#icon-xitongyunzhuanqingkuang</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-chakan"></use> |
|||
</svg> |
|||
<div class="name">查看</div> |
|||
<div class="fontclass">#icon-chakan</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-lianjie"></use> |
|||
</svg> |
|||
<div class="name">链接</div> |
|||
<div class="fontclass">#icon-lianjie</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shujudaochu-01"></use> |
|||
</svg> |
|||
<div class="name">数据导出-01</div> |
|||
<div class="fontclass">#icon-shujudaochu-01</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-xitongzhuangtai"></use> |
|||
</svg> |
|||
<div class="name">系统状态</div> |
|||
<div class="fontclass">#icon-xitongzhuangtai</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-xiaofeimingxidan"></use> |
|||
</svg> |
|||
<div class="name">消费明细单</div> |
|||
<div class="fontclass">#icon-xiaofeimingxidan</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-SQLshenhe"></use> |
|||
</svg> |
|||
<div class="name">SQL审核</div> |
|||
<div class="fontclass">#icon-SQLshenhe</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-aislogo"></use> |
|||
</svg> |
|||
<div class="name">aislogo</div> |
|||
<div class="fontclass">#icon-aislogo</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-qiao"></use> |
|||
</svg> |
|||
<div class="name">桥</div> |
|||
<div class="fontclass">#icon-qiao</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-tashiqizhongji"></use> |
|||
</svg> |
|||
<div class="name">塔式起重机</div> |
|||
<div class="fontclass">#icon-tashiqizhongji</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-dwggeshi"></use> |
|||
</svg> |
|||
<div class="name">dwg格式</div> |
|||
<div class="fontclass">#icon-dwggeshi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-luyouqi"></use> |
|||
</svg> |
|||
<div class="name">路由器</div> |
|||
<div class="fontclass">#icon-luyouqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-anzhuangshigong-xianxing"></use> |
|||
</svg> |
|||
<div class="name">244安装、施工-线性</div> |
|||
<div class="fontclass">#icon-anzhuangshigong-xianxing</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shaixuanguolv"></use> |
|||
</svg> |
|||
<div class="name">245筛选过滤</div> |
|||
<div class="fontclass">#icon-shaixuanguolv</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-anzhuangshigong"></use> |
|||
</svg> |
|||
<div class="name">244安装、施工</div> |
|||
<div class="fontclass">#icon-anzhuangshigong</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-tiaoxingtu-xianxing"></use> |
|||
</svg> |
|||
<div class="name">408条形图-线性</div> |
|||
<div class="fontclass">#icon-tiaoxingtu-xianxing</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-zhexiantu-xianxing"></use> |
|||
</svg> |
|||
<div class="name">409折线图-线性</div> |
|||
<div class="fontclass">#icon-zhexiantu-xianxing</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-tieta"></use> |
|||
</svg> |
|||
<div class="name">铁塔</div> |
|||
<div class="fontclass">#icon-tieta</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_wendangtxt"></use> |
|||
</svg> |
|||
<div class="name">800格式_文档txt</div> |
|||
<div class="fontclass">#icon-geshi_wendangtxt</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_wendangdoc"></use> |
|||
</svg> |
|||
<div class="name">801格式_文档doc</div> |
|||
<div class="fontclass">#icon-geshi_wendangdoc</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_wendangpdf"></use> |
|||
</svg> |
|||
<div class="name">807格式_文档pdf</div> |
|||
<div class="fontclass">#icon-geshi_wendangpdf</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_wendangxls"></use> |
|||
</svg> |
|||
<div class="name">803格式_文档xls</div> |
|||
<div class="fontclass">#icon-geshi_wendangxls</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_tongyongwendang"></use> |
|||
</svg> |
|||
<div class="name">819格式_通用文档</div> |
|||
<div class="fontclass">#icon-geshi_tongyongwendang</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_shipinmp"></use> |
|||
</svg> |
|||
<div class="name">840格式_视频mp4</div> |
|||
<div class="fontclass">#icon-geshi_shipinmp</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_tupianjpg"></use> |
|||
</svg> |
|||
<div class="name">860格式_图片jpg</div> |
|||
<div class="fontclass">#icon-geshi_tupianjpg</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-geshi_tupianpng"></use> |
|||
</svg> |
|||
<div class="name">865格式_图片png</div> |
|||
<div class="fontclass">#icon-geshi_tupianpng</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-guangzhaochuanganqi"></use> |
|||
</svg> |
|||
<div class="name">光照传感器</div> |
|||
<div class="fontclass">#icon-guangzhaochuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-building"></use> |
|||
</svg> |
|||
<div class="name">建筑</div> |
|||
<div class="fontclass">#icon-building</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-yanwuchuanganqi"></use> |
|||
</svg> |
|||
<div class="name">烟雾传感器</div> |
|||
<div class="fontclass">#icon-yanwuchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shizheng"></use> |
|||
</svg> |
|||
<div class="name">市政</div> |
|||
<div class="fontclass">#icon-shizheng</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-chuanganqi"></use> |
|||
</svg> |
|||
<div class="name">传感器</div> |
|||
<div class="fontclass">#icon-chuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-WSD"></use> |
|||
</svg> |
|||
<div class="name">温湿度传感器</div> |
|||
<div class="fontclass">#icon-WSD</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-yalichuanganqi"></use> |
|||
</svg> |
|||
<div class="name">压力传感器</div> |
|||
<div class="fontclass">#icon-yalichuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-yinglichuanganqi"></use> |
|||
</svg> |
|||
<div class="name">应力传感器</div> |
|||
<div class="fontclass">#icon-yinglichuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-chenjiangchuanganqi"></use> |
|||
</svg> |
|||
<div class="name">沉降传感器</div> |
|||
<div class="fontclass">#icon-chenjiangchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-yalichuanganqi1"></use> |
|||
</svg> |
|||
<div class="name">压力传感器</div> |
|||
<div class="fontclass">#icon-yalichuanganqi1</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-YWC"></use> |
|||
</svg> |
|||
<div class="name">液位传感器</div> |
|||
<div class="fontclass">#icon-YWC</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-computer"></use> |
|||
</svg> |
|||
<div class="name">computer</div> |
|||
<div class="fontclass">#icon-computer</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-empty"></use> |
|||
</svg> |
|||
<div class="name">empty</div> |
|||
<div class="fontclass">#icon-empty</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-offline"></use> |
|||
</svg> |
|||
<div class="name">offline</div> |
|||
<div class="fontclass">#icon-offline</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-daba"></use> |
|||
</svg> |
|||
<div class="name">大坝</div> |
|||
<div class="fontclass">#icon-daba</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shenbuweiyi"></use> |
|||
</svg> |
|||
<div class="name">深部位移</div> |
|||
<div class="fontclass">#icon-shenbuweiyi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-maosuochuanganqi"></use> |
|||
</svg> |
|||
<div class="name">锚索传感器</div> |
|||
<div class="fontclass">#icon-maosuochuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-yuliangchuanganqi"></use> |
|||
</svg> |
|||
<div class="name">雨量传感器</div> |
|||
<div class="fontclass">#icon-yuliangchuanganqi</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-weiyiji"></use> |
|||
</svg> |
|||
<div class="name">位移计</div> |
|||
<div class="fontclass">#icon-weiyiji</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-qixiangzhan_"></use> |
|||
</svg> |
|||
<div class="name">气象站_1</div> |
|||
<div class="fontclass">#icon-qixiangzhan_</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-shenjikeng"></use> |
|||
</svg> |
|||
<div class="name">深基坑</div> |
|||
<div class="fontclass">#icon-shenjikeng</div> |
|||
</li> |
|||
|
|||
</ul> |
|||
|
|||
|
|||
<h2 id="symbol-">symbol引用</h2> |
|||
<hr> |
|||
|
|||
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a> |
|||
这种用法其实是做了一个svg的集合,与另外两种相比具有如下特点:</p> |
|||
<ul> |
|||
<li>支持多色图标了,不再受单色限制。</li> |
|||
<li>通过一些技巧,支持像字体那样,通过<code>font-size</code>,<code>color</code>来调整样式。</li> |
|||
<li>兼容性较差,支持 ie9+,及现代浏览器。</li> |
|||
<li>浏览器渲染svg的性能一般,还不如png。</li> |
|||
</ul> |
|||
<p>使用步骤如下:</p> |
|||
<h3 id="-symbol-">第一步:引入项目下面生成的symbol代码:</h3> |
|||
<pre><code class="lang-js hljs javascript"><span class="hljs-comment"><script src="./iconfont.js"></script></span></code></pre> |
|||
<h3 id="-css-">第二步:加入通用css代码(引入一次就行):</h3> |
|||
<pre><code class="lang-js hljs javascript"><style type=<span class="hljs-string">"text/css"</span>> |
|||
.icon { |
|||
width: <span class="hljs-number">1</span>em; height: <span class="hljs-number">1</span>em; |
|||
vertical-align: <span class="hljs-number">-0.15</span>em; |
|||
fill: currentColor; |
|||
overflow: hidden; |
|||
} |
|||
<<span class="hljs-regexp">/style></span></code></pre> |
|||
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3> |
|||
<pre><code class="lang-js hljs javascript"><svg <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"icon"</span> aria-hidden=<span class="hljs-string">"true"</span>><span class="xml"><span class="hljs-tag"> |
|||
<<span class="hljs-name">use</span> <span class="hljs-attr">xlink:href</span>=<span class="hljs-string">"#icon-xxx"</span>></span><span class="hljs-tag"></<span class="hljs-name">use</span>></span> |
|||
</span><<span class="hljs-regexp">/svg> |
|||
</span></code></pre> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,552 @@ |
|||
|
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"/> |
|||
<title>IconFont</title> |
|||
<link rel="stylesheet" href="demo.css"> |
|||
|
|||
<style type="text/css"> |
|||
|
|||
@font-face {font-family: "sc"; |
|||
src: url('iconfont.eot'); /* IE9*/ |
|||
src: url('iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */ |
|||
url('iconfont.woff') format('woff'), /* chrome, firefox */ |
|||
url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ |
|||
url('iconfont.svg#sc') format('svg'); /* iOS 4.1- */ |
|||
} |
|||
|
|||
.sc { |
|||
font-family:"sc" !important; |
|||
font-size:16px; |
|||
font-style:normal; |
|||
-webkit-font-smoothing: antialiased; |
|||
-webkit-text-stroke-width: 0.2px; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
|
|||
</style> |
|||
</head> |
|||
<body> |
|||
<div class="main markdown"> |
|||
<h1>IconFont 图标</h1> |
|||
<ul class="icon_lists clear"> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">流量</div> |
|||
<div class="code">&#xe602;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">轻轨</div> |
|||
<div class="code">&#xe66f;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">风速3</div> |
|||
<div class="code">&#xe635;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">calendar</div> |
|||
<div class="code">&#xe74a;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">box</div> |
|||
<div class="code">&#xe6cb;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">审核失败</div> |
|||
<div class="code">&#xe61d;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">边坡</div> |
|||
<div class="code">&#xe676;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">公路</div> |
|||
<div class="code">&#xe607;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">GNSS采点</div> |
|||
<div class="code">&#xe825;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">传感器设备</div> |
|||
<div class="code">&#xe612;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">电流传感器</div> |
|||
<div class="code">&#xe62c;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">电压传感器</div> |
|||
<div class="code">&#xe62f;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">温度传感器</div> |
|||
<div class="code">&#xe637;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">新建</div> |
|||
<div class="code">&#xe61f;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">涵洞</div> |
|||
<div class="code">&#xe89b;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">管网工程</div> |
|||
<div class="code">&#xe646;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">审核</div> |
|||
<div class="code">&#xe639;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">智慧城市</div> |
|||
<div class="code">&#xe600;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">边坡位移</div> |
|||
<div class="code">&#xe60a;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">建筑</div> |
|||
<div class="code">&#xe65f;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">储罐</div> |
|||
<div class="code">&#xe636;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">隧道</div> |
|||
<div class="code">&#xe61e;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">data</div> |
|||
<div class="code">&#xe757;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">矿山开采</div> |
|||
<div class="code">&#xe608;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">网络</div> |
|||
<div class="code">&#xe617;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">监控</div> |
|||
<div class="code">&#xe619;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">大数据</div> |
|||
<div class="code">&#xe61a;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">数据库</div> |
|||
<div class="code">&#xe61b;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">审核成功</div> |
|||
<div class="code">&#xe627;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">监控</div> |
|||
<div class="code">&#xe620;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">网络系统</div> |
|||
<div class="code">&#xe62e;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">定位</div> |
|||
<div class="code">&#xe630;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">系统运转情况</div> |
|||
<div class="code">&#xe631;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">查看</div> |
|||
<div class="code">&#xe63e;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">链接</div> |
|||
<div class="code">&#xe63f;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">数据导出-01</div> |
|||
<div class="code">&#xe640;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">系统状态</div> |
|||
<div class="code">&#xe642;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">消费明细单</div> |
|||
<div class="code">&#xe643;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">SQL审核</div> |
|||
<div class="code">&#xe645;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">aislogo</div> |
|||
<div class="code">&#xe648;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">桥</div> |
|||
<div class="code">&#xe715;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">塔式起重机</div> |
|||
<div class="code">&#xe615;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">dwg格式</div> |
|||
<div class="code">&#xe82b;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">路由器</div> |
|||
<div class="code">&#xe603;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">244安装、施工-线性</div> |
|||
<div class="code">&#xe8d6;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">245筛选过滤</div> |
|||
<div class="code">&#xe8d7;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">244安装、施工</div> |
|||
<div class="code">&#xe8d8;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">408条形图-线性</div> |
|||
<div class="code">&#xe904;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">409折线图-线性</div> |
|||
<div class="code">&#xe906;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">铁塔</div> |
|||
<div class="code">&#xe605;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">800格式_文档txt</div> |
|||
<div class="code">&#xe6b8;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">801格式_文档doc</div> |
|||
<div class="code">&#xe6b9;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">807格式_文档pdf</div> |
|||
<div class="code">&#xe6bc;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">803格式_文档xls</div> |
|||
<div class="code">&#xe6be;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">819格式_通用文档</div> |
|||
<div class="code">&#xe6c0;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">840格式_视频mp4</div> |
|||
<div class="code">&#xe6c8;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">860格式_图片jpg</div> |
|||
<div class="code">&#xe6cc;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">865格式_图片png</div> |
|||
<div class="code">&#xe6ce;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">光照传感器</div> |
|||
<div class="code">&#xe638;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">建筑</div> |
|||
<div class="code">&#xe61c;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">烟雾传感器</div> |
|||
<div class="code">&#xe610;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">市政</div> |
|||
<div class="code">&#xe6ca;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">传感器</div> |
|||
<div class="code">&#xe60f;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">温湿度传感器</div> |
|||
<div class="code">&#xe697;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">压力传感器</div> |
|||
<div class="code">&#xe60e;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">应力传感器</div> |
|||
<div class="code">&#xe611;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">沉降传感器</div> |
|||
<div class="code">&#xe601;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">压力传感器</div> |
|||
<div class="code">&#xe606;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">液位传感器</div> |
|||
<div class="code">&#xe699;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">computer</div> |
|||
<div class="code">&#xe6eb;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">empty</div> |
|||
<div class="code">&#xe6f7;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">offline</div> |
|||
<div class="code">&#xe712;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">大坝</div> |
|||
<div class="code">&#xe632;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">深部位移</div> |
|||
<div class="code">&#xe613;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">锚索传感器</div> |
|||
<div class="code">&#xe614;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">雨量传感器</div> |
|||
<div class="code">&#xe616;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">位移计</div> |
|||
<div class="code">&#xe618;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">气象站_1</div> |
|||
<div class="code">&#xe60d;</div> |
|||
</li> |
|||
|
|||
<li> |
|||
<i class="icon sc"></i> |
|||
<div class="name">深基坑</div> |
|||
<div class="code">&#xe62a;</div> |
|||
</li> |
|||
|
|||
</ul> |
|||
<h2 id="unicode-">unicode引用</h2> |
|||
<hr> |
|||
|
|||
<p>unicode是字体在网页端最原始的应用方式,特点是:</p> |
|||
<ul> |
|||
<li>兼容性最好,支持ie6+,及所有现代浏览器。</li> |
|||
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li> |
|||
<li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li> |
|||
</ul> |
|||
<blockquote> |
|||
<p>注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式</p> |
|||
</blockquote> |
|||
<p>unicode使用步骤如下:</p> |
|||
<h3 id="-font-face">第一步:拷贝项目下面生成的font-face</h3> |
|||
<pre><code class="lang-js hljs javascript">@font-face { |
|||
font-family: <span class="hljs-string">'sc'</span>; |
|||
src: url(<span class="hljs-string">'iconfont.eot'</span>); |
|||
src: url(<span class="hljs-string">'iconfont.eot?#iefix'</span>) format(<span class="hljs-string">'embedded-opentype'</span>), |
|||
url(<span class="hljs-string">'iconfont.woff'</span>) format(<span class="hljs-string">'woff'</span>), |
|||
url(<span class="hljs-string">'iconfont.ttf'</span>) format(<span class="hljs-string">'truetype'</span>), |
|||
url(<span class="hljs-string">'iconfont.svg#sc'</span>) format(<span class="hljs-string">'svg'</span>); |
|||
} |
|||
</code></pre> |
|||
<h3 id="-iconfont-">第二步:定义使用iconfont的样式</h3> |
|||
<pre><code class="lang-js hljs javascript">.sc{ |
|||
font-family:<span class="hljs-string">"sc"</span> !important; |
|||
font-size:<span class="hljs-number">16</span>px;font-style:normal; |
|||
-webkit-font-smoothing: antialiased; |
|||
-webkit-text-stroke-width: <span class="hljs-number">0.2</span>px; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
</code></pre> |
|||
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3> |
|||
<pre><code class="lang-js hljs javascript"><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"sc"</span>>&#x33;<span class="xml"><span class="hljs-tag"></<span class="hljs-name">i</span>></span></span></code></pre> |
|||
|
|||
<blockquote> |
|||
<p>"sc"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p> |
|||
</blockquote> |
|||
</div> |
|||
|
|||
|
|||
</body> |
|||
</html> |
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 148 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -0,0 +1,521 @@ |
|||
|
|||
@font-face {font-family: "anticon"; |
|||
src: url('iconfont.eot?t=1494480257283'); /* IE9*/ |
|||
src: url('iconfont.eot?t=1494480257283#iefix') format('embedded-opentype'), /* IE6-IE8 */ |
|||
url('iconfont.woff?t=1494480257283') format('woff'), /* chrome, firefox */ |
|||
url('iconfont.ttf?t=1494480257283') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ |
|||
url('iconfont.svg?t=1494480257283#anticon') format('svg'); /* iOS 4.1- */ |
|||
} |
|||
|
|||
.anticon { |
|||
font-family:"anticon" !important; |
|||
font-size:16px; |
|||
font-style:normal; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
|
|||
.icon-stepforward:before { content: "\e600"; } |
|||
|
|||
.icon-stepbackward:before { content: "\e601"; } |
|||
|
|||
.icon-forward:before { content: "\e602"; } |
|||
|
|||
.icon-banckward:before { content: "\e603"; } |
|||
|
|||
.icon-caretright:before { content: "\e604"; } |
|||
|
|||
.icon-caretleft:before { content: "\e605"; } |
|||
|
|||
.icon-caretdown:before { content: "\e606"; } |
|||
|
|||
.icon-caretup:before { content: "\e607"; } |
|||
|
|||
.icon-rightcircle:before { content: "\e608"; } |
|||
|
|||
.icon-leftcircle:before { content: "\e609"; } |
|||
|
|||
.icon-upcircle:before { content: "\e60a"; } |
|||
|
|||
.icon-downcircle:before { content: "\e60b"; } |
|||
|
|||
.icon-rightcircleo:before { content: "\e60c"; } |
|||
|
|||
.icon-leftcircleo:before { content: "\e60d"; } |
|||
|
|||
.icon-upcircleo:before { content: "\e60e"; } |
|||
|
|||
.icon-downcircleo:before { content: "\e60f"; } |
|||
|
|||
.icon-verticleleft:before { content: "\e610"; } |
|||
|
|||
.icon-verticleright:before { content: "\e611"; } |
|||
|
|||
.icon-rollback:before { content: "\e612"; } |
|||
|
|||
.icon-retweet:before { content: "\e613"; } |
|||
|
|||
.icon-shrink:before { content: "\e614"; } |
|||
|
|||
.icon-arrowsalt:before { content: "\e615"; } |
|||
|
|||
.icon-doubleright:before { content: "\e617"; } |
|||
|
|||
.icon-doubleleft:before { content: "\e618"; } |
|||
|
|||
.icon-arrowdown:before { content: "\e619"; } |
|||
|
|||
.icon-arrowup:before { content: "\e61a"; } |
|||
|
|||
.icon-arrowright:before { content: "\e61b"; } |
|||
|
|||
.icon-arrowleft:before { content: "\e61c"; } |
|||
|
|||
.icon-down:before { content: "\e61d"; } |
|||
|
|||
.icon-up:before { content: "\e61e"; } |
|||
|
|||
.icon-right:before { content: "\e61f"; } |
|||
|
|||
.icon-left:before { content: "\e620"; } |
|||
|
|||
.icon-minussquareo:before { content: "\e621"; } |
|||
|
|||
.icon-minuscircle:before { content: "\e622"; } |
|||
|
|||
.icon-minuscircleo:before { content: "\e623"; } |
|||
|
|||
.icon-minus:before { content: "\e624"; } |
|||
|
|||
.icon-pluscircleo:before { content: "\e625"; } |
|||
|
|||
.icon-pluscircle:before { content: "\e626"; } |
|||
|
|||
.icon-plus:before { content: "\e627"; } |
|||
|
|||
.icon-infocirlce:before { content: "\e628"; } |
|||
|
|||
.icon-infocirlceo:before { content: "\e629"; } |
|||
|
|||
.icon-info:before { content: "\e62a"; } |
|||
|
|||
.icon-exclamation:before { content: "\e62b"; } |
|||
|
|||
.icon-exclamationcircle:before { content: "\e62c"; } |
|||
|
|||
.icon-exclamationcircleo:before { content: "\e62d"; } |
|||
|
|||
.icon-closecircle:before { content: "\e62e"; } |
|||
|
|||
.icon-closecircleo:before { content: "\e62f"; } |
|||
|
|||
.icon-checkcircle:before { content: "\e630"; } |
|||
|
|||
.icon-checkcircleo:before { content: "\e631"; } |
|||
|
|||
.icon-check:before { content: "\e632"; } |
|||
|
|||
.icon-close:before { content: "\e633"; } |
|||
|
|||
.icon-customerservice:before { content: "\e634"; } |
|||
|
|||
.icon-creditcard:before { content: "\e635"; } |
|||
|
|||
.icon-codesquareo:before { content: "\e636"; } |
|||
|
|||
.icon-book:before { content: "\e637"; } |
|||
|
|||
.icon-barschart:before { content: "\e638"; } |
|||
|
|||
.icon-bars:before { content: "\e639"; } |
|||
|
|||
.icon-question:before { content: "\e63a"; } |
|||
|
|||
.icon-questioncircle:before { content: "\e63b"; } |
|||
|
|||
.icon-questioncircleo:before { content: "\e63c"; } |
|||
|
|||
.icon-pause:before { content: "\e63d"; } |
|||
|
|||
.icon-pausecircle:before { content: "\e63e"; } |
|||
|
|||
.icon-pausecircleo:before { content: "\e63f"; } |
|||
|
|||
.icon-clockcircle:before { content: "\e640"; } |
|||
|
|||
.icon-clockcircleo:before { content: "\e641"; } |
|||
|
|||
.icon-swap:before { content: "\e642"; } |
|||
|
|||
.icon-swapleft:before { content: "\e643"; } |
|||
|
|||
.icon-swapright:before { content: "\e644"; } |
|||
|
|||
.icon-plussquareo:before { content: "\e645"; } |
|||
|
|||
.icon-frown:before { content: "\e646"; } |
|||
|
|||
.icon-menufold:before { content: "\e658"; } |
|||
|
|||
.icon-mail:before { content: "\e659"; } |
|||
|
|||
.icon-link:before { content: "\e65b"; } |
|||
|
|||
.icon-areachart:before { content: "\e65c"; } |
|||
|
|||
.icon-linechart:before { content: "\e65d"; } |
|||
|
|||
.icon-home:before { content: "\e65e"; } |
|||
|
|||
.icon-laptop:before { content: "\e65f"; } |
|||
|
|||
.icon-star:before { content: "\e660"; } |
|||
|
|||
.icon-staro:before { content: "\e661"; } |
|||
|
|||
.icon-filter:before { content: "\e663"; } |
|||
|
|||
.icon-meho:before { content: "\e666"; } |
|||
|
|||
.icon-meh:before { content: "\e667"; } |
|||
|
|||
.icon-shoppingcart:before { content: "\e668"; } |
|||
|
|||
.icon-save:before { content: "\e669"; } |
|||
|
|||
.icon-user:before { content: "\e66a"; } |
|||
|
|||
.icon-videocamera:before { content: "\e66b"; } |
|||
|
|||
.icon-totop:before { content: "\e66c"; } |
|||
|
|||
.icon-team:before { content: "\e66d"; } |
|||
|
|||
.icon-sharealt:before { content: "\e671"; } |
|||
|
|||
.icon-setting:before { content: "\e672"; } |
|||
|
|||
.icon-picture:before { content: "\e674"; } |
|||
|
|||
.icon-phone:before { content: "\e675"; } |
|||
|
|||
.icon-paperclip:before { content: "\e676"; } |
|||
|
|||
.icon-notification:before { content: "\e677"; } |
|||
|
|||
.icon-menuunfold:before { content: "\e679"; } |
|||
|
|||
.icon-inbox:before { content: "\e67a"; } |
|||
|
|||
.icon-lock:before { content: "\e67b"; } |
|||
|
|||
.icon-qrcode:before { content: "\e67c"; } |
|||
|
|||
.icon-tags:before { content: "\e67d"; } |
|||
|
|||
.icon-tagso:before { content: "\e67e"; } |
|||
|
|||
.icon-cloudo:before { content: "\e67f"; } |
|||
|
|||
.icon-cloud:before { content: "\e680"; } |
|||
|
|||
.icon-cloudupload:before { content: "\e681"; } |
|||
|
|||
.icon-clouddownload:before { content: "\e682"; } |
|||
|
|||
.icon-clouddownloado:before { content: "\e683"; } |
|||
|
|||
.icon-clouduploado:before { content: "\e684"; } |
|||
|
|||
.icon-enviroment:before { content: "\e685"; } |
|||
|
|||
.icon-enviromento:before { content: "\e686"; } |
|||
|
|||
.icon-eye:before { content: "\e687"; } |
|||
|
|||
.icon-eyeo:before { content: "\e688"; } |
|||
|
|||
.icon-camera:before { content: "\e689"; } |
|||
|
|||
.icon-camerao:before { content: "\e68a"; } |
|||
|
|||
.icon-windows:before { content: "\e68b"; } |
|||
|
|||
.icon-export2:before { content: "\e690"; } |
|||
|
|||
.icon-export:before { content: "\e691"; } |
|||
|
|||
.icon-circledowno:before { content: "\e693"; } |
|||
|
|||
.icon-circledown:before { content: "\e694"; } |
|||
|
|||
.icon-hdd:before { content: "\e69a"; } |
|||
|
|||
.icon-ie:before { content: "\e69b"; } |
|||
|
|||
.icon-delete:before { content: "\e69f"; } |
|||
|
|||
.icon-enter:before { content: "\e6a0"; } |
|||
|
|||
.icon-pushpino:before { content: "\e6a1"; } |
|||
|
|||
.icon-pushpin:before { content: "\e6a2"; } |
|||
|
|||
.icon-heart:before { content: "\e6a3"; } |
|||
|
|||
.icon-hearto:before { content: "\e6a4"; } |
|||
|
|||
.icon-smile-circle:before { content: "\e6a7"; } |
|||
|
|||
.icon-smileo:before { content: "\e6a8"; } |
|||
|
|||
.icon-frowno:before { content: "\e6a9"; } |
|||
|
|||
.icon-calculator:before { content: "\e6aa"; } |
|||
|
|||
.icon-chrome:before { content: "\e6ac"; } |
|||
|
|||
.icon-github:before { content: "\e6ad"; } |
|||
|
|||
.icon-iconfontdesktop:before { content: "\e6b4"; } |
|||
|
|||
.icon-caretcircleoup:before { content: "\e6b5"; } |
|||
|
|||
.icon-upload:before { content: "\e6b6"; } |
|||
|
|||
.icon-download:before { content: "\e6b7"; } |
|||
|
|||
.icon-piechart:before { content: "\e6b8"; } |
|||
|
|||
.icon-lock1:before { content: "\e6b9"; } |
|||
|
|||
.icon-unlock:before { content: "\e6ba"; } |
|||
|
|||
.icon-windowso:before { content: "\e6bc"; } |
|||
|
|||
.icon-dotchart:before { content: "\e6bd"; } |
|||
|
|||
.icon-barchart:before { content: "\e6be"; } |
|||
|
|||
.icon-codesquare:before { content: "\e6bf"; } |
|||
|
|||
.icon-plussquare:before { content: "\e6c0"; } |
|||
|
|||
.icon-minussquare:before { content: "\e6c1"; } |
|||
|
|||
.icon-closesquare:before { content: "\e6c2"; } |
|||
|
|||
.icon-closesquareo:before { content: "\e6c3"; } |
|||
|
|||
.icon-checksquare:before { content: "\e6c4"; } |
|||
|
|||
.icon-checksquareo:before { content: "\e6c5"; } |
|||
|
|||
.icon-fastbackward:before { content: "\e6c6"; } |
|||
|
|||
.icon-fastforward:before { content: "\e6c7"; } |
|||
|
|||
.icon-upsquare:before { content: "\e6c8"; } |
|||
|
|||
.icon-downsquare:before { content: "\e6c9"; } |
|||
|
|||
.icon-leftsquare:before { content: "\e6ca"; } |
|||
|
|||
.icon-rightsquare:before { content: "\e6cb"; } |
|||
|
|||
.icon-rightsquareo:before { content: "\e6cc"; } |
|||
|
|||
.icon-leftsquareo:before { content: "\e6cd"; } |
|||
|
|||
.icon-down-square-o:before { content: "\e6ce"; } |
|||
|
|||
.icon-up-square-o:before { content: "\e6cf"; } |
|||
|
|||
.icon-play:before { content: "\e6d0"; } |
|||
|
|||
.icon-playcircleo:before { content: "\e6d1"; } |
|||
|
|||
.icon-tag:before { content: "\e6d2"; } |
|||
|
|||
.icon-tago:before { content: "\e6d3"; } |
|||
|
|||
.icon-addfile:before { content: "\e910"; } |
|||
|
|||
.icon-folder1:before { content: "\e662"; } |
|||
|
|||
.icon-file1:before { content: "\e664"; } |
|||
|
|||
.icon-switcher:before { content: "\e913"; } |
|||
|
|||
.icon-addfolder:before { content: "\e914"; } |
|||
|
|||
.icon-folderopen:before { content: "\e699"; } |
|||
|
|||
.icon-search1:before { content: "\e670"; } |
|||
|
|||
.icon-ellipsis1:before { content: "\e647"; } |
|||
|
|||
.icon-calendar:before { content: "\e6bb"; } |
|||
|
|||
.icon-filetext1:before { content: "\e698"; } |
|||
|
|||
.icon-copy1:before { content: "\e648"; } |
|||
|
|||
.icon-jpgfile1:before { content: "\e69c"; } |
|||
|
|||
.icon-pdffile1:before { content: "\e6b3"; } |
|||
|
|||
.icon-exclefile1:before { content: "\e6b0"; } |
|||
|
|||
.icon-pptfile1:before { content: "\e6b1"; } |
|||
|
|||
.icon-unknowfile1:before { content: "\e6af"; } |
|||
|
|||
.icon-wordfile1:before { content: "\e6b2"; } |
|||
|
|||
.icon-dingding:before { content: "\e923"; } |
|||
|
|||
.icon-dingding-o:before { content: "\e925"; } |
|||
|
|||
.icon-mobile1:before { content: "\e678"; } |
|||
|
|||
.icon-tablet1:before { content: "\e66e"; } |
|||
|
|||
.icon-bells:before { content: "\e64e"; } |
|||
|
|||
.icon-disconnect:before { content: "\e64f"; } |
|||
|
|||
.icon-database:before { content: "\e650"; } |
|||
|
|||
.icon-barcode:before { content: "\e652"; } |
|||
|
|||
.icon-hourglass:before { content: "\e653"; } |
|||
|
|||
.icon-key:before { content: "\e654"; } |
|||
|
|||
.icon-flag:before { content: "\e655"; } |
|||
|
|||
.icon-layout:before { content: "\e656"; } |
|||
|
|||
.icon-printer:before { content: "\e673"; } |
|||
|
|||
.icon-USB:before { content: "\e6d7"; } |
|||
|
|||
.icon-skin:before { content: "\e6d8"; } |
|||
|
|||
.icon-tool:before { content: "\e6d9"; } |
|||
|
|||
.icon-car:before { content: "\e6dc"; } |
|||
|
|||
.icon-addusergroup:before { content: "\e6dd"; } |
|||
|
|||
.icon-carryout:before { content: "\e6df"; } |
|||
|
|||
.icon-deleteuser:before { content: "\e6e0"; } |
|||
|
|||
.icon-deleteusergroup:before { content: "\e6e1"; } |
|||
|
|||
.icon-man:before { content: "\e6e2"; } |
|||
|
|||
.icon-isv:before { content: "\e6e3"; } |
|||
|
|||
.icon-gift:before { content: "\e6e4"; } |
|||
|
|||
.icon-idcard:before { content: "\e6e5"; } |
|||
|
|||
.icon-medicinebox:before { content: "\e6e6"; } |
|||
|
|||
.icon-redenvelopes:before { content: "\e6e7"; } |
|||
|
|||
.icon-rest:before { content: "\e6e8"; } |
|||
|
|||
.icon-Safety:before { content: "\e6ea"; } |
|||
|
|||
.icon-wallet:before { content: "\e6eb"; } |
|||
|
|||
.icon-woman:before { content: "\e6ec"; } |
|||
|
|||
.icon-adduser:before { content: "\e6ed"; } |
|||
|
|||
.icon-bank:before { content: "\e6ee"; } |
|||
|
|||
.icon-Trophy:before { content: "\e6ef"; } |
|||
|
|||
.icon-loading1:before { content: "\e6ae"; } |
|||
|
|||
.icon-loading2:before { content: "\e64d"; } |
|||
|
|||
.icon-like2:before { content: "\e69d"; } |
|||
|
|||
.icon-dislike2:before { content: "\e69e"; } |
|||
|
|||
.icon-like1:before { content: "\e64c"; } |
|||
|
|||
.icon-dislike1:before { content: "\e64b"; } |
|||
|
|||
.icon-bulb1:before { content: "\e649"; } |
|||
|
|||
.icon-rocket1:before { content: "\e90f"; } |
|||
|
|||
.icon-select1:before { content: "\e64a"; } |
|||
|
|||
.icon-apple1:before { content: "\e68c"; } |
|||
|
|||
.icon-apple-o:before { content: "\e6d4"; } |
|||
|
|||
.icon-android1:before { content: "\e938"; } |
|||
|
|||
.icon-android:before { content: "\e68d"; } |
|||
|
|||
.icon-aliwangwang-o1:before { content: "\e68f"; } |
|||
|
|||
.icon-aliwangwang:before { content: "\e68e"; } |
|||
|
|||
.icon-pay-circle1:before { content: "\e6a5"; } |
|||
|
|||
.icon-pay-circle-o1:before { content: "\e6a6"; } |
|||
|
|||
.icon-poweroff:before { content: "\e6d5"; } |
|||
|
|||
.icon-trademark:before { content: "\e651"; } |
|||
|
|||
.icon-find:before { content: "\e6db"; } |
|||
|
|||
.icon-copyright:before { content: "\e6de"; } |
|||
|
|||
.icon-sound:before { content: "\e6e9"; } |
|||
|
|||
.icon-earth:before { content: "\e6f1"; } |
|||
|
|||
.icon-wifi:before { content: "\e6d6"; } |
|||
|
|||
.icon-sync:before { content: "\e6da"; } |
|||
|
|||
.icon-login:before { content: "\e657"; } |
|||
|
|||
.icon-logout:before { content: "\e65a"; } |
|||
|
|||
.icon-reload1:before { content: "\e616"; } |
|||
|
|||
.icon-message1:before { content: "\e6ab"; } |
|||
|
|||
.icon-shake:before { content: "\e94f"; } |
|||
|
|||
.icon-API:before { content: "\e951"; } |
|||
|
|||
.icon-appstore-o:before { content: "\e695"; } |
|||
|
|||
.icon-appstore1:before { content: "\e696"; } |
|||
|
|||
.icon-scan1:before { content: "\e697"; } |
|||
|
|||
.icon-exception1:before { content: "\e665"; } |
|||
|
|||
.icon-contacts:before { content: "\e6f0"; } |
|||
|
|||
.icon-solution1:before { content: "\e66f"; } |
|||
|
|||
.icon-fork:before { content: "\e6f2"; } |
|||
|
|||
.icon-edit1:before { content: "\e692"; } |
|||
|
Binary file not shown.
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 140 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 646 KiB |
After Width: | Height: | Size: 2.6 MiB |
After Width: | Height: | Size: 7.8 KiB |
@ -0,0 +1,25 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<link rel="shortcut icon" href="/assets/images/favicon.ico"> |
|||
<link rel="stylesheet" type="text/css" href="/assets/font_sc/iconfont.css"> |
|||
</head> |
|||
<style> |
|||
@font-face { |
|||
font-family: YouSheBiaoTiHei; |
|||
src: url("/assets/font_sc/YouSheBiaoTiHei-2.ttf"); |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: D-DIN-Bold; |
|||
src: url("/assets/font_sc/D-DIN-Bold.ttf"); |
|||
} |
|||
</style> |
|||
|
|||
<body style="background: transparent"> |
|||
<div id='App'></div> |
|||
</body> |
|||
|
|||
</html> |
@ -0,0 +1,28 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title></title> |
|||
<link rel="shortcut icon" href="/assets/images/favicon.ico"> |
|||
<link rel="stylesheet" type="text/css" href="/assets/font_sc/iconfont.css"> |
|||
</head> |
|||
<style> |
|||
@font-face { |
|||
font-family: YouSheBiaoTiHei; |
|||
src: url("/assets/font_sc/YouSheBiaoTiHei-2.ttf"); |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: D-DIN-Bold; |
|||
src: url("/assets/font_sc/D-DIN-Bold.ttf"); |
|||
} |
|||
</style> |
|||
|
|||
<body style="background: #0F1C2A;"> |
|||
<div id='App'></div> |
|||
<script type="text/javascript" src="http://localhost:5401/client/build/vendor.js"></script> |
|||
<script type="text/javascript" src="http://localhost:5401/client/build/app.js"></script> |
|||
</body> |
|||
|
|||
</html> |
@ -0,0 +1,19 @@ |
|||
/** |
|||
* User: liuxinyi/liu.xinyi@free-sun.com.cn |
|||
* Date: 2016/2/22 |
|||
* Time: 15:29 |
|||
* |
|||
*/ |
|||
'use strict'; |
|||
|
|||
const views = require('koa-view'); |
|||
const path = require('path'); |
|||
module.exports = { |
|||
entry: function (app, router, opt) { |
|||
app.use(views(__dirname)); |
|||
|
|||
router.get('(.*)', async function (ctx){ |
|||
await ctx.render(path.join(__dirname, './index')); |
|||
}); |
|||
} |
|||
}; |
@ -0,0 +1,27 @@ |
|||
'use strict'; |
|||
|
|||
import React, { useEffect } from 'react'; |
|||
import Layout from './layout'; |
|||
import Auth from './sections/auth'; |
|||
import homePage from './sections/homePage'; |
|||
|
|||
const App = props => { |
|||
const { projectName } = props |
|||
|
|||
useEffect(() => { |
|||
document.title = projectName; |
|||
}, []) |
|||
|
|||
return ( |
|||
<Layout |
|||
title={projectName} |
|||
sections={[ |
|||
homePage, |
|||
Auth |
|||
]} |
|||
/> |
|||
) |
|||
|
|||
} |
|||
|
|||
export default App; |
@ -0,0 +1,316 @@ |
|||
'use strict'; |
|||
|
|||
import React, { Component } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Spin, Upload, message, Modal, Card, Button } from 'antd'; |
|||
import moment from 'moment'; |
|||
import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; |
|||
|
|||
class Uploads extends Component { |
|||
constructor(props) { |
|||
super(props); |
|||
this.ApiRoot = FS_API_ROOT |
|||
this.state = { |
|||
fileUploading: false, |
|||
fileList: [], |
|||
curPreviewPic: '', |
|||
delPicIng: false, |
|||
removeFilesList: [] |
|||
}; |
|||
} |
|||
|
|||
dealName = (uploaded) => { |
|||
let realName = uploaded.split('/')[2] |
|||
let x1 = realName.split('.') |
|||
let x2 = x1[0].split('_') |
|||
let showName = `${x2[0]}.${x1[1]}` |
|||
return showName |
|||
} |
|||
|
|||
// setFileList = (value) => {
|
|||
// let defaultFileList = [];
|
|||
// defaultFileList = value.map((u, index) => {
|
|||
// let fileUrl = `${this.ApiRoot}/${u.url}`;
|
|||
// return {
|
|||
// uid: -index - 1,
|
|||
// name: this.dealName(u.url),
|
|||
// status: 'done',
|
|||
// storageUrl: u.url,
|
|||
// url: fileUrl
|
|||
// };
|
|||
// });
|
|||
// onChange(defaultFileList)
|
|||
// this.setState({
|
|||
// fileList: defaultFileList
|
|||
// });
|
|||
// };
|
|||
|
|||
componentDidMount () { |
|||
const { value } = this.props; |
|||
if (value) { |
|||
this.setState(value); |
|||
} |
|||
} |
|||
|
|||
componentWillReceiveProps (np) { |
|||
const { dispatch, value: thisEditData, onChange } = this.props; |
|||
const { value: nextEditData } = np; |
|||
|
|||
const setFileList = () => { |
|||
let defaultFileList = []; |
|||
defaultFileList = nextEditData.map((u, index) => { |
|||
let fileUrl = `${this.ApiRoot}/${u.storageUrl}`; |
|||
return { |
|||
uid: -index - 1, |
|||
name: this.dealName(u.storageUrl), |
|||
status: 'done', |
|||
storageUrl: u.storageUrl, |
|||
url: fileUrl, |
|||
size: u.size || -1 |
|||
}; |
|||
}); |
|||
this.setState({ |
|||
fileList: defaultFileList |
|||
}); |
|||
}; |
|||
|
|||
if (nextEditData && nextEditData.length) { |
|||
if (!thisEditData || !this.state.fileList.length) { |
|||
setFileList(); |
|||
} else if (nextEditData.length != thisEditData.length) { |
|||
setFileList(); |
|||
} else { |
|||
let repeat = true; |
|||
for (let i = 0; i < thisEditData.length; i++) { |
|||
if (thisEditData[i] != nextEditData[i]) { |
|||
repeat = false; |
|||
break; |
|||
} |
|||
} |
|||
if (!repeat) { |
|||
setFileList(); |
|||
} |
|||
} |
|||
} |
|||
// else{
|
|||
// this.setState({
|
|||
// fileList:[],
|
|||
// })
|
|||
// }
|
|||
} |
|||
|
|||
render () { |
|||
const UploadPath = { |
|||
project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'png', 'jpg', 'rar', 'zip'], |
|||
report: ['doc', 'docx', 'xls', 'xlsx', 'pdf'], |
|||
data: ['txt', 'xls', 'xlsx'], |
|||
image: ['png', 'jpg', 'svg', 'jpeg'], |
|||
three: ['js'], |
|||
video: ['mp4'] |
|||
}; |
|||
/** |
|||
* uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; |
|||
* disabled 【boolean】 上传是否可用 |
|||
* maxFilesNum 【number】 最大上传数量 |
|||
* fileTypes 【array[string]】 可允许上传的文件类型; |
|||
* maxFileSize 【number】 单个文件最大大小 M |
|||
* listType 【antd】 upload 组件的属性 |
|||
* onChange 【function】 文件数量变化时候回调 返回文件 |
|||
* value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] |
|||
* onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } |
|||
*/ |
|||
const { |
|||
uploadType, |
|||
disabled, |
|||
maxFilesNum, |
|||
fileTypes, |
|||
maxFileSize, |
|||
listType, |
|||
onChange, |
|||
value, |
|||
showUploadList, |
|||
onStateChange |
|||
} = this.props; |
|||
const { fileList, curPreviewPic, delPicIng, removeFilesList } = this.state; |
|||
const that = this; |
|||
let uploadType_ = uploadType || 'project'; |
|||
let maxFilesNum_ = maxFilesNum || 1; |
|||
let defaultFileTypes = fileTypes || UploadPath[uploadType_]; |
|||
const uploadProps = { |
|||
name: 'checkFile_', |
|||
multiple: false, |
|||
showUploadList: showUploadList || true, |
|||
action: `${this.ApiRoot}/attachments/${uploadType_}`, |
|||
listType: listType || 'text', |
|||
disabled: disabled, |
|||
beforeUpload: (file) => { |
|||
if (fileList.length >= maxFilesNum_) { |
|||
message.warning(`最多选择${maxFilesNum_}个文件上传`); |
|||
return false; |
|||
} |
|||
if (file.name.length > 60) { |
|||
message.warning(`文件名过长(大于60字符),请修改后上传`); |
|||
return false; |
|||
} |
|||
const extNames = file.name.split('.'); |
|||
var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/; |
|||
if (!reg.exec(file.name)) { |
|||
message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`); |
|||
return false; |
|||
} |
|||
let isDAE = false; |
|||
if (extNames.length > 0) { |
|||
let fileType = extNames[extNames.length - 1].toLowerCase(); |
|||
isDAE = defaultFileTypes.some((f) => f == fileType); |
|||
} |
|||
if (!isDAE) { |
|||
message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); |
|||
return false; |
|||
} |
|||
const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); |
|||
if (!isLt) { |
|||
message.error(`文件必须小于${maxFileSize || 3}MB!`); |
|||
return false; |
|||
} |
|||
this.setState({ |
|||
fileUploading: true |
|||
}); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: true }); |
|||
} |
|||
}, |
|||
onChange (info) { |
|||
const status = info.file.status; |
|||
if (status === 'uploading') { |
|||
that.setState({ |
|||
fileList: info.fileList |
|||
}); |
|||
} |
|||
if (status === 'done') { |
|||
let { uploaded, url } = info.file.response; |
|||
let size = info.file.size; |
|||
let nextFileList = fileList; |
|||
nextFileList[nextFileList.length - 1] = { |
|||
uid: -moment().unix(), |
|||
name: that.dealName(uploaded), |
|||
status: 'done', |
|||
storageUrl: uploaded, |
|||
url: url, |
|||
size: size |
|||
}; |
|||
onChange(nextFileList); |
|||
that.setState({ |
|||
fileUploading: false, |
|||
fileList: nextFileList |
|||
}); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: false }); |
|||
} |
|||
} else if (status === 'error') { |
|||
that.setState({ |
|||
fileUploading: false |
|||
}); |
|||
message.error(`${info.file.name} 上传失败,请重试`); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: false }); |
|||
} |
|||
} |
|||
}, |
|||
onRemove (file) { |
|||
let nextFileList = []; |
|||
fileList.map((f, i) => { |
|||
if (f.uid != file.uid) { |
|||
nextFileList.push(f); |
|||
} |
|||
}); |
|||
let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); |
|||
if (curPreviewPic == file.url) { |
|||
that.setState({ |
|||
curPreviewPic: '' |
|||
}); |
|||
} |
|||
onChange(nextFileList); |
|||
that.setState({ |
|||
fileList: nextFileList, |
|||
removeFilesList: nextRemoveFiles |
|||
}); |
|||
}, |
|||
onPreview (file) { |
|||
let filePostfix = file.url.split('.').pop(); |
|||
filePostfix = filePostfix.toLowerCase(); |
|||
if (UploadPath.image.some((img) => img == filePostfix)) { |
|||
that.setState({ |
|||
curPreviewPic: file.url |
|||
}); |
|||
} else { |
|||
message.warn('仅支持图片预览'); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
let fileList_ = fileList |
|||
// .map(f => {
|
|||
// if (f.storageUrl) {
|
|||
// let realName = f.storageUrl.split('/').pop()
|
|||
// if (f.name != realName) {
|
|||
// f.name = realName
|
|||
// }
|
|||
// }
|
|||
// return f
|
|||
// })
|
|||
|
|||
return ( |
|||
<div> |
|||
<Spin spinning={delPicIng}> |
|||
<Upload {...uploadProps} fileList={fileList_}> |
|||
{ |
|||
disabled ? ( |
|||
'' |
|||
) : |
|||
listType == 'picture-card' ? |
|||
( |
|||
fileList.length >= maxFilesNum_ ? null : ( |
|||
<div style={{}}> |
|||
<PlusOutlined /> |
|||
<div>上传图片</div> |
|||
</div> |
|||
) |
|||
) : ( |
|||
<Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}> 文件上传 </Button> |
|||
) |
|||
} |
|||
</Upload> |
|||
{ |
|||
curPreviewPic ? ( |
|||
<Card |
|||
bodyStyle={{ |
|||
padding: 8 |
|||
}} |
|||
> |
|||
<div style={{ marginBottom: 8 }} > |
|||
<span>文件预览</span> |
|||
<span |
|||
style={{ float: 'right' }} |
|||
onClick={() => { this.setState({ curPreviewPic: '' }); }} |
|||
> |
|||
<CloseOutlined style={{ fontSize: 20 }} /> |
|||
</span> |
|||
</div> |
|||
<img style={{ width: '100%' }} src={curPreviewPic}></img> |
|||
</Card> |
|||
) : '' |
|||
} |
|||
</Spin> |
|||
</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
function mapStateToProps (state) { |
|||
const { auth } = state |
|||
return { |
|||
user: auth.user |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(Uploads); |
@ -0,0 +1,339 @@ |
|||
'use strict'; |
|||
|
|||
import React, { Component } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Spin, Upload, message, Modal, Card, Button } from 'antd'; |
|||
import moment from 'moment'; |
|||
import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; |
|||
import { RouteRequest } from '@peace/utils'; |
|||
import { RouteTable } from '$utils' |
|||
const { confirm } = Modal; |
|||
class Uploads extends Component { |
|||
constructor(props) { |
|||
super(props); |
|||
this.state = { |
|||
fileUploading: false, |
|||
fileList: [], |
|||
curPreviewPic: '', |
|||
delPicIng: false, |
|||
removeFilesList: [] |
|||
}; |
|||
} |
|||
dealName = (uploaded) => { |
|||
let realName = uploaded.split('/')[2] |
|||
let x1 = realName.split('.') |
|||
let x2 = x1[0].split('_') |
|||
let showName = `${x2[0]}.${x1[1]}` |
|||
return showName |
|||
} |
|||
|
|||
// setFileList = (value) => {
|
|||
// let defaultFileList = [];
|
|||
// defaultFileList = value.map((u, index) => {
|
|||
// let fileUrl = `${this.ApiRoot}/${u.url}`;
|
|||
// return {
|
|||
// uid: -index - 1,
|
|||
// name: this.dealName(u.url),
|
|||
// status: 'done',
|
|||
// storageUrl: u.url,
|
|||
// url: fileUrl
|
|||
// };
|
|||
// });
|
|||
// onChange(defaultFileList)
|
|||
// this.setState({
|
|||
// fileList: defaultFileList
|
|||
// });
|
|||
// };
|
|||
|
|||
componentDidMount() { |
|||
const { value } = this.props; |
|||
if (value) { |
|||
// this.setState(value);
|
|||
this.setState({ fileList: value }) |
|||
} |
|||
} |
|||
|
|||
UNSAFE_componentWillReceiveProps(np) { |
|||
const { dispatch, value: thisEditData, onChange } = this.props; |
|||
const { value: nextEditData } = np; |
|||
|
|||
const setFileList = () => { |
|||
let defaultFileList = []; |
|||
defaultFileList = nextEditData.map((u, index) => { |
|||
let fileUrl = u.filename; |
|||
return { |
|||
uid: -index - 1, |
|||
name: u.name, |
|||
status: 'done', |
|||
storageUrl: u.filename, |
|||
url: fileUrl, |
|||
size: u.size || -1 |
|||
}; |
|||
}); |
|||
this.setState({ |
|||
fileList: defaultFileList |
|||
}); |
|||
}; |
|||
|
|||
if (nextEditData && nextEditData.length) { |
|||
if (!thisEditData || !this.state.fileList.length) { |
|||
setFileList(); |
|||
} else if (nextEditData.length != thisEditData.length) { |
|||
setFileList(); |
|||
} else { |
|||
let repeat = true; |
|||
for (let i = 0; i < thisEditData.length; i++) { |
|||
if (thisEditData[i] != nextEditData[i]) { |
|||
repeat = false; |
|||
break; |
|||
} |
|||
} |
|||
if (!repeat) { |
|||
setFileList(); |
|||
} |
|||
} |
|||
} |
|||
// else{
|
|||
// this.setState({
|
|||
// fileList:[],
|
|||
// })
|
|||
// }
|
|||
} |
|||
//删除文件
|
|||
deleteFile(file) { |
|||
if (file.url) { |
|||
RouteRequest.delete(RouteTable.cleanUpUploadTrash, { url: file.url }); |
|||
}; |
|||
} |
|||
handleOk = (that, file, fileList, curPreviewPic, removeFilesList) => { |
|||
let nextFileList = []; |
|||
fileList.map((f, i) => { |
|||
if (f.uid != file.uid) { |
|||
nextFileList.push(f); |
|||
} |
|||
}); |
|||
that.deleteFile(file); |
|||
let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); |
|||
if (curPreviewPic == file.url) { |
|||
that.setState({ |
|||
curPreviewPic: '' |
|||
}); |
|||
} |
|||
that.props.onChange(nextFileList); |
|||
that.setState({ |
|||
fileList: nextFileList, |
|||
removeFilesList: nextRemoveFiles |
|||
}); |
|||
} |
|||
render() { |
|||
const UploadPath = { |
|||
project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'png', 'jpg', 'rar', 'zip'], |
|||
report: ['doc', 'docx', 'xls', 'xlsx', 'pdf'], |
|||
data: ['txt', 'xls', 'xlsx'], |
|||
image: ['png', 'jpg', 'svg', 'jpeg'], |
|||
three: ['js'], |
|||
video: ['mp4'] |
|||
}; |
|||
/** |
|||
* uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; |
|||
* disabled 【boolean】 上传是否可用 |
|||
* maxFilesNum 【number】 最大上传数量 |
|||
* fileTypes 【array[string]】 可允许上传的文件类型; |
|||
* maxFileSize 【number】 单个文件最大大小 M |
|||
* listType 【antd】 upload 组件的属性 |
|||
* onChange 【function】 文件数量变化时候回调 返回文件 |
|||
* value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] |
|||
* onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } |
|||
*/ |
|||
const { |
|||
uploadType, |
|||
disabled, |
|||
maxFilesNum, |
|||
fileTypes, |
|||
maxFileSize, |
|||
listType, |
|||
onChange, |
|||
value, |
|||
showUploadList, |
|||
onStateChange, |
|||
addNew |
|||
} = this.props; |
|||
const { fileList, curPreviewPic, delPicIng, removeFilesList } = this.state; |
|||
const that = this; |
|||
let uploadType_ = uploadType || 'project'; |
|||
let maxFilesNum_ = maxFilesNum || 1; |
|||
let defaultFileTypes = fileTypes || UploadPath[uploadType_]; |
|||
const uploadProps = { |
|||
name: 'checkFile_', |
|||
multiple: false, |
|||
showUploadList: showUploadList || true, |
|||
action: "/_upload/new?type=project", |
|||
listType: listType || 'text', |
|||
disabled: disabled, |
|||
beforeUpload: (file) => { |
|||
if (fileList.length >= maxFilesNum_) { |
|||
message.warning(`最多选择${maxFilesNum_}个文件上传`); |
|||
return false; |
|||
} |
|||
if (file.name.length > 60) { |
|||
message.warning(`文件名过长(大于60字符),请修改后上传`); |
|||
return false; |
|||
} |
|||
const extNames = file.name.split('.'); |
|||
var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/; |
|||
// if (!reg.exec(file.name)) {
|
|||
// message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`);
|
|||
// return false;
|
|||
// }
|
|||
let isDAE = false; |
|||
if (extNames.length > 0) { |
|||
let fileType = extNames[extNames.length - 1].toLowerCase(); |
|||
isDAE = defaultFileTypes.some((f) => f == fileType); |
|||
} |
|||
if (!isDAE) { |
|||
message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); |
|||
return false; |
|||
} |
|||
const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); |
|||
if (!isLt) { |
|||
message.error(`文件必须小于${maxFileSize || 3}MB!`); |
|||
return false; |
|||
} |
|||
this.setState({ |
|||
fileUploading: true |
|||
}); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: true }); |
|||
} |
|||
}, |
|||
onChange(info) { |
|||
const status = info.file.status; |
|||
if (status === 'uploading') { |
|||
that.setState({ |
|||
fileList: info.fileList |
|||
}); |
|||
} |
|||
if (status === 'done') { |
|||
let { filename, realName } = info.file.response; |
|||
let size = info.file.size; |
|||
let nextFileList = fileList; |
|||
nextFileList[nextFileList.length - 1] = { |
|||
uid: -moment().unix(), |
|||
name: info.file.name, |
|||
status: 'done', |
|||
storageUrl: filename, |
|||
url: filename, |
|||
size: size, |
|||
realName: realName |
|||
}; |
|||
onChange(nextFileList); |
|||
that.setState({ |
|||
fileUploading: false, |
|||
fileList: nextFileList |
|||
}); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: false }); |
|||
} |
|||
} else if (status === 'error') { |
|||
that.setState({ |
|||
fileUploading: false |
|||
}); |
|||
message.error(`${info.file.name} 上传失败,请重试`); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: false }); |
|||
} |
|||
} |
|||
}, |
|||
onRemove(file) { |
|||
// if (confirm('请确认是否删除此文件?删除后将不可恢复!') === true) {
|
|||
if (addNew) { |
|||
that.handleOk(that, file, fileList, curPreviewPic, removeFilesList); |
|||
} else { |
|||
confirm({ |
|||
title: '请确认是否删除此文件?删除后将不可恢复!', |
|||
onOk() { |
|||
that.handleOk(that, file, fileList, curPreviewPic, removeFilesList); |
|||
}, |
|||
onCancel() { }, |
|||
}); |
|||
} |
|||
}, |
|||
onPreview(file) { |
|||
let filePostfix = file.url.split('.').pop(); |
|||
filePostfix = filePostfix.toLowerCase(); |
|||
if (UploadPath.image.some((img) => img == filePostfix)) { |
|||
that.setState({ |
|||
curPreviewPic: file.url |
|||
}); |
|||
} else { |
|||
message.warn('仅支持图片预览'); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
let fileList_ = fileList |
|||
// .map(f => {
|
|||
// if (f.storageUrl) {
|
|||
// let realName = f.storageUrl.split('/').pop()
|
|||
// if (f.name != realName) {
|
|||
// f.name = realName
|
|||
// }
|
|||
// }
|
|||
// return f
|
|||
// })
|
|||
|
|||
return ( |
|||
<div> |
|||
<Spin spinning={delPicIng}> |
|||
<Upload {...uploadProps} fileList={fileList_}> |
|||
{ |
|||
disabled ? ( |
|||
'' |
|||
) : |
|||
listType == 'picture-card' ? |
|||
( |
|||
fileList.length >= maxFilesNum_ ? null : ( |
|||
<div style={{}}> |
|||
<PlusOutlined /> |
|||
<div>上传图片</div> |
|||
</div> |
|||
) |
|||
) : ( |
|||
<Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}> 文件上传 </Button> |
|||
) |
|||
} |
|||
</Upload> |
|||
{ |
|||
curPreviewPic ? ( |
|||
<Card |
|||
bodyStyle={{ |
|||
padding: 8 |
|||
}} |
|||
> |
|||
<div style={{ marginBottom: 8 }} > |
|||
<span>文件预览</span> |
|||
<span |
|||
style={{ float: 'right' }} |
|||
onClick={() => { this.setState({ curPreviewPic: '' }); }} |
|||
> |
|||
<CloseOutlined style={{ fontSize: 20 }} /> |
|||
</span> |
|||
</div> |
|||
<img style={{ width: '100%' }} src={curPreviewPic}></img> |
|||
</Card> |
|||
) : '' |
|||
} |
|||
</Spin> |
|||
</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth } = state |
|||
return { |
|||
user: auth.user |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(Uploads); |
@ -0,0 +1,391 @@ |
|||
'use strict'; |
|||
|
|||
import React, { Component } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Spin, Upload, message, Modal, Card, Button } from 'antd'; |
|||
import moment from 'moment'; |
|||
import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; |
|||
|
|||
class Uploads extends Component { |
|||
constructor(props) { |
|||
super(props); |
|||
this.ApiRoot = localStorage.getItem('tyApiRoot') |
|||
this.qnDomain = localStorage.getItem('qnDomain'); |
|||
this.aliAdmin = localStorage.getItem('aliAdmin'); |
|||
this.state = { |
|||
fileUploading: false, |
|||
fileList: [], |
|||
curPreviewPic: '', |
|||
curPreviewVideo: '', |
|||
delPicIng: false, |
|||
removeFilesList: [] |
|||
}; |
|||
} |
|||
|
|||
dealName = (uploaded) => { |
|||
let realName = uploaded.split('/')[2] |
|||
// let x1 = realName.split('.')
|
|||
// let postfix = x1.pop()
|
|||
// let allName = x1.join('.')
|
|||
// let x2 = allName.split('_')
|
|||
// let showName = `${x2[0]}.${postfix}`
|
|||
return realName |
|||
} |
|||
|
|||
// setFileList = (value) => {
|
|||
// let defaultFileList = [];
|
|||
// defaultFileList = value.map((u, index) => {
|
|||
// let fileUrl = `${this.ApiRoot}/${u.url}`;
|
|||
// return {
|
|||
// uid: -index - 1,
|
|||
// name: this.dealName(u.url),
|
|||
// status: 'done',
|
|||
// storageUrl: u.url,
|
|||
// url: fileUrl
|
|||
// };
|
|||
// });
|
|||
// onChange(defaultFileList)
|
|||
// this.setState({
|
|||
// fileList: defaultFileList
|
|||
// });
|
|||
// };
|
|||
|
|||
setFileList = (nextEditData, isQiniu, isAli) => { |
|||
let defaultFileList = []; |
|||
if (nextEditData.length) { |
|||
defaultFileList = nextEditData.map((u, index) => { |
|||
let fileUrl = |
|||
isQiniu ? `/_file-server/${u.storageUrl}` |
|||
: isAli ? `/_file-ali-server/${u.storageUrl}` |
|||
: `${this.ApiRoot}/${u.storageUrl}`; |
|||
|
|||
return { |
|||
uid: -index - 1, |
|||
name: this.dealName(u.storageUrl), |
|||
status: 'done', |
|||
storageUrl: u.storageUrl, |
|||
url: fileUrl, |
|||
size: u.size || -1 |
|||
}; |
|||
}); |
|||
} |
|||
this.setState({ |
|||
fileList: defaultFileList |
|||
}); |
|||
}; |
|||
|
|||
componentDidMount() { |
|||
const { value, defaultValue, isQiniu, isAli } = this.props; |
|||
if (defaultValue) { |
|||
this.setFileList(defaultValue, isQiniu, isAli) |
|||
} |
|||
} |
|||
|
|||
UNSAFE_componentWillReceiveProps(np) { |
|||
const { dispatch, value: thisEditData, onChange } = this.props; |
|||
const { value: nextEditData, isQiniu, isAli } = np; |
|||
// this.setFileList(nextEditData, isQiniu)
|
|||
// const setFileList = () => {
|
|||
// let defaultFileList = [];
|
|||
// defaultFileList = nextEditData.map((u, index) => {
|
|||
// let fileUrl = isQiniu ? `/_file-server/${u.storageUrl}` : `${this.ApiRoot}/${u.storageUrl}`;
|
|||
// return {
|
|||
// uid: -index - 1,
|
|||
// name: this.dealName(u.storageUrl),
|
|||
// status: 'done',
|
|||
// storageUrl: u.storageUrl,
|
|||
// url: fileUrl,
|
|||
// size: u.size || -1
|
|||
// };
|
|||
// });
|
|||
// this.setState({
|
|||
// fileList: defaultFileList
|
|||
// });
|
|||
// };
|
|||
if (nextEditData && nextEditData.length) { |
|||
if (!thisEditData || !this.state.fileList.length) { |
|||
this.setFileList(nextEditData, isQiniu, isAli); |
|||
} else if (nextEditData.length != thisEditData.length) { |
|||
this.setFileList(nextEditData, isQiniu, isAli); |
|||
} else { |
|||
let repeat = true; |
|||
for (let i = 0; i < thisEditData.length; i++) { |
|||
if (thisEditData[i] != nextEditData[i]) { |
|||
repeat = false; |
|||
break; |
|||
} |
|||
} |
|||
if (!repeat) { |
|||
this.setFileList(nextEditData, isQiniu, isAli); |
|||
} |
|||
} |
|||
} |
|||
// else{
|
|||
// this.setState({
|
|||
// fileList:[],
|
|||
// })
|
|||
// }
|
|||
} |
|||
|
|||
render() { |
|||
const UploadPath = { |
|||
project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf', 'pptx', 'png', 'jpg', 'svg', 'jpeg', 'rar', 'zip', 'jpeg', 'mp4'], |
|||
report: ['doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf'], |
|||
data: ['txt', 'xls', 'xlsx', 'csv'], |
|||
image: ['png', 'jpg', 'svg', 'jpeg'], |
|||
three: ['js'], |
|||
video: ['mp4'] |
|||
}; |
|||
/** |
|||
* uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; |
|||
* disabled 【boolean】 上传是否可用 |
|||
* maxFilesNum 【number】 最大上传数量 |
|||
* fileTypes 【array[string]】 可允许上传的文件类型; |
|||
* maxFileSize 【number】 单个文件最大大小 M |
|||
* listType 【antd】 upload 组件的属性 |
|||
* onChange 【function】 文件数量变化时候回调 返回文件 |
|||
* value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] |
|||
* onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } |
|||
*/ |
|||
const { |
|||
uploadType, |
|||
disabled, |
|||
maxFilesNum, |
|||
fileTypes, |
|||
maxFileSize, |
|||
listType, |
|||
onChange = () => { }, |
|||
value, |
|||
showUploadList, |
|||
onStateChange, |
|||
isQiniu, |
|||
isAli, |
|||
} = this.props; |
|||
const { fileList, curPreviewPic, curPreviewVideo, delPicIng, removeFilesList } = this.state; |
|||
const that = this; |
|||
let uploadType_ = uploadType || 'project'; |
|||
let maxFilesNum_ = maxFilesNum || 1; |
|||
let defaultFileTypes = fileTypes || UploadPath[uploadType_]; |
|||
// debugger
|
|||
const uploadProps = { |
|||
name: 'checkFile_', |
|||
multiple: false, |
|||
showUploadList: showUploadList || true, |
|||
action: |
|||
isQiniu ? `/_upload/attachments/${uploadType_}` |
|||
: isAli ? `/_upload/attachments/ali/${uploadType_}` |
|||
: `${this.ApiRoot}/attachments/${uploadType_}`, |
|||
listType: listType || 'text', |
|||
disabled: disabled, |
|||
beforeUpload: (file) => { |
|||
if (fileList.length >= maxFilesNum_) { |
|||
message.warning(`最多选择${maxFilesNum_}个文件上传`); |
|||
return false; |
|||
} |
|||
if (file.name.length > 60) { |
|||
message.warning(`文件名过长(大于60字符),请修改后上传`); |
|||
return false; |
|||
} |
|||
const extNames = file.name.split('.'); |
|||
// var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/;
|
|||
// if (!reg.exec(file.name)) {
|
|||
// message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`);
|
|||
// return false;
|
|||
// }
|
|||
let isDAE = false; |
|||
if (extNames.length > 0) { |
|||
let fileType = extNames[extNames.length - 1].toLowerCase(); |
|||
isDAE = defaultFileTypes.some((f) => f == fileType); |
|||
} |
|||
if (!isDAE) { |
|||
message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); |
|||
return false; |
|||
} |
|||
const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); |
|||
if (!isLt) { |
|||
message.error(`文件必须小于${maxFileSize || 3}MB!`); |
|||
return false; |
|||
} |
|||
this.setState({ |
|||
fileUploading: true |
|||
}); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: true }); |
|||
} |
|||
}, |
|||
onChange(info) { |
|||
const status = info.file.status; |
|||
if (status === 'uploading') { |
|||
that.setState({ |
|||
fileList: info.fileList |
|||
}); |
|||
} |
|||
if (status === 'done') { |
|||
let { uploaded, url } = info.file.response; |
|||
let size = info.file.size; |
|||
let nextFileList = fileList; |
|||
nextFileList[nextFileList.length - 1] = { |
|||
uid: -moment().unix(), |
|||
name: that.dealName(uploaded), |
|||
status: 'done', |
|||
storageUrl: uploaded, |
|||
url: |
|||
isQiniu ? '/_file-server/' + uploaded : |
|||
isAli ? `/_file-ali-server/${uploaded}` : |
|||
url, |
|||
size: size |
|||
}; |
|||
onChange(nextFileList); |
|||
that.setState({ |
|||
fileUploading: false, |
|||
fileList: nextFileList |
|||
}); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: false }); |
|||
} |
|||
} else if (status === 'error') { |
|||
that.setState({ |
|||
fileUploading: false |
|||
}); |
|||
message.error(`${info.file.name} 上传失败,请重试`); |
|||
if (onStateChange) { |
|||
onStateChange({ uploading: false }); |
|||
} |
|||
} |
|||
}, |
|||
onRemove(file) { |
|||
let nextFileList = []; |
|||
fileList.map((f, i) => { |
|||
if (f.uid != file.uid) { |
|||
nextFileList.push(f); |
|||
} |
|||
}); |
|||
let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); |
|||
if (curPreviewPic == file.url) { |
|||
that.setState({ |
|||
curPreviewPic: '' |
|||
}); |
|||
} |
|||
if (curPreviewVideo == file.url) { |
|||
that.setState({ |
|||
curPreviewVideo: '' |
|||
}); |
|||
} |
|||
onChange(nextFileList); |
|||
that.setState({ |
|||
fileList: nextFileList, |
|||
removeFilesList: nextRemoveFiles |
|||
}); |
|||
}, |
|||
onPreview(file) { |
|||
let filePostfix = file.url.split('.').pop(); |
|||
filePostfix = filePostfix.toLowerCase(); |
|||
if (UploadPath.image.some((img) => img == filePostfix)) { |
|||
that.setState({ |
|||
curPreviewPic: file.url |
|||
}); |
|||
} else if (UploadPath.video.some((img) => img == filePostfix)) { |
|||
that.setState({ |
|||
curPreviewVideo: file.url |
|||
}); |
|||
} else { |
|||
//message.warn('仅支持图片预览');
|
|||
preview(file.storageUrl) |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const preview = (url) => { |
|||
let link = isQiniu ? encodeURI(`${this.qnDomain}/${url}`) : |
|||
isAli ? encodeURI(`${this.aliAdmin}/${url}`) : '' |
|||
if (link) |
|||
if (url.indexOf("pdf") !== -1 || url.indexOf("csv") !== -1) { |
|||
window.open(link) |
|||
} else { |
|||
window.open(`https://view.officeapps.live.com/op/view.aspx?src=${link}`) |
|||
} |
|||
} |
|||
|
|||
let fileList_ = fileList |
|||
// .map(f => {
|
|||
// if (f.storageUrl) {
|
|||
// let realName = f.storageUrl.split('/').pop()
|
|||
// if (f.name != realName) {
|
|||
// f.name = realName
|
|||
// }
|
|||
// }
|
|||
// return f
|
|||
// })
|
|||
//下载文件
|
|||
const handleDownload = (file) => { |
|||
saveAs(file) |
|||
}; |
|||
const saveAs = (file) => { |
|||
const link = document.createElement('a'); |
|||
link.href = file.url; |
|||
link.download = file.name; |
|||
link.style.display = 'none'; |
|||
link.click(); |
|||
} |
|||
//自定义下载
|
|||
return ( |
|||
<div> |
|||
<Spin spinning={delPicIng}> |
|||
<Upload {...uploadProps} fileList={fileList_} showUploadList={{ showDownloadIcon: true }} onDownload={handleDownload}> |
|||
{ |
|||
disabled ? ( |
|||
'' |
|||
) : |
|||
listType == 'picture-card' ? |
|||
( |
|||
fileList.length >= maxFilesNum_ ? null : ( |
|||
<div style={{}}> |
|||
<PlusOutlined /> |
|||
<div>添加附件</div> |
|||
</div> |
|||
) |
|||
) : ( |
|||
<Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}> 文件上传 </Button> |
|||
) |
|||
} |
|||
</Upload> |
|||
{ |
|||
curPreviewPic ? ( |
|||
<Card bodyStyle={{ padding: 8 }}> |
|||
<div style={{ marginBottom: 8 }} > |
|||
<span>图片预览</span> |
|||
<span style={{ float: 'right' }} onClick={() => { this.setState({ curPreviewPic: '' }) }}> |
|||
<CloseOutlined style={{ fontSize: 20 }} /> |
|||
</span> |
|||
</div> |
|||
<img style={{ width: '100%' }} src={curPreviewPic} /> |
|||
</Card> |
|||
) : '' |
|||
} |
|||
{ |
|||
curPreviewVideo ? (<Card bodyStyle={{ padding: 8 }}> |
|||
<div style={{ marginBottom: 8 }} > |
|||
<span>视频预览</span> |
|||
<span style={{ float: 'right' }} onClick={() => { this.setState({ curPreviewVideo: '' }) }}> |
|||
<CloseOutlined style={{ fontSize: 20 }} /> |
|||
</span> |
|||
</div> |
|||
<video controls style={{ width: '100%' }}> |
|||
<source src={curPreviewVideo} type="video/mp4"></source> |
|||
</video> |
|||
</Card>) : '' |
|||
} |
|||
</Spin> |
|||
</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth } = state |
|||
return { |
|||
user: auth.user |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(Uploads); |
@ -0,0 +1,51 @@ |
|||
'use strict'; |
|||
|
|||
import React, { Component } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Button, Popover, Icon } from 'antd'; |
|||
import { EllipsisOutlined } from '@ant-design/icons'; |
|||
|
|||
class ButtonGroup extends Component { |
|||
constructor(props) { |
|||
super(props); |
|||
this.state = { |
|||
|
|||
}; |
|||
} |
|||
|
|||
content = () => { |
|||
<Button></Button> |
|||
} |
|||
|
|||
render_ = () => { |
|||
const { children } = this.props |
|||
return ( |
|||
<div style={{ cursor: 'pointer' }}> |
|||
<Popover placement="bottomRight" content={children} arrowPointAtCenter> |
|||
<EllipsisOutlined style={{ fontSize: 20, fontWeight: 'bolder' }} /> |
|||
</Popover> |
|||
</div > |
|||
) |
|||
} |
|||
|
|||
render() { |
|||
const { children } = this.props |
|||
if (children) { |
|||
if (Array.isArray(children)) { |
|||
if (children.some(c => c)) { |
|||
return this.render_() |
|||
} |
|||
} else { |
|||
return this.render_() |
|||
} |
|||
} |
|||
return '' |
|||
} |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
return { |
|||
} |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(ButtonGroup); |
@ -0,0 +1,683 @@ |
|||
/** |
|||
* Created by Xumeng 2020/04/22. |
|||
*/ |
|||
|
|||
import React, { useState, useEffect } from 'react'; |
|||
import PropTypes from 'prop-types'; |
|||
import { |
|||
Row, Col, Space, Button, message, notification, Form, Input, Tooltip, |
|||
} from 'antd'; |
|||
import moment from 'moment'; |
|||
import XLSX from 'xlsx'; |
|||
import { fromJS } from 'immutable'; |
|||
import { Request } from '@peace/utils'; |
|||
import FileSaver from 'file-saver'; |
|||
import './index.less'; |
|||
|
|||
// 通用前端导入导出组件 使用方法查看底部propTypes
|
|||
function ExportAndImport (props) { |
|||
const [form] = Form.useForm(); |
|||
const [exportLoading, setExportLoading] = useState(false); |
|||
const [importLoading, setImportLoading] = useState(false); |
|||
const { |
|||
importDataCallback, onImportSucess, handelData, importMethod = 'post', |
|||
} = props; |
|||
|
|||
useEffect(() => () => { |
|||
// 只有unmount 时调用
|
|||
notification.close('import-notification'); |
|||
}); |
|||
const importExcel = (file, type) => { |
|||
setImportLoading(true); |
|||
// 获取上传的文件对象
|
|||
const { files } = file.target; |
|||
// 判断xls、xlsx格式
|
|||
if (files[0].type.indexOf('sheet') > -1 || files[0].type.indexOf('ms-excel') > -1) { |
|||
// 通过FileReader对象读取文件
|
|||
const fileReader = new FileReader(); |
|||
fileReader.onload = (event) => { |
|||
try { |
|||
const { importRequest = true, importUrl, importQuery } = props; |
|||
if (importRequest && !importUrl) { |
|||
message.error('获取导入接口失败!'); |
|||
form.resetFields(); |
|||
return; |
|||
} |
|||
const { result } = event.target; |
|||
// 以二进制流方式读取得到整份excel表格对象
|
|||
const workbook = XLSX.read(result, { type: 'binary', cellDates: true }); |
|||
let data = []; // 存储获取到的数据
|
|||
// 遍历每张工作表进行读取(这里默认只读取第一张表)
|
|||
for (const sheet in workbook.Sheets) { |
|||
if (workbook.Sheets.hasOwnProperty(sheet)) { |
|||
// 利用 sheet_to_json 方法将 excel 转成 json 数据
|
|||
data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet])); |
|||
break; // 如果只取第一张表,就取消注释这行
|
|||
} |
|||
} |
|||
if (data.length > 10000) { |
|||
message.error('一次最多导入10000条数据,请分批导入!'); |
|||
form.resetFields(); |
|||
setImportLoading(false); |
|||
return; |
|||
} |
|||
if (importRequest) { |
|||
message.success('获取文件数据成功,开始处理导入...'); |
|||
const importData = handelData ? handelData(data) : data; |
|||
Request[importMethod](importUrl, { data: importData }, importQuery || {}).then((res) => { |
|||
message.success('导入数据成功'); |
|||
form.resetFields(); |
|||
notification.close('import-notification'); |
|||
setImportLoading(false); |
|||
onImportSucess && onImportSucess(); |
|||
}, (err) => { |
|||
if (err.status === 500) { |
|||
message.error('数据导入出错,导入失败'); |
|||
} else if (err.status === 400) { |
|||
message.error(err.body.message || '数据验证出错,请检查数据格式是否正确'); |
|||
} else { |
|||
message.error('导入失败'); |
|||
} |
|||
form.resetFields(); |
|||
setImportLoading(false); |
|||
}); |
|||
} else { |
|||
form.resetFields(); |
|||
setImportLoading(false); |
|||
importDataCallback && importDataCallback(data, type); |
|||
notification.close('import-notification'); |
|||
} |
|||
} catch (e) { |
|||
console.log(e); |
|||
// 这里可以抛出文件类型错误不正确的相关提示
|
|||
message.error('文件格式不正确!'); |
|||
setImportLoading(false); |
|||
form.resetFields(); |
|||
} |
|||
}; |
|||
// fileReader.onloadend = (event) => {
|
|||
// console.log(event)
|
|||
// }
|
|||
// 以二进制方式打开文件
|
|||
fileReader.readAsBinaryString(files[0]); |
|||
} else { |
|||
message.error('文件格式不正确!'); |
|||
form.resetFields(); |
|||
setImportLoading(false); |
|||
} |
|||
}; |
|||
|
|||
const loop = (data, keypath, values) => { // deal with array
|
|||
const dkey = keypath.slice(0, 1)[0]; |
|||
console.log(dkey); |
|||
if (dkey) { |
|||
const dvalue = data[dkey]; |
|||
const otherKeypath = keypath.slice(1); |
|||
if (Array.isArray(dvalue)) { |
|||
if (otherKeypath.length) { |
|||
const immutableData = fromJS(data); |
|||
for (let index = 0; index < dvalue.length; index++) { |
|||
const tmp = immutableData.getIn([dkey, index]).toJS(); |
|||
loop(tmp, otherKeypath, values); |
|||
} |
|||
} |
|||
} else { |
|||
values.push(dvalue); |
|||
} |
|||
} |
|||
return values; |
|||
}; |
|||
const getColumnData = (opts) => { |
|||
const { |
|||
data, keypath, render, spliter, rawdata, |
|||
} = opts; |
|||
let v = null; |
|||
const outer = data[keypath[0]]; |
|||
|
|||
if (Array.isArray(outer)) { |
|||
const values = loop(data, keypath, []); |
|||
v = rawdata ? values : values.join(spliter || ','); |
|||
} else { |
|||
v = fromJS(data).getIn(keypath); |
|||
} |
|||
// 处理render
|
|||
if (render && typeof render === 'function') { |
|||
v = render(outer, data); |
|||
} |
|||
return v; |
|||
}; |
|||
const getDataSource = (attrs, filterData) => { |
|||
// let token = JSON.parse(sessionStorage.getItem('user')).token;
|
|||
const dataSource = filterData.map((item) => { |
|||
const record = {}; |
|||
attrs.forEach((attr) => { |
|||
const { |
|||
key, dataIndex, render, child, |
|||
} = attr; |
|||
if (child) { |
|||
record[key] = getDataSource(child, item[key]); |
|||
} else { |
|||
const v = getColumnData({ |
|||
data: item, |
|||
keypath: dataIndex || [key], |
|||
render: render || null, |
|||
}); |
|||
record[key] = v; |
|||
} |
|||
}); |
|||
|
|||
return record; |
|||
}); |
|||
return dataSource; |
|||
}; |
|||
// 暂时只处理两层
|
|||
const getFlatData = (attrs, filterData, dataToAoa, deep = 0) => { |
|||
filterData.map((item) => { |
|||
let cur = dataToAoa[deep]; |
|||
if (!cur) { |
|||
cur = dataToAoa[deep] = []; |
|||
} |
|||
attrs.map((attr, index) => { |
|||
const { key, child } = attr; |
|||
if (child) { |
|||
if (Array.isArray(item[key])) { |
|||
// getFlatData(child,item[key],dataToAoa,deep)
|
|||
|
|||
item[key].map((s, i) => { |
|||
if (i == 0) { |
|||
child.map((c) => { |
|||
cur.push(s[c.key]); |
|||
}); |
|||
} else { |
|||
deep++; |
|||
const childCur = dataToAoa[deep] = []; |
|||
pushNull(childCur, index); |
|||
child.map((c) => { |
|||
childCur.push(s[c.key]); |
|||
}); |
|||
} |
|||
}); |
|||
} |
|||
} else { |
|||
cur.push(item[key]); |
|||
} |
|||
}); |
|||
deep++; |
|||
}); |
|||
}; |
|||
|
|||
const getHeader = (headers, excelHeader, deep, perOffset) => { |
|||
let offset = 0; |
|||
let cur = excelHeader[deep]; |
|||
if (!cur) { |
|||
cur = excelHeader[deep] = []; |
|||
} |
|||
pushNull(cur, perOffset - cur.length); |
|||
for (let i = 0; i < headers.length; i++) { |
|||
const head = headers[i]; |
|||
cur.push(head.name); |
|||
if (head.hasOwnProperty('child') && Array.isArray(head.child) && head.child.length > 0) { |
|||
const childOffset = getHeader(head.child, excelHeader, deep + 1, cur.length - 1); |
|||
pushNull(cur, childOffset - 1); |
|||
offset += childOffset; |
|||
} else { |
|||
offset++; |
|||
} |
|||
} |
|||
return offset; |
|||
}; |
|||
|
|||
const pushNull = (arr, count) => { |
|||
for (let i = 0; i < count; i++) { |
|||
arr.push(null); |
|||
} |
|||
}; |
|||
const fillNull = (arr) => { |
|||
const max = Math.max(...(arr.map((a) => a.length))); |
|||
arr.filter((e) => e.length < max).forEach((e) => pushNull(e, max - e.length)); |
|||
}; |
|||
const doMerges = (arr) => { |
|||
// 要么横向合并 要么纵向合并
|
|||
const deep = arr.length; |
|||
const merges = []; |
|||
for (let y = 0; y < deep; y++) { |
|||
// 先处理横向合并
|
|||
const row = arr[y]; |
|||
let colSpan = 0; |
|||
for (let x = 0; x < row.length; x++) { |
|||
if (row[x] === null) { |
|||
colSpan++; |
|||
if (((x + 1) === row.length) && (colSpan > 0 && x > colSpan)) { |
|||
merges.push({ s: { r: y, c: x - colSpan }, e: { r: y, c: x } }); |
|||
} |
|||
} else if (colSpan > 0 && x > colSpan) { |
|||
merges.push({ s: { r: y, c: x - colSpan - 1 }, e: { r: y, c: x - 1 } }); |
|||
colSpan = 0; |
|||
} else { |
|||
colSpan = 0; |
|||
} |
|||
} |
|||
} |
|||
// 再处理纵向合并
|
|||
const colLength = arr[0].length; |
|||
for (let x = 0; x < colLength; x++) { |
|||
let rowSpan = 0; |
|||
for (let y = 0; y < deep; y++) { |
|||
if (arr[y][x] != null) { |
|||
rowSpan = 0; |
|||
} else { |
|||
rowSpan++; |
|||
} |
|||
} |
|||
if (rowSpan > 0) { |
|||
merges.push({ s: { r: deep - rowSpan - 1, c: x }, e: { r: deep - 1, c: x } }); |
|||
} |
|||
} |
|||
return merges; |
|||
}; |
|||
// 内容暂只出了纵向合并
|
|||
const doContetMerges = (arr, headerLength) => { |
|||
const deep = arr.length; |
|||
const merges = []; |
|||
// 处理纵向合并
|
|||
const colLength = arr[0].length; |
|||
for (let x = 0; x < colLength; x++) { |
|||
let rowSpan = 0; |
|||
const mergY = 0; |
|||
for (let y = 0; y < deep; y++) { |
|||
if (rowSpan > 0) { |
|||
// 如果还有null 继续加
|
|||
if (arr[y][x] === null) { |
|||
rowSpan += 1; |
|||
} else { |
|||
// 不为null 增加merge
|
|||
merges.push({ s: { r: headerLength + (y - rowSpan - 1), c: x }, e: { r: headerLength + y - 1, c: x } }); |
|||
rowSpan = 0; |
|||
} |
|||
} else if (arr[y][x] === null) { |
|||
rowSpan += 1; |
|||
} |
|||
} |
|||
if (rowSpan > 0) { |
|||
merges.push({ s: { r: headerLength + (deep - rowSpan - 1), c: x }, e: { r: headerLength + deep - 1, c: x } }); |
|||
rowSpan = 0; |
|||
} |
|||
} |
|||
return merges; |
|||
}; |
|||
const exportMergeExcel = async () => { |
|||
setExportLoading(true); |
|||
const { |
|||
column, data, fileName, exportUrl, exportQuery, exportBody, requestType, header, showYearMouth, |
|||
} = props || {}; |
|||
|
|||
let resultData = []; |
|||
if (exportUrl) { |
|||
resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { |
|||
// 数据接口返回的结果 如果是对象 必须把返回数组放入rows
|
|||
if (typeof data === 'object' && data.rows) { |
|||
return data.rows; |
|||
} |
|||
return data; |
|||
}, (err) => { |
|||
message.error('获取数据失败,导出失败!'); |
|||
}) : await Request.get(exportUrl, exportQuery || {}).then((data) => { |
|||
if (typeof data === 'object' && data.rows) { |
|||
return data.rows; |
|||
} |
|||
return data; |
|||
}, (err) => { |
|||
message.error('获取数据失败,导出失败!'); |
|||
}); |
|||
if (!resultData) { |
|||
return; |
|||
} |
|||
} else { |
|||
resultData = data; |
|||
} |
|||
const excelHeader = []; |
|||
getHeader(column, excelHeader, 0, 0); |
|||
fillNull(excelHeader); |
|||
|
|||
// console.log(excelHeader);
|
|||
|
|||
const loopData = getDataSource(column, resultData); |
|||
// console.log(loopData)
|
|||
|
|||
const dataToAoa = []; |
|||
getFlatData(column, loopData, dataToAoa, 0); |
|||
fillNull(dataToAoa); |
|||
// console.log(dataToAoa);
|
|||
|
|||
const aoa = [].concat(excelHeader, dataToAoa); |
|||
// console.log(aoa)
|
|||
|
|||
const headerMerges = doMerges(excelHeader); |
|||
const contentMerages = doContetMerges(dataToAoa, excelHeader.length); |
|||
const merges = [].concat(headerMerges, contentMerages); |
|||
// console.log(contentMerages)
|
|||
|
|||
// let opts = {
|
|||
// defaultCellStyle: {
|
|||
// font: { name: "宋体", sz: 11, color: { auto: 1 } },
|
|||
// border: {
|
|||
// color: { auto: 1 }
|
|||
// },
|
|||
// alignment: {
|
|||
// /// 自动换行
|
|||
// wrapText: 1,
|
|||
// // 居中
|
|||
// horizontal: "center",
|
|||
// vertical: "center",
|
|||
// indent: 0
|
|||
// }
|
|||
// }
|
|||
// }
|
|||
const sheet = XLSX.utils.aoa_to_sheet(aoa); |
|||
// let newSheet = {};
|
|||
// for (let [key, value] of Object.entries(sheet)) {
|
|||
// if(key == '!ref'){
|
|||
// newSheet[key] = value
|
|||
// }else if(typeof value === 'object'){
|
|||
// newSheet[key] = {
|
|||
// ...value,
|
|||
// s: opts.defaultCellStyle
|
|||
// }
|
|||
// }
|
|||
// }
|
|||
const wpx = column.map((c) => ({ |
|||
wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, |
|||
})); |
|||
sheet['!cols'] = wpx; |
|||
sheet['!merges'] = merges; |
|||
|
|||
// 构建 workbook 对象
|
|||
const workbook = XLSX.utils.book_new(); |
|||
|
|||
const time = moment().format('YYYY-MM-DD'); |
|||
|
|||
XLSX.utils.book_append_sheet(workbook, sheet, 'mySheet'); |
|||
// 导出 Excel
|
|||
XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : '导出数据.xlsx'); |
|||
setExportLoading(false); |
|||
// message.success(`成功导出了 ${loopData.length || 0} 条数据`);
|
|||
}; |
|||
|
|||
const exportProExcel = async () => { |
|||
setExportLoading(true); |
|||
const { |
|||
column, data, fileName, exportUrl, exportQuery, exportBody, requestType, showYearMouth, |
|||
} = props || {}; |
|||
let resultData = []; |
|||
if (exportUrl) { |
|||
resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { |
|||
// 数据接口返回的结果 如果是对象 必须把返回数组放入rows
|
|||
if (typeof data === 'object') { |
|||
return data.data ? data.data : data.rows; |
|||
} |
|||
return data; |
|||
}, (err) => { |
|||
message.error('获取数据失败,导出失败!'); |
|||
}) : await Request.get(exportUrl, exportQuery || {}).then((data) => { |
|||
if (showYearMouth) { |
|||
|
|||
} |
|||
if (typeof data === 'object' && data.rows) { |
|||
return data.rows; |
|||
} |
|||
return data; |
|||
}, (err) => { |
|||
message.error('获取数据失败,导出失败!'); |
|||
}); |
|||
if (!resultData) { |
|||
return; |
|||
} |
|||
} else { |
|||
resultData = data; |
|||
} |
|||
|
|||
const loopData = getDataSource(column, resultData); |
|||
|
|||
let content = ''; |
|||
let header = '<tr>'; |
|||
// header += `<th><div>序号</div></th>`;
|
|||
column.map((colum) => { |
|||
header += `<th><div>${colum.name}</div></th>`; |
|||
}); |
|||
header += '</tr>'; |
|||
loopData.map((data) => { |
|||
content += '<tr>'; |
|||
column.map((c) => { |
|||
if (c.style) { |
|||
content += `<th style="${c.style}"><div>${data[c.dataIndex || c.key]}</div></th>`; |
|||
} else { |
|||
content += `<th><div>${data[c.dataIndex || c.key]}</div></th>`; |
|||
} |
|||
}); |
|||
content += '</tr>'; |
|||
}); |
|||
|
|||
const exportTable = `\uFEFF
|
|||
<table style='text-alagin:center' border="1"> |
|||
${header} |
|||
${content} |
|||
</table> |
|||
`;
|
|||
const time = moment().format('YYYY-MM-DD'); |
|||
const tempStrs = new Blob([exportTable], { type: 'text/xls' }); |
|||
FileSaver.saveAs(tempStrs, fileName ? `${fileName}-${time}.xls` : '导出数据.xls'); |
|||
setExportLoading(false); |
|||
// message.success(`成功导出了 ${loopData.length || 0} 条数据`);
|
|||
}; |
|||
|
|||
const exportExcel = async () => { |
|||
setExportLoading(true); |
|||
const { |
|||
column, data, fileName, exportUrl, exportQuery, exportBody, requestType, |
|||
} = props || {}; |
|||
const _headers = column |
|||
.map((item, i) => ({ key: item.key, title: item.name, position: String.fromCharCode(65 + i) + 1 })) |
|||
.reduce((prev, next) => ({ ...prev, [next.position]: { key: next.key, v: next.title } }), {}); |
|||
let resultData = []; |
|||
if (exportUrl) { |
|||
resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { |
|||
// 数据接口返回的结果 如果是对象 必须把返回数组放入rows
|
|||
|
|||
if (typeof data === 'object' && (data.rows || data.data)) { |
|||
return data.data ? data.data : data.rows; |
|||
} |
|||
return data; |
|||
}, (err) => { |
|||
message.error('获取数据失败,导出失败!'); |
|||
}) : await Request.get(exportUrl, exportQuery || {}).then((data) => { |
|||
if (typeof data === 'object' && data.rows) { |
|||
return data.rows; |
|||
} |
|||
return data; |
|||
}, (err) => { |
|||
message.error('获取数据失败,导出失败!'); |
|||
}); |
|||
if (!resultData) { |
|||
return; |
|||
} |
|||
} else { |
|||
resultData = data; |
|||
} |
|||
|
|||
const loopDate = getDataSource(column, resultData); |
|||
|
|||
const wpx = column.map((c) => ({ |
|||
wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, |
|||
})); |
|||
if (!(loopDate.length > 0)) { |
|||
setExportLoading(false); |
|||
return; |
|||
} |
|||
const _data = loopDate |
|||
.map((item, i) => column.map((key, j) => ({ content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) }))) |
|||
// 对刚才的结果进行降维处理(二维数组变成一维数组)
|
|||
.reduce((prev, next) => prev.concat(next)) |
|||
// 转换成 worksheet 需要的结构
|
|||
.reduce((prev, next) => ({ ...prev, [next.position]: { v: next.content } }), {}); |
|||
|
|||
// 合并 column 和 data
|
|||
const output = { ..._headers, ..._data }; |
|||
// 获取所有单元格的位置
|
|||
const outputPos = Object.keys(output); |
|||
// 计算出范围 ,["A1",..., "H2"]
|
|||
const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`; |
|||
|
|||
// 构建 workbook 对象
|
|||
const workbook = { |
|||
SheetNames: ['mySheet'], |
|||
Sheets: { |
|||
mySheet: { |
|||
|
|||
...output, |
|||
'!ref': ref, |
|||
'!cols': wpx, |
|||
}, |
|||
}, |
|||
}; |
|||
const time = moment().format('YYYY-MM-DD'); |
|||
// 导出 Excel
|
|||
XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : '导出数据.xlsx'); |
|||
setExportLoading(false); |
|||
// message.success(`成功导出了 ${loopDate.length || 0} 条数据`);
|
|||
}; |
|||
|
|||
const exportTemplete = async () => { |
|||
const { importTemColumn, importTemData, fileName } = props || {}; |
|||
const _headers = importTemColumn |
|||
.map((item, i) => { |
|||
let group = 0; // 用于处理Z1的时候,重计算AA1
|
|||
if (parseInt(i / 26) > group) { |
|||
group = parseInt(i / 26); |
|||
} |
|||
if (group > 0) { // AA1 BA1 CA1
|
|||
const position = String.fromCharCode(65 + (group - 1)); |
|||
return { key: item.key, title: item.name, position: position + String.fromCharCode(65 + (i % 26)) + 1 }; |
|||
} return { key: item.key, title: item.name, position: String.fromCharCode(65 + i) + 1 }; |
|||
}) |
|||
.reduce((prev, next) => ({ ...prev, [next.position]: { key: next.key, v: next.title } }), {}); |
|||
|
|||
const loopDate = getDataSource(importTemColumn, importTemData); |
|||
|
|||
const wpx = importTemColumn.map((c) => ({ |
|||
wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, |
|||
})); |
|||
const _data = loopDate.length ? loopDate |
|||
.map((item, i) => importTemColumn.map((key, j) => ({ content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) }))) |
|||
// 对刚才的结果进行降维处理(二维数组变成一维数组)
|
|||
.reduce((prev, next) => prev.concat(next)) |
|||
// 转换成 worksheet 需要的结构
|
|||
.reduce((prev, next) => ({ ...prev, [next.position]: { v: next.content } }), {}) : []; |
|||
// 合并 column 和 data
|
|||
const output = { ..._headers, ..._data }; |
|||
// 获取所有单元格的位置
|
|||
const outputPos = Object.keys(output); |
|||
// 计算出范围 ,["A1",..., "H2"]
|
|||
const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`; |
|||
|
|||
// 构建 workbook 对象
|
|||
const workbook = { |
|||
SheetNames: ['mySheet'], |
|||
Sheets: { |
|||
mySheet: { |
|||
|
|||
...output, |
|||
'!ref': ref, |
|||
'!cols': wpx, |
|||
}, |
|||
}, |
|||
}; |
|||
// 导出 Excel
|
|||
XLSX.writeFile(workbook, fileName ? `${fileName}-导入模板.xlsx` : '导入模板.xlsx'); |
|||
}; |
|||
const tips = (type) => { |
|||
const { tips, templeteBth = true } = props; |
|||
const description = ( |
|||
<div className="export-import"> |
|||
{tips && tips} |
|||
<Row gutter={16}> |
|||
<Col span={12}> |
|||
<Form form={form} initialValues={{}}> |
|||
<Form.Item name="import-file"> |
|||
<Input className="file-uploader" type="file" accept=".xlsx, .xls" onChange={(e) => importExcel(e, type)} /> |
|||
<Button style={props.btnStyle} className={props.btnClass} loading={importLoading}> |
|||
选择文件 |
|||
</Button> |
|||
</Form.Item> |
|||
</Form> |
|||
</Col> |
|||
{templeteBth && ( |
|||
<Col span={12}> |
|||
<Button style={props.btnStyle} className={props.btnClass} onClick={exportTemplete}> |
|||
模板下载 |
|||
</Button> |
|||
</Col> |
|||
)} |
|||
</Row> |
|||
</div> |
|||
); |
|||
|
|||
notification.info({ |
|||
message: '支持 .xlsx、.xls 格式的文件', |
|||
description, |
|||
key: 'import-notification', |
|||
duration: null, |
|||
}); |
|||
}; |
|||
|
|||
return ( |
|||
<Space> |
|||
{ |
|||
props.import && ( |
|||
<Button style={props.btnStyle} className={props.btnClass} loading={importLoading} onClick={tips}> |
|||
{props.importBtnName || '导入'} |
|||
</Button> |
|||
) |
|||
} |
|||
{ |
|||
props.export && ( |
|||
<Tooltip placement="top" title={props.exportBtnTips || '默认导出所有数据'}> |
|||
<Button style={props.btnStyle} className={props.btnClass} loading={exportLoading} onClick={props.exportType === 'pro' ? exportProExcel : exportExcel}> |
|||
{props.exportBtnName || '导出'} |
|||
</Button> |
|||
</Tooltip> |
|||
) |
|||
} |
|||
</Space> |
|||
); |
|||
} |
|||
|
|||
ExportAndImport.propTypes = { |
|||
export: PropTypes.bool, // 是否显示导出按钮
|
|||
exportBtnName: PropTypes.string, // 导出按钮文字
|
|||
importBtnName: PropTypes.string, // 导入按钮文字
|
|||
import: PropTypes.bool, // 是否显示导入按钮
|
|||
variedImport: PropTypes.bool, // 是否显示多样导入
|
|||
variedImportDisable: PropTypes.bool, // 多样导入禁用
|
|||
variedImportBtnName: PropTypes.string, // 多样导入文字
|
|||
column: PropTypes.array, // 导出显示的header数组 兼容antd column 可直接拿table的column使用 注:column每列的属性wpx设置导出的execl每列的宽度值 默认 100
|
|||
data: PropTypes.array, // 导出的数据 兼容antd table 数组嵌套处理
|
|||
exportUrl: PropTypes.string, // 导出数据从接口获取的url地址 返回的数据1、数组必须支持column的设置 ,2、如果是对象,数组需放在rows属性上
|
|||
exportBody: PropTypes.object, // 导出数据接口body参数
|
|||
exportQuery: PropTypes.object, // 导出数据从接口获取的url地址上的参数
|
|||
exportBtnTips: PropTypes.string, // 导出按钮tips文字提示
|
|||
importUrl: PropTypes.string, // 导入接口url
|
|||
importQuery: PropTypes.object, // 导入接口url地址上的参数
|
|||
btnClass: PropTypes.string, // 按钮className
|
|||
btnStyle: PropTypes.object, // 按钮style
|
|||
tips: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), // 上传文件提示的信息
|
|||
onImportSucess: PropTypes.func, // 上传成功后 返回处理函数
|
|||
importTemColumn: PropTypes.array, // 导入模板设置 头部字段数组
|
|||
importTemData: PropTypes.array, // 导入模板默认数据
|
|||
requestType: PropTypes.string, // 请求类型
|
|||
importDataCallback: PropTypes.func, // 上传后数据返回
|
|||
templeteBth: PropTypes.bool, // 模板按钮
|
|||
importRequest: PropTypes.bool, // 请求导入接口,false时搭配importDataCallback,
|
|||
exportType: PropTypes.string, // 导出执行的函数名
|
|||
}; |
|||
|
|||
export default ExportAndImport; |
@ -0,0 +1,13 @@ |
|||
.export-import { |
|||
.file-uploader { |
|||
position: absolute; |
|||
width: 100%; |
|||
height: 100%; |
|||
top: 0; |
|||
left: 0; |
|||
outline: none; |
|||
opacity: 0; |
|||
background-color: transparent; |
|||
z-index: 10; |
|||
} |
|||
} |
@ -0,0 +1,18 @@ |
|||
|
|||
'use strict'; |
|||
|
|||
import Upload from './Upload'; |
|||
import Uploads from './Uploads'; |
|||
import NoResource from './no-resource'; |
|||
import ExportAndImport from './export'; |
|||
import ButtonGroup from './buttonGroup'; |
|||
import UploadLocal from './UploadLocal'; |
|||
|
|||
export { |
|||
Upload, |
|||
Uploads, |
|||
NoResource, |
|||
ExportAndImport, |
|||
ButtonGroup, |
|||
UploadLocal |
|||
}; |
@ -0,0 +1,21 @@ |
|||
'use strict'; |
|||
|
|||
import React from 'react'; |
|||
import { Result} from 'antd'; |
|||
import { MehOutlined } from '@ant-design/icons'; |
|||
class NoResource extends React.Component { |
|||
constructor(props) { |
|||
super(props); |
|||
} |
|||
render() { |
|||
const title = this.props.title ? this.props.title : "抱歉,没有可访问的资源!" |
|||
return ( |
|||
<Result |
|||
icon={<MehOutlined />} |
|||
title={title} |
|||
/> |
|||
); |
|||
} |
|||
} |
|||
|
|||
export default NoResource; |
@ -0,0 +1,7 @@ |
|||
'use strict'; |
|||
|
|||
import React from 'react'; |
|||
import { render } from 'react-dom'; |
|||
import App from './app'; |
|||
|
|||
render((<App projectName="政务数据资源中心" />), document.getElementById('App')); |
@ -0,0 +1,27 @@ |
|||
'use strict'; |
|||
import { RouteRequest } from '@peace/utils'; |
|||
import { RouteTable } from '$utils' |
|||
|
|||
export const INIT_LAYOUT = 'INIT_LAYOUT'; |
|||
export function initLayout (title, copyright, sections, actions) { |
|||
return { |
|||
type: INIT_LAYOUT, |
|||
payload: { |
|||
title, |
|||
copyright, |
|||
sections, |
|||
actions |
|||
} |
|||
}; |
|||
} |
|||
|
|||
export const RESIZE = 'RESIZE'; |
|||
export function resize (clientHeight, clientWidth) { |
|||
return { |
|||
type: RESIZE, |
|||
payload: { |
|||
clientHeight, |
|||
clientWidth |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
'use strict'; |
|||
import React from 'react'; |
|||
import style from './style.css'; |
|||
|
|||
export default class Footer extends React.Component { |
|||
render() { |
|||
const {footerProps} = this.props; |
|||
|
|||
return ( |
|||
<div className={style.footer} {...footerProps}> |
|||
{this.props.children} |
|||
</div> |
|||
); |
|||
} |
|||
}; |
@ -0,0 +1,5 @@ |
|||
.footer { |
|||
text-align: center; |
|||
font-size: 12px; |
|||
color: #999; |
|||
} |
@ -0,0 +1,100 @@ |
|||
'use strict'; |
|||
import React from 'react'; |
|||
import { Menu } from 'antd'; |
|||
import { Link } from 'react-router-dom'; |
|||
import { connect } from 'react-redux'; |
|||
import styles from './style.css'; |
|||
import { |
|||
MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LogoutOutlined |
|||
} from '@ant-design/icons'; |
|||
import ResetPasswordModal from '../../../sections/memberManagement/components/resetPassword'; |
|||
const Header = props => { |
|||
const { dispatch, history, user, pathname, toggleCollapsed, collapsed, actions } = props |
|||
|
|||
const onFinish = async (values) => { |
|||
const dataToSave = { ...values } |
|||
return dispatch( |
|||
actions.memberManagement.modifyUser(user.id, dataToSave, values?.msg || ''), |
|||
).then((res) => { |
|||
if (res.success) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
const handelClick = item => { |
|||
if (item.key == 'logout') { |
|||
dispatch(actions.auth.logout(user)); |
|||
history.push(`/signin`); |
|||
} |
|||
} |
|||
|
|||
let current = pathname; |
|||
if (pathname == '/' || pathname == '') { |
|||
current = 'default'; |
|||
} else if (pathname.charAt(0) == '/') { |
|||
current = pathname.substring(1); |
|||
} |
|||
|
|||
if (current.indexOf('/') != -1) { |
|||
current = current.substring(0, current.indexOf('/')); |
|||
} |
|||
|
|||
return ( |
|||
<div className={styles.header}> |
|||
<div className={styles['header-fold']}> |
|||
<span onClick={toggleCollapsed} style={{ marginRight: 20 }}> |
|||
{ |
|||
collapsed ? |
|||
<MenuUnfoldOutlined /> : <MenuFoldOutlined /> |
|||
} |
|||
</span> |
|||
<div className={styles['header-title']} style={{}}> |
|||
<img src='/assets/images/favicon.ico' style={{ margin: '0 12px 4px 12px', height: 42, borderRadius: 4 }} />政务数据资源中心 |
|||
</div> |
|||
</div> |
|||
<div id="nav" className={styles['header-nav']}> |
|||
<Menu |
|||
mode='horizontal' |
|||
selectedKeys={[current]} |
|||
style={{ border: 0, background: '#1890ff' }} |
|||
onClick={handelClick} |
|||
theme={'light'} |
|||
items={[{ |
|||
label: <span style={{ color: 'aliceblue' }}>{user.displayName}</span>, |
|||
key: "user", |
|||
icon: <img className={styles['header-nav-user-img']} src={`/assets/images/avatar/5.png`} />, |
|||
children: [ |
|||
{ |
|||
icon: <UserOutlined />, |
|||
label: <ResetPasswordModal |
|||
editData={user} |
|||
triggerRender={<a>修改密码</a>} |
|||
title="修改密码" |
|||
onFinish={onFinish} |
|||
key="resetPassword" |
|||
/>, |
|||
key: 'resetPassword' |
|||
}, |
|||
{ |
|||
label: '退出', key: 'logout', icon: <LogoutOutlined /> |
|||
}, |
|||
], |
|||
}]} |
|||
/> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
function mapStateToProps(state) { |
|||
const { global, auth } = state; |
|||
return { |
|||
actions: global.actions, |
|||
user: auth.user |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(Header); |
@ -0,0 +1,41 @@ |
|||
.header { |
|||
position: relative; |
|||
height: 65px; |
|||
min-width: 520px; |
|||
background-color: #1890ff; |
|||
} |
|||
|
|||
.header-fold { |
|||
float: left; |
|||
padding-left: 32px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.header-title { |
|||
line-height: 60px; |
|||
display: inline-block; |
|||
font-size: 20px; |
|||
color: #fff; |
|||
text-shadow: 0 4px 3px rgba(54, 77, 108, 0.20); |
|||
} |
|||
|
|||
.header-nav { |
|||
float: right; |
|||
} |
|||
|
|||
.header-nav-notification { |
|||
/* color : #666; */ |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.header-nav-user-img-wrapper { |
|||
display: inline; |
|||
margin: 14px 8px; |
|||
} |
|||
|
|||
.header-nav-user-img { |
|||
width: 36px; |
|||
height: 36px; |
|||
position: relative; |
|||
bottom: 2px; |
|||
} |
@ -0,0 +1,95 @@ |
|||
import React, { Component, useEffect, useState } from 'react'; |
|||
import { Menu } from 'antd'; |
|||
const JumpUrls = [ |
|||
{ url: '/risk/hiddenrectification_approval', keys: 'riskHiddenrectification_approval' }, |
|||
{ url: '/safetymanage/hiddenrectification_approval', keys: 'hiddenrectification_approval' }, |
|||
{ url: '/metadataManagement/latestMetadata', keys: 'latestMetadata' }, |
|||
] |
|||
const Sider = (props) => { |
|||
const [items, setItems] = useState([]) |
|||
const [selectedKeys, setSelectedKeys] = useState([]) |
|||
const [openKeys, setOpenKeys] = useState([]) |
|||
const { pathname } = props; |
|||
useEffect(() => { |
|||
let jumpurlObj = JumpUrls.find(s => s.url == pathname && selectedKeys != s.keys) |
|||
if (jumpurlObj) { |
|||
localStorage.setItem('governmentDataResourceCenter_selected_sider', JSON.stringify([jumpurlObj.keys])) |
|||
setSelectedKeys(jumpurlObj.keys) |
|||
} |
|||
if (pathname.indexOf('metadataManagement/latestMetadata') < 0) |
|||
sessionStorage.removeItem('jumpSelectedKey'); |
|||
if (pathname.indexOf('metadataManagement/businessMetadata') < 0) |
|||
sessionStorage.removeItem('jumpBusinessSelectedKey'); |
|||
}, [pathname]) |
|||
|
|||
useEffect(() => { |
|||
const { sections, dispatch, user } = props; |
|||
let items = sections.reduce((p, c) => { |
|||
if (typeof c.getNavItem == 'function') { |
|||
let item = c.getNavItem(user, dispatch); |
|||
if (item != null) { |
|||
if (Array.isArray(item)) { |
|||
p = p.concat(item); |
|||
} else { |
|||
p.push(item); |
|||
} |
|||
} |
|||
} |
|||
return p; |
|||
}, []); |
|||
setItems(items) |
|||
|
|||
let selectedKeys = [] |
|||
let openKeys = [] |
|||
const lastSelectedKeys = localStorage.getItem('governmentDataResourceCenter_selected_sider') |
|||
if (lastSelectedKeys) { |
|||
selectedKeys = JSON.parse(lastSelectedKeys) |
|||
} |
|||
const lastOpenKeys = localStorage.getItem('governmentDataResourceCenter_open_sider') |
|||
if (lastOpenKeys) { |
|||
openKeys = JSON.parse(lastOpenKeys) |
|||
} |
|||
if (!selectedKeys.length && !openKeys.length) { |
|||
let firstItem = items[0] || null |
|||
|
|||
if (firstItem) { |
|||
let children = firstItem.props.children |
|||
if (Array.isArray(children)) { |
|||
selectedKeys = [children[0].key] |
|||
openKeys = [firstItem.key] |
|||
} else if (children.key) { |
|||
selectedKeys = [children.key] |
|||
openKeys = [firstItem.key] |
|||
} else { |
|||
selectedKeys = [firstItem.key] |
|||
} |
|||
} |
|||
} |
|||
localStorage.setItem('governmentDataResourceCenter_selected_sider', JSON.stringify(selectedKeys)) |
|||
setSelectedKeys(selectedKeys) |
|||
localStorage.setItem('governmentDataResourceCenter_open_sider', JSON.stringify(openKeys)) |
|||
setOpenKeys(openKeys) |
|||
}, []) |
|||
|
|||
|
|||
return ( |
|||
<Menu id="sider" mode="inline" |
|||
theme={'light'} |
|||
selectedKeys={selectedKeys} |
|||
openKeys={openKeys} |
|||
onSelect={(e) => { |
|||
const { selectedKeys } = e; |
|||
setSelectedKeys(selectedKeys) |
|||
localStorage.setItem('governmentDataResourceCenter_selected_sider', JSON.stringify(selectedKeys)) |
|||
}} |
|||
onOpenChange={(openKeys) => { |
|||
setOpenKeys(openKeys) |
|||
localStorage.setItem('governmentDataResourceCenter_open_sider', JSON.stringify(openKeys)) |
|||
}} |
|||
> |
|||
{items} |
|||
</Menu> |
|||
) |
|||
} |
|||
|
|||
export default Sider; |
@ -0,0 +1,6 @@ |
|||
'use strict'; |
|||
import Layout from './layout'; |
|||
import NoMatch from './no-match'; |
|||
|
|||
export { Layout }; |
|||
export { NoMatch }; |
@ -0,0 +1,48 @@ |
|||
import React from 'react'; |
|||
import { Breadcrumb } from 'antd'; |
|||
import withBreadcrumbs from 'react-router-breadcrumbs-hoc'; |
|||
import { Link } from 'react-router-dom'; |
|||
|
|||
const extRoutes = [{ path: '/project-monitor/things/struct/:id/configuration/station', breadcrumb: '测点' }]; |
|||
|
|||
function Breadcrumbs(props) { |
|||
const excludePaths = [ |
|||
'/', |
|||
'/metadataManagement/latestMetadata/detail', |
|||
'/metadataAcquisition/adapter/detail', |
|||
]; |
|||
|
|||
const { routes } = props; |
|||
|
|||
const Bread = withBreadcrumbs(routes.concat(extRoutes), { excludePaths })(({ breadcrumbs }) => ( |
|||
<Breadcrumb separator="/" style={{ height: 25 }}> |
|||
{ |
|||
breadcrumbs.map((bc, index) => ( |
|||
<Breadcrumb.Item key={index}> |
|||
{ |
|||
bc.component |
|||
? ( |
|||
<Link |
|||
to={{ |
|||
pathname: bc.match.url, |
|||
state: bc.match.params ? bc.match.params : {}, |
|||
query: bc.location.query ? bc.location.query : {}, |
|||
}} |
|||
> |
|||
{bc.breadcrumb} |
|||
</Link> |
|||
) |
|||
: bc.breadcrumb |
|||
} |
|||
</Breadcrumb.Item> |
|||
)) |
|||
} |
|||
</Breadcrumb> |
|||
)); |
|||
|
|||
return ( |
|||
<Bread /> |
|||
); |
|||
} |
|||
|
|||
export default Breadcrumbs; |
@ -0,0 +1,132 @@ |
|||
'use strict'; |
|||
|
|||
import './index.less'; |
|||
import React, { useState, useEffect } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { message, Layout } from 'antd'; |
|||
import Sider from '../../components/sider'; |
|||
import Header from '../../components/header'; |
|||
import Footer from '../../components/footer'; |
|||
import Breadcrumbs from './breadcrumb'; |
|||
import { resize } from '../../actions/global'; |
|||
import * as NProgress from 'nprogress'; |
|||
import PerfectScrollbar from 'perfect-scrollbar'; |
|||
|
|||
NProgress.configure({ |
|||
template: ` |
|||
<div class="bar" style="height:2px" role="bar"> |
|||
<div class="peg"></div> |
|||
</div> |
|||
<div class="spinner" role="spinner"> |
|||
<div class="spinner-icon"></div> |
|||
</div> |
|||
` |
|||
}); |
|||
|
|||
const headerHeight = 64 |
|||
const footerHeight = 0 |
|||
let scrollbar |
|||
|
|||
const LayoutContainer = props => { |
|||
const { dispatch, msg, user, copyright, children, sections, clientWidth, clientHeight, location, match, routes, history } = props |
|||
const [collapsed, setCollapsed] = useState(false) |
|||
|
|||
NProgress.start(); |
|||
|
|||
const resize_ = (collapsed) => { |
|||
const extraHeight = headerHeight + footerHeight; |
|||
dispatch(resize( |
|||
document.body.clientHeight - extraHeight - 12, |
|||
document.body.clientWidth - (collapsed ? 120 : 220) |
|||
)); |
|||
} |
|||
|
|||
useEffect(() => { |
|||
resize_(collapsed) |
|||
scrollbar = new PerfectScrollbar('#page-content', { suppressScrollX: true }); |
|||
}, []) |
|||
|
|||
useEffect(() => { |
|||
NProgress.done(); |
|||
if (!user || !user.authorized) { |
|||
history.push('/signin'); |
|||
} |
|||
if (msg) { |
|||
message.destroy(); |
|||
if (msg.done) { |
|||
message.success(msg.done); |
|||
} |
|||
if (msg.error) { |
|||
message.error(msg.error); |
|||
} |
|||
} |
|||
const dom = document.getElementById('page-content'); |
|||
if (dom) { |
|||
scrollbar.update(); |
|||
dom.scrollTop = 0; |
|||
} |
|||
}) |
|||
// console.log(FS_API_ROOT);
|
|||
return ( |
|||
<Layout id="layout"> |
|||
<Layout.Header style={{ padding: 0 }}> |
|||
<Header |
|||
user={user} |
|||
pathname={location.pathname} |
|||
toggleCollapsed={() => { |
|||
setCollapsed(!collapsed); |
|||
resize_(!collapsed) |
|||
}} |
|||
collapsed={collapsed} |
|||
history={history} |
|||
/> |
|||
</Layout.Header> |
|||
<Layout> |
|||
<Layout.Sider trigger={null} collapsible collapsed={collapsed} theme={'light'}> |
|||
<Sider |
|||
sections={sections} |
|||
dispatch={dispatch} |
|||
user={user} |
|||
pathname={location.pathname} |
|||
collapsed={collapsed} |
|||
/> |
|||
</Layout.Sider> |
|||
<Layout.Content id="page-content" style={{ |
|||
position: 'relative', |
|||
margin: '12px 12px 0px', |
|||
padding: '8px', |
|||
height: clientHeight, |
|||
background: '#fff' |
|||
}}> |
|||
<div style={{ minWidth: 520 }}> |
|||
<div style={{ padding: '0px 16px 4px', borderBottom: '1px solid #e8e8e8' }}> |
|||
<Breadcrumbs routes={routes} /> |
|||
</div> |
|||
<div style={{ padding: '12px 12px 0px 12px' }}> |
|||
{children} |
|||
</div> |
|||
</div> |
|||
</Layout.Content> |
|||
{/* <Layout.Footer {...footerProps}> |
|||
{copyright} |
|||
</Layout.Footer> */} |
|||
</Layout> |
|||
</Layout> |
|||
) |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { global, auth, ajaxResponse } = state; |
|||
return { |
|||
title: global.title, |
|||
copyright: global.copyright, |
|||
sections: global.sections, |
|||
actions: global.actions, |
|||
clientWidth: global.clientWidth, |
|||
clientHeight: global.clientHeight, |
|||
msg: ajaxResponse.msg, |
|||
user: auth.user, |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(LayoutContainer); |
@ -0,0 +1,3 @@ |
|||
@import '~perfect-scrollbar/css/perfect-scrollbar.css'; |
|||
@import '~nprogress/nprogress.css'; |
|||
@import '~simplebar-react/dist/simplebar.min.css'; |
@ -0,0 +1,18 @@ |
|||
'use strict'; |
|||
|
|||
import React from 'react'; |
|||
import moment from 'moment' |
|||
|
|||
const NoMatch = props => { |
|||
return ( |
|||
<div style={{ textAlign: 'center', padding: 120 }}> |
|||
<p style={{ fontSize: 80, lineHeight: 1.5 }}>404</p> |
|||
<p style={{ fontSize: 32, lineHeight: 2 }}>PAGE NOT FOUND</p> |
|||
<p>很遗憾,您暂时无法访问该页面。</p> |
|||
<p>请检查您访问的链接地址是否正确。</p> |
|||
<p style={{ marginTop: 80 }}>Copyright © {moment().year()} 飞尚</p> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
export default NoMatch; |
@ -0,0 +1,179 @@ |
|||
'use strict'; |
|||
import React, { useEffect, useState } from 'react'; |
|||
import moment from 'moment'; |
|||
import configStore from './store'; |
|||
import { Provider } from 'react-redux'; |
|||
import { createBrowserHistory } from 'history'; |
|||
import { ConnectedRouter } from 'connected-react-router' |
|||
import { Layout, NoMatch } from './containers'; |
|||
import { Switch, Route } from "react-router-dom"; |
|||
import { ConfigProvider } from 'antd'; |
|||
import * as layoutActions from './actions/global'; |
|||
import zhCN from 'antd/lib/locale/zh_CN'; |
|||
import { basicReducer } from '@peace/utils'; |
|||
import 'moment/locale/zh-cn'; |
|||
import 'antd/dist/antd.less'; |
|||
|
|||
moment.locale('zh-cn'); |
|||
|
|||
const { initLayout } = layoutActions; |
|||
|
|||
const Root = props => { |
|||
const { sections, title, copyright } = props; |
|||
const [history, setHistory] = useState(null) |
|||
const [store, setStore] = useState(null) |
|||
const [outerRoutes, setOuterRoutes] = useState([]) |
|||
const [combineRoutes, setCombineRoutes] = useState([]) |
|||
const [innnerRoutes, setInnerRoutes] = useState([]) |
|||
|
|||
const flatRoutes = (routes) => { |
|||
const combineRoutes = []; |
|||
|
|||
function flat(routes, parentRoute) { |
|||
routes.forEach((route, i) => { |
|||
const obj = { |
|||
path: route.path, |
|||
breadcrumb: route.breadcrumb, |
|||
component: route.component || null, |
|||
authCode: route.authCode || '', |
|||
key: route.key, |
|||
}; |
|||
if (!route.path.startsWith('/')) { |
|||
console.error(`路由配置需以 "/" 开始:${route.path}`); |
|||
} |
|||
if (route.path.length > 1 && route.path[route.path.length] == '/') { |
|||
console.error(`除根路由路由配置不可以以 "/" 结束:${route.path}`); |
|||
} |
|||
if (parentRoute && parentRoute != '/') { |
|||
obj.path = parentRoute + route.path; |
|||
} |
|||
if (route.exact === false) { |
|||
obj.exact = false; |
|||
} |
|||
if (route.hasOwnProperty('childRoutes')) { |
|||
combineRoutes.push(obj); |
|||
flat(route.childRoutes, obj.path); |
|||
} else { |
|||
combineRoutes.push(obj); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
flat(routes); |
|||
return combineRoutes; |
|||
}; |
|||
|
|||
|
|||
const initReducer = (reducers, reducerName, action) => { |
|||
let reducerParams = {} |
|||
const { actionType, initReducer, reducer } = action()() |
|||
if (initReducer || reducer) { |
|||
if (reducer) { |
|||
if (reducer.name) { |
|||
reducerName = reducer.name |
|||
} |
|||
if (reducer.params) { |
|||
reducerParams = reducer.params |
|||
} |
|||
} else { |
|||
reducerName = `${reducerName}Rslt` |
|||
} |
|||
reducers[reducerName] = function (state, action) { |
|||
return basicReducer(state, action, Object.assign({ actionType: actionType }, reducerParams)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
useEffect(() => { |
|||
let innerRoutes = [] |
|||
let outerRoutes = [] |
|||
let reducers = {} |
|||
let actions = { |
|||
layout: layoutActions |
|||
} |
|||
|
|||
for (let s of sections) { |
|||
if (!s.key) console.warn('请给你的section添加一个key值,section name:' + s.name); |
|||
for (let r of s.routes) { |
|||
if (r.type == 'inner' || r.type == 'home') { |
|||
innerRoutes.push(r.route) |
|||
} else if (r.type == 'outer') { |
|||
outerRoutes.push(r.route) |
|||
} |
|||
} |
|||
if (s.reducers) { |
|||
reducers = { ...reducers, ...s.reducers } |
|||
} |
|||
if (s.actions) { |
|||
actions = { ...actions, [s.key]: s.actions } |
|||
if (s.key != 'auth') { |
|||
for (let ak in s.actions) { |
|||
let actions = s.actions[ak] |
|||
if (actions && typeof actions == 'object') { |
|||
for (let actionName in actions) { |
|||
initReducer(reducers, actionName, actions[actionName]) |
|||
} |
|||
} else if (typeof actions == 'function') { |
|||
initReducer(reducers, ak, actions) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
let history = createBrowserHistory(); |
|||
let store = configStore(reducers, history); |
|||
store.dispatch(initLayout(title, copyright, sections, actions)); |
|||
store.dispatch(actions.auth.initAuth()); |
|||
|
|||
const combineRoutes = flatRoutes(innerRoutes); |
|||
|
|||
setInnerRoutes(combineRoutes) |
|||
setHistory(history) |
|||
setStore(store) |
|||
setOuterRoutes(outerRoutes.map(route => ( |
|||
<Route |
|||
key={route.key} |
|||
exact |
|||
path={route.path} |
|||
component={route.component} |
|||
/> |
|||
))) |
|||
setCombineRoutes(combineRoutes.map(route => ( |
|||
<Route |
|||
key={route.key} |
|||
exact={Object.prototype.hasOwnProperty.call(route, 'exact') ? route.exact : true} |
|||
path={route.path} |
|||
component={route.component} |
|||
/> |
|||
))) |
|||
}, []) |
|||
|
|||
return ( |
|||
store ? |
|||
<ConfigProvider locale={zhCN}> |
|||
<Provider store={store}> |
|||
<ConnectedRouter history={history}> |
|||
<div> |
|||
<Switch> |
|||
{outerRoutes} |
|||
<Layout |
|||
history={history} |
|||
routes={innnerRoutes} |
|||
> |
|||
{combineRoutes} |
|||
</Layout> |
|||
<Route |
|||
path={'*'} |
|||
component={NoMatch} |
|||
/> |
|||
</Switch> |
|||
</div> |
|||
</ConnectedRouter> |
|||
</Provider> |
|||
</ConfigProvider> |
|||
: '' |
|||
) |
|||
} |
|||
|
|||
export default Root; |
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Created by liu.xinyi |
|||
* on 2016/4/1. |
|||
*/ |
|||
'use strict'; |
|||
const initState = { |
|||
msg: null |
|||
}; |
|||
|
|||
import Immutable from 'immutable'; |
|||
|
|||
/** |
|||
* 全局ajax响应处理: |
|||
* 判断action中是否有done字段,如果有,则修改store中的msg.done |
|||
* 判断action中是否有error字段,如果有,则修改store中msg.error |
|||
* 在layout中根据msg的值,呈现提示信息。 |
|||
*/ |
|||
export default function ajaxResponse(state = initState, action) { |
|||
if (action.done) { |
|||
return Immutable.fromJS(state).set('msg', {done: action.done}).toJS(); |
|||
} |
|||
|
|||
if (action.error) { |
|||
return Immutable.fromJS(state).set('msg', {error: action.error}).toJS(); |
|||
} |
|||
|
|||
return {msg: null}; |
|||
}; |
@ -0,0 +1,36 @@ |
|||
'use strict'; |
|||
import Immutable from 'immutable'; |
|||
import { INIT_LAYOUT, RESIZE } from '../actions/global'; |
|||
|
|||
function global (state = { |
|||
title: '', |
|||
copyright: '', |
|||
sections: [], |
|||
actions: {}, |
|||
plugins: {}, |
|||
clientHeight: 768, |
|||
clientWidth: 1024, |
|||
}, action) { |
|||
const payload = action.payload; |
|||
switch (action.type) { |
|||
case RESIZE: |
|||
return Immutable.fromJS(state).merge({ |
|||
clientHeight: payload.clientHeight, |
|||
clientWidth: payload.clientWidth |
|||
}).toJS(); |
|||
case INIT_LAYOUT: |
|||
return { |
|||
title: payload.title, |
|||
copyright: payload.copyright, |
|||
sections: payload.sections, |
|||
actions: payload.actions, |
|||
plugins: payload.plugins, |
|||
clientHeight: state.clientHeight, |
|||
clientWidth: state.clientWidth, |
|||
}; |
|||
default: |
|||
return state; |
|||
} |
|||
} |
|||
|
|||
export default global; |
@ -0,0 +1,15 @@ |
|||
/** |
|||
* User: liuxinyi/liu.xinyi@free-sun.com.cn |
|||
* Date: 2016/1/13 |
|||
* Time: 17:52 |
|||
* |
|||
*/ |
|||
'use strict'; |
|||
|
|||
import global from './global'; |
|||
import ajaxResponse from './ajaxResponse'; |
|||
|
|||
export default { |
|||
global, |
|||
ajaxResponse |
|||
}; |
@ -0,0 +1,16 @@ |
|||
/** |
|||
* User: liuxinyi/liu.xinyi@free-sun.com.cn |
|||
* Date: 2016/1/13 |
|||
* Time: 17:51 |
|||
* |
|||
*/ |
|||
'use strict'; |
|||
|
|||
let store = null; |
|||
if(process.env.NODE_ENV == 'production'){ |
|||
store = require('./store.prod').default; |
|||
}else { |
|||
store = require('./store.dev').default; |
|||
} |
|||
|
|||
export default store; |
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Created by liu.xinyi |
|||
* on 2016/4/8. |
|||
*/ |
|||
'use strict'; |
|||
import { createStore, combineReducers, applyMiddleware, compose } from 'redux'; |
|||
import reduxThunk from 'redux-thunk'; |
|||
import { connectRouter, routerMiddleware } from 'connected-react-router'; |
|||
import innerReducers from '../reducers'; |
|||
|
|||
function configStore(reducers, history) { |
|||
const reducer = Object.assign({}, innerReducers, reducers, { |
|||
router: connectRouter(history) |
|||
}); |
|||
|
|||
const composeEnhancers = |
|||
typeof window === 'object' && |
|||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? |
|||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ |
|||
// Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
|
|||
}) : compose; |
|||
|
|||
const enhancers = composeEnhancers( |
|||
applyMiddleware(routerMiddleware(history), reduxThunk) |
|||
); |
|||
|
|||
return createStore(combineReducers(reducer), {}, enhancers); |
|||
} |
|||
|
|||
export default configStore; |
@ -0,0 +1,20 @@ |
|||
/** |
|||
* Created by liu.xinyi |
|||
* on 2016/4/8. |
|||
*/ |
|||
'use strict'; |
|||
|
|||
import { createStore, combineReducers, applyMiddleware } from 'redux'; |
|||
import reduxThunk from 'redux-thunk'; |
|||
import { connectRouter, routerMiddleware } from 'connected-react-router'; |
|||
import innerReducers from '../reducers'; |
|||
|
|||
function configStore(reducers, history){ |
|||
const reducer = Object.assign({}, innerReducers, reducers, { |
|||
router: connectRouter(history) |
|||
}); |
|||
|
|||
return createStore(combineReducers(reducer), {}, applyMiddleware(routerMiddleware(history), reduxThunk)); |
|||
} |
|||
|
|||
export default configStore; |
@ -0,0 +1,62 @@ |
|||
'use strict'; |
|||
|
|||
import { ApiTable } from '$utils' |
|||
import { Request } from '@peace/utils' |
|||
|
|||
export const INIT_AUTH = 'INIT_AUTH'; |
|||
export function initAuth() { |
|||
const user = JSON.parse(sessionStorage.getItem('user')) || {}; |
|||
return { |
|||
type: INIT_AUTH, |
|||
payload: { |
|||
user: user |
|||
} |
|||
}; |
|||
} |
|||
|
|||
export const REQUEST_LOGIN = 'REQUEST_LOGIN'; |
|||
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; |
|||
export const LOGIN_ERROR = 'LOGIN_ERROR'; |
|||
export function login({ username, password, phone, code }) { |
|||
return dispatch => { |
|||
dispatch({ type: REQUEST_LOGIN }); |
|||
|
|||
return Request.post(ApiTable.login, { username, password, phone, code }) |
|||
.then(user => { |
|||
sessionStorage.setItem('user', JSON.stringify(user)); |
|||
dispatch({ |
|||
type: LOGIN_SUCCESS, |
|||
payload: { user: user }, |
|||
}); |
|||
}, error => { |
|||
let { body } = error.response; |
|||
dispatch({ |
|||
type: LOGIN_ERROR, |
|||
payload: { |
|||
error: body && body.message ? body.message : '登录失败' |
|||
} |
|||
}) |
|||
}); |
|||
} |
|||
} |
|||
|
|||
export const LOGOUT = 'LOGOUT'; |
|||
export function logout(user) { |
|||
const token = user.token; |
|||
const url = ApiTable.logout; |
|||
sessionStorage.removeItem('user'); |
|||
localStorage.removeItem('governmentDataResourceCenter_selected_sider') |
|||
localStorage.removeItem('governmentDataResourceCenter_open_sider') |
|||
Request.put(url, { |
|||
token: token |
|||
}); |
|||
return { |
|||
type: LOGOUT |
|||
}; |
|||
} |
|||
|
|||
export default { |
|||
initAuth, |
|||
login, |
|||
logout |
|||
} |
@ -0,0 +1,10 @@ |
|||
/** |
|||
* Created by liu.xinyi |
|||
* on 2016/4/1. |
|||
*/ |
|||
'use strict'; |
|||
import auth from './auth'; |
|||
|
|||
export default { |
|||
...auth |
|||
}; |
@ -0,0 +1,4 @@ |
|||
'use strict'; |
|||
import Login from './login'; |
|||
|
|||
export { Login }; |
@ -0,0 +1,158 @@ |
|||
'use strict'; |
|||
import React, { useState, useEffect, useRef } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { push } from 'react-router-redux'; |
|||
import SHA1 from 'crypto-js/sha1'; |
|||
import Hex from 'crypto-js/enc-hex'; |
|||
import { ApiTable } from '$utils' |
|||
import { Request } from '@peace/utils' |
|||
import { Button, Input, Form, Row, Col, message, Tabs } from 'antd'; |
|||
import { login, LOGIN_ERROR } from '../actions/auth'; |
|||
import { ExclamationCircleOutlined } from '@ant-design/icons'; |
|||
import { Uploads } from '$components' |
|||
import '../style.less'; |
|||
|
|||
const FormItem = Form.Item; |
|||
|
|||
let codCountDownInterval = null |
|||
const Login = props => { |
|||
const { dispatch, user, error, isRequesting } = props |
|||
const [username, setUserName] = useState('') |
|||
const [password, setPassword] = useState('') |
|||
const [phone, setPhone] = useState('') |
|||
const [code, setCode] = useState('') |
|||
const [inputChanged, setInputChanged] = useState(false) |
|||
const [curTabKey, setCurTabKey] = useState(1) |
|||
const [codSending, setCodSending] = useState(false) |
|||
const [codCountDown, setCodeCountDown] = useState(60) |
|||
const codCountDownRef = useRef(0) |
|||
|
|||
useEffect(() => { |
|||
sessionStorage.removeItem('user'); |
|||
localStorage.removeItem('governmentDataResourceCenter_selected_sider') |
|||
localStorage.removeItem('governmentDataResourceCenter_open_sider') |
|||
}, []) |
|||
|
|||
|
|||
useEffect(() => { |
|||
if (user && user.authorized) { |
|||
user?.role == '数据消费者' ? dispatch(push('/metadataManagement/latestMetadata')) : dispatch(push('/homePage')); |
|||
} |
|||
}, [user]) |
|||
|
|||
useEffect(() => { |
|||
if (codSending) { |
|||
setCodeCountDown(59) |
|||
codCountDownRef.current = 59 |
|||
codCountDownInterval = setInterval(() => { |
|||
codCountDownRef.current -= 1 |
|||
if (codCountDownRef.current == 0) { |
|||
setCodSending(false) |
|||
setCodeCountDown(60) |
|||
clearInterval(codCountDownInterval) |
|||
codCountDownInterval = null |
|||
} else { |
|||
setCodeCountDown(codCountDownRef.current) |
|||
} |
|||
}, 1000); |
|||
} else { |
|||
if (codCountDownInterval) { |
|||
clearInterval(codCountDownInterval) |
|||
codCountDownInterval = null |
|||
setCodeCountDown(60) |
|||
} |
|||
} |
|||
}, [codSending]) |
|||
|
|||
const doLogin = () => { |
|||
if (curTabKey == 1) { |
|||
if (!username || !password) |
|||
dispatch({ |
|||
type: LOGIN_ERROR, |
|||
payload: { error: '请输入账号名和密码' } |
|||
}); |
|||
setInputChanged(false) |
|||
dispatch(login({ username, password })); |
|||
} else { |
|||
if (!phone || !code) |
|||
dispatch({ |
|||
type: LOGIN_ERROR, |
|||
payload: { error: '请输入手机号和验证码' } |
|||
}); |
|||
dispatch(login({ phone, code })); |
|||
} |
|||
} |
|||
|
|||
const enterHandler = e => { |
|||
if (e.key === 'Enter') { |
|||
doLogin() |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<div className='login'> |
|||
<div className='left'></div> |
|||
<div className='right'> |
|||
<div className='loginBox'> |
|||
<div className='_title'>欢迎登录系统</div> |
|||
<div className='_divider'></div> |
|||
<Form onKeyDown={enterHandler}> |
|||
|
|||
<FormItem> |
|||
<Input |
|||
style={{ marginTop: 30 }} |
|||
placeholder='请输入账号' |
|||
className='loginInp' |
|||
type="text" |
|||
value={username} |
|||
// maxlength={11}
|
|||
onChange={e => { |
|||
setUserName(e.target.value) |
|||
setInputChanged(true) |
|||
}} |
|||
/> |
|||
</FormItem> |
|||
<FormItem> |
|||
<Input |
|||
style={{ marginTop: 30 }} |
|||
placeholder='请输入密码' |
|||
className='loginInp' |
|||
type="password" |
|||
value={password} |
|||
onChange={e => { |
|||
setPassword(e.target.value) |
|||
setInputChanged(true) |
|||
}} |
|||
/> |
|||
</FormItem> |
|||
</Form> |
|||
<Row style={{ |
|||
paddingLeft: '10%' |
|||
}}> |
|||
{ |
|||
inputChanged || !error ? |
|||
<span style={{ |
|||
visibility: 'hidden' |
|||
}}>-</span> : |
|||
<span> |
|||
<ExclamationCircleOutlined style={{ color: 'red' }} />{error} |
|||
</span> |
|||
} |
|||
</Row> |
|||
<Button style={{ borderRadius: 28 }} type="primary" className='loginBtn' loading={isRequesting} onClick={doLogin}>登录</Button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth } = state; |
|||
return { |
|||
user: auth.user, |
|||
error: auth.error, |
|||
isRequesting: auth.isRequesting |
|||
} |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(Login); |
@ -0,0 +1,12 @@ |
|||
'use strict'; |
|||
|
|||
import routes from './routes'; |
|||
import reducers from './reducers'; |
|||
import actions from './actions'; |
|||
|
|||
export default { |
|||
key: 'auth', |
|||
reducers: reducers, |
|||
routes: routes, |
|||
actions: actions |
|||
}; |
@ -0,0 +1,40 @@ |
|||
'use strict'; |
|||
import * as actionTypes from '../actions/auth'; |
|||
import Immutable from 'immutable'; |
|||
|
|||
const initState = { |
|||
user: {}, |
|||
isRequesting: false, |
|||
error: null |
|||
}; |
|||
|
|||
function auth(state = initState, action) { |
|||
const payload = action.payload; |
|||
switch (action.type){ |
|||
case actionTypes.INIT_AUTH: |
|||
return Immutable.fromJS(state).set('user', payload.user).toJS(); |
|||
case actionTypes.REQUEST_LOGIN: |
|||
return Immutable.fromJS(state).merge({ |
|||
isRequesting: true, |
|||
error: null |
|||
}).toJS(); |
|||
case actionTypes.LOGIN_SUCCESS: |
|||
return Immutable.fromJS(state).merge({ |
|||
isRequesting: false, |
|||
user: payload.user |
|||
}).toJS(); |
|||
case actionTypes.LOGIN_ERROR: |
|||
return Immutable.fromJS(state).merge({ |
|||
isRequesting: false, |
|||
error: payload.error |
|||
}).toJS(); |
|||
case actionTypes.LOGOUT: |
|||
return Immutable.fromJS(state).merge({ |
|||
user: null |
|||
}).toJS(); |
|||
default: |
|||
return state; |
|||
} |
|||
} |
|||
|
|||
export default auth; |
@ -0,0 +1,6 @@ |
|||
'use strict'; |
|||
import auth from './auth' |
|||
|
|||
export default { |
|||
auth |
|||
}; |
@ -0,0 +1,12 @@ |
|||
'use strict'; |
|||
|
|||
import { Login } from './containers'; |
|||
|
|||
export default [{ |
|||
type: 'outer', |
|||
route: { |
|||
key:'signin', |
|||
path: "/signin", |
|||
component: Login |
|||
} |
|||
}]; |
@ -0,0 +1,112 @@ |
|||
.login { |
|||
width: 100%; |
|||
height: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
background-image: url('/assets/images/login_bg.png'); |
|||
background-size: 100% 100%; |
|||
|
|||
.left { |
|||
|
|||
background-size: 100% 100%; |
|||
background-repeat: no-repeat; |
|||
width: 55%; |
|||
height: 100%; |
|||
float: left; |
|||
top: 0px; |
|||
left: 0px; |
|||
} |
|||
|
|||
.right { |
|||
width: 45%; |
|||
height: 100%; |
|||
// background-color: #000066; |
|||
float: left; |
|||
right: 0px; |
|||
bottom: 0px; |
|||
} |
|||
} |
|||
|
|||
@media screen and (max-height:1440px) { |
|||
.loginBox { |
|||
top: 25%; |
|||
} |
|||
} |
|||
|
|||
@media screen and (max-height: 768px) { |
|||
.loginBox { |
|||
top: 20%; |
|||
} |
|||
} |
|||
|
|||
@media screen and (max-height: 630px) { |
|||
.loginBox { |
|||
top: 10%; |
|||
} |
|||
} |
|||
|
|||
.loginBox { |
|||
height: 50%; |
|||
width: 25%; |
|||
position: absolute; |
|||
right: 16.5%; |
|||
z-index: 20; |
|||
background: #fff; |
|||
text-align: center; |
|||
padding-top: 30px; |
|||
|
|||
@media screen and (min-height:1080px) { |
|||
height: 40%; |
|||
} |
|||
|
|||
._title { |
|||
font-family: SourceHanSansCN-Medium; |
|||
font-weight: 500; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.75); |
|||
letter-spacing: 0; |
|||
} |
|||
|
|||
._divider { |
|||
width: 58px; |
|||
height: 4px; |
|||
background: #4263F7; |
|||
display: inline-block; |
|||
} |
|||
|
|||
h1 { |
|||
color: #fff; |
|||
font-size: 58px; |
|||
} |
|||
|
|||
.loginFormTit { |
|||
width: 20%; |
|||
font-size: 18px; |
|||
color: rgb(255, 255, 255); |
|||
// margin-bottom: 10px; |
|||
} |
|||
|
|||
.loginInp { |
|||
width: 80%; |
|||
height: 50px; |
|||
background: #ffffff; |
|||
border: 1px solid #C2C2C2; |
|||
border-radius: 5px; |
|||
} |
|||
|
|||
.loginBtn { |
|||
width: 80%; |
|||
height: 50px; |
|||
margin-top: 40px; |
|||
border-radius: 5px; |
|||
font-size: 16px; |
|||
background: #4263F7; |
|||
border-color: #4263F7; |
|||
} |
|||
|
|||
.loginBtn:hover { |
|||
background: #4263F7; |
|||
border-color: #4263F7; |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
'use strict'; |
|||
|
|||
import { basicAction } from '@peace/utils' |
|||
import { ApiTable } from '$utils' |
|||
|
|||
// export function getMembers(orgId) {
|
|||
// return dispatch => basicAction({
|
|||
// type: 'get',
|
|||
// dispatch: dispatch,
|
|||
// actionType: 'GET_MEMBERS',
|
|||
// url: `${ApiTable.getEnterprisesMembers.replace('{enterpriseId}', orgId)}`,
|
|||
// msg: { error: '获取用户列表失败' },
|
|||
// reducer: { name: 'members' }
|
|||
// });
|
|||
// }
|
@ -0,0 +1,7 @@ |
|||
'use strict'; |
|||
|
|||
import * as example from './example' |
|||
|
|||
export default { |
|||
...example, |
|||
} |
@ -0,0 +1,49 @@ |
|||
import React, { useEffect, useState } from 'react' |
|||
import CarouselList from './public/carousel-list'; |
|||
import { Tooltip } from 'antd'; |
|||
import { ApiTable, useFsRequest } from '$utils'; |
|||
import moment from 'moment'; |
|||
function AbnormalMonitoring(props) { |
|||
|
|||
const { data: logs = {} } = useFsRequest({ |
|||
url: ApiTable.getLogs, |
|||
query: { |
|||
logState: false, |
|||
startTime: moment().subtract(7, 'days').format('YYYY-MM-DD HH:mm:ss'), |
|||
endTime: moment().format('YYYY-MM-DD HH:mm:ss') |
|||
}, |
|||
pollingInterval: 1000 * 60 |
|||
}); |
|||
|
|||
const dataSource = logs?.rows ? logs?.rows?.map(s => { |
|||
return [ |
|||
<div style={{ color: '#fff' }}> |
|||
<Tooltip placement="top" title={s?.acquisitionTask?.taskName}> |
|||
{s?.acquisitionTask?.taskName?.length > 20 ? s?.acquisitionTask?.taskNamesubstring(0, 20) + '...' : s?.acquisitionTask?.taskName} |
|||
</Tooltip> |
|||
</div>, |
|||
moment(s?.startTime).format('YYYY-MM-DD HH:mm:ss'), |
|||
moment(s?.endTime).valueOf() - moment(s?.startTime).valueOf() + '毫秒', |
|||
<div style={{ color: 'rgba(245, 27, 27, 1)' }}> |
|||
<Tooltip placement="top" title={s?.details}> |
|||
{s?.details?.length > 20 ? s?.details.substring(0, 20) + '...' : s?.details} |
|||
</Tooltip> |
|||
</div> |
|||
] |
|||
}) : [] |
|||
return <div style={{ height: 149, border: '1px solid #50c9d74d', backgroundImage: 'linear-gradient(180deg, rgba(0, 32, 74, 0) 3%, rgba(80, 201, 247, 0.1) 100%)' }}> |
|||
<div className='center-card-title' style={{ marginBottom: 6 }}><div className='_icon_left' />异常监控<div className='_icon_right' /></div> |
|||
<CarouselList |
|||
header={['任务名称', '采集时间', '耗时', '异常日志']} |
|||
data={dataSource} |
|||
rowNum={2} |
|||
height={100} |
|||
multiellipsis |
|||
marginTop={-50} |
|||
/> |
|||
</div> |
|||
} |
|||
|
|||
export default AbnormalMonitoring; |
|||
|
|||
|
@ -0,0 +1,36 @@ |
|||
import React from 'react' |
|||
import Box from './public/table-card'; |
|||
import { useFsRequest } from '$utils'; |
|||
import { mathRound } from './util' |
|||
function AccessData() { |
|||
|
|||
const { data: accessdata = [] } = useFsRequest({ |
|||
url: 'homepage/accessdata', |
|||
pollingInterval: 1000 * 60, |
|||
cacheKey: 'accessdata', |
|||
}); |
|||
|
|||
|
|||
const renderBody = () => { |
|||
return <div className='access_data'> |
|||
<div className='_img'></div> |
|||
<div className='data_unit'> |
|||
数据单位<div className='data_number'>{!accessdata?.projects ? '-' : accessdata?.projects?.split(',')?.length}</div>个 |
|||
</div> |
|||
<div className='data_today'> |
|||
今日数据<div className='data_number'>{!accessdata?.res?.stat?.today ? '-' : accessdata?.res?.stat?.today > 1000 ? mathRound(accessdata?.res?.stat?.today) : accessdata?.res?.stat?.today}</div>{accessdata?.res?.stat?.today > 1000 ? '万条' : '条'} |
|||
</div> |
|||
<div className='data_total'> |
|||
数据总量<div className='data_number'>{accessdata?.res?.stat?.datas ? Math.round(accessdata?.res?.stat?.datas / 10000) : '-'}</div>万条 |
|||
</div> |
|||
</div> |
|||
} |
|||
|
|||
return <Box title={"接入数据统计"} > |
|||
{renderBody()} |
|||
</Box> |
|||
} |
|||
|
|||
export default AccessData; |
|||
|
|||
|
@ -0,0 +1,52 @@ |
|||
import React from 'react' |
|||
import Box from './public/table-card'; |
|||
import CarouselList from './public/carousel-list'; |
|||
import { Tooltip } from 'antd'; |
|||
import moment from 'moment'; |
|||
import NoData from './public/noData'; |
|||
import { useFsRequest } from '$utils'; |
|||
|
|||
function AlarmList(props) { |
|||
const { cardContentHeight } = props; |
|||
const { data: alarms = [] } = useFsRequest({ |
|||
url: 'homepage/alarms', |
|||
pollingInterval: 1000 * 60, |
|||
cacheKey: 'alarms', |
|||
}); |
|||
|
|||
|
|||
const data = alarms.map(s => { |
|||
return [ |
|||
s.content, |
|||
s.level == 1 ? '一级' : s.level == 2 ? '二级' : s.level == 3 ? '三级' : '四级', |
|||
moment(s.time).format('YYYY-MM-DD HH:mm:ss') |
|||
] |
|||
}) |
|||
|
|||
const renderBody = () => { |
|||
return <CarouselList |
|||
header={['预警内容', '预警等级', '预警时间']} |
|||
data={data?.map(s => { |
|||
return [ |
|||
<Tooltip placement="top" title={s[0]}> |
|||
{s[0].length > 20 ? s[0]?.substring(0, 20) + '...' : s[0]} |
|||
</Tooltip>, |
|||
<div style={{ color: s[1] == '一级' ? 'rgba(245, 27, 27, 1)' : s[1] == '二级' ? '#FF7900' : s[1] == '三级' ? '#FFCD00' : '#00DA9F' }}>{s[1]}</div>, |
|||
s[2] |
|||
] |
|||
})} |
|||
rowNum={6} |
|||
height={cardContentHeight} |
|||
multiellipsis |
|||
columnWidth={[180, 80, 150]} |
|||
/> |
|||
} |
|||
|
|||
return <Box title={"预警列表"}> |
|||
{alarms?.length > 0 ? renderBody() : <NoData />} |
|||
</Box> |
|||
} |
|||
|
|||
export default AlarmList; |
|||
|
|||
|
@ -0,0 +1,19 @@ |
|||
import React from 'react' |
|||
import './style.less' |
|||
|
|||
function CenterTop(props) { |
|||
|
|||
|
|||
return <div className='_top'> |
|||
<div className='center_top_data'> |
|||
<div className='_center_card1'>共享交换</div> |
|||
<div className='_center_card2'>数据监控</div> |
|||
<div className='_center_card3'>数据治理</div> |
|||
<div className='_center_card4'>数据采集</div> |
|||
</div> |
|||
</div> |
|||
} |
|||
|
|||
export default CenterTop; |
|||
|
|||
|
@ -0,0 +1,54 @@ |
|||
import React from 'react' |
|||
import Box from './public/table-card'; |
|||
import { useFsRequest } from '$utils'; |
|||
import { mathRound } from './util'; |
|||
function DataShare(props) { |
|||
|
|||
const { data: dataTotal = {} } = useFsRequest({ |
|||
url: 'homepage/datatotal/top5', |
|||
pollingInterval: 1000 * 60, |
|||
cacheKey: 'datatotal', |
|||
}); |
|||
|
|||
const { data: restfulInfo = {} } = useFsRequest({ |
|||
url: 'homepage/restful/info', |
|||
pollingInterval: 1000 * 60, |
|||
cacheKey: 'restfulInfo', |
|||
}); |
|||
|
|||
const renderItem = (s) => { |
|||
return <div className='_item_content'> |
|||
<div className={'_item_icon' + s.key} /> |
|||
<div className='_item_text'> |
|||
{s.title} |
|||
<div className='number_container'> |
|||
<span className='_number'>{s.data}</span>{s.unit} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
} |
|||
|
|||
const leftData = [ |
|||
{ key: '1', data: mathRound(dataTotal?.total), unit: '万条', title: '共享库数据总量' }, |
|||
{ key: '2', data: restfulInfo?.total, unit: '次', title: '访问接口总次数' }, |
|||
{ key: '3', data: restfulInfo?.totalUser, unit: '个', title: '访问接口用户总数' }] |
|||
const rightData = [ |
|||
{ key: '2', data: restfulInfo?.todayTotal, unit: '次', title: '接口访问次数' }, |
|||
{ key: '3', data: restfulInfo?.todayUser, unit: '个', title: '访问接口用户总数' }] |
|||
|
|||
return <Box title={"数据共享"} > |
|||
<div className='data_share'> |
|||
<div className='_left_content'> |
|||
{leftData.map(s => renderItem(s))} |
|||
</div> |
|||
<div className='_right_content'> |
|||
<div className='_today_text'>今日</div> |
|||
{rightData.map(s => renderItem(s))} |
|||
</div> |
|||
</div> |
|||
</Box> |
|||
} |
|||
|
|||
export default DataShare; |
|||
|
|||
|
@ -0,0 +1,262 @@ |
|||
import React, { useEffect, useState } from 'react' |
|||
import Box from './public/table-card'; |
|||
import ReactEcharts from 'echarts-for-react'; |
|||
import './style.less'; |
|||
import { useFsRequest } from '$utils'; |
|||
import { mathRound } from './util'; |
|||
import NoData from './public/noData'; |
|||
function DataTop5(props) { |
|||
const { cardContentHeight } = props; |
|||
const { data: dataTotal = {} } = useFsRequest({ |
|||
url: 'homepage/datatotal/top5', |
|||
pollingInterval: 1000 * 60, |
|||
cacheKey: 'datatotal', |
|||
}); |
|||
|
|||
const renderBody = () => { |
|||
let chartData = dataTotal?.top5?.map(x => { |
|||
return { |
|||
name: x?.dataSource?.resourceCatalog?.name, |
|||
value: mathRound(x.dbRecordCount), |
|||
} |
|||
}) || [] |
|||
|
|||
let options = { |
|||
xAxis: { |
|||
splitLine: { |
|||
show: false, |
|||
}, |
|||
axisLabel: { |
|||
show: false, |
|||
}, |
|||
axisTick: { |
|||
show: false, |
|||
}, |
|||
splitArea: { show: false }, |
|||
axisLine: { |
|||
show: false, |
|||
}, |
|||
}, |
|||
tooltip: { |
|||
confine: true, |
|||
trigger: 'axis', |
|||
axisPointer: { |
|||
type: 'shadow', |
|||
}, |
|||
backgroundColor: 'rgba(13,30,44, 0.7)', |
|||
borderColor: 'rgba(3, 65, 118, 0.8)', |
|||
textStyle: { |
|||
color: '#fff', |
|||
}, |
|||
formatter: function (params) { |
|||
var name = params[0].name |
|||
if (name.length > 20) { |
|||
name = name.replace(/(.{20})/g, '$1<br>') // 每 30 个字符添加一个换行符
|
|||
} |
|||
var content = name |
|||
|
|||
return content + ' : <b>' + params[0].value + '</b>万条' |
|||
} |
|||
}, |
|||
grid: { |
|||
top: 13, |
|||
bottom: -10, |
|||
left: '5%', |
|||
}, |
|||
yAxis: { |
|||
inverse: true, |
|||
axisLine: { |
|||
show: false, |
|||
}, |
|||
axisTick: { |
|||
show: false, |
|||
}, |
|||
axisLabel: { |
|||
textStyle: { |
|||
color: '#fff', |
|||
padding: [-5, 0, 35, 18], |
|||
}, |
|||
formatter(value, index) { |
|||
let str = '', num = 'TOP' + (index + 1) |
|||
let valueHandle = value.length > 10 ? value.substring(0, 10) + '...' : value |
|||
if (index === 0) { |
|||
str = '{a| ' + num + '}{title| ' + valueHandle + '}' |
|||
} else if (index === 1) { |
|||
str = '{b| ' + num + '}{title| ' + valueHandle + '}' |
|||
} else if (index === 2) { |
|||
str = '{c| ' + num + '}{title| ' + valueHandle + '}' |
|||
} else { |
|||
str = '{d| ' + num + '}{title| ' + valueHandle + '}' |
|||
} |
|||
return str |
|||
}, |
|||
rich: { |
|||
a: { |
|||
borderColor: '#EE6F7C', |
|||
borderWidth: 1, |
|||
borderRadius: [0, 10, 10, 0], |
|||
padding: [3.5, 10, 1, -13], |
|||
backgroundColor: 'rgba(238, 111, 124, 0.8)', |
|||
}, |
|||
b: { |
|||
borderColor: '#FFCF5F', |
|||
borderWidth: 1, |
|||
borderRadius: [0, 10, 10, 0], |
|||
padding: [3.5, 10, 1, -13], |
|||
backgroundColor: 'rgba(255, 207, 95, 0.7)', |
|||
}, |
|||
c: { |
|||
borderColor: '#00E8FF', |
|||
borderWidth: 1, |
|||
borderRadius: [0, 10, 10, 0], |
|||
padding: [3.5, 10, 1, -13], |
|||
backgroundColor: 'rgba(0, 232, 255, 0.7)', |
|||
}, |
|||
d: { |
|||
borderColor: '#1A90FF', |
|||
borderWidth: 1, |
|||
borderRadius: [0, 10, 10, 0], |
|||
padding: [3.5, 10, 1, -13], |
|||
backgroundColor: 'rgba(26, 144, 255, 0.7)', |
|||
}, |
|||
title: { |
|||
padding: [0, 0, 0, 3], |
|||
}, |
|||
}, |
|||
align: 'left', |
|||
}, |
|||
data: chartData.map((item) => item.name), |
|||
}, |
|||
series: [ |
|||
{ |
|||
type: 'pictorialBar', |
|||
symbol: 'rect', |
|||
symbolRotate: 30, |
|||
symbolRepeat: 'fixed', |
|||
symbolClip: true, |
|||
symbolOffset: [0, -1.5], |
|||
symbolSize: [2, 12], |
|||
symbolMargin: '3', |
|||
itemStyle: { |
|||
normal: { |
|||
color: '#000726', |
|||
}, |
|||
}, |
|||
label: { |
|||
show: true, |
|||
color: '#C8F0FF', |
|||
fontFamily: 'Bebas', |
|||
fontSize: 12, |
|||
offset: [-9, 1], |
|||
position: 'right', |
|||
formatter(params) { |
|||
let result = '' |
|||
switch (params.dataIndex) { |
|||
case 0: |
|||
result = '{img|}{index0|' + params.value + '}{unit|}' |
|||
break |
|||
case 1: |
|||
result = '{img|}{index1|' + params.value + '}{unit|}' |
|||
break |
|||
case 2: |
|||
result = '{img|}{index2|' + params.value + '}{unit|}' |
|||
break |
|||
default: |
|||
result = '{img|}{index3|' + params.value + '}{unit|}' |
|||
break |
|||
} |
|||
return result |
|||
}, |
|||
rich: { |
|||
img: { |
|||
height: 18, |
|||
width: 20, |
|||
// backgroundColor: { image: arrow },这个图片自己切,这里上传不了(加了一个尾巴的形状)
|
|||
}, |
|||
unit: { |
|||
color: '#C8F0FF', |
|||
fontSize: 11, |
|||
}, |
|||
index0: { |
|||
color: '#FFF', |
|||
fontFamily: 'Bebas', |
|||
padding: [-2, 2, 0, 0], |
|||
fontWeight: 'bold', |
|||
fontSize: 16, |
|||
}, |
|||
index1: { |
|||
color: '#FFF', |
|||
fontFamily: 'Bebas', |
|||
padding: [-2, 2, 0, 0], |
|||
fontWeight: 'bold', |
|||
fontSize: 16, |
|||
}, |
|||
index2: { |
|||
color: '#FFF', |
|||
fontFamily: 'Bebas', |
|||
padding: [-2, 2, 0, 0], |
|||
fontWeight: 'bold', |
|||
fontSize: 16, |
|||
}, |
|||
index3: { |
|||
color: '#FFF', |
|||
fontFamily: 'Bebas', |
|||
padding: [-2, 2, 0, 0], |
|||
fontWeight: 'bold', |
|||
fontSize: 16, |
|||
}, |
|||
}, |
|||
}, |
|||
symbolBoundingData: Math.max(...chartData.map((item) => item.value)) * 1.3, |
|||
data: chartData.map((item) => item.value), |
|||
z: 2, |
|||
}, |
|||
{ |
|||
type: 'bar', |
|||
barWidth: 10, |
|||
data: chartData.map((item) => item.value), |
|||
itemStyle: { |
|||
normal: { |
|||
color: '#54DEFA', |
|||
}, |
|||
}, |
|||
z: 1, |
|||
}, |
|||
{ |
|||
type: 'bar', |
|||
barGap: '-125%', // 设置外框粗细
|
|||
data: chartData.map((items) => Math.max(...chartData.map((item) => item.value)) * 1.3), |
|||
barWidth: 15, |
|||
itemStyle: { |
|||
color: 'none', |
|||
borderColor: '#979797', |
|||
}, |
|||
z: 0, |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
return <ReactEcharts |
|||
option={options} |
|||
notMerge |
|||
lazyUpdate |
|||
style={{ height: cardContentHeight }} |
|||
/> |
|||
} |
|||
|
|||
return <Box title={"数据量TOP5单位"} bodyPaddingTop={1} > |
|||
{ |
|||
dataTotal?.top5?.length > 0 ? |
|||
<> |
|||
<div className='data_top5_unit'>数据量:万条</div> |
|||
{renderBody()} |
|||
</> |
|||
: <NoData /> |
|||
} |
|||
|
|||
</Box> |
|||
} |
|||
|
|||
export default DataTop5; |
|||
|
|||
|
@ -0,0 +1,42 @@ |
|||
import React, { useEffect, useState } from 'react' |
|||
import Box from './public/table-card'; |
|||
import NoData from './public/noData'; |
|||
import './style.less'; |
|||
import { ApiTable, useFsRequest } from '$utils'; |
|||
function HotspotData(props) { |
|||
|
|||
const { data: restfulInfo = {} } = useFsRequest({ |
|||
url: 'homepage/restful/info', |
|||
pollingInterval: 1000 * 60, |
|||
cacheKey: 'restfulInfo', |
|||
}); |
|||
|
|||
const top3 = restfulInfo?.top3 |
|||
return <Box title={"热点数据"} bodyPaddingTop={25} > |
|||
{top3?.length > 0 ? |
|||
<div className='hotspot_data_container'> |
|||
<div className='_img'></div> |
|||
<div className='_top1'> |
|||
<span className='hotspot_title' title={top3[0].name}>{top3[0].name?.length > 8 ? top3[0].name.substring(0, 8) + '...' : top3[0].name}</span> |
|||
<div className='hotspot_data_number'>{top3[0].count}</div> |
|||
</div> |
|||
<div className='_top2'> |
|||
{top3?.length > 2 && <> |
|||
<span className='hotspot_title' title={top3[2].name}>{top3[2].name?.length > 8 ? top3[2].name.substring(0, 8) + '...' : top3[2].name}</span> |
|||
<div className='hotspot_data_number'>{top3[2].count}</div> |
|||
</>} |
|||
</div> |
|||
<div className='_top3'> |
|||
{top3?.length > 1 && <> |
|||
<span className='hotspot_title' title={top3[1].name}>{top3[1].name?.length > 8 ? top3[1].name.substring(0, 8) + '...' : top3[1].name}</span> |
|||
<div className='hotspot_data_number'>{top3[1].count}</div> |
|||
</>} |
|||
</div> |
|||
</div> : <NoData /> |
|||
} |
|||
</Box> |
|||
} |
|||
|
|||
export default HotspotData; |
|||
|
|||
|
@ -0,0 +1,39 @@ |
|||
import React, { useEffect, useState } from 'react' |
|||
import Box from './public/table-card'; |
|||
import { ApiTable, useFsRequest } from '$utils'; |
|||
import './style.less'; |
|||
function NodeResource(props) { |
|||
const { data: cluters = {} } = useFsRequest({ |
|||
url: 'homepage/datatotal/cluters', |
|||
pollingInterval: 1000 * 20, |
|||
}); |
|||
|
|||
const renderBody = () => { |
|||
return <div className='node-resource-container'> |
|||
<div className='_item'> |
|||
<div className='_noderesource_data'>{cluters?.disk}<span className='_percent'>%</span></div> |
|||
<div className='_noderesource_title'>硬盘</div> |
|||
<div className='disk_icon' /> |
|||
</div> |
|||
<div className='_item'> |
|||
<div className='_noderesource_data'>{cluters?.memory}<span className='_percent'>%</span></div> |
|||
<div className='_noderesource_title'>内存</div> |
|||
<div className='memory_icon' /> |
|||
</div> |
|||
<div className='_item'> |
|||
<div className='_noderesource_data'>{cluters?.cpu}<span className='_percent'>%</span></div> |
|||
<div className='_noderesource_title'>CPU</div> |
|||
<div className='cpu_icon' /> |
|||
</div> |
|||
</div> |
|||
|
|||
} |
|||
|
|||
return <Box title={"节点资源"} > |
|||
{renderBody()} |
|||
</Box> |
|||
} |
|||
|
|||
export default NodeResource; |
|||
|
|||
|
@ -0,0 +1,33 @@ |
|||
/* 轮播列表组件 */ |
|||
import React from 'react'; |
|||
import ScrollBoard from './scrollBoard'; |
|||
import NoData from './noData'; |
|||
import './index.less'; |
|||
function CarouselList(props) { |
|||
const { |
|||
header = [], data = [], rowNum = 4, height, columnWidth, multiellipsis, waitTime = 2000, marginTop, ...restProps |
|||
} = props; |
|||
|
|||
const config = { |
|||
header, |
|||
rowNum, |
|||
headerBGC: 'rgba(81, 200, 247, 0.2)', |
|||
oddRowBGC: 'transparent', |
|||
evenRowBGC: 'transparent', |
|||
headerHeight: 30, |
|||
data, |
|||
waitTime, |
|||
columnWidth: columnWidth || [], |
|||
}; |
|||
|
|||
return data.length > 0 ? ( |
|||
<ScrollBoard |
|||
config={config} |
|||
style={{ height }} |
|||
className={multiellipsis ? 'scroll-board-multi' : 'scroll-board'} |
|||
{...restProps} |
|||
/> |
|||
) : <NoData marginTop={marginTop || 0} />; |
|||
} |
|||
|
|||
export default CarouselList; |
@ -0,0 +1,80 @@ |
|||
.opcityBackground { |
|||
background-color: rgba(8, 27, 55, 0.6); |
|||
} |
|||
|
|||
.card-title { |
|||
// background: linear-gradient(to bottom, #fafafb, #92cbff); |
|||
// background-clip: border-box; |
|||
// -webkit-background-clip: text; |
|||
color: #fff; |
|||
font-size: 22px; |
|||
font-family: YouSheBiaoTiHei; |
|||
padding-left: 20px; |
|||
// font-weight: 600; |
|||
} |
|||
|
|||
/* 滚动列表 */ |
|||
.scroll-board { |
|||
width: 533px; |
|||
height: 220px; |
|||
margin-top: 10px; |
|||
margin-left: 6px; |
|||
|
|||
.header { |
|||
height: 30px; |
|||
border-top: 1px solid #0047ba; |
|||
border-bottom: 1px solid #0047ba; |
|||
|
|||
.header-item { |
|||
// background: rgba(12, 49, 110, 0.3); |
|||
margin-right: 10px; |
|||
} |
|||
} |
|||
|
|||
.rows { |
|||
.row-item { |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.row-item:hover { |
|||
background: linear-gradient(270deg, rgba(17, 183, 247, 0) 0%, rgba(17, 183, 247, 0.85) 100%); |
|||
color: #9ac8fc; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.scroll-board-multi { |
|||
padding: 5px 0px 5px; |
|||
color: rgba(204, 228, 255, 1) !important; |
|||
|
|||
.header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
font-size: 12px !important; |
|||
color: rgba(204, 228, 255, 1) !important; |
|||
// border-bottom: 1px solid #124C79 !important; |
|||
} |
|||
|
|||
.rows { |
|||
color: rgba(204, 228, 255, 1) !important; |
|||
|
|||
.row-item { |
|||
border-bottom: 1px solid #124C79 !important; |
|||
} |
|||
|
|||
.row-item:hover { |
|||
background: linear-gradient(270deg, rgba(17, 183, 247, 0) 0%, rgba(17, 183, 247, 0.85) 100%); |
|||
color: #9ac8fc; |
|||
} |
|||
} |
|||
} |
|||
|
|||
._sorrow { |
|||
display: inline-block; |
|||
width: 15px; |
|||
height: 15px; |
|||
background: url('/assets/images/homePage/bigscreen/sorrow.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
margin-left: 13px; |
|||
} |
@ -0,0 +1,18 @@ |
|||
/* 公共模块暂无数据组件 */ |
|||
import React from 'react'; |
|||
import { Empty } from 'antd'; |
|||
|
|||
function NoData({ height = 180, marginTop = 0 }) { |
|||
return ( |
|||
<Empty |
|||
image="/assets/images/homePage/bigscreen/empty.png" |
|||
imageStyle={{ |
|||
height, |
|||
marginTop |
|||
}} |
|||
description={false} |
|||
/> |
|||
); |
|||
} |
|||
|
|||
export default NoData; |
@ -0,0 +1,469 @@ |
|||
import React, { |
|||
useEffect, useState, useRef, useMemo, forwardRef, |
|||
} from 'react'; |
|||
|
|||
import PropTypes from 'prop-types'; |
|||
|
|||
import classnames from 'classnames'; |
|||
|
|||
import { deepMerge } from '@jiaminghi/charts/lib/util/index'; |
|||
|
|||
import { deepClone } from '@jiaminghi/c-render/lib/plugin/util'; |
|||
|
|||
import { useAutoResize, co } from '@jiaminghi/data-view-react'; |
|||
|
|||
import './style.less'; |
|||
|
|||
const defaultConfig = { |
|||
/** |
|||
* @description Board header |
|||
* @type {Array<String>} |
|||
* @default header = [] |
|||
* @example header = ['column1', 'column2', 'column3'] |
|||
*/ |
|||
header: [], |
|||
/** |
|||
* @description Board data |
|||
* @type {Array<Array>} |
|||
* @default data = [] |
|||
*/ |
|||
data: [], |
|||
/** |
|||
* @description Row num |
|||
* @type {Number} |
|||
* @default rowNum = 5 |
|||
*/ |
|||
rowNum: 5, |
|||
/** |
|||
* @description Header background color |
|||
* @type {String} |
|||
* @default headerBGC = '#00BAFF' |
|||
*/ |
|||
headerBGC: '#00BAFF', |
|||
/** |
|||
* @description Odd row background color |
|||
* @type {String} |
|||
* @default oddRowBGC = '#003B51' |
|||
*/ |
|||
oddRowBGC: '#003B51', |
|||
/** |
|||
* @description Even row background color |
|||
* @type {String} |
|||
* @default evenRowBGC = '#003B51' |
|||
*/ |
|||
evenRowBGC: '#0A2732', |
|||
/** |
|||
* @description Scroll wait time |
|||
* @type {Number} |
|||
* @default waitTime = 2000 |
|||
*/ |
|||
waitTime: 2000, |
|||
/** |
|||
* @description Header height |
|||
* @type {Number} |
|||
* @default headerHeight = 35 |
|||
*/ |
|||
headerHeight: 35, |
|||
/** |
|||
* @description Column width |
|||
* @type {Array<Number>} |
|||
* @default columnWidth = [] |
|||
*/ |
|||
columnWidth: [], |
|||
/** |
|||
* @description Column align |
|||
* @type {Array<String>} |
|||
* @default align = [] |
|||
* @example align = ['left', 'center', 'right'] |
|||
*/ |
|||
align: [], |
|||
/** |
|||
* @description Show index |
|||
* @type {Boolean} |
|||
* @default index = false |
|||
*/ |
|||
index: false, |
|||
/** |
|||
* @description index Header |
|||
* @type {String} |
|||
* @default indexHeader = '#' |
|||
*/ |
|||
indexHeader: '#', |
|||
/** |
|||
* @description Carousel type |
|||
* @type {String} |
|||
* @default carousel = 'single' |
|||
* @example carousel = 'single' | 'page' |
|||
*/ |
|||
carousel: 'single', |
|||
/** |
|||
* @description Pause scroll when mouse hovered |
|||
* @type {Boolean} |
|||
* @default hoverPause = true |
|||
* @example hoverPause = true | false |
|||
*/ |
|||
hoverPause: true, |
|||
}; |
|||
|
|||
function calcHeaderData({ header, index, indexHeader }) { |
|||
if (!header.length) { |
|||
return []; |
|||
} |
|||
|
|||
header = [...header]; |
|||
|
|||
if (index) header.unshift(indexHeader); |
|||
|
|||
return header; |
|||
} |
|||
|
|||
function calcRows({ |
|||
data, index, headerBGC, rowNum, |
|||
}) { |
|||
if (index) { |
|||
data = data.map((row, i) => { |
|||
row = [...row]; |
|||
|
|||
const indexTag = `<span class="index" style="background-color: ${headerBGC};">${i |
|||
+ 1}</span>`; |
|||
|
|||
row.unshift(indexTag); |
|||
|
|||
return row; |
|||
}); |
|||
} |
|||
|
|||
data = data.map((ceils, i) => ({ ceils, rowIndex: i })); |
|||
|
|||
const rowLength = data.length; |
|||
|
|||
if (rowLength > rowNum && rowLength < 2 * rowNum) { |
|||
data = [...data, ...data]; |
|||
} |
|||
|
|||
return data.map((d, i) => ({ ...d, scroll: i })); |
|||
} |
|||
|
|||
function calcAligns(mergedConfig, header) { |
|||
const columnNum = header.length; |
|||
|
|||
const aligns = new Array(columnNum).fill('left'); |
|||
|
|||
const { align } = mergedConfig; |
|||
|
|||
return deepMerge(aligns, align); |
|||
} |
|||
|
|||
const ScrollBoard = forwardRef(({ |
|||
onClick, config = {}, className, style, onMouseOver, |
|||
}, ref) => { |
|||
const { width, height, domRef } = useAutoResize(ref); |
|||
|
|||
const [state, setState] = useState({ |
|||
mergedConfig: null, |
|||
|
|||
header: [], |
|||
|
|||
rows: [], |
|||
|
|||
rowsShow: [], |
|||
|
|||
widths: [], |
|||
|
|||
heights: [], |
|||
|
|||
aligns: [], |
|||
}); |
|||
|
|||
const { |
|||
mergedConfig, header, rows, widths, heights, aligns, rowsShow, |
|||
} = state; |
|||
|
|||
const stateRef = useRef({ |
|||
...state, |
|||
rowsData: [], |
|||
avgHeight: 0, |
|||
animationIndex: 0, |
|||
}); |
|||
|
|||
Object.assign(stateRef.current, state); |
|||
|
|||
function onResize() { |
|||
if (!mergedConfig) return; |
|||
|
|||
const widths = calcWidths(mergedConfig, stateRef.current.rowsData); |
|||
|
|||
const heights = calcHeights(mergedConfig, header); |
|||
|
|||
const data = { widths, heights }; |
|||
|
|||
Object.assign(stateRef.current, data); |
|||
setState((state) => ({ ...state, ...data })); |
|||
} |
|||
const [init, setInit] = useState(true); |
|||
|
|||
function calcData() { |
|||
// const mergedConfig = deepMerge(
|
|||
// deepClone(defaultConfig, true),
|
|||
// config || {},
|
|||
// );
|
|||
const mergedConfig = { |
|||
...defaultConfig, |
|||
...config, |
|||
}; |
|||
|
|||
const header = calcHeaderData(mergedConfig); |
|||
|
|||
const rows = calcRows(mergedConfig); |
|||
|
|||
const widths = calcWidths(mergedConfig, stateRef.current.rowsData); |
|||
|
|||
const heights = calcHeights(mergedConfig, header); |
|||
|
|||
const aligns = calcAligns(mergedConfig, header); |
|||
|
|||
const data = { |
|||
mergedConfig, |
|||
header, |
|||
rows, |
|||
widths, |
|||
aligns, |
|||
heights: init ? heights : state.heights.concat(heights), |
|||
rowsShow: init ? rows : state.rowsShow, |
|||
}; |
|||
setInit(false); |
|||
Object.assign(stateRef.current, data, { |
|||
rowsData: rows, |
|||
animationIndex: stateRef.current.animationIndex, |
|||
}); |
|||
|
|||
setState((state) => ({ ...state, ...data })); |
|||
} |
|||
|
|||
function calcWidths({ columnWidth, header }, rowsData) { |
|||
const usedWidth = columnWidth.reduce((all, w) => all + w, 0); |
|||
|
|||
let columnNum = 0; |
|||
if (rowsData[0]) { |
|||
columnNum = rowsData[0].ceils.length; |
|||
} else if (header.length) { |
|||
columnNum = header.length; |
|||
} |
|||
|
|||
const avgWidth = (width - usedWidth) / (columnNum - columnWidth.length); |
|||
|
|||
const widths = new Array(columnNum).fill(avgWidth); |
|||
|
|||
return deepMerge(widths, columnWidth); |
|||
} |
|||
|
|||
function calcHeights({ headerHeight, rowNum, data }, header) { |
|||
let allHeight = height; |
|||
|
|||
if (header.length) allHeight -= headerHeight; |
|||
|
|||
const avgHeight = allHeight / rowNum; |
|||
|
|||
Object.assign(stateRef.current, { avgHeight }); |
|||
|
|||
return new Array(data.length).fill(avgHeight); |
|||
} |
|||
|
|||
function* animation(start = false) { |
|||
let { |
|||
avgHeight, |
|||
animationIndex, |
|||
mergedConfig: { waitTime, carousel, rowNum }, |
|||
rowsData, |
|||
} = stateRef.current; |
|||
|
|||
const rowLength = rowsData.length; |
|||
|
|||
if (start) yield new Promise((resolve) => setTimeout(resolve, waitTime)); |
|||
|
|||
const animationNum = carousel === 'single' ? 1 : rowNum; |
|||
|
|||
let rows = rowsData.slice(animationIndex); |
|||
rows.push(...rowsData.slice(0, animationIndex)); |
|||
rows = rows.slice(0, carousel === 'page' ? rowNum * 2 : rowNum + 1); |
|||
|
|||
const heights = new Array(rowLength).fill(avgHeight); |
|||
setState((state) => ({ |
|||
...state, rows, heights, rowsShow: rows, |
|||
})); |
|||
|
|||
yield new Promise((resolve) => setTimeout(resolve, 300)); |
|||
|
|||
animationIndex += animationNum; |
|||
|
|||
const back = animationIndex - rowLength; |
|||
if (back >= 0) animationIndex = back; |
|||
|
|||
const newHeights = [...heights]; |
|||
newHeights.splice(0, animationNum, ...new Array(animationNum).fill(0)); |
|||
|
|||
Object.assign(stateRef.current, { animationIndex }); |
|||
setState((state) => ({ ...state, heights: newHeights })); |
|||
} |
|||
|
|||
function emitEvent(handle, ri, ci, row, ceil) { |
|||
const { ceils, rowIndex } = row; |
|||
|
|||
handle && handle({ |
|||
row: ceils, ceil, rowIndex, columnIndex: ci, |
|||
}); |
|||
} |
|||
|
|||
function handleHover(enter, ri, ci, row, ceil) { |
|||
if (enter) emitEvent(onMouseOver, ri, ci, row, ceil); |
|||
|
|||
if (!mergedConfig.hoverPause) return; |
|||
|
|||
const { pause, resume } = task.current; |
|||
|
|||
enter && pause && resume ? pause() : resume && resume(); |
|||
} |
|||
|
|||
// updateRows(rows, animationIndex) {
|
|||
// const { mergedConfig, animationHandler, animation } = this
|
|||
// this.mergedConfig = {
|
|||
// ...mergedConfig,
|
|||
// data: [...rows]
|
|||
// }
|
|||
// this.needCalc = true
|
|||
// if (typeof animationIndex === 'number') this.animationIndex = animationIndex
|
|||
// if (!animationHandler) animation(true)
|
|||
// }
|
|||
|
|||
const getBackgroundColor = (rowIndex) => mergedConfig[rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC']; |
|||
|
|||
const task = useRef({}); |
|||
|
|||
useEffect(() => { |
|||
calcData(); |
|||
|
|||
let start = true; |
|||
|
|||
function* loop() { |
|||
while (true) { |
|||
yield* animation(start); |
|||
|
|||
start = false; |
|||
|
|||
const { waitTime } = stateRef.current.mergedConfig; |
|||
|
|||
yield new Promise((resolve) => setTimeout(resolve, waitTime - 300)); |
|||
} |
|||
} |
|||
|
|||
const { |
|||
mergedConfig: { rowNum }, |
|||
rows: rowsData, |
|||
} = stateRef.current; |
|||
|
|||
const rowLength = rowsData.length; |
|||
|
|||
if (rowNum >= rowLength) { |
|||
setState((prestate) => ({ |
|||
...prestate, rowsShow: state.rows, |
|||
})); |
|||
return; |
|||
} |
|||
|
|||
task.current = co(loop); |
|||
|
|||
return task.current.end; |
|||
}, [config, domRef.current]); |
|||
|
|||
useEffect(onResize, [width, height, domRef.current]); |
|||
|
|||
const classNames = useMemo(() => classnames('dv-scroll-board', className), [ |
|||
className, |
|||
]); |
|||
|
|||
return ( |
|||
<div className={classNames} style={style} ref={domRef}> |
|||
{!!header.length && !!mergedConfig && ( |
|||
<div |
|||
className="header" |
|||
style={{ backgroundColor: `${mergedConfig.headerBGC}` }} |
|||
> |
|||
{header.map((headerItem, i) => ( |
|||
<div |
|||
className="header-item" |
|||
key={`${headerItem}-${i}`} |
|||
style={{ |
|||
height: `${mergedConfig.headerHeight}px`, |
|||
lineHeight: `${mergedConfig.headerHeight}px`, |
|||
width: `${widths[i]}px`, |
|||
}} |
|||
align={aligns[i]} |
|||
dangerouslySetInnerHTML={{ __html: headerItem }} |
|||
/> |
|||
))} |
|||
</div> |
|||
)} |
|||
|
|||
{!!mergedConfig && ( |
|||
<div |
|||
className="rows" |
|||
style={{ |
|||
height: `${height |
|||
- (header.length ? mergedConfig.headerHeight : 0)}px`,
|
|||
}} |
|||
> |
|||
{rowsShow.map((row, ri) => ( |
|||
<div |
|||
className="row-item" |
|||
key={`${row.toString()}-${row.scroll}`} |
|||
style={{ |
|||
height: `${heights[ri]}px`, |
|||
lineHeight: `${heights[ri]}px`, |
|||
backgroundColor: `${getBackgroundColor(row.rowIndex)}`, |
|||
}} |
|||
> |
|||
{row.ceils.map((ceil, ci) => { |
|||
if (typeof (ceil) === 'string') { |
|||
return ( |
|||
<div |
|||
className="ceil" |
|||
key={`${ceil}-${ri}-${ci}`} |
|||
style={{ width: `${widths[ci]}px` }} |
|||
align={aligns[ci]} |
|||
dangerouslySetInnerHTML={{ __html: ceil }} |
|||
onClick={() => emitEvent(onClick, ri, ci, row, ceil)} |
|||
onMouseEnter={() => handleHover(true, ri, ci, row, ceil)} |
|||
onMouseLeave={() => handleHover(false)} |
|||
/> |
|||
); |
|||
} |
|||
return ( |
|||
<div |
|||
className="ceil" |
|||
style={{ width: `${widths[ci]}px` }} |
|||
align={aligns[ci]} |
|||
key={`${ri}-${ci}`} |
|||
onMouseEnter={() => handleHover(true, ri, ci, row, ceil)} |
|||
onMouseLeave={() => handleHover(false)} |
|||
> |
|||
{ceil} |
|||
</div> |
|||
); |
|||
})} |
|||
</div> |
|||
))} |
|||
</div> |
|||
)} |
|||
</div> |
|||
); |
|||
}); |
|||
|
|||
ScrollBoard.propTypes = { |
|||
config: PropTypes.object, |
|||
onClick: PropTypes.func, |
|||
onMouseOver: PropTypes.func, |
|||
className: PropTypes.string, |
|||
style: PropTypes.object, |
|||
}; |
|||
|
|||
export default ScrollBoard; |
@ -0,0 +1,44 @@ |
|||
.dv-scroll-board { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 100%; |
|||
color: #fff; |
|||
|
|||
.text { |
|||
padding: 0 10px; |
|||
box-sizing: border-box; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
font-size: 15px; |
|||
|
|||
.header-item { |
|||
.text; |
|||
transition: all 0.3s; |
|||
} |
|||
} |
|||
|
|||
.rows { |
|||
overflow: hidden; |
|||
|
|||
.row-item { |
|||
display: flex; |
|||
font-size: 14px; |
|||
transition: all 0.3s; |
|||
} |
|||
|
|||
.ceil { |
|||
.text; |
|||
} |
|||
|
|||
.index { |
|||
border-radius: 3px; |
|||
padding: 0px 3px; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,34 @@ |
|||
'use strict' |
|||
|
|||
import React from 'react' |
|||
import './index.less' |
|||
class Box extends React.Component { |
|||
render() { |
|||
const { title, height = '100%', children, bodyPaddingTop = 1, titlePaddingTop, margin, overflow } = this.props |
|||
|
|||
const headerbg = { |
|||
background: 'url(/assets/images/homePage/bigscreen/headertitlebg.png) no-repeat', |
|||
backgroundSize: '100% 100%', |
|||
} |
|||
return ( |
|||
<div style={{ height, width: '100%', margin: margin || "0px 0px 28px" }}> |
|||
<div style={{ |
|||
height: height, listStyle: 'none', overflow: overflow || 'hidden', |
|||
backgroundImage: 'linear-gradient(180deg, #00204a00 3%, #50c9f71a 100%)', |
|||
}}> |
|||
<div style={{ height: 42, paddingLeft: 24, paddingTop: '4px', wordBreak: 'keep-all', whiteSpace: 'nowrap', width: '100%', ...headerbg }}> |
|||
<span className='card-title'>{title}</span><div className='_sorrow' /> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
width: '100%', height: 2, |
|||
marginTop: titlePaddingTop || 10, marginBottom: bodyPaddingTop || 25, |
|||
}} /> |
|||
{children} |
|||
</div> |
|||
</div> |
|||
) |
|||
} |
|||
} |
|||
export default Box |
|||
|
@ -0,0 +1,373 @@ |
|||
@card-height: calc(100% - 42px - 13px); //左右卡片内容高度定义 目前卡片为等高 |
|||
|
|||
//节点资源 |
|||
.node-resource-container { |
|||
display: flex; |
|||
height: @card-height; |
|||
width: 100%; |
|||
align-items: center; |
|||
|
|||
._item { |
|||
width: 33%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
|
|||
._noderesource_data { |
|||
font-family: D-DINExp-Bold; |
|||
font-weight: 600; |
|||
font-size: 24px; |
|||
color: #FFFFFF; |
|||
line-height: 43.2px; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
._percent { |
|||
opacity: 0.8; |
|||
font-family: PingFangSC-Regular; |
|||
font-weight: 400; |
|||
font-size: 12px; |
|||
color: #C8F0FF; |
|||
text-align: left; |
|||
line-height: 24px; |
|||
} |
|||
} |
|||
|
|||
._noderesource_title { |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 20px; |
|||
color: #D8F0FF; |
|||
letter-spacing: 1.54px; |
|||
text-align: center; |
|||
text-shadow: 0 0 10px rgba(0, 145, 255, 0.5); |
|||
margin-bottom: 17px; |
|||
} |
|||
|
|||
.disk_icon { |
|||
width: 68.73px; |
|||
height: 62.77px; |
|||
background: url('/assets/images/homePage/bigscreen/disk.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
.cpu_icon { |
|||
width: 68.73px; |
|||
height: 62.77px; |
|||
background: url('/assets/images/homePage/bigscreen/cpu.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
.memory_icon { |
|||
width: 68.73px; |
|||
height: 62.77px; |
|||
background: url('/assets/images/homePage/bigscreen/memory.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
//接入数据统计 |
|||
.access_data { |
|||
display: flex; |
|||
height: @card-height; |
|||
width: 100%; |
|||
justify-content: center; |
|||
|
|||
font-family: PingFangSC-Regular; |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
color: #FFFFFF; |
|||
|
|||
._img { |
|||
width: 230px; |
|||
height: 95%; |
|||
background: url('/assets/images/homePage/bigscreen/accessdata.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
.data_unit { |
|||
position: absolute; |
|||
top: 27%; |
|||
right: 21%; |
|||
|
|||
.data_number { |
|||
line-height: 25px; |
|||
font-family: D-DINExp-Bold; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
color: #3E86FF; |
|||
letter-spacing: 0; |
|||
} |
|||
} |
|||
|
|||
.data_today { |
|||
position: absolute; |
|||
bottom: 13%; |
|||
right: 79%; |
|||
text-align: right; |
|||
|
|||
.data_number { |
|||
line-height: 25px; |
|||
font-family: D-DINExp-Bold; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
color: #00F6E4; |
|||
letter-spacing: 0; |
|||
} |
|||
} |
|||
|
|||
.data_total { |
|||
position: absolute; |
|||
bottom: 13%; |
|||
left: 79%; |
|||
|
|||
.data_number { |
|||
line-height: 25px; |
|||
font-family: D-DINExp-Bold; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
color: #FFDC4E; |
|||
letter-spacing: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.data_top5_unit { |
|||
position: absolute; |
|||
right: 4%; |
|||
top: 18%; |
|||
font-family: PingFangSC-Regular; |
|||
font-weight: 400; |
|||
font-size: 12px; |
|||
color: #C8F0FF; |
|||
} |
|||
|
|||
.hotspot_data_container { |
|||
display: flex; |
|||
height: @card-height; |
|||
width: 100%; |
|||
justify-content: center; |
|||
|
|||
font-family: PingFangSC-Regular; |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
color: #FFFFFF; |
|||
|
|||
._img { |
|||
width: 203px; |
|||
height: 80%; |
|||
background: url('/assets/images/homePage/bigscreen/hotspotdatabg.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
.hotspot_title { |
|||
padding: 2px; |
|||
padding-left: 6px; |
|||
padding-right: 6px; |
|||
background: rgba(77, 241, 227, 0.08); |
|||
border: 1px solid rgba(77, 241, 227, 0.1); |
|||
box-shadow: inset 0 0 20px 0 rgba(28, 185, 196, 0.23); |
|||
} |
|||
|
|||
|
|||
.hotspot_data_number { |
|||
font-family: D-DINExp-Bold; |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
._top1 { |
|||
position: absolute; |
|||
top: 25%; |
|||
right: 63%; |
|||
text-align: right; |
|||
} |
|||
|
|||
._top2 { |
|||
position: absolute; |
|||
bottom: 22%; |
|||
right: 67%; |
|||
text-align: center; |
|||
} |
|||
|
|||
._top3 { |
|||
position: absolute; |
|||
bottom: 34%; |
|||
left: 73%; |
|||
} |
|||
} |
|||
|
|||
//数据共享 |
|||
.data_share { |
|||
display: flex; |
|||
height: @card-height; |
|||
|
|||
._left_content { |
|||
width: 50%; |
|||
height: 90%; |
|||
padding-left: 30px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
._right_content { |
|||
._today_text { |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 24px; |
|||
color: #FFFFFF; |
|||
letter-spacing: 0.5px; |
|||
position: absolute; |
|||
right: 6%; |
|||
top: 21%; |
|||
} |
|||
|
|||
padding-top: 23px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 47%; |
|||
height: 95%; |
|||
background: url(/assets/images/homePage/bigscreen/todaybg.png); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
justify-content: space-evenly; |
|||
align-items: center; |
|||
|
|||
} |
|||
|
|||
._item_content { |
|||
display: flex; |
|||
|
|||
|
|||
._item_icon1 { |
|||
width: 52px; |
|||
height: 52px; |
|||
background: url('/assets/images/homePage/bigscreen/1.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
._item_icon2 { |
|||
width: 52px; |
|||
height: 52px; |
|||
background: url('/assets/images/homePage/bigscreen/2.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
._item_icon3 { |
|||
width: 52px; |
|||
height: 52px; |
|||
background: url('/assets/images/homePage/bigscreen/3.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
._item_text { |
|||
color: #C8F0FF; |
|||
padding-left: 6px; |
|||
|
|||
.number_container { |
|||
._number { |
|||
font-family: D-DINExp-Bold; |
|||
font-weight: 700; |
|||
font-size: 22px; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-evenly; |
|||
width: 112px; |
|||
height: 28px; |
|||
background-image: linear-gradient(227deg, #3196AB 0%, #2091cd00 100%); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//大屏中间上部分 |
|||
.center_top_data { |
|||
|
|||
._center_card1 { |
|||
width: 353px; |
|||
height: 74px; |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 22px; |
|||
color: #FFFFFF; |
|||
letter-spacing: 0.46px; |
|||
text-align: center; |
|||
position: absolute; |
|||
top: -3%; |
|||
left: 32%; |
|||
background: url(/assets/images/homePage/bigscreen/centerdatabg1.png); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
._center_card2 { |
|||
width: 146px; |
|||
height: 35px; |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 16px; |
|||
color: #35D0FF; |
|||
letter-spacing: 0.46px; |
|||
text-align: center; |
|||
position: absolute; |
|||
top: 26%; |
|||
left: 42%; |
|||
background: url(/assets/images/homePage/bigscreen/centerdatabg2.png); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
._center_card3 { |
|||
width: 146px; |
|||
height: 35px; |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 16px; |
|||
color: #35D0FF; |
|||
letter-spacing: 0.46px; |
|||
text-align: center; |
|||
position: absolute; |
|||
top: 52%; |
|||
left: 42%; |
|||
background: url(/assets/images/homePage/bigscreen/centerdatabg2.png); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
._center_card4 { |
|||
width: 146px; |
|||
height: 35px; |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 16px; |
|||
color: #35D0FF; |
|||
letter-spacing: 0.46px; |
|||
text-align: center; |
|||
position: absolute; |
|||
top: 74%; |
|||
left: 42%; |
|||
background: url(/assets/images/homePage/bigscreen/centerdatabg2.png); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
} |
@ -0,0 +1,3 @@ |
|||
export const mathRound = (number) => { |
|||
return number ? Math.round(number / 1000) / 10 : 0 |
|||
} |
@ -0,0 +1,74 @@ |
|||
import React, { useEffect, useState } from 'react' |
|||
import { connect } from 'react-redux'; |
|||
import { push } from 'react-router-redux'; |
|||
import AccessData from '../components/accessData' |
|||
import AlarmList from '../components/alarmList' |
|||
import DataShare from '../components/dataShare' |
|||
import DataTop5 from '../components/dataTop5' |
|||
import HotspotData from '../components/hotspotData' |
|||
import NodeResource from '../components/nodeResource' |
|||
import AbnormalMonitoring from '../components/abnormalMonitoring' |
|||
import CenterTop from '../components/centerTop' |
|||
import './style.less' |
|||
|
|||
function homePage(props) { |
|||
const { dispatch } = props; |
|||
const childStyle = { height: '32%', color: '#fff', marginBottom: 17 } |
|||
const cardHeight = document.body.clientHeight * 0.896 * 0.32 |
|||
const cardContentHeight = cardHeight - 42 - 13 |
|||
return <div className='homepage'> |
|||
<div className='_title'> |
|||
<div onClick={() => { dispatch(push('/metadataManagement/latestMetadata')) }} className='_exit' ><div className='_icon' />进入后台</div> |
|||
</div> |
|||
<div className='homepage-left homepage-left-left'> |
|||
<div className="list"> |
|||
<div className='child' style={childStyle}> |
|||
<AccessData /> |
|||
</div> |
|||
<div className='child' style={childStyle}> |
|||
<NodeResource /> |
|||
</div> |
|||
<div className='child' style={childStyle}> |
|||
<AlarmList cardContentHeight={cardContentHeight} /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div className='homepage-center'> |
|||
<CenterTop /> |
|||
<div className="list"> |
|||
<div className='child-top'> |
|||
<AbnormalMonitoring /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div className='homepage-left homepage-left-right'> |
|||
<div className="list"> |
|||
<div className='child-right' style={childStyle}> |
|||
<DataShare /> |
|||
</div> |
|||
<div className='child-right' style={childStyle}> |
|||
<DataTop5 cardContentHeight={cardContentHeight} /> |
|||
</div> |
|||
<div className='child-right' style={childStyle}> |
|||
<HotspotData /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { |
|||
auth, global |
|||
} = state; |
|||
return { |
|||
clientHeight: global.clientHeight, |
|||
actions: global.actions, |
|||
|
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(homePage); |
|||
|
|||
|
@ -0,0 +1,6 @@ |
|||
'use strict'; |
|||
|
|||
import homePage from './homePage'; |
|||
|
|||
|
|||
export default homePage ; |
@ -0,0 +1,224 @@ |
|||
.homepage { |
|||
width: 100%; |
|||
height: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
background: url('/assets/images/homePage/bigscreen/bg.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
overflow: hidden; |
|||
|
|||
._title { |
|||
width: 100%; |
|||
height: 88px; |
|||
background: url('/assets/images/homePage/bigscreen/top.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
} |
|||
|
|||
._exit { |
|||
position: absolute; |
|||
right: 60px; |
|||
top: 38px; |
|||
cursor: pointer; |
|||
color: #C8F0FF; |
|||
display: flex; |
|||
|
|||
._icon { |
|||
display: inline-block; |
|||
width: 28px; |
|||
height: 28px; |
|||
background: url('/assets/images/homePage/bigscreen/exit.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
margin-right: 3px; |
|||
} |
|||
} |
|||
|
|||
.homepage-left { |
|||
width: 21.8%; |
|||
height: 89.6%; |
|||
position: absolute; |
|||
top: 8.2%; |
|||
z-index: 300; |
|||
} |
|||
|
|||
.homepage-center { |
|||
width: 49.16%; |
|||
height: 89.6%; |
|||
position: absolute; |
|||
bottom: 2.4%; |
|||
left: 25.5%; |
|||
padding-left: 16px; |
|||
padding-right: 16px; |
|||
z-index: 400; |
|||
|
|||
._top { |
|||
margin-top: 5%; |
|||
height: calc(100% - 200px); |
|||
background: url('/assets/images/homePage/bigscreen/centerbg.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
position: relative; |
|||
} |
|||
} |
|||
|
|||
.homepage-left-left { |
|||
left: 48px; |
|||
} |
|||
|
|||
.homepage-left-right { |
|||
right: 48px; |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
.list { |
|||
list-style: none; |
|||
height: 100%; |
|||
} |
|||
|
|||
.list .child { |
|||
box-sizing: border-box; |
|||
opacity: 0; |
|||
transform: translateX(-300px); |
|||
animation: show .5s forwards; |
|||
} |
|||
|
|||
.list .child.show { |
|||
animation-delay: 0s !important; |
|||
} |
|||
|
|||
.list .child.hide { |
|||
opacity: 1; |
|||
transform: translateX(0); |
|||
animation-name: hide; |
|||
animation-delay: 0s; |
|||
} |
|||
|
|||
/*animation-delay*/ |
|||
.list .child:not(.hide):nth-child(5n + 1) { |
|||
animation-delay: .3s; |
|||
} |
|||
|
|||
.list .child:not(.hide):nth-child(5n + 2) { |
|||
animation-delay: .6s; |
|||
} |
|||
|
|||
.list .child:not(.hide):nth-child(5n + 3) { |
|||
animation-delay: .9s; |
|||
} |
|||
|
|||
.list .child:not(.hide):nth-child(5n + 4) { |
|||
animation-delay: 1.2s; |
|||
} |
|||
|
|||
.list .child:not(.hide):nth-child(5n + 5) { |
|||
animation-delay: 1.5s; |
|||
} |
|||
|
|||
.list .child-right { |
|||
box-sizing: border-box; |
|||
opacity: 0; |
|||
transform: translateX(300px); |
|||
animation: show .5s forwards; |
|||
} |
|||
|
|||
.list .child-right.show { |
|||
animation-delay: 0s !important; |
|||
} |
|||
|
|||
.list .child-right.hide { |
|||
opacity: 1; |
|||
transform: translateX(0); |
|||
animation-name: hide; |
|||
animation-delay: 0s; |
|||
} |
|||
|
|||
/*animation-delay*/ |
|||
.list .child-right:not(.hide):nth-child(5n + 1) { |
|||
animation-delay: .3s; |
|||
} |
|||
|
|||
.list .child-right:not(.hide):nth-child(5n + 2) { |
|||
animation-delay: .6s; |
|||
} |
|||
|
|||
.list .child-right:not(.hide):nth-child(5n + 3) { |
|||
animation-delay: .9s; |
|||
} |
|||
|
|||
.list .child-right:not(.hide):nth-child(5n + 4) { |
|||
animation-delay: 1.2s; |
|||
} |
|||
|
|||
.list .child-right:not(.hide):nth-child(5n + 5) { |
|||
animation-delay: 1.5s; |
|||
} |
|||
|
|||
.list .child-top { |
|||
box-sizing: border-box; |
|||
opacity: 0; |
|||
transform: translateY(300px); |
|||
animation: show 1s forwards; |
|||
} |
|||
|
|||
.list .child-top.show { |
|||
animation-delay: 0s !important; |
|||
} |
|||
|
|||
.list .child-top.hide { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
animation-name: hide; |
|||
animation-delay: 0s; |
|||
} |
|||
|
|||
|
|||
@keyframes show { |
|||
to { |
|||
opacity: 1; |
|||
transform: translateX(0); |
|||
} |
|||
} |
|||
|
|||
@keyframes hide { |
|||
to { |
|||
opacity: 0; |
|||
transform: translateX(100px); |
|||
max-height: 0; |
|||
margin: 0; |
|||
} |
|||
} |
|||
|
|||
.center-card-title { |
|||
height: 31px; |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 24px; |
|||
color: #FFFFFF; |
|||
display: flex; |
|||
align-items: center; |
|||
margin-top: 5px; |
|||
|
|||
._icon_left { |
|||
width: 32px; |
|||
height: 17px; |
|||
background: url('/assets/images/homePage/bigscreen/center-left.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
margin-right: 11px; |
|||
margin-left: 10px; |
|||
} |
|||
|
|||
._icon_right { |
|||
width: 32px; |
|||
height: 17px; |
|||
background: url('/assets/images/homePage/bigscreen/center-right.png'); |
|||
background-repeat: no-repeat; |
|||
background-size: 100% 100%; |
|||
margin-right: 11px; |
|||
margin-left: 10px; |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
'use strict'; |
|||
|
|||
import reducers from './reducers'; |
|||
import routes from './routes'; |
|||
import actions from './actions'; |
|||
import { getNavItem } from './nav-item'; |
|||
|
|||
export default { |
|||
key: 'homePage', |
|||
name: '首页', |
|||
reducers: reducers, |
|||
routes: routes, |
|||
actions: actions, |
|||
getNavItem: getNavItem |
|||
}; |
@ -0,0 +1,11 @@ |
|||
import React from 'react'; |
|||
import { Link } from 'react-router-dom'; |
|||
import { Menu } from 'antd'; |
|||
import { HomeOutlined } from '@ant-design/icons'; |
|||
export function getNavItem(user) { |
|||
return ( |
|||
user?.role == '系统管理员' && <Menu.Item key="homePage" icon={<HomeOutlined />}> |
|||
<Link to="/homePage">数据监控平台</Link> |
|||
</Menu.Item> |
|||
); |
|||
} |
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
export default { |
|||
|
|||
} |
@ -0,0 +1,13 @@ |
|||
'use strict'; |
|||
import homePage from './containers/index'; |
|||
|
|||
export default [{ |
|||
type: 'outer', |
|||
route: { |
|||
path: '/homePage', |
|||
key: 'homePage', |
|||
breadcrumb: '数据监控平台', |
|||
// 不设置 component 则面包屑禁止跳转
|
|||
component: homePage |
|||
} |
|||
}]; |
@ -0,0 +1,10 @@ |
|||
|
|||
@icon-url: "/assets/fonticon/iconfont"; |
|||
|
|||
.tree-transfer .ant-transfer-list-body { |
|||
overflow: auto !important; |
|||
} |
|||
|
|||
.ant-pro-table-search { |
|||
background-color: @component-background !important; |
|||
} |
@ -0,0 +1,16 @@ |
|||
@import "~antd/lib/style/themes/default.less"; |
|||
@primary-color : @blue-6; |
|||
@link-color : @primary-color; |
|||
@secondary-color : fade(@primary-color, 20%); |
|||
@btn-primary-bg : @primary-color; |
|||
@select-item-selected-option-color: @primary-color; |
|||
@processing-color : @primary-color; |
|||
@select-item-selected-bg : @background-color-base; |
|||
@skeleton-color : @primary-color; |
|||
@btn-primary-bg : @primary-color; |
|||
|
|||
@component-background: transparent; |
|||
|
|||
:root { |
|||
--PC: @primary-color; |
|||
} |
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
export const AuthorizationCode = { |
|||
|
|||
}; |
@ -0,0 +1,13 @@ |
|||
'use strict'; |
|||
|
|||
export default class Func { |
|||
static isAuthorized(authcode) { |
|||
if (JSON.parse(sessionStorage.getItem('user'))) { |
|||
const { resources } = JSON.parse(sessionStorage.getItem('user')); |
|||
return resources.includes(authcode); |
|||
}else{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue