Commit d6056276 by Administrator

copy

parent 8929aee9

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

last 2 version
> 1%
maintained node versions
not dead
not ie <= 10
\ No newline at end of file
{
"presets":[
[
"@babel/preset-env",
{
"targets": {
"browsers": ["last 3 versions"],
"ie": "10"
},
"useBuiltIns": "usage",
"corejs": "core-js@3",
"debug": false
// "debug": true
}
],
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-transform-runtime",
"react-hot-loader/babel",
["import", {
"libraryName": "antd",
"libraryDirectory": "es",
"style": "css" // `style: true` 会加载 less 文件
}],
["import", { "libraryName": "antd-mobile", "libraryDirectory": "lib","style": "css"}, "antd-mobile"],
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-modules-commonjs"
]
}
\ No newline at end of file
/**
* 用于说明 commit 的类别,只允许使用下面7个标识。
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
bug:这个是自定义的
* */
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'test',
'chore',
'revert',
'bug',
'merge',
],
],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
},
};
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 80
trim_trailing_whitespace = true
[*.md]
max_line_length = 0
trim_trailing_whitespace = false
[COMMIT_EDITMSG]
max_line_length = 0
\ No newline at end of file
node_modules
dist
.vscode
.DS_Store
.git
*.log
*.log.*
*.DS_Store
*.iml
*.idea
*.lock
*.idea
chrome-user-data
*.sublime-project
*.sublime-workspace
*.pom
.md
.idea
.dea
.DS_Store
dll
dist
src\util\request.js
package-lock.json
\ No newline at end of file
node_modules
dist
docs
dll
.cache
src/static/lib
src/static
node_modules/
build
docs
src/locales
src/api
src/themes
**/node_modules
**/dist
**/src/static/
.vscode
.commitlintrc.js
.eslintrc.js
.prettierrc.js
.eslintrc.js
.prettierrc.js
.prettierignore
.stylelintrc
.gitignore
.browserslistrc
.babelrc
.commitlintrc.js
.editorconfig
sitbuildmaster.sh
sitbuilduat.sh
theme.json
yarn.lock
jsconfig.json
package-lock.json
package.json
build.sh
dev.sh
devbat.sh
README.md
module.exports = {
printWidth: 80, // 超过最大80值换行
semi: true, // 句尾添加分号
trailingComma: "es5", // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号
requirePragma: false, //限制为仅格式化在文件顶部包含特殊注释(称为编译指示)的文件。
"tabWidth": 2,
};
{
"extends": "stylelint-config-standard"
}
\ No newline at end of file
# sass-admin <!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [未木云管理端项目](#%E6%9C%AA%E6%9C%A8%E4%BA%91%E7%AE%A1%E7%90%86%E7%AB%AF%E9%A1%B9%E7%9B%AE)
- [首次运行项目:](#%E9%A6%96%E6%AC%A1%E8%BF%90%E8%A1%8C%E9%A1%B9%E7%9B%AE)
- [启动项目](#%E5%90%AF%E5%8A%A8%E9%A1%B9%E7%9B%AE)
- [项目启动页面展示](#%E9%A1%B9%E7%9B%AE%E5%90%AF%E5%8A%A8%E9%A1%B5%E9%9D%A2%E5%B1%95%E7%A4%BA)
- [项目打包](#%E9%A1%B9%E7%9B%AE%E6%89%93%E5%8C%85)
- [git 操作](#git-%E6%93%8D%E4%BD%9C)
- [代码规范](#%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83)
- [项目架构目录](#%E9%A1%B9%E7%9B%AE%E6%9E%B6%E6%9E%84%E7%9B%AE%E5%BD%95)
- [组件代抽](#%E7%BB%84%E4%BB%B6%E4%BB%A3%E6%8A%BD)
- [Other](#other)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# 未木云管理端项目
#### 首次运行项目:
> npm install // 跑环境,简称安装依赖 只有首次或者新的安装依赖运行
> npm run dll || yarn dll // 抽离基础包
#### 启动项目
> deve: 开发环境 ; sit: 测试环境 uat: uat环境;prod: 生产环境
> npm run deve || npm run sit || npm run uat || npm run prod
#### 项目启动页面展示
![Alt text](https://fulan-test.oss-cn-hangzhou.aliyuncs.com/test/rc-upload-1590556235484-2.png)
#### 项目打包
> npm run build:prod // 打包
> npm run server 打包后启动本地服务测试打包后的效果和运行 会自动打开浏览器 登录名 shyz 密码 12345
#### git 操作
每天的 git 操作
> git pull // 拉去最新分支
> git merge origin/sit // 合并远程仓库 sit 分支
**开发者推送 develop 开发分支操作** <font color='red'>切记自己分支不要合 develop</font>
> git checkout develop
> git pull
> <font color='red'>切记自己分支不要合 develop</font> > <font color='red'>正确做法是 develop 合并自己任务或者 bug 的分支</font>
> git merge 分支(本地自己分支)(切记是 develop 合并自己的分支)
**代码推送 严格按照 docs/commitlintrc.md 文档推送**
> git add .
> git commit -m''bug: 修复bug-10000-cwj 解决问题分页加载' ;
或者任务提交
> git commit -m''feat: feature_957_chenwanjun 任务完成第一版分页迭代'
或者其他commit
```javascript
feat:新功能(feature
fix:修补bug
docs:文档(documentation
style:格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
bugbug修复
```
> git push
分支名称分为:bug 分支和任务分支规则如下
创建 bug 分支:example
> git branch bug-886-chenwanjun // bug 后跟随 bug 号和开发者名字
创建任务分支:example
> git branch feature_957_chenwanjun // feature 后跟随任务号和开发者名字
#### 代码规范
> <font color='red'>合并冲突的时候一定要问 不要自己盲目合并</font>
> <font color='red'>gitlab网站上提供的合并功能在有冲突时的合并时双向合并,如果只需要单向合并不要在网页上操作</font>
> <font color='red'>代码备注,方便维护</font>
#### 项目架构目录
```text
.
├── \ .browserslistrc // 浏览器
├── README.md
├── build // 打包配置
│ ├── cssloader.config.js
│ ├── server.dev.js
│ ├── server.prod.js
│ ├── webpack.base.config.js
│ ├── webpack.dev.config.js
│ ├── webpack.entryOut.config.js
│ └── webpack.prod.config.js
├── docs // 文档说明
│ ├── babelrc.md
│ ├── base.config.md
│ ├── browserslistrc.md
│ ├── commitlintrc.md
│ ├── cssloader.config.md
│ ├── dev.config.md
│ ├── editorconfig.md
│ ├── gitdiff.md
│ ├── package-lock-jso.md
│ ├── prductError.md
│ ├── prettierrc.md
│ ├── prod.config.md
│ ├── runError.md
│ └── server.prod.md
├── jsconfig.json
├── package-lock.json
├── package.json
├── src
│ ├── app.js //根组件
│ ├── common // 公共包
│ ├── index.html
│ ├── locales // 语音包
│ ├── main.jsx //入口
│ ├── pages // 业务代码
│ ├── redux // redux
│ ├── routes // 路由
│ ├── services // 服务接口
│ ├── static // 静态资源
│ ├── themes // 主题
│ └── util // 工具包
├── theme.json
└── yarn.lock
```
### 组件样式注意事项
> <font color='red'>采用css modules 样式模块化必须采用驼峰命名languageContentName,不能使用language-Content-Name </font>
```javascript
//语法糖:file
import style from "./styles/index";
<div className={style.languageContentName}></div>
/**
* 多个类名的写法
* */
<div className={`${style["languageContentName"]} ${style["languageContent"]}`}></div>
```
> <font color='red'>less的语法糖 </font>
```css
/**
* 改变第三方组件样式不能污染全局在less文件写法
*/
.language {
background: red;
:global .ant-col-4{
background: #000;
}
}
/**
* global样式在文件 themes/index.less; 使用必须在自己内部样式引用不要在js引用
* */
@import "~themes/index.less";
```
### 组件代抽
1. 分页
2. formItemLayout(表单)
3. 或略大小写
4. 设置可见范围组件封装
5. 添加关键词组件封装
6. 输入框组件封装,一般输入框限制特殊字符输入,数字输入框仅能输入数字
### Other
```python
echo 删除本地uat分支
git branch -d uat
echo 删除远程仓库uat分支
git push origin --delete uat
echo 创建分支uat
git branch uat
echo 同步上传到远程
git push -u origin uat
echo 完成ok
tree 命令
-a 显示所有文件和目录。
-A 使用ASNI绘图字符显示树状图而非以ASCII字符组合。
-C 在文件和目录清单加上色彩,便于区分各种类型。
-d 显示目录名称而非内容。
-D 列出文件或目录的更改时间。
-f 在每个文件或目录之前,显示完整的相对路径名称。
-F 在执行文件,目录,Socket,符号连接,管道名称名称,各自加上"*","/","=","@","|"号。
-g 列出文件或目录的所属群组名称,没有对应的名称时,则显示群组识别码。
-i 不以阶梯状列出文件或目录名称。
-I 忽略文件,不显示符合范本样式的文件或目录名称。
-l 如遇到性质为符号连接的目录,直接列出该连接所指向的原始目录。
-n 不在文件和目录清单加上色彩。
-N 直接列出文件和目录名称,包括控制字符。
-p 列出权限标示。
-P 只显示符合范本样式的文件或目录名称。
-q "?"号取代控制字符,列出文件和目录名称。
-s 列出文件或目录大小。
-t 用文件和目录的更改时间排序。
-u 列出文件或目录的拥有者名称,没有对应的名称时,则显示用户识别码。
-x 将范围局限在现行的文件系统中,若指定目录下的某些子目录,其存放于另一个文件系统上,则将该子目录予以排除在寻找范围外。
tree -I "node_modules|dist|cache|test_*" -L 2 -C
```
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<title></title>
<script src="./jquery.min.js"></script>
<style type="text/css">
.spinner{margin:210px auto;width:20px;height:20px;position:relative;}
.container1 > div,.container2 > div,.container3 > div{width:6px;height:6px;background-color:#333;border-radius:100%;position:absolute;-webkit-animation:bouncedelay 1.2s infinite ease-in-out;animation:bouncedelay 1.2s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both;}
.spinner .spinner-container{position:absolute;width:100%;height:100%;}
.container2{-webkit-transform:rotateZ(45deg);transform:rotateZ(45deg);}
.container3{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg);}
.circle1{top:0;left:0;}
.circle2{top:0;right:0;}
.circle3{right:0;bottom:0;}
.circle4{left:0;bottom:0;}
.container2 .circle1{-webkit-animation-delay:-1.1s;animation-delay:-1.1s;}
.container3 .circle1{-webkit-animation-delay:-1.0s;animation-delay:-1.0s;}
.container1 .circle2{-webkit-animation-delay:-0.9s;animation-delay:-0.9s;}
.container2 .circle2{-webkit-animation-delay:-0.8s;animation-delay:-0.8s;}
.container3 .circle2{-webkit-animation-delay:-0.7s;animation-delay:-0.7s;}
.container1 .circle3{-webkit-animation-delay:-0.6s;animation-delay:-0.6s;}
.container2 .circle3{-webkit-animation-delay:-0.5s;animation-delay:-0.5s;}
.container3 .circle3{-webkit-animation-delay:-0.4s;animation-delay:-0.4s;}
.container1 .circle4{-webkit-animation-delay:-0.3s;animation-delay:-0.3s;}
.container2 .circle4{-webkit-animation-delay:-0.2s;animation-delay:-0.2s;}
.container3 .circle4{-webkit-animation-delay:-0.1s;animation-delay:-0.1s;}@-webkit-keyframes bouncedelay{0%,80%,100%{-webkit-transform:scale(0.0)}40%{-webkit-transform:scale(1.0)}}@keyframes bouncedelay{0%,80%,100%{transform:scale(0.0);-webkit-transform:scale(0.0);}40%{transform:scale(1.0);-webkit-transform:scale(1.0);}}
</style>
</head>
<body id="body">
<div class="spinner" id="erro_wrap">
<div class="spinner-container container1">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container2">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container3">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
</div>
<script src="./rajump.js"></script>
</body>
</html>
\ No newline at end of file
// 1.计算加载时间
function getPerformanceTiming() {
var performance = window.performance;
if (!performance) {
// 当前浏览器不支持
console.log('你的浏览器不支持 performance 接口');
return;
}
var t = performance.timing;
var times = {};
//【重要】页面加载完成的时间
//【原因】这几乎代表了用户等待页面可用的时间
times.loadPage = t.loadEventEnd - t.navigationStart;
//【重要】解析 DOM 树结构的时间
//【原因】反省下你的 DOM 树嵌套是不是太多了!
times.domReady = t.domComplete - t.responseEnd;
//【重要】重定向的时间
//【原因】拒绝重定向!比如,http://example.com/ 就不该写成 http://example.com
times.redirect = t.redirectEnd - t.redirectStart;
//【重要】DNS 查询时间
//【原因】DNS 预加载做了么?页面内是不是使用了太多不同的域名导致域名查询的时间太长?
// 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
//【重要】读取页面第一个字节的时间
//【原因】这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加CDN 处理了么?加带宽了么?加 CPU 运算速度了么?
// TTFB 即 Time To First Byte 的意思
// 维基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
times.ttfb = t.responseStart - t.navigationStart;
//【重要】内容加载完成的时间
//【原因】页面内容经过 gzip 压缩了么,静态资源 css/js 等压缩了么?
times.request = t.responseEnd - t.requestStart;
//【重要】执行 onload 回调函数的时间
//【原因】是否太多不必要的操作都放到 onload 回调函数里执行了,考虑过延迟加载、按需加载的策略么?
times.loadEvent = t.loadEventEnd - t.loadEventStart;
// DNS 缓存时间
times.appcache = t.domainLookupStart - t.fetchStart;
// 卸载页面的时间
times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;
// TCP 建立连接完成握手的时间
times.connect = t.connectEnd - t.connectStart;
return times;
}
// 2.计算加载时间
function getEntryTiming(entry) {
var t = entry;
var times = {};
// 重定向的时间
times.redirect = t.redirectEnd - t.redirectStart;
// DNS 查询时间
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
// 内容加载完成的时间
times.request = t.responseEnd - t.requestStart;
// TCP 建立连接完成握手的时间
times.connect = t.connectEnd - t.connectStart;
// 挂载 entry 返回
times.name = entry.name;
times.entryType = entry.entryType;
times.initiatorType = entry.initiatorType;
times.duration = entry.duration;
return times;
}
// 例如:
function entriesTimes() {
var entries = window.performance.getEntries();//这个函数返回的将是一个数组,包含了页面中所有的 HTTP 请求
entries.forEach(function (entry) {
var times = getEntryTiming(entry);
console.log(times);
});
}
entriesTimes()
$(function() {
let comGetLocation={
//hash parm
getUrlParam() {
var search = location.search;
if (location.search.indexOf("?") == -1) {
return '';
}
var queryString = search.split("?")[1];
if (queryString.indexOf("&") != -1) {
var data={};
var arr = queryString.split("&"); // split
arr.map((item)=>{
data[item.split("=")[0]]=item.substring(item.indexOf("=")+1)
})
return data;
}else {
return '';
}
}
};
function getAuthorization(parms,href_url) {
if(!parms.md5nm){
alert("login_name没有找到")
return;
}
console.log(href_url,"url")
let {appId,mp,companyCode,siteCode,md5nm,token,salt,sign}= parms;
console.log(appId,'appid');
console.log(mp,'mp');
console.log(appId,'appid');
console.log(companyCode,'companyCode');
console.log(siteCode,'siteCode');
console.log(md5nm,'md5nm');
console.log(token,'token');
console.log(salt,'salt');
console.log(sign,'sign');
// md5nm -->name ,mp -> terminalType,hrefUrl
var data={appId,name:md5nm,token,salt,sign,hrefUrl:href_url,type:parms.authType?parms.authType:1};
if(parms.mp==1||parms.mp==0){
data.terminalType=3;
}else{
data.terminalType=parms.mp;
}
var origin= location.origin;
$.ajax({
type: "post",
url: origin+"/system/public/api/plus/getAccount?companyCode=" + companyCode + "&siteCode=" + siteCode,
async: true,
dataType: "json",
contentType: 'application/json;charset=UTF-8',
data:JSON.stringify(data),
success: function (res) {
if (res.code == 1000) {
sessionStorage.setItem("mgtk",res.data.Authorization)
sessionStorage.setItem("userName", res.data.userInfo.name);
sessionStorage.setItem("dev", res.data.userInfo.dev);
href_url=decodeURIComponent(href_url);
location.replace(href_url);
}else {
$("#body").html("<span style='color: red'>错误信息:</span>"+JSON.stringify(res))
}
},
error:function (err) {
$("#body").html(`<span style='color: red'>错误信息:${JSON.stringify(err)}</span>`)
}
});
};
let datas= comGetLocation.getUrlParam();
console.log('集合',datas);
var parms = datas;
let {appId,mp,companyCode,siteCode,md5nm,token,salt,sign}= parms;
if(appId&&companyCode&&siteCode&&md5nm&&token&&salt&&sign){
}else{
alert("参数不全,不发请求跳转");
return;
}
getAuthorization(parms,datas.href_url);
});
\ No newline at end of file
// 1.计算加载时间
function getPerformanceTiming() {
var performance = window.performance;
if (!performance) {
// 当前浏览器不支持
console.log('你的浏览器不支持 performance 接口');
return;
}
var t = performance.timing;
var times = {};
//【重要】页面加载完成的时间
//【原因】这几乎代表了用户等待页面可用的时间
times.loadPage = t.loadEventEnd - t.navigationStart;
//【重要】解析 DOM 树结构的时间
//【原因】反省下你的 DOM 树嵌套是不是太多了!
times.domReady = t.domComplete - t.responseEnd;
//【重要】重定向的时间
//【原因】拒绝重定向!比如,http://example.com/ 就不该写成 http://example.com
times.redirect = t.redirectEnd - t.redirectStart;
//【重要】DNS 查询时间
//【原因】DNS 预加载做了么?页面内是不是使用了太多不同的域名导致域名查询的时间太长?
// 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
//【重要】读取页面第一个字节的时间
//【原因】这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加CDN 处理了么?加带宽了么?加 CPU 运算速度了么?
// TTFB 即 Time To First Byte 的意思
// 维基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
times.ttfb = t.responseStart - t.navigationStart;
//【重要】内容加载完成的时间
//【原因】页面内容经过 gzip 压缩了么,静态资源 css/js 等压缩了么?
times.request = t.responseEnd - t.requestStart;
//【重要】执行 onload 回调函数的时间
//【原因】是否太多不必要的操作都放到 onload 回调函数里执行了,考虑过延迟加载、按需加载的策略么?
times.loadEvent = t.loadEventEnd - t.loadEventStart;
// DNS 缓存时间
times.appcache = t.domainLookupStart - t.fetchStart;
// 卸载页面的时间
times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;
// TCP 建立连接完成握手的时间
times.connect = t.connectEnd - t.connectStart;
return times;
}
// 2.计算加载时间
function getEntryTiming(entry) {
var t = entry;
var times = {};
// 重定向的时间
times.redirect = t.redirectEnd - t.redirectStart;
// DNS 查询时间
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
// 内容加载完成的时间
times.request = t.responseEnd - t.requestStart;
// TCP 建立连接完成握手的时间
times.connect = t.connectEnd - t.connectStart;
// 挂载 entry 返回
times.name = entry.name;
times.entryType = entry.entryType;
times.initiatorType = entry.initiatorType;
times.duration = entry.duration;
return times;
}
// 例如:
function entriesTimes() {
var entries = window.performance.getEntries();//这个函数返回的将是一个数组,包含了页面中所有的 HTTP 请求
entries.forEach(function (entry) {
var times = getEntryTiming(entry);
console.log(times);
});
}
var os = require('os'), IP = '', ifaces = os.networkInterfaces() // 获取本机IP
out:
for (var i in ifaces) {
for (var j in ifaces[i]) {
var val = ifaces[i][j]
if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
IP = val.address
break out
}
}
};
const host = {
prod: {
BASE_URL: "https://mg.kmelearning.com",
},
deve: {
BASE_URL: "http://dev.mg.kmelearning.com",
},
sit: {
BASE_URL: "https://test.mg.kmelearning.com",
},
uat: {
BASE_URL: "https://uat.mg.kmelearning.com",
},
other: {
BASE_URL: "",
},
};
module.exports = {IP,host};
\ No newline at end of file
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能: 校验样式
* */
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ENV = process.env.NODE_ENV || "development";
const postcssLoader =
ENV === "production"
? {
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: [
require("postcss-preset-env")({
flexbox: "no-2009",
}),
require("cssnano")({
preset: [
"default",
{
discardComments: {
removeAll: true,
},
},
],
}),
],
},
}
: {
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: [
require("postcss-preset-env")({
flexbox: "no-2009",
}),
],
},
};
const styleLoader =
ENV !== "production"
? {
loader: "style-loader",
}
: {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../",
},
};
const cssLoader = [
{
test: /\.(css|less)$/,
include: /node_modules/,
use: [
styleLoader,
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
},
},
postcssLoader,
],
},
{
test: /\.(css|less)$/,
exclude: /node_modules/,
use: [
styleLoader,
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: {
localIdentName: "[local]__[hash:base64:5]",
},
},
},
postcssLoader,
{
loader: "less-loader",
options: {
modules: {
localIdentName: "[local]__[hash:base64:5]",
},
javascriptEnabled: true,
},
},
],
},
];
module.exports = cssLoader;
const webpack = require('webpack');
const path = require("path");
const Libs = {
ui: [
'antd',
//暂时不抽 加载渲染 200ms 大小 2.7m
// 'antd/es/input',
// 'antd/es/message',
// 'antd/es/modal',
// 'antd/es/icon',
],
base: [
'lodash/fp/get',
'lodash/fp/set',
],
report:[
'echarts'
],
reactCli:[
'react',
'react-dom',
'react-router-dom',
]
}
module.exports = {
output: {
path: path.join(__dirname, "../libs"),
filename: '[name].js',
library: '[name]_library',
},
entry: {
...Libs
},
plugins: [
new webpack.BannerPlugin('构建时间:'+new Date()),
new webpack.DllPlugin({
path: path.join(__dirname, "../libs/[name].manifest.json"),
name: '[name]_library',
context: __dirname,
}),
],
};
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能: 启动开发服务
* */
var path = require("path");
var webpack = require("webpack");
var express = require("express");
var devMiddleware = require("webpack-dev-middleware");
var hotMiddleware = require("webpack-hot-middleware");
const { createProxyMiddleware } = require('http-proxy-middleware');
var bodyParser = require("body-parser");
var config = require("./webpack.dev.config");
var rootPath = path.resolve(__dirname, "../dist/");
var app = express();
var compiler = webpack(config);
compiler.apply(new webpack.ProgressPlugin());
app.all("*", function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", " 3.2.1");
res.header("Content-Type", "text/html");
next();
});
/*
* 新增IP 方法
* */
const {IP,host}= require('./Ip');
const NODE_ENV_API = process.env.NODE_ENV_API;
// 新增跨域代理
app.use(createProxyMiddleware('/admin', {target: host[NODE_ENV_API].BASE_URL,changeOrigin: true,pathRewrite: {'^/admin': ''}}))
// 要是直接 / 直接把DNS 代理到线上代码了,而不是本地代码
// app.use('/', createProxyMiddleware({ target: host[NODE_ENV_API].BASE_URL, changeOrigin: true }));
app.use(bodyParser.urlencoded({ extended: false }));
const devMiddlewareResult = devMiddleware(compiler, {
publicPath: config.output.publicPath,
historyApiFallback: true,
hot: true,
overlay: true,
});
app.use(hotMiddleware(compiler));
app.use(devMiddlewareResult);
app.use(express.static(rootPath));
app.get("*", function(req, res) {
const htmlBuffer = devMiddlewareResult.fileSystem.readFileSync(
`${config.output.path}/index.html`
);
res.send(htmlBuffer.toString());
});
app.listen(5002,[IP, "localhost"], function(err) {
if (err) {
return console.error(err);
}
console.log(
"Listening at http://localhost:5001/shyz/shyz/login, waiting for compile"
);
});
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能: 启动本地打包的静态文件,生产环境测试
* */
var path = require("path");
var express = require("express");
var app = express();
var open = require("open");
var rootPath = path.resolve(__dirname, "..");
app.use(express.static(rootPath+'/dist'));
app.all("*", function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", " 3.2.1");
res.header("Content-Type", "text/html");
next();
});
app.get("*", function(req, res) {
res.sendFile(path.join(rootPath, "dist/index.html"));
});
app.listen(3001, function(err) {
if (err) {
return console.error(err);
}
open("http://localhost:3001/shyz/shyz/login");
});
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能: 生产和开发,共享包
* */
const path = require("path");
const rootPath = path.resolve(__dirname, "..");
const src = path.join(rootPath, "src");
const webpack = require("webpack");
const ENV = process.env.NODE_ENV || "development";
const threadLoader = require("thread-loader");
const cssloader = require("./cssloader.config.js");
const jsWorkerPool = {
workers: 2,
poolTimeout: 2000,
};
threadLoader.warmup(jsWorkerPool, ["babel-loader"]);
const baseConfig = {
mode: ENV,
devtool: ENV == "development" ? "source-map" : "none",
entry:
ENV !== "development"
? {
bundle: "./src/main",
vendor: ["react", "react-dom", "react-redux"],
}
: [
"react-hot-loader/patch",
"webpack-hot-middleware/client",
"./src/main",
],
output:
ENV === "development"
? {
path: src,
filename: "[name]-[hash:6].js",
publicPath: "/static/",
chunkFilename: "[name]-[chunkhash:6].js",
}
: {
filename: "js/[name]-[chunkhash:6].js",
chunkFilename: "js/[name]-[chunkhash:6].js",
publicPath: "/",
path: rootPath+ "/dist/",
},
resolve: {
extensions: [".js", ".json", ".jsx", ".css", ".less", ".ts"],
alias: {
"@": path.resolve(rootPath, "src"),
themes: path.join(src, "themes"),
'react-dom': '@hot-loader/react-dom'
},
},
externals:{
QMap:'qq.maps'
},
module: {
rules: [
{
test: /\.jsx|js?$/,
include: src,
exclude(path) {
return path.match(/node_modules/);
},
use: [
{
loader: "thread-loader",
options: jsWorkerPool,
},
"babel-loader",
],
},
...cssloader,
{
test: /\.(jpe?g|png|gif|svg)$/,
use: [
{
loader: "file-loader",
options: {
esModule: false,
name: "[name].[hash].[ext]",
limit: 8192,
outputPath: 'images',
},
},
],
},
{
test: /\.(woff|woff2|svg|eot|ttf)\??.*$/,
use: [
{
loader: "file-loader",
options: {
esModule: false,
name: "[name].[hash:8].[ext]",
},
},
],
},
],
},
performance: {
hints: "warning",
maxAssetSize: 30000000,
maxEntrypointSize: 50000000,
assetFilter: function(assetFilename) {
return assetFilename.endsWith(".css") || assetFilename.endsWith(".js");
},
},
// 插件
plugins: [
new webpack.ProgressPlugin()
],
};
module.exports = baseConfig;
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能: 开发环境
* */
var path = require("path");
var addAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin");
var webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
var config = require("./webpack.base.config.js");
var DashboardPlugin = require("webpack-dashboard/plugin");
// const apiConfig = require("../src/services/baseUrl.js");
var _ = require("lodash");
const TARGET = process.env.npm_lifecycle_event;
const ROUTERTYPE = process.env.NODE_ROUTER_MODE;
const commonConfig = {
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
ROUTER_MODE: JSON.stringify(ROUTERTYPE),
// API_CONFIG: JSON.stringify(apiConfig),
NODEENV: JSON.stringify(process.env.NODE_ENV),
BUILD_VERSION: JSON.stringify(new Date().toString()),
}),
new HtmlWebpackPlugin({
template: "src/index.html",
inject: "body",
filename: "index.html",
}),
new addAssetHtmlWebpackPlugin([{
 filepath: path.resolve(__dirname, '../src/static/sm2.min.js') 
}])
],
};
if (TARGET === "dev") {
commonConfig.plugins.unshift(new DashboardPlugin());
}
let mergedConfig = commonConfig;
mergedConfig = _.merge(config, commonConfig);
module.exports = mergedConfig;
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能: 生产环境
* */
var path = require("path");
var webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const ROUTERTYPE = process.env.NODE_ROUTER_MODE;
var _ = require("lodash");
var config = require("./webpack.base.config.js");
// const apiConfig = require("../src/services/baseUrl.js");
// const CopyWebpackPlugin = require("copy-webpack-plugin");
console.log(process.env.NODE_ENV,'============')
var rootPath = path.resolve(__dirname, "..");
module.exports = _.merge(config, {
optimization: {
minimize: true,
runtimeChunk: {
name: entrypoint => `runtime~${entrypoint.name}`
},
minimizer: [
new TerserPlugin({
terserOptions: {
parallel: true,
ecma: undefined,
warnings: false,
parse: {},
// compress: { warnings: false, drop_console: true },
mangle: true, // Note `mangle.properties` is `false` by default.
module: false,
// output: {
// comments: false,
// },
extractComments: false,
toplevel: false,
nameCache: null,
ie8: false,
keep_classnames: undefined,
keep_fnames: false,
safari10: false,
},
}),
],
splitChunks: {
chunks: "all",
minChunks: 3,
cacheGroups: {
vendor: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true,
},
},
},
},
plugins: [
// new CopyWebpackPlugin({
// patterns: [
// {
// from: path.resolve(__dirname, '../src/static'),
// to: path.resolve(__dirname, '../dist/src/static')
// },
// ],
// }),
new webpack.DllReferencePlugin({
manifest: require("../libs/base.manifest.json"),
context: __dirname
}),
new webpack.DllReferencePlugin({
manifest: require("../libs/reactCli.manifest.json"),
context: __dirname
}),
new webpack.DllReferencePlugin({
manifest: require("../libs/report.manifest.json"),
context: __dirname
}),
new webpack.DllReferencePlugin({
manifest: require("../libs/ui.manifest.json"),
context: __dirname
}),
new MiniCssExtractPlugin({
filename: "css/[name].[hash:5].css",
publicPath: path.join(rootPath, "dist"),
ignoreOrder: true,
}),
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
ROUTER_MODE: JSON.stringify(ROUTERTYPE),
NODEENV: JSON.stringify(process.env.NODE_ENV),
BUILD_VERSION: JSON.stringify(new Date().toString()),
}),
new HtmlWebpackPlugin({
template: "src/index.html",
inject: "body",
filename: "index.html",
}),
new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, '../libs/*.js'),
}),
],
});
#简介说明
> 作者:小兵
> 来源:项目重构
下面是简易说明,更多说明:https://babeljs.io/docs/en/babelrc
浏览器兼容语法预览:https://kangax.github.io/compat-table/es6/
1. 作用:Babel是一个广泛使用的转码器,可以将es6, es7, es8...代码转为ES5代码
```
{
"presets":[
[
"@babel/preset-env",
{
"targets": {
"browsers": ["last 2 versions"],
"chrome": "60",
"firefox": "60",
"safari": "10",
"ie": "11",
"edge": "17",
"android": "4.0",
"ios": "10"
},
"useBuiltIns": "usage", //此选项配置如何@babel/preset-env处理polyfill
"corejs": "core-js@3", // 此选项只有在使用时产生影响 useBuiltIns:使用 或 useBuiltIns:条目 ,并确保 @babel / preset-env 为你注入正确的进口 core-js 的版本。
"debug": true //默认值是false 启动不输出,ture启动输出目标/插件使用和在指定的版本 插件数据版本 来 console.log 。
}
],
"@babel/preset-react"
],
"plugins": [
//按需加载 引入antd
["import", { "libraryName": "antd", "libraryDirectory": "lib", "style": "css" },"ant"],
// 按需加载 引入antd-mobile
["import", { "libraryName": "antd-mobile", "libraryDirectory": "lib","style": "css"}, "antd-mobile"],
// 动态使用import函数导入
"@babel/plugin-syntax-dynamic-import",
//class 转译
"@babel/plugin-proposal-class-properties",
// 在webpack打包的时候,可以在js文件中混用require和export。但是不能混用import 以及module.exports。
"@babel/plugin-transform-modules-commonjs",
@ babel / polyfill使用的对象污染了全局范围Promise。鉴于这可能会对库作者产生问题,因此有@ babel / s选项。它可以作为Babel插件启用,并且通过以不需要代码的方式重写代码来避免全局变量的问题
]
}
```
2. "presets" 预设就是一堆插件(Plugin)的组合,(简单概括就是是一系列的plugins 集合)
从而达到某种转译的能力。就比如 react 中使用到的 @babel/preset-react ,它就是下面几种插件的组合。
@babel/plugin-syntax-jsx
@babel/plugin-transform-react-jsx
@babel/plugin-transform-react-display-name
预设的执行顺序,它是从右往左,这主要是为了确保向后兼容,因为大多数用户将 "es2015" 放在 "stage-0" 之前。
```
#按照Babel官网的介绍,其实Preset和Stage-X都是归属到Plugin里面的,只不过所覆盖的范围不同而已。
举个例子,如果需要转换ES2015(ES6)的语法,那么你可以在.babelrc的plugins中按需引入check-es2015-constants、es2015-arrow-functions、es2015-block-scoped-functions等等几十个不同作用的plugin。
#但是Babel团队为了方便,将同属ES2015的几十个Transform Plugins集合到@babel/preset-env一个Preset如果没有
#targets:指定目标,如果没有配置默认值是{}. @babel / preset-env 默认情况下将改变所有ECMAScript 2015 +代码。更多配置 https://babeljs.io/docs/en/babel-preset-env/#options
#"@babel/preset-react" react转移集合 https://babeljs.io/docs/en/babel-preset-react#docsNav
```
> "plugins" 是在结合中没有的需要单独配置一下,比如转译class antd 动态导入improt ,node等等,插件的执行顺序是从左往右
#简介说明
> 作者:小兵
> 来源:项目重构
> 细节看官方 http://expressjs.com/
1. 作用:启动server 启动build的静态文件
```java
const path = require("path");
// 项目根目录
const rootPath = path.resolve(__dirname, "..");
// 开发源码目录
const src = path.join(rootPath, "src");
// webpack 4
const webpack = require("webpack");
// html 模板
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 环境配置
const ENV = process.env.NODE_ENV || "development";
// 多线程加载器
const threadLoader = require("thread-loader");
const ROUTERTYPE = process.env.NODE_ROUTER_MODE;
const cssloader = require("./cssloader.config.js");
// 请求api环境配置
const apiConfig = require("../src/services/baseUrl.js");
/**
* 解析loader 多线程
* workers:产生的 worker 的数量,默认是 (cpu 核心数 - 1),当 require('os').cpus() 是 undefined 时,则为 1
* poolTimeout:闲置时定时删除 worker 进程,默认为 500ms可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在
*/
// console.log(webpack,"webpack")
const jsWorkerPool = {
workers: 2,
poolTimeout: 2000,
};
threadLoader.warmup(jsWorkerPool, ["babel-loader"]);
const entryOutConfig = require("./webpack.entryOut.config");
const _ = require("lodash");
const baseConfig = {
mode: ENV,
module: {
rules: [
// {
// enforce: 'pre',
// test: /\.jsx|js?$/,
// use: 'eslint-loader',
// exclude(path) {
// return path.match(/node_modules/);
// },
// },
{
test: /\.jsx|js?$/,
include: src,
exclude(path) {
return path.match(/node_modules/);
},
use: [
{
loader: "thread-loader",
options: jsWorkerPool,
},
"babel-loader",
],
},
...cssloader,
{
test: /\.(jpe?g|png|gif|svg)$/,
use: [
{
loader: "file-loader",
options: {
esModule: false, // 这里设置为false
name: "[name].[hash].[ext]", // 输入的图片名
limit: 8192,
},
},
],
},
{
test: /\.(woff|woff2|svg|eot|ttf)\??.*$/,
use: [
{
loader: "file-loader",
options: {
esModule: false, // 这里设置为false
name: "[name].[hash:8].[ext]",
},
},
],
},
],
},
performance: {
hints: "warning", // 枚举
maxAssetSize: 30000000, // 整数类型(以字节为单位)
maxEntrypointSize: 50000000, // 整数类型(以字节为单位)
assetFilter: function(assetFilename) {
// 提供资源文件名的断言函数
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
},
// 插件
plugins: [
// 打包进度
new webpack.ProgressPlugin(),
// 生产和开发默认开启或者关闭插件
new HtmlWebpackPlugin({
template: "src/index.html",
inject: "body",
filename: "index.html",
}),
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
ROUTER_MODE: JSON.stringify(ROUTERTYPE),
API_CONFIG: JSON.stringify(apiConfig),
BUILD_VERSION: JSON.stringify(new Date().toString()),
}),
],
};
module.exports = _.merge(entryOutConfig, baseConfig);
```
\ No newline at end of file
#简介说明
> 作者:小兵
> 来源:项目重构
# Browsers that we support 可以单独配置也可以配置在package.json
# https://github.com/browserslist/browserslist#readme || https://survivejs.com/webpack/styling/autoprefixing/
#Browserslist 的数据都是来自Can I Use的。如果你想知道配置语句的查询结果可以使用[online demo] (https://browserl.ist/)
\ No newline at end of file
#简介说明
> 作者:小兵
> 来源:项目重构
下面是简易说明,更多说明:https://github.com/conventional-changelog/commitlint#config
1. 作用:根据commitlint-config-conventional(基于Angular约定)的常见类型可以是(用于说明 commit 的类别,只允许使用下面11个标识):
build
ci
chore
docs
feat
fix
perf
refactor
revert
style
test
```
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
bug:这个是自定义的,注意不能用中文
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "test", "chore", "revert","bug"]
],
"subject-full-stop": [0, "never"],
"subject-case": [0, "never"]
}
};
```
\ No newline at end of file
```javascript
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能:
* */
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ENV = process.env.NODE_ENV || "development";
/**
* post css loader
*/
const postcssLoader =
ENV === "production"
? {
// 帮助我们自动给那些可以添加厂商前缀的样式添加厂商前缀
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: [
require("postcss-preset-env")({
flexbox: "no-2009",
}),
// 让 CSS 样式文件加载速度更快。https://www.cssnano.cn/
require("cssnano")({
preset: [
"default",
{
discardComments: {
removeAll: true,
},
},
],
}),
],
},
}
: {
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: [
require("postcss-preset-env")({
flexbox: "no-2009",
}),
],
},
};
const styleLoader =
ENV !== "production" // 生产分离出样式
? {
loader: "style-loader", // creates style nodes from JS strings
}
: {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../",
},
};
const cssLoader = [
{
test: /\.(css|less)$/,
include: /node_modules/,
use: [
styleLoader,
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
},
},
postcssLoader,
],
},
// 项目中开启css modules
{
test: /\.(css|less)$/,
exclude: /node_modules/,
use: [
styleLoader,
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: {
localIdentName: "[local]__[hash:base64:5]", // css module
},
},
},
postcssLoader,
{
loader: "less-loader", // compiles Less to LESS
options: {
modules: {
localIdentName: "[local]__[hash:base64:5]", // css module
},
javascriptEnabled: true,
},
},
],
},
];
module.exports = cssLoader;
```
\ No newline at end of file
#简介说明
> 作者:小兵
> 来源:项目重构
> 细节看官方 http://expressjs.com/
1. 作用:启动server 启动build的静态文件
```java
var webpack = require("webpack");
var config = require("./webpack.base.config.js");
var DashboardPlugin = require("webpack-dashboard/plugin");
var _ = require("lodash");
const TARGET = process.env.npm_lifecycle_event;
const commonConfig = {
plugins: [
new webpack.ProgressPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
};
if (TARGET === "dev") {
commonConfig.plugins.unshift(new DashboardPlugin());
}
let mergedConfig = commonConfig;
mergedConfig = _.merge(config, commonConfig);
module.exports = mergedConfig;
```
\ No newline at end of file
#简介说明
> 作者:小兵
> 来源:项目重构
更多说明:# http://editorconfig.org
使用EditorConfig配置IDE和编辑器#
EditorConfig允许您为任何文件类型定义缩进样式和其他空白设置。这样您的编辑器可以自动选择正确的设置。当开发人员使用带有不同行尾的平台时,例如Mac和Windows,这非常方便。
这是一个典型的配置(.editorconfig),具有针对Markdown,JSON和YAML文件的单独规则:
EditorConfig有助于维护跨多个编辑器和IDE从事同一项目的多个开发人员的一致编码风格。EditorConfig项目包括一个用于定义编码样式的文件格式和一个文本编辑器插件集合,这些文本编辑器插件使编辑器可以读取文件格式并遵循定义的样式。EditorConfig文件易于阅读,并且可以与版本控制系统很好地协同工作。
```
root = true
[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{json,yml,md}]
indent_style = space
indent_size = 2
```
.editorconfig
\ No newline at end of file
#npm run diff 说明
##简介说明
> 作者:小兵
> 来源:项目重构
"diff":" git diff $1 $2", // $1 参数1 $2 ,参数2 参数可以传可以不传
例子直传一个参数
> npm run diff sit
例子传递两个参数
>
git diff 文件对比 说明
filepath:文件路径
branchName:分支
1. git diff branchName filepath 当前分支的文件与branchName 分支的文件进行比较
例子:
和本地sit 文件对比
> git diff sit build/webpack.dev.config.js
和远程仓库 master 文件对比
> git diff origin/master .gitignore
2. git diff commitId filepath 与某一次提交进行比较
例子
// 与历史版本号 下的文件对比
> git diff 46e8eaa build/webpack.dev.config.js 比较历史记录号为 46e8eaa的修改
3. git reset --hard 46e8eaa // 回退到历史那个版本
或者暴力强行推送 强制将本地代码推送至远程仓库之中,使用 git push -f origin master
```
/*1.新建分支*/
git checkout -b temp //新建分支并切换到temp分支
git push origin temp:temp //将代码push到temp分支
/*2.删除主分支*/
git push origin --delete master //删除远端主分支
git branch -d master //删除本地主分支
/*3.新建主分支*/
git checkout -b master //新建主分支并切换到主分支
git push origin master //提交主分支
/*4.删除暂存分支*/
git branch -d temp
git push origin --delete temp
```
\ No newline at end of file
#简介说明
> 作者:小兵
> 来源:项目重构
下面是简易说明来自官方,更多说明:https://docs.npmjs.com/files/package-lock.json
即使您在package.json中使用了确切的版本,您也可能会遇到问题,因为依赖关系的依赖关系未锁定。补丁包中某些深层嵌套的依赖项的重大更改可能会破坏您的构建。当它在CI上或在部署期间发生时,尤其难以调试。
从版本5开始,npm支持lockfiles。npm install会将已安装软件包的版本写入文件package-lock.json中。该文件应提交到项目存储库。下次有人运行时npm install,npm将使用此锁定文件中指定的版本。
Yarn是npm的替代方案,它首先实现了锁定文件的概念,但是它们使用了不兼容的格式和yarn.lock文件。
是锁定安装时的包的版本号(锁住大版本),并且需要上传到git,以保证其他人在npm install时大家的依赖能保证一致。
```
package-lock.json会为npm修改node_modules树或的任何操作自动生成package.json。它描述了生成的确切树,因此无论中间依赖项更新如何,后续安装都可以生成相同的树。
该文件旨在提交到源存储库中,并具有多种用途:
描述一个依赖关系树的单一表示,这样可以确保队友,部署和持续集成安装完全相同的依赖关系。
为用户提供一种工具,使其可以“时间旅行”到以前的状态,node_modules而不必提交目录本身。
为了通过可读的源代码控制差异更好地了解树的变化。
并允许npm跳过以前安装的软件包的重复元数据解析,从而优化安装过程。
关于package-lock.json它的一个关键细节是它无法发布,并且如果在顶级软件包之外的任何地方找到它,它将被忽略。它与npm-shrinkwrap.json共享一种格式,该格式本质上是相同的文件,但是可以发布。除非部署CLI工具或使用发布过程来生产生产软件包,否则不建议这样做。
如果软件包的根目录中同时存在package-lock.json和npm-shrinkwrap.json,package-lock.json将被完全忽略。
```
\ No newline at end of file
```javascript
"scripts": {
/**
* 打包 NODE_ENV_API 环境变量 设置api 环境变量NODE_ENV设置打包区别生产和本地
* --profile 输出性能数据,可以看到每一步的耗时
* --progress 输出当前编译的进度,以百分比的形式呈现
* --display-modules 默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块
* --display-error-details 输出详细的错误信息
* --display-optimization-bailout Webpack对哪些代码做了降级处理
* */
"build": "NODE_ENV_API=other NODE_ENV=production BUILD_ENV=prod webpack --display-optimization-bailout --config build/webpack.prod.config.js --progress --profile",
"build:prod": "NODE_ENV_API=prod NODE_ENV=production BUILD_ENV=prod webpack --display-optimization-bailout --config build/webpack.prod.config.js --progress --profile",
/**
* dev:开发测试性能使用
* 打包cross-env 为了兼容window; NODE_ENV_API环境变量 设置api
* webpack-dashboard 打包分析包 -c magenta 颜色 --title 控制台启动头部
* webpack-dev-server 服务 --config 配置
* --port 端口
* */
"dev": "cross-env NODE_ENV_API=deve NODE_ENV=development webpack-dashboard -c magenta --title [浏览器输入http://localhost:5003/shyz/shyz/login] -- webpack-dev-server --config ./build/webpack.dev.config.js --port 5003",
/**
* diff 对比分支
* */
"diff": "git diff $1 $2",
/**
* lint:css 检验css
* */
"lint:css": "stylelint --fix --aei '**/*.less,.css'",
/**
* lint:css 检验js
* */
"lint:js": "eslint --fix --ext --write .js,.jsx src",
/**
* format:使用prettier根式话代码
* */
"format": "prettier --write \"./src/pages/**/*.{js,jsx,css,less}\"",
/**
* server 打包后启动服务
* */
"server": "node build/server.prod.js",
/**
* sort 排序package-json
* */
"sort": "npx sort-package-json",
/**
* sit 本地启动测试环境连接api
* */
"sit": "cross-env NODE_ENV_API=sit node -max_old_space_size=10240 build/server.dev.js",
/**
* deve 本地启动开发环境连接api
* */
"deve": "cross-env NODE_ENV_API=deve node -max_old_space_size=10240 build/server.dev.js",
/**
* uat 本地启动预发布环境连接api
* */
"uat": "NODE_ENV_API=uat node -max_old_space_size=10240 build/server.dev.js",
/**
* prod 本地启动连接生产api
* */
"prod": "NODE_ENV_API=prod node -max_old_space_size=10240 build/server.dev.js"
},
/**
* husky 使用 hooks 对提交代码lint-staged检查
* */
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.{js,jsx}": [
"prettier --check --write \"./src/pages/**/*.{js,jsx}\"",
"git add ."
]
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
},
"prettier": {
"path": "./node_modules/prettier"
}
},
```
\ No newline at end of file
##webpack升级错误收集
> Cannot find module 'eslint/lib/formatters/stylish'
> 错误原因:没有找到对应的模块
解决:eslint-loader:‘1.3.0’ 版本太低,升级到3.0 以上
#简介说明
> 作者:小兵
> 来源:项目重构
使能每一种语言默认格式化规则,更多说明:# https://prettier.io/docs/en/index.html 插件选项看
{
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
/* prettier的配置 */
"prettier.printWidth": 100, // 超过最大值换行
"prettier.tabWidth": 4, // 缩进字节数
"prettier.useTabs": false, // 缩进不使用tab,使用空格
"prettier.semi": true, // 句尾添加分号
"prettier.singleQuote": true, // 使用单引号代替双引号
"prettier.proseWrap": "preserve", // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
"prettier.arrowParens": "avoid", // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号
"prettier.bracketSpacing": true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
"prettier.disableLanguages": ["jsx"], // 不格式化jsx文件,jsx文件的格式化单独设置
"prettier.endOfLine": "auto", // 结尾是 \n \r \n\r auto
"prettier.eslintIntegration": false, //不让prettier使用eslint的代码格式进行校验
"prettier.htmlWhitespaceSensitivity": "ignore",
"prettier.ignorePath": ".prettierignore", // 不使用prettier格式化的文件填写在项目的.prettierignore文件中
"prettier.jsxBracketSameLine": false, // 在jsx中把'>' 是否单独放一行
"prettier.jsxSingleQuote": false, // 在jsx中使用单引号代替双引号
"prettier.parser": "babylon", // 格式化的解析器,默认是babylon
"prettier.requireConfig": false, // Require a 'prettierconfig' to format prettier
"prettier.stylelintIntegration": false, //不让prettier使用stylelint的代码格式进行校验
"prettier.trailingComma": "es5", // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
"prettier.tslintIntegration": false // 不让prettier使用tslint的代码格式进行校验
}
\ No newline at end of file
```java
var path = require("path");
var webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
var _ = require("lodash");
var config = require("./webpack.base.config.js");
// var ZipPlugin = require('zip-webpack-plugin');
const apiConfig = require("../src/util/baseUrl.js");
const ROUTERTYPE = process.env.NODE_ROUTER_MODE;
/**
* HardSourceWebpackPlugin是webpack的插件,用于为模块提供中间缓存步骤。为了查看结果,您需要使用此插件运行两次webpack:第一个构建将花费正常时间。第二个版本将明显更快。
* 代替 dll 分包
*/
const HardSourceWebpackPlugin = require("hard-source-webpack-plugin");
// 项目根目录
var rootPath = path.resolve(__dirname, "..");
// 开发源码目录
console.log(rootPath, "rootPath");
module.exports = _.merge(config, {
optimization: {
// runtimeChunk: {
// name: '构建时间:'+new Date()+"runtime"
// },
minimizer: [
// https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
new TerserPlugin({
terserOptions: {
parallel: true,
cache: true,
compress: { warnings: false, drop_console: true },
comments: /Build in/i,
},
}),
],
splitChunks: {
chunks: "all",
minChunks: 3,
cacheGroups: {
vendor: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true,
},
},
},
},
plugins: [
new CleanWebpackPlugin(),
/**
* from 定义要拷贝的源文件 from:__dirname+'/src/components'
to 定义要拷贝到的目标文件夹 to: __dirname+'/dist'
toType file 或者 dir 可选,默认是文件
force 强制覆盖前面的插件 可选,默认是文件
context 可选,默认base context可用specific context
flatten 只拷贝指定的文件 可以用模糊匹配
ignore 忽略拷贝指定的文件 可以模糊匹配
* **/
new CopyWebpackPlugin([
{
from: rootPath + "/src/static",
to: rootPath + "/dist/src/static",
},
]),
new HardSourceWebpackPlugin(),
// 如果您希望使用html-webpack-plugin的替代方案,请参见mini-html-webpack-plugin。它做的更少,但也更易于理解。
new HtmlWebpackPlugin({
template: "src/index.html",
inject: "body",
filename: "index.html",
}),
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
ROUTER_MODE: JSON.stringify(ROUTERTYPE),
API_CONFIG: JSON.stringify(apiConfig),
BUILD_VERSION: JSON.stringify(new Date().toString()),
}),
new MiniCssExtractPlugin({
filename: "css/[name].[hash:5].css",
publicPath: path.join(rootPath, "dist"),
ignoreOrder: true,
}),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.BannerPlugin({
banner: "hello world20000000000000000",
}),
// new ZipPlugin({
// path: '../',
// pathPrefix: 'www',
// filename: 'dist.zip',
// }),
],
});
```
\ No newline at end of file
浏览器报错:React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6 features
需要安装
> $ npm i -D @hot-loader/react-dom
然后在入口处配置别名
```java
resolve: {
alias: {
'react-dom': '@hot-loader/react-dom'
},
},
```
具体查看官网 https://github.com/gaearon/react-hot-loader/issues/1227
\ No newline at end of file
#简介说明
> 作者:小兵
> 来源:项目重构
> 细节看官方 http://expressjs.com/
1. 作用:启动server 启动build的静态文件
```java
//路径
var path = require('path');
// node.js 启动web服务框架
var express = require('express');
// 实例化
var app = express();
// 打开诸如URL,文件,可执行文件之类的东西。跨平台 更多查看https://github.com/sindresorhus/open#readme
var open = require("open");
// node 路径模块引入根目录
var rootPath = path.resolve(__dirname, '..');
// 启动静态文件使用根目录
app.use(express.static(rootPath));
// 设置相应头
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'X-Requested-With');
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
res.header('X-Powered-By', ' 3.2.1');
res.header('Content-Type', 'text/html');
next();
});
// 获取静态页面入口
app.get('*', function(req, res) {
res.sendFile(path.join(rootPath, 'dist/index.html'));
});
//监听端口
app.listen(3001, function(err) {
if (err) {
return console.error(err);
}
// 打开路径
open("http://localhost:3001/fualn/fulan/login");
});
```
\ No newline at end of file
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
\ No newline at end of file
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
{"name":"reactCli_library","content":{"../node_modules/react/index.js":{"id":0,"buildMeta":{"providedExports":true}},"../node_modules/prop-types/index.js":{"id":1,"buildMeta":{"providedExports":true}},"../node_modules/react-dom/index.js":{"id":11,"buildMeta":{"providedExports":true}},"../node_modules/object-assign/index.js":{"id":37,"buildMeta":{"providedExports":true}},"../node_modules/webpack/buildin/global.js":{"id":43,"buildMeta":{"providedExports":true}},"../node_modules/@babel/runtime/helpers/esm/extends.js":{"id":73,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"../node_modules/tiny-invariant/dist/tiny-invariant.esm.js":{"id":100,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"../node_modules/history/esm/history.js":{"id":112,"buildMeta":{"exportsType":"namespace","providedExports":["createBrowserHistory","createHashHistory","createMemoryHistory","createLocation","locationsAreEqual","parsePath","createPath"]}},"../node_modules/react-is/index.js":{"id":125,"buildMeta":{"providedExports":true}},"../node_modules/@babel/runtime/helpers/esm/inheritsLoose.js":{"id":132,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"../node_modules/react-router/esm/react-router.js":{"id":174,"buildMeta":{"exportsType":"namespace","providedExports":["MemoryRouter","Prompt","Redirect","Route","Router","StaticRouter","Switch","__RouterContext","generatePath","matchPath","useHistory","useLocation","useParams","useRouteMatch","withRouter"]}},"../node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js":{"id":216,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"../node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js":{"id":335,"buildMeta":{"providedExports":true}},"../node_modules/gud/index.js":{"id":406,"buildMeta":{"providedExports":true}},"../node_modules/react/cjs/react.production.min.js":{"id":469,"buildMeta":{"providedExports":true}},"../node_modules/react-dom/cjs/react-dom.production.min.js":{"id":479,"buildMeta":{"providedExports":true}},"../node_modules/scheduler/index.js":{"id":480,"buildMeta":{"providedExports":true}},"../node_modules/scheduler/cjs/scheduler.production.min.js":{"id":481,"buildMeta":{"providedExports":true}},"../node_modules/react-is/cjs/react-is.production.min.js":{"id":482,"buildMeta":{"providedExports":true}},"../node_modules/prop-types/factoryWithThrowingShims.js":{"id":484,"buildMeta":{"providedExports":true}},"../node_modules/prop-types/lib/ReactPropTypesSecret.js":{"id":485,"buildMeta":{"providedExports":true}},"../node_modules/@babel/runtime/helpers/inheritsLoose.js":{"id":660,"buildMeta":{"providedExports":true}},"../node_modules/path-to-regexp/index.js":{"id":661,"buildMeta":{"providedExports":true}},"../node_modules/mini-create-react-context/dist/esm/index.js":{"id":1202,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"../node_modules/resolve-pathname/esm/resolve-pathname.js":{"id":1203,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"../node_modules/value-equal/esm/value-equal.js":{"id":1204,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"../node_modules/react-router-dom/esm/react-router-dom.js":{"id":1845,"buildMeta":{"exportsType":"namespace","providedExports":["MemoryRouter","Prompt","Redirect","Route","Router","StaticRouter","Switch","__RouterContext","generatePath","matchPath","useHistory","useLocation","useParams","useRouteMatch","withRouter","BrowserRouter","HashRouter","Link","NavLink"]}},"../node_modules/path-to-regexp/node_modules/isarray/index.js":{"id":1846,"buildMeta":{"providedExports":true}}}}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "wmyadmin",
"version": "3.1.1",
"description": "未木云学习平台",
"homepage": "http://dev.mg.kmelearning.com/shyz/shyz/login",
"bugs": {
"url": "http://chandao.kmelearning.com/zentao/my/"
},
"repository": {
"type": "git",
"url": "ssh://git@g.km365.pw:122/frontend/sass-admin.git"
},
"license": "ISC",
"author": "陈万军",
"main": "index.js",
"st": "$1",
"scripts": {
"dll": "webpack --config build/dll.config.js -p --progress --profile",
"build": "rm -rf dist && cross-env NODE_ENV_API=other NODE_ROUTER_MODE=history cross-env NODE_ENV=production BUILD_ENV=prod webpack --progress --config build/webpack.prod.config.js && npm run addSm2 && npm run cp",
"build:prod": "rm -rf dist && NODE_ENV_API=prod NODE_ROUTER_MODE=history BUILD_ENV=prod webpack --display-optimization-bailout --profile --progress --config build/webpack.prod.config.js && npm run addSm2",
"dev": "cross-env NODE_ENV_API=deve NODE_ENV=development webpack-dashboard -c magenta --title [浏览器输入http://localhost:5001/shyz/shyz/login] -- webpack-dev-server --config ./build/webpack.dev.config.js --port 5001",
"diff": "git diff $1 $2",
"lint:css": "stylelint --fix --aei '**/*.less,.css'",
"lint:js": "eslint --fix --ext --write .js,.jsx src",
"format": "npx prettier@2.0.5 --check --write \"./src/pages/Login/*.{js,jsx}\"",
"server": "node build/server.prod.js",
"sort": "npx sort-package-json",
"sit": "cross-env NODE_ENV_API=sit NODE_ROUTER_MODE=history node -max_old_space_size=10240 build/server.dev.js",
"//test": "cross-env NODE_ENV_API=sit NODE_ROUTER_MODE=history nodemon -max_old_space_size=10240 build/server.dev.js",
"deve": "cross-env NODE_ENV_API=deve NODE_ROUTER_MODE=history node -max_old_space_size=10240 build/server.dev.js",
"uat": "cross-env NODE_ENV_API=uat NODE_ROUTER_MODE=history node -max_old_space_size=10240 build/server.dev.js",
"prod": "cross-env NODE_ENV_API=prod NODE_ROUTER_MODE=history node -max_old_space_size=10240 build/server.dev.js",
"addSm2": "cp -i ./src/static/lib/sm2.min.js ./dist",
"cp": "cp -rf ./RJump ./dist/libs"
},
"dependencies": {
"@ant-design/icons": "^4.2.2",
"antd": "^3.26.13",
"babel-runtime": "^6.18.0",
"braft-editor": "^2.3.7",
"braft-utils": "^3.0.12",
"browserslist": "^4.14.7",
"classnames": "^2.2.5",
"core-js": "^3.6.4",
"cssnano": "^4.1.10",
"draftjs-utils": "^0.9.4",
"echarts": "^4.1.0",
"echarts-for-react": "^2.0.13",
"fetch-jsonp": "^1.1.3",
"gg-editor": "^2.0.4",
"history": "^4.10.1",
"immutability-helper": "^2.9.1",
"immutable": "^3.8.1",
"jsbarcode": "^3.11.0",
"jszip": "^3.1.5",
"lodash": "^4.17.4",
"md5": "^2.2.1",
"qrcode.react": "^1.0.0",
"react": "^16.13.1",
"react-cookies": "^0.1.1",
"react-dnd": "^2.6.0",
"react-dnd-html5-backend": "^2.6.0",
"react-dom": "^16.13.1",
"react-intl-universal": "^2.2.5",
"react-redux": "^7.2.0",
"react-router-dom": "^5.1.2",
"react-tools": "^0.13.0-beta.2",
"redux": "^4.0.5",
"redux-actions": "^2.6.5",
"redux-logger": "^3.0.6",
"redux-saga": "^1.1.3",
"redux-thunk": "^2.3.0",
"sm-crypto": "^0.1.2"
},
"devDependencies": {
"@babel/core": "^7.7.7",
"@babel/plugin-proposal-class-properties": "^7.7.4",
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
"@babel/plugin-transform-modules-commonjs": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/preset-env": "^7.7.7",
"@babel/preset-react": "^7.7.4",
"@babel/runtime-corejs3": "^7.7.7",
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"@hot-loader/react-dom": "^16.13.0",
"@types/react": "^16.9.17",
"add-asset-html-webpack-plugin": "^3.1.3",
"antd-dayjs-webpack-plugin": "0.0.8",
"autoprefixer": "^6.7.7",
"axios": "^0.18.0",
"babel-eslint": "^7.2.3",
"babel-loader": "^8.0.6",
"babel-plugin-import": "^1.13.0",
"babelify": "^10.0.0",
"body-parser": "^1.15.2",
"braft-finder": "0.0.21",
"clean-webpack-plugin": "^3.0.0",
"copy-to-clipboard": "^3.0.8",
"copy-webpack-plugin": "^6.0.3",
"cross-env": "^6.0.3",
"css-loader": "^3.4.2",
"eslint": "^6.8.0",
"eslint-config-ali": "^9.0.2",
"eslint-config-prettier": "^6.10.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "^6.10.3",
"eslint-plugin-react-hooks": "^2.5.0",
"express": "^4.16.3",
"express-session": "^1.15.6",
"file-loader": "^5.1.0",
"html-webpack-plugin": "^4.0.0-beta.11",
"http-proxy-middleware": "^1.0.6",
"husky": "^4.2.3",
"jsbarcode": "^3.11.0",
"jsx-loader": "^0.13.2",
"less": "^3.11.1",
"less-loader": "^5.0.0",
"lint-staged": "^10.0.8",
"mini-css-extract-plugin": "^0.9.0",
"moment": "^2.28.0",
"open": "^7.0.3",
"postcss-flexbugs-fixes": "^4.2.0",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"postcss-pxtorem": "^5.1.1",
"prettier": "^1.19.1",
"react-color": "^2.17.3",
"react-copy-to-clipboard": "^5.0.1",
"react-cropper": "^1.3.0",
"react-hot-loader": "^4.12.20",
"react-loadable": "^5.5.0",
"react-perfect-scrollbar": "^1.5.8",
"rimraf": "^2.5.4",
"store": "^2.0.12",
"style-loader": "^1.1.3",
"stylelint": "^13.2.0",
"stylelint-config-standard": "^20.0.0",
"terser-webpack-plugin": "^2.2.1",
"thread-loader": "^2.1.3",
"url-loader": "^3.0.0",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dashboard": "^3.2.0",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.10.2",
"webpack-hot-middleware": "^2.25.0"
},
"peerDependencies": {
"eslint": ">=1.6.0 <6.0.0",
"react": "> = 16.8",
"react-dom": "> = 16.8",
"webpack": ">4.41.5",
"webpack-cli": "^3.3.10"
}
}
/**
* anth: 陈万军
* time: 2020-05-1
* 集成功能:热更新,错误收集,ConfigProvider,国际化,redux,路由
* */
import React from "react";
// 热更新
import { hot } from "react-hot-loader/root";
// redux 管理
import { Provider } from "react-redux";
import createStore from "@/redux/store/configureStore.js";
const store = createStore();
// 总路由管理
import Routes from "@/routes/index.js";
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Routes />
</Provider>
);
}
}
export default hot(App);
import React, { Component } from "react";
import AliVideoPlayer from "./js/videoplayer";
import $ from "@/util/domJq";
import "./less/aliVideo.less";
const defaultCover = "http://player.alicdn.com/cover/cover2.png";
const defaultSource =
'{"HD":"//player.alicdn.com/video/aliyunmedia.mp4","SD":"http://player.alicdn.com/video/1.mp4"}';
export default class AliVideo extends Component {
constructor(props) {
super(props);
this.state = {
param: {
id: "J_prismPlayer", //容器盒子
x5_type: "h5",
x5_video_orientation: "landscape|portrait",
autoplay: false, //自动播放
isLive: false, //播放内容是否为直播
playsinline: true, //H5是否内置播放,有的Android浏览器不起作用
width: "100%",
height: "3.2rem",
controlBarVisibility: "always", //控制面板的实现,默认为‘click’,可选的值为:‘click’、‘hover’、‘always’。
useH5Prism: true, //指定使用H5播放器
useFlashPrism: false, //指定使用Flash播放器。
//资源,HD高清,SD超清 我写了两个资源是为了区分高清和超清
source:
'{"HD":"//player.alicdn.com/video/aliyunmedia.mp4","SD":"http://player.alicdn.com/video/1.mp4"}',
cover: "http://player.alicdn.com/cover/cover2.png", //封面
skinLayout: [
//controlBar控制条 配置相关 查看文档skinLayout的属性 链接直达 https://help.aliyun.com/document_detail/62948.html?spm=a2c4g.11186623.2.21.jd8qdF
{
name: "controlBar",
align: "blabs",
x: 0,
y: 0,
children: [
{ name: "progress", align: "tlabs", x: 0, y: 0 },
{ name: "playButton", align: "tl", x: 15, y: 12 },
{ name: "timeDisplay", align: "tl", x: 10, y: 7 },
{ name: "fullScreenButton", align: "tr", x: 10, y: 10 },
//{name: "snapshot", align: "tr", x: 10, y: 10},
{ name: "volume", align: "tr", x: 10, y: 10 },
{ name: "streamButton", align: "tr", x: 0, y: 10 },
{ name: "speedButton", align: "tr", x: 0, y: 10 },
],
},
{ name: "bigPlayButton", align: "cc" },
{ name: "H5Loading", align: "cc" },
{ name: "errorDisplay", align: "tlabs", x: 0, y: 0 },
{ name: "infoDisplay", align: "cc" },
],
},
callback: player => {
// console.log(player);
},
};
this.videoStart = this.videoStart.bind(this);
this.videoComplete = this.videoComplete.bind(this);
}
componentDidMount() {
let player = "";
if (this.props.source) {
var { param } = this.state;
if (this.props.hideProgress) {
var tempChildren = param.skinLayout[0].children.filter(item => {
return item.name != "progress";
});
param.skinLayout[0].children = tempChildren;
}
param.height = this.props.height + "px";
param.autoplay = this.props.autoplay ? this.props.autoplay : false;
param.isLive = this.props.isLive ? this.props.isLive : false;
param.cover = this.props.cover ? this.props.cover : defaultCover;
param.source = JSON.stringify(this.props.source);
if (!param.source.HD) {
param.source = this.props.tempSource;
}
param.videoStart = this.videoStart;
param.videoComplete = this.videoComplete;
player = new AliVideoPlayer(this.state.param, this.props.getPlayer);
$("#J_prismPlayer")
.find("video")
.attr("x5-video-player-type", "h5")
.attr("x5-video-orientation", "landscape|portrait");
}
}
videoStart() {
this.props.start("video");
}
videoComplete() {
this.props.complete("video");
}
render() {
if (this.props.source) {
return <div className="prism-player live-video" id="J_prismPlayer" />;
} else {
return (
<div
className="prism-player live-video"
style={{ height: this.props.height ? this.props.height : 400 }}
/>
);
}
}
}
//使用方法直接饮用组件就可以
//例子使用
{
/*<AliVideo*/
}
{
/*key={this.state.randomKey}*/
}
{
/*height={600}*/
}
{
/*cover={this.state.materialVo.image}*/
}
{
/*source={{*/
}
{
/*FD: this.state.materialVo.ldUrl,*/
}
{
/*SD: this.state.materialVo.fdUrl,*/
}
{
/*HD: this.state.materialVo.sdUrl*/
}
{
/*}}*/
}
{
/*tempSource={this.state.materialVo.originalFileUrl}*/
}
{
/*autoplay={false}*/
}
{
/*hideProgress={this.state.hideProgress}*/
}
{
/*getPlayer={this.getVideoPlayer}*/
}
{
/*start={this.playStart}*/
}
{
/*complete={this.playComplete}*/
}
{
/*/>*/
}
.enter-x5-player video.center
{
object-position:50% 50% !important;
}
.prism-progress-cursor
{
margin-left:0px !important;
}
/*.enter-x5-player video
{
object-position: 0px 10px;
/*height:auto !important;*/
/*}*/
<div class="prism-player" id="J_prismPlayer" style="width:100%; height:252px">
</div>
\ No newline at end of file
import "./index.css";
import $ from "@/util/domJq";
export default class VideoPlayer {
constructor(props) {
this.player;
this.props = props;
this._setup();
this._bindEvent();
this._firstFullscreen = true;
}
loadByUrl(url) {
if (this.player) this.player.loadByUrl(url);
}
dispose() {
if (this.player) {
this.player.dispose();
Zepto("#" + this.props.id).empty();
}
}
_setup() {
this.player = new Aliplayer(this.props);
}
_bindEvent() {
let that = this;
this.player.on("ready", e => {
// console.log('ready');
that.props.videoStart();
});
this.player.on("play", e => {
// console.log('play');
});
this.player.on("ended", e => {
// console.log('ended');
that.props.videoComplete();
});
this.player.on("pause", e => {
// console.log('pause');
});
this.player.on("requestFullScreen", e => {
let video = $(that.player.tag);
video.addClass("center");
if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
$(that.player.el()).removeClass("prism-fullscreen");
}
});
this.player.on("x5cancelFullScreen", e => {
let service = that.player.fullscreenService;
if (service.getIsFullScreen()) {
service.cancelFullScreen();
}
$(that.player.el()).removeClass("enter-x5-player");
var layout = that.player.originalLayout;
if (layout) {
that.player.tag.style.height = layout.video.height;
}
h;
});
this.player.on("x5requestFullScreen", e => {
//调整视频的位置
$(that.player.el()).addClass("enter-x5-player");
var screenHeight =
document.body.clientHeight * (window.devicePixelRatio || 1) + "px";
that.player.tag.style.height = screenHeight;
let video = $(that.player.tag);
setTimeout(() => {
video.removeClass("x5-top-left");
});
});
this.player.on("cancelFullScreen", e => {
let video = $(that.player.tag);
setTimeout(() => {
video.removeClass("center");
video.removeClass("x5-top-left");
});
});
//微信左上角退出按钮触发是,关闭页面
this.player.tag.addEventListener("x5videoexitfullscreen", () => {
if (WeixinJSBridge) WeixinJSBridge.call("closeWindow");
else {
try {
window.location.refresh();
} catch (e) {}
}
});
$(document).on("WeixinJSBridgeReady", () => {
let video = $(that.player.el()).find("video")[0];
video.play();
});
}
_unbindEvent() {
let that = this;
this.player.off("ready", function(e) {
// 解决ios不自动播放的问题
if ($.os.ios) that._autoPlay();
// console.log('ready');
});
this.player.off("play", function(e) {
// console.log('play');
});
this.player.off("ended", function(e) {
// console.log('ended');
});
this.player.off("pause", function(e) {
// console.log('pause');
});
}
}
// .prism-fullscreen{
// z-index: 1000!important;
// }
//.notFullScreen {
// .prism-player .prism-big-play-btn {
// width: 80px !important;
// height: 80px !important;
// }
// .prism-player .prism-play-btn {
// width: 56px !important;
// height: 56px !important;
// }
// .prism-player .prism-time-display {
// font-size: 24px !important;
// }
// .prism-speed-selector .current-speed-selector {
// width: 100px !important;
// }
// .prism-speed-selector {
// font-size: 26px !important;
// }
// .prism-player .prism-volume .volume-control-icon, .prism-player .prism-volume .volume-icon {
// width: 48px !important;
// height: 48px !important;
// }
// .prism-player .prism-fullscreen-btn {
// width: 48px !important;
// height: 48px !important;
// }
// .prism-stream-selector .current-stream-selector {
// font-size: 24px !important;
// }
// .prism-player .prism-liveshift-progress, .prism-player .prism-progress {
// height: 6px !important;
// }
// .prism-speed-selector .speed-selector-list li {
// line-height: 36px !important;
// }
// .prism-stream-selector .stream-selector-list li {
// font-size: 24px !important;
// line-height: 48px !important;
// }
// .prism-player .prism-volume .volume-control {
// left: 14px !important;
// bottom: 64px !important;
// height: auto !important;
// }
// .prism-player .prism-volume .volume-control .volume-control-icon {
// bottom: 22px !important;
// left: -7px !important;
// }
// .prism-player .prism-volume .volume-control .volume-control-icon {
// display: none !important;
// }
// .prism-player .prism-volume .volume-range {
// width: 7px !important;
// height: 120px !important;
// left: 30% !important;
// bottom: 7px !important;
// }
// .prism-player .prism-volume .volume-cursor {
// left: -9px !important;
// width: 20px !important;
// height: 20px !important;
// }
// .prism-stream-selector .current-stream-selector {
// width: 80px !important;
// }
// .prism-stream-selector {
// font-size: 24px !important;
// }
// .prism-player .prism-info-left-bottom {
// bottom: 100px !important;
// }
// .prism-stream-selector .stream-selector-list {
// left: 10px;
// }
//}
.bread {
position : fixed;
top : 64px;
right : 0;
width : calc(100% - 200px);
z-index : 29;
transition : width 0.2s;
height : 60px;
background-color: rgb(255, 255, 255);
box-shadow:0px 1px 4px 0px rgba(0,21,41,0.12);
}
.collapsed {
position : fixed;
top : 64px;
right : 0;
width : calc(100% - 200px);
z-index : 29;
transition : width 0.2s;
height : 60px;
background-color: rgb(255, 255, 255);
width : ~"calc(100% - 80px)";
box-shadow:0px 1px 4px 0px rgba(0,21,41,0.12);
}
\ No newline at end of file
import React from "react";
import { get as getGlobalData } from "@/util/globalData.js";
import styles from "./Bread.less";
import { connect } from "react-redux";
class Breadcrumb extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
const {collapsed,title}=this.props;
return (
<div
className={collapsed?styles.collapsed:styles.bread}
>
<a
style={{
fontSize: "20px",
fontWeight: 500,
color: "rgba(51,51,51,1)",
lineHeight: "60px",
marginLeft: "32px",
backgroundColor: "#FFF",
}}
>
{title}
</a>
</div>
);
}
}
function mapStateToProps(state, ownProps) {
const { login } = state;
const collapsed = login.collapsedFlag
return {
collapsed,
};
}
function mapDispatchToProps(dispatch) {
return {
};
}
export default connect(mapStateToProps, { ...mapDispatchToProps })(Breadcrumb);
import React from 'react'
import { Dropdown, Button, Menu, Icon } from 'antd'
const DropOption = ({
onMenuClick,
menuOptions = [],
buttonStyle,
dropdownProps,
}) => {
const menu = menuOptions.map(item => (
<Menu.Item key={item.key}>{item.name}</Menu.Item>
))
return (
<Dropdown
overlay={<Menu onClick={onMenuClick}>{menu}</Menu>}
{...dropdownProps}
>
<Button style={{ border: 'none', ...buttonStyle }}>
更多
<Icon type="down" />
</Button>
</Dropdown>
)
}
export default DropOption
/**
* 更多文档:https://www.yuque.com/braft-editor/be/
*
*
* */
import React, { PureComponent } from "react";
import BraftEditor from "braft-editor";
import "braft-editor/dist/index.css";
import styles from "./editor.less";
import { connect } from "react-redux";
import { gupfetch } from "../UpLoad/redux/actions";
class Editor extends PureComponent {
constructor() {
super(...arguments);
this.state = {
editorState: "",
defaultValue: "",
};
}
componentDidMount() {
const { importContent } = this.props;
if (importContent) {
return {
defaultValue: BraftEditor.createEditorState(importContent),
importContent,
};
}
this.props.gupfetch();
}
static getDerivedStateFromProps(nextProps, prevState) {
const { importContent } = nextProps;
if (importContent !== prevState.importContent) {
return {
defaultValue: BraftEditor.createEditorState(importContent),
importContent,
};
}
return null;
}
submitContent = () => {
// 在编辑器获得焦点时按下ctrl+s会执行此方法
// 编辑器内容提交到服务端之前,可直接调用editorState.toHTML()来获取HTML格式的内容
const htmlContent = this.state.editorState.toHTML();
};
handleEditorChange = editorState => {
let html = editorState.toHTML();
this.setState({ editorState, html });
this.props.cbReceiver(html);
};
blockExportFn = (contentState, block) => {
const previousBlock = contentState.getBlockBefore(block.key);
if (
block.type === "unstyled" &&
previousBlock &&
previousBlock.getType() === "atomic"
) {
return {
start: "",
end: "",
};
}
};
render() {
const { uploadParam } = this.props;
const { editorState, defaultValue } = this.state;
const set = [
"undo",
"redo",
"separator",
"font-size",
"font-family",
"line-height",
"letter-spacing",
"separator",
"text-color",
"bold",
"italic",
"underline",
"strike-through",
"separator",
"superscript",
"subscript",
"remove-styles",
// "emoji",//bug-12227-cwj liujiadan 让去掉的
"separator",
"text-indent",
"text-align",
"separator",
"headings",
"list-ul",
"list-ol",
"blockquote",
"code",
"separator",
"link",
"separator",
"hr",
"separator",
"media",
"separator",
"clear",
];
let fontFamilies = [];
var agent = navigator.userAgent.toLowerCase();
var isMac = /macintosh|mac os x/i.test(navigator.userAgent);
if (
agent.indexOf("win32") >= 0 ||
agent.indexOf("wow32") >= 0 ||
agent.indexOf("win64") >= 0 ||
agent.indexOf("wow64") >= 0
) {
fontFamilies = [
{
name: "Araial",
family: "Arial, Helvetica, sans-serif",
},
{
name: "Georgia",
family: "Georgia, serif",
},
{
name: "Impact",
family: "Impact, serif",
},
{
name: "Monospace",
family: '"Courier New", Courier, monospace',
},
{
name: "Tahoma",
family: 'tahoma, arial, "Hiragino Sans GB", 宋体, sans-serif',
},
{
name: "黑体",
family: "SimHei, 黑体",
},
{
name: "宋体",
family: "SimSun, 宋体",
},
{
name: "仿宋",
family: "FangSong, 仿宋",
},
{
name: "新宋体",
family: "NSimSun, 新宋体",
},
{
name: "楷体",
family: "KaiTi, 楷体, Helvetica, sans-serif",
},
{
name: "微软雅黑",
family: "微软雅黑, Microsoft YaHei , Helvetica, sans-serif",
},
{
name: "微软正黑体",
family: "微软正黑体, Microsoft JhengHei , Helvetica, sans-serif",
},
];
}
if (isMac) {
fontFamilies = [
{
name: "Araial",
family: "Arial, Helvetica, sans-serif",
},
{
name: "Georgia",
family: "Georgia, serif",
},
{
name: "Impact",
family: "Impact, serif",
},
{
name: "Monospace",
family: '"Courier New", Courier, monospace',
},
{
name: "Tahoma",
family: 'tahoma, arial, "Hiragino Sans GB", 宋体, sans-serif',
},
{
name: "华文黑体",
family: "STHeiti, 华文黑体",
},
{
name: "华文宋体",
family: "STSong, 华文宋体",
},
{
name: "华文仿宋",
family: "STFangsong, 华文仿宋",
},
{
name: "华文楷体",
family: "STKaiti, 华文楷体",
},
{
name: "冬青黑体简",
family: "Hiragino Sans GB, 冬青黑体简",
},
{
name: "兰亭黑",
family: "Lantinghei SC, 兰亭黑",
},
{
name: "宋体",
family: "Songti SC, 宋体",
},
{
name: "娃娃体",
family: "Wawati SC, 娃娃体",
},
];
}
const fontSizes = [
// 1,
// 4,
// 8,
12,
14,
16,
18,
20,
24,
28,
30,
32,
36,
40,
48,
56,
64,
72,
96,
120,
144,
];
const myBlockExport = (contentState, block) => {
// const previousBlock = contentState.getBlockBefore(block.key);
//
// if (
// block.type === "unstyled" &&
// previousBlock &&
// previousBlock.getType() === "atomic"
// ) {
// return {
// start: "",
// end: ""
// };
// }
};
const myUploadFn = param => {
const { uploadParam } = this.props;
const serverURL = uploadParam.host;
const xhr = new XMLHttpRequest();
const fd = new FormData();
// 文件名时间戳
const time = new Date().getTime();
const fileName = `${param.id + time}.${
param.file.name.split(".")[param.file.name.split(".").length - 1]
}`;
fd.append("name", param.file.name);
fd.append("Filename", `${uploadParam.dir}/${fileName}`);
fd.append("key", `${uploadParam.dir}/${fileName}`);
fd.append("policy", uploadParam.policy);
fd.append("OSSAccessKeyId", uploadParam.accessid);
fd.append("success_action_status", "200");
fd.append("signature", uploadParam.signature);
fd.append("file", param.file);
xhr.open("POST", serverURL, true);
xhr.send(fd);
const successFn = response => {
// 假设服务端直接返回文件上传后的地址
// 上传成功后调用param.success并传入上传后的文件地址
param.success({
url: `${uploadParam.host}/${uploadParam.dir}/${fileName}`,
meta: {
id: "1",
title: "1",
alt: "image",
},
});
};
const errorFn = response => {
// 上传发生错误时调用param.error
param.error({
msg: "unable to upload.",
});
};
// 上传成功的时候
xhr.addEventListener("load", successFn, false);
// 上传失败
xhr.addEventListener("error", errorFn, false);
xhr.addEventListener("failed ", errorFn, false);
};
return (
<BraftEditor
imageResizable
converts={{ blockExportFn: myBlockExport }}
forceNewLine={false}
media={{ uploadFn: myUploadFn }}
className={styles.edit}
// value={editorState} //动态赋值会造成光标位移
defaultValue={defaultValue}
fontFamilies={fontFamilies}
fontSizes={fontSizes}
controls={set}
onChange={this.handleEditorChange}
onSave={this.submitContent}
/>
);
}
}
function mapStateToProps(state, ownProps) {
return {
uploadParam: state.uploadParam.param,
};
}
function mapDispatchToProps(dispatch) {
return {
gupfetch: () => dispatch(gupfetch()),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Editor);
:global {
.bf-video-player video {
height: 300px !important;
}
.bf-container {
border: 1px solid #d9d9d9;
}
}
import React from "react";
// import commonFunc from "@/util/commonFunc.js";
// import { Button } from "antd";
class ErrorBoundary extends React.Component {
static getDerivedStateFromError(error) {
// 更新状态,以便下一个渲染将显示后备UI。
console.log("=================getDerivedStateFromError===================");
console.log(error);
return { hasError: true };
}
constructor(props) {
super(props);
this.state = { hasError: false, info: null };
}
componentDidCatch(hasError, info) {
console.log("=================hasError===================");
console.log(hasError);
console.log("=================hasErrorEnd===================");
console.log("==================info==================");
console.log(info);
console.log("==================infoEND==================");
this.setState({ hasError, info });
// 您还可以将错误记录到错误报告服务中
// 请求回传接口
}
render() {
// timeRecordArray.push(tempObj);
console.log("=================e===================",this.props);
if (this.state.hasError) {
return (
<div style={{display:"flex",alignItems:"center",
justifyContent:"center",position:"relative",top:"125px"}}>
<div>
<img style={{width:"241px",height:"202px"}} alt="https://customproject.oss-cn-shanghai.aliyuncs.com/photo/errorboundary.png" src='https://customproject.oss-cn-shanghai.aliyuncs.com/photo/errorboundary.png'/>
</div>
<div>
<div style={{width:"274px",marginLeft:"20px"}} >
<p>抱歉,您访问的页面受阻, 请联系管理员,代码:#002内容。尝试刷新,或者点击其他功能刷新使用</p>
</div>
</div>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
import React from "react";
class ParamError extends React.Component {
render() {
const { props } = this.props;
return (
<div className="paramError">
<div style={{display:"flex",alignItems:"center",
justifyContent:"center",position:"relative",top:"125px"}}>
<div>
<img style={{width:"241px",height:"202px"}} alt="https://customproject.oss-cn-shanghai.aliyuncs.com/photo/errorboundary.png" src='https://customproject.oss-cn-shanghai.aliyuncs.com/photo/errorboundary.png'/>
</div>
<div>
<div style={{width:"274px",marginLeft:"20px"}} >
<p>抱歉,您访问的页面不存在, 请联系管理员,代码:#001路由。</p>
</div>
</div>
</div>
</div>
);
}
}
export default ParamError;
// 字体图标自定义
import { Icon } from "antd";
const IconFont = Icon.createFromIconfontCN({
scriptUrl:
"https://customproject.kmelearning.com/1253551622685487104/iconfont.js",
});
export default IconFont;
// 预览图标
//http://customproject.kmelearning.com/1253551622685487104/demo_index.html
// 查看第三个tab Symbol 预览使用的字体
// 使用实例
{
/* <IconFont type="icon-Dashboard-White-65"/> */
}
@black: #000;
.globalFooter {
margin: 48px 0 24px 0;
padding: 0 16px;
text-align: center;
.links {
margin-bottom: 8px;
a {
color: fade(@black, 65%);
transition: all 0.3s;
&:not(:last-child) {
margin-right: 40px;
}
&:hover {
color: fade(@black, 45%);
}
}
}
.copyright {
color: fade(@black, 65%);
font-size: 14px;
}
}
import React from "react";
import classNames from "classnames";
import styles from "./GlobalFooter.less";
import { Icon } from "antd";
const GlobalFooter = ({ className, links, copyright }) => {
const clsString = classNames(styles.globalFooter, className);
return (
<footer className={clsString}>
{links && (
<div className={styles.links}>
{links.map(link => (
<a
key={link.key}
title={link.key}
target={link.blankTarget ? "_blank" : "_self"}
href={link.href}
>
{link.title}
</a>
))}
</div>
)}
{copyright && (
<div className={styles.copyright}>
<Icon type="copyright" />
{copyright}
</div>
)}
</footer>
);
};
export default GlobalFooter;
@import "~themes/vars.less";
@header-hover-bg: rgba(0, 0, 0, 0.075);
.action {
display: inline-block;
height: 100%;
padding: 0 24px;
cursor: pointer;
transition: all 0.3s;
> i {
color: @text-color;
vertical-align: middle;
}
&:hover {
background: @header-hover-bg;
}
&:global(.opened) {
background: @header-hover-bg;
}
}
.header {
padding: 0;
box-shadow: @shadow-2;
position: relative;
display: flex;
justify-content: space-between;
height: 64px;
z-index: 9;
align-items: center;
background-color: #fff;
box-shadow:0px 1px 4px 0px rgba(0,21,41,0.12);
border-bottom: 1px solid #F0F0F0;
&.fixed {
position: fixed;
top: 0;
right: 0;
width: ~"calc(100% - 200px)";
z-index: 29;
transition: width 0.2s;
&.collapsed {
width: ~"calc(100% - 80px)";
}
}
:global {
.ant-menu-submenu-title {
height: 72px;
}
.ant-menu-horizontal {
line-height: 72px;
& > .ant-menu-submenu:hover {
color: @primary-color;
background-color: @hover-color;
}
}
.ant-menu {
border-bottom: none;
height: 72px;
}
.ant-menu-horizontal > .ant-menu-submenu {
top: 0;
margin-top: 0;
}
.ant-menu-horizontal > .ant-menu-item,
.ant-menu-horizontal > .ant-menu-submenu {
border-bottom: none;
}
.ant-menu-horizontal > .ant-menu-item-active,
.ant-menu-horizontal > .ant-menu-item-open,
.ant-menu-horizontal > .ant-menu-item-selected,
.ant-menu-horizontal > .ant-menu-item:hover,
.ant-menu-horizontal > .ant-menu-submenu-active,
.ant-menu-horizontal > .ant-menu-submenu-open,
.ant-menu-horizontal > .ant-menu-submenu-selected,
.ant-menu-horizontal > .ant-menu-submenu:hover {
border-bottom: none;
}
}
.rightContainer {
display: flex;
align-items: center;
}
.button {
float: left;
width: 72px;
height: 64px;
line-height: 64px;
text-align: center;
font-size: 24px;
margin-top: 4px;
cursor: pointer;
transition: @transition-ease-in;
&:hover {
color: @primary-color;
background-color: @hover-color;
}
}
.logo {
float: left;
height: 72px;
margin-left: 20px;
}
.image {
border-radius: 5px;
height: 40px;
width: 128px;
}
}
.iconButton {
width: 48px;
height: 48px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 24px;
cursor: pointer;
.background-hover();
&:hover {
.iconFont {
color: @primary-color;
}
}
& + .iconButton {
margin-left: 8px;
}
.iconFont {
color: #b2b0c7;
font-size: 24px;
}
}
.notification {
padding: 24px 0;
width: 320px;
.notificationItem {
transition: all 0.3s;
padding: 12px 24px;
cursor: pointer;
&:hover {
background-color: @hover-color;
}
}
.clearButton {
text-align: center;
height: 48px;
line-height: 48px;
cursor: pointer;
.background-hover();
}
}
.selectDiv {
position: absolute;
width: 200px;
margin-left: 150px;
}
.switchDiv {
position: absolute;
width: 100px;
margin-left: 50px;
display: flex;
align-items: center;
justify-content: center;
}
.notificationPopover {
:global {
.ant-popover-inner-content {
padding: 0;
}
.ant-popover-arrow {
display: none;
}
.ant-list-item-content {
flex: 0;
margin-left: 16px;
}
}
}
@media (max-width: 767px) {
.header {
width: 100% !important;
}
}
.assDiv {
padding: 0 32px;
display: flex;
background: #FB8893;
align-items: center;
.iconDiv {
display: flex;
align-items: center;
}
.assText {
margin-left: 10px;
font-weight: 400;
color: #FFFFFF;
}
&:hover {
background: #FBB9BC;
}
}
import React, { PureComponent } from "react";
import { Dropdown } from "antd";
import classNames from "classnames";
import styles from "./HeaderDropdown.less";
export default class HeaderDropdown extends PureComponent {
render() {
const { overlayClassName, ...props } = this.props;
return (
<Dropdown
trigger={['click']}
overlayClassName={classNames(styles.container, overlayClassName)}
{...props}
/>
);
}
}
import ScrollBar from "react-perfect-scrollbar";
import "react-perfect-scrollbar/dist/css/styles.css";
import "./ScrollBar.less";
export default ScrollBar;
:global {
.ps--active-x > .ps__rail-x,
.ps--active-y > .ps__rail-y {
background-color: transparent;
}
.ps__rail-x:hover > .ps__thumb-x,
.ps__rail-x:focus > .ps__thumb-x {
height: 8px;
}
.ps__rail-y:hover > .ps__thumb-y,
.ps__rail-y:focus > .ps__thumb-y {
width: 8px;
}
.ps__rail-y,
.ps__rail-x {
z-index: 9;
}
.ps__thumb-y {
width: 4px;
right: 4px;
}
.ps__thumb-x {
height: 4px;
bottom: 4px;
}
}
\ No newline at end of file
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { langageActions, siteLanguagePage, selectLanguageSave } from "./redux/actions";
import { Menu, Icon } from "antd";
import classNames from "classnames";
import HeaderDropdown from "./HeaderDropdown";
import ScrollBar from "./ScrollBar";
import {
get as getGlobalData,
set as setGlobalData,
} from "@/util/globalData.js";
import styles from "./SelectLang.less";
import { lacalesApi } from "@/locales/api";
import intl from "react-intl-universal";
class SelectLang extends PureComponent {
constructor(props){
super(props);
this.state = {
showLanguage: "",
showLanImg: ""
}
}
changeLang = (locale) => {
let code = locale.languageCode;
let param = {
languageCode: code
}
if(!location.href.includes("login")){//登录系统后,切换语言,发送给后台
this.props.selectLanguageSave(param, res => {
sessionStorage.setItem("lang", code);
window.location.reload();//强制刷新
})
}else{
sessionStorage.setItem("lang", code);
window.location.reload();//强制刷新
}
};
componentDidMount() {
let param = {
pageNo: 1,
pageSize: 100,
status: 1
}
this.props.siteLanguagePage(param, res=>{
if(sessionStorage.getItem("lang")){
let showLanImg = "";
let cache = res.data.map(item => {
if(item.languageCode == sessionStorage.getItem("lang")){
showLanImg = item.languageImg;
return item.languageName
}
})
this.setState({
showLanguage: cache,
showLanImg
})
}else{
this.setState({
showLanguage: res.data[0]["backupDesc"],
showLanImg: res.data[0]["languageImg"],
})
}
})
}
handLanguage = (locale) => {
// debugger
// this.sessionStorage.setItem("key", locale.languageCode);
this.changeLang(locale);
}
arrShift = (arr, code) => {
if (arr.length == 0) return arr
let znIndex = arr.findIndex(val => val.languageCode == code);
let cache = arr[znIndex];
if (znIndex != -1) {
arr.splice(znIndex, 1);
arr.unshift(cache);
}
return arr;
}
render() {
const { className } = this.props;
const selectedLang = getGlobalData("language");
let cacheLan = this.props.langage.languageType || [];
// let locales = this.arrShift(cacheLan, "zh_CN");
// locales = this.arrShift(cacheLan, "en_US");
let locales = cacheLan; //bug-13498-liyuan
// locales = this.props.langage.languageType || ["zh_CN"];
// const languageLabels = {
// zh_CN: "简体中文",
// zh_TW: "繁体中文",
// en_US: "英语",
// pt_BR: "葡萄牙",
// ja_JP: "日语",
// };
// const languageIcons = {
// zh_CN: "🇨🇳",
// zh_TW: "🇭🇰",
// en_US: "🇬🇧",
// pt_BR: "🇧🇷",
// ja_JP: "🇯🇵",
// };
const langMenu = (
<div className={styles.langmenu}>
<ScrollBar
options={{
suppressScrollX: true,
}}>
<Menu
className={styles.menu}
selectedKeys={[selectedLang]}
// onClick={this.changeLang}
>
{locales.map(locale => (
<Menu.Item key={locale.id} onClick={()=>this.handLanguage(locale)} title={locale.des || ""}>
{/* <span role="img" aria-label={languageLabels[locale]}>
{languageIcons[locale]}
</span>{" "}
{languageLabels[locale]} */}
<img src={locale.languageImg} style={{width: '20px', height: '20px', marginRight: '10px', borderRadius: '50%'}}></img>
<span label-tip={locale.des}>
{locale.languageName}
</span>
</Menu.Item>
))}
</Menu>
</ScrollBar>
</div>
);
return (
<HeaderDropdown overlay={langMenu} placement="bottomRight">
<span className={classNames(styles.dropDown, className)}>
<img src={this.state.showLanImg} style={{width: '20px', height: "20px", borderRadius: "50%"}}/>
{/* <Icon type="global" style={{fontSize: '18px'}}/> */}
{location.href.includes("login") && <span style={{fontSize: '14px', color: '#666666', marginLeft: '5px'}}>{this.state.showLanguage}</span>}
</span>
</HeaderDropdown>
);
}
}
function mapStateToProps(state) {
return { langage: state.langageReducers };
}
function mapDispatchToProps(dispatch) {
return {
langageActions: data => dispatch(langageActions(data)),
siteLanguagePage: (data, cb) => dispatch(siteLanguagePage(data, cb)),
selectLanguageSave: (data, cb) => dispatch(selectLanguageSave(data, cb)),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(SelectLang);
.langmenu{
// max-height: "calc(50%)";
height: 500px;
:global{
.ant-menu-vertical > .ant-menu-item{
line-height: 30px;
height: 30px;
}
}
}
\ No newline at end of file
import services from "@/services/serve";
export default {
siteLanguagePageApi: `GET ${services.webManage}/siteLanguage/public/page`,
publicLanguageGetApi: `GET ${services.webManage}/international/public/language/get`,
selectLanguageSaveApi: `GET ${services.webManage}/siteLanguage/record/international/selectLanguage/save`,
};
\ No newline at end of file
import React, { PureComponent } from "react";
import { withRouter } from "react-router-dom";
import PropTypes from "prop-types";
import { Tooltip, Dropdown, Menu, Icon, Layout, Avatar } from "antd";
import classnames from "classnames";
import styles from "./Header.less";
import SelectLang from "./SelectLang";{/* bug-11961-cwj暂时注释 2期上 */}
import HeaderDropdown from "./HeaderDropdown";
// import cookie from "react-cookies";bug-12952-cwj
import headerLogo from "../../../static/imgs/headerLogo.png";
class Header extends PureComponent {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {}
handleClickMenu = e => {
e.key === "SignOut" && this.props.onSignOut();
};
render() {
const {
fixed,
collapsed,
onCollapseChange,
siteDataJson,
nav,
onHandleMenuClick,
onMenuClick,
menus,
onToAss,
} = this.props;
// 站点选择
const siteMenu = (
<Menu onClick={onHandleMenuClick}>
{siteDataJson.map(item => (
<Menu.Item key={item.siteCode}>{item.siteName}</Menu.Item>
))}
</Menu>
);
// 个人选择
const menu = (
<Menu className={styles.menu}>
<Menu.Item key="userInfo" style={{ cursor: "text" }}>
<Icon type="user" />
{/* bug-12952-cwj */}
{sessionStorage.getItem("userName")}
</Menu.Item>
<Menu.Item key="logout" onClick={onMenuClick}>
<Icon type="logout" />
退出登录
</Menu.Item>
</Menu>
);
// 是否开通了社群
let associationButton = false
let hasAssociation = menus.filter(item => item.name === '社群');
if(hasAssociation.length > 0){
associationButton = true
}
return (
<Layout.Header
className={classnames(styles.header, {
[styles.fixed]: fixed,
[styles.collapsed]: collapsed,
})}
id="layoutHeader"
>
<div>
{collapsed &&
<div
className={styles.button}
onClick={onCollapseChange.bind(this, !collapsed)}
>
<Icon
type={classnames({
"menu-unfold": collapsed,
"menu-fold": !collapsed,
})}
/>
</div>}
<div className={styles.logo}>
<img className={styles.image} src={nav.logo ? nav.logo : headerLogo} />
</div>
</div>
<div className={styles.rightContainer}>
{/* bug-11961-cwj暂时注释 2期上 */}
{/* <Icon type="folder-open" style={{ padding: "0 12px" }} /> */}
{/* 语言 */}
{/* bug-11961-cwj暂时注释 2期上 */}
{/* <SelectLang className={styles.action} /> */}
{associationButton &&
<a className={styles.assDiv} onClick={onToAss.bind(this)}>
<div className={styles.iconDiv}><Icon style={{ color: 'white' }} type="home" /></div>
<div className={styles.assText}>社群平台</div>
</a>
}
<Tooltip title={"使用帮助"}>
<a
target="_blank"
href="http://help.kmelearning.com/hc/"
rel="noopener noreferrer"
className={styles.action}
>
<Icon type="question-circle-o" />
</a>
</Tooltip>
<Tooltip title={"站点切换"}>
<Dropdown overlay={siteMenu} style={{ zIndex: 1200 }} trigger={['click']}>
<a className="ant-dropdown-link">
{nav.siteName}
<Icon type="down" />
</a>
</Dropdown>
</Tooltip>
<Tooltip title={"个人设置"}>
<HeaderDropdown overlay={menu}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar
size="small"
className={styles.avatar}
icon="user"
alt="avatar"
/>
</span>
</HeaderDropdown>
</Tooltip>
</div>
</Layout.Header>
);
}
}
Header.propTypes = {
fixed: PropTypes.bool,
user: PropTypes.object,
menus: PropTypes.array,
collapsed: PropTypes.bool,
onSignOut: PropTypes.func,
onCollapseChange: PropTypes.func,
};
export default withRouter(Header);
// 登录和checkToken
export const SET_LANGAGE = "SET_LANGAGE";
import * as Types from "./actionTypes";
import request from "@/util/request.js";
import api from "../api";
const {
siteLanguagePageApi,
publicLanguageGetApi,
selectLanguageSaveApi
} = api;
// 设置语音
export function langageActions(parms) {
console.log("parms", parms);
return dispatch => {
dispatch({ type: Types.SET_LANGAGE, langage: parms });
};
}
export function siteLanguagePage(data, callback) {
return dispath => {
return request({
url: siteLanguagePageApi,
data: data,
}).then(res => {
if (callback) callback(res);
dispath({
type: 'SITE_LANGUAGE_PAGE',
payload: {languageType: res.data}
})
});
};
}
export function publicLanguageGet(data, callback) {
return dispath => {
return request({
url: publicLanguageGetApi,
data: data,
}).then(res => {
dispath({
type: 'SITE_LANGUAGE_PAGE',
payload: {languageData: res.data}
})
if (callback) callback(res);
});
};
}
export function selectLanguageSave(data, callback) {
return dispath => {
return request({
url: selectLanguageSaveApi,
data: data,
}).then(res => {
if (callback) callback(res);
});
};
}
import * as Types from "./actionTypes";
const initialState = {
langage: "zh_CN",
languageType: [],
languageData: {}
};
export default function langageReducers(state = initialState, action) {
switch (action.type) {
case Types.SET_LANGAGE:
return { ...state, langage: action.langage };
case "SITE_LANGUAGE_PAGE":
return { ...state, ...action.payload}
}
return state;
}
import React, { PureComponent, Fragment } from "react";
import { Menu, Icon } from "antd";
import IconFont from "@/common/IconFont";
import { set as setGlobalData, get as getGlobalData } from "@/util/globalData.js";
import { Link, withRouter } from "react-router-dom";
import styles from "./Sider.less";
import { arrayToTree, queryAncestors, pathMatchRegexp } from "@/util/index";
import store from "store";
const { SubMenu } = Menu;
class SiderMenu extends PureComponent {
state = {
openKeys: store.get("openKeys") || [],
iconType: false,
};
onOpenChange = openKeys => {
const { menus } = this.props;
const rootSubmenuKeys = menus.filter(_ => !_.menuParentId).map(_ => _.id);
const latestOpenKey = openKeys.find(
key => this.state.openKeys.indexOf(key) === -1
);
let newOpenKeys = openKeys;
if (rootSubmenuKeys.indexOf(latestOpenKey) !== -1) {
newOpenKeys = latestOpenKey ? [latestOpenKey] : [];
}
this.setState({
openKeys: newOpenKeys,
});
store.set("openKeys", newOpenKeys);
};
generateMenus = data => {
const { match } = this.props;
const { iconType } = this.state;
let currentMenuId = getGlobalData("currentMenuId");
return data.map(item => {
if (item.children) {
return (
<SubMenu
key={item.id}
popupClassName={styles.wmySubMenu}
onSelect={te => {
console.log("activeIcon", iconType);
this.setState({ iconType: true });
}}
title={
<Fragment>
{item.icon && (
// <IconFont className={item.id==currentMenuId&&this.props.collapsed?styles.activeIconFont:""} key={item.id} type={item.id==currentMenuId ? item.activeIcon : item.icon} />
<IconFont className={item.id == currentMenuId && this.props.collapsed ? styles.activeIconFont : ""} key={item.id} type={item.icon} />
)}
<span>{item.name}</span>
</Fragment>
}
>
{this.generateMenus(item.children)}
</SubMenu>
);
}
return (
item.menuType == 2 ? <Menu.ItemGroup title={item.name} key={item.id}></Menu.ItemGroup> :
<Menu.Item key={item.id}>
{item.url &&
<Link
to={`${match.url}${item.url.trim()}`}// bug-12622-cwj
onClick={() => {
setGlobalData("breadName", item.name);
setGlobalData("currentMenuId", item.id[0] - 0);
}}
>
<span className='title'>{item.name}</span>
<span style={{ float: "right" }}>{item.total}</span>
{/* <span>{item.total}</span> */}
</Link>
}
{!item.url &&
<div
>
<IconFont className={item.id == currentMenuId && this.props.collapsed ? styles.activeIconFont : ""} key={item.id} type={item.icon} />
<span className='title'>{item.name}</span>
<span style={{ float: "right" }}>{item.total}</span>
</div>
}
</Menu.Item>
);
});
};
render() {
const { collapsed, theme, menus, match } = this.props;
// Generating tree-structured data for menu content.
let nwesmenus = menus.filter(item => item.name !== '社群');
const menuTree = arrayToTree(nwesmenus, "id", "menuParentId");
// Find a menu that matches the pathname.
const currentMenu = nwesmenus.find(
_ => _.url && pathMatchRegexp(match.url + _.url, window.location.pathname)
);
if (currentMenu) {
setGlobalData("breadName", currentMenu.name);
setGlobalData("currentMenuId", currentMenu.id[0] - 0);
}
// const currentMenu = ""; currentMenu.name
// Find the key that should be selected according to the current menu.
const selectedKeys = currentMenu
? queryAncestors(nwesmenus, currentMenu, "menuParentId").map(_ => _.id)
: [];
const menuProps = collapsed ? {} : { openKeys: this.state.openKeys };
return (
<Menu
mode="inline"
theme={theme}
onOpenChange={this.onOpenChange}
selectedKeys={selectedKeys}
defaultOpenKeys={this.state.openKeys}
defaultSelectedKeys={selectedKeys}
{...menuProps}
>
{this.generateMenus(menuTree, selectedKeys)}
</Menu>
);
}
}
export default withRouter(SiderMenu);
.imgDiv {
max-width: 14px;
width: 14px;
margin-right: 10px;
font-size: 13px;
}
import ScrollBar from "react-perfect-scrollbar";
import "react-perfect-scrollbar/dist/css/styles.css";
import "./ScrollBar.less";
export default ScrollBar;
:global {
.ps--active-x > .ps__rail-x,
.ps--active-y > .ps__rail-y {
background-color: transparent;
}
.ps__rail-x:hover > .ps__thumb-x,
.ps__rail-x:focus > .ps__thumb-x {
height: 8px;
}
.ps__rail-y:hover > .ps__thumb-y,
.ps__rail-y:focus > .ps__thumb-y {
width: 8px;
}
.ps__rail-y,
.ps__rail-x {
z-index: 9;
}
.ps__thumb-y {
width: 4px;
right: 4px;
}
.ps__thumb-x {
height: 4px;
bottom: 4px;
}
}
\ No newline at end of file
@import "~themes/vars.less";
.wmySubMenu {
background-image: linear-gradient(to bottom, #404C5B, #384350);
:global {
.ant-menu-vertical.ant-menu-sub {
background-image: linear-gradient(to bottom, #404C5B, #2E3945);
overflow-x: scroll;
max-height: 100vh;
.ant-menu-item-active,
.ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open,
.ant-menu-submenu-active,
.ant-menu-submenu-title:hover {
color: white;
}
.ant-menu-item-selected {
opacity : 0.85;
background : rgba(255, 255, 255, 1);
border-radius: 4px;
margin-left : 8px;
text-indent: -8px;
width : ~"calc(100% - 16px)";
.title {
font-weight: 400;
color : rgba(0, 0, 0, 1);
}
}
.ant-menu-item-selected {
&:hover {
color: rgba(0, 0, 0, 1);
}
}
.ant-menu-submenu-selected {
opacity : 0.85;
background : rgba(255, 255, 255, 1);
border-radius: 4px;
margin-left : 8px;
text-indent: -8px;
width : ~"calc(100% - 16px)";
color : rgba(0, 0, 0, 1);
.ant-menu-submenu-title {
&:hover {
color: rgba(0, 0, 0, 1);
}
}
.ant-menu-submenu-title :before {
background-color: black;
}
.ant-menu-submenu-title :after {
background-color: black;
}
}
}
.ant-menu-vertical.ant-menu-sub ::-webkit-scrollbar{
display: none;
}
.ant-menu-vertical.ant-menu-sub::-webkit-scrollbar {
width: 0.16rem;
background-color: transparent;
}
.ant-menu-vertical.ant-menu-sub::-webkit-scrollbar-track {
background-color: transparent;
}
.ant-menu-vertical.ant-menu-sub::-webkit-scrollbar-thumb {
border-radius: 0.08rem;
background-color: rgba(255, 255, 255, 0);
box-shadow: 0px 1px 3px 0px rgba(44, 47, 49, 0);
}
/*滚动条的上下两端的按钮*/
.ant-menu-vertical.ant-menu-sub::-webkit-scrollbar-button {
height: 0px;
}
}
.wmySubMenu {
left: 164px !important;
}
}
.sider {
box-shadow : fade(@primary-color, 10%) 0 0 28px 0;
z-index : 10;
background-image: linear-gradient(to bottom, #404C5B, #2E3945);
:global {
.ant-layout-sider-children {
display : flex;
flex-direction : column;
justify-content: space-between;
}
}
.brand {
z-index : 1;
height : 64px;
display : flex;
align-items: center;
padding : 0 20px;
box-shadow : 0 1px 9px -3px rgba(0, 0, 0, 0.2);
.logoAll {
display : flex;
align-items: center;
width : 100%;
.extCni{
cursor: pointer;
&:hover{
.icon,.logoText{
color: #fff;
}
}
}
.logoText {
font-size: 21px;
color : rgba(255, 255, 255, .65);
margin-left: 5px;
}
.button {
margin-left: 20px;
float : left;
text-align : center;
font-size : 24px;
cursor : pointer;
transition : @transition-ease-in;
&:hover{
.icon {
color: #fff;
}
}
.menuFold {
color : rgba(255, 255, 255, .65);
&:hover{
color: #fff;
}
}
}
.icon {
font-size: 20px;
color : rgba(255, 255, 255, .65);
}
}
.logoOne {
display : flex;
align-items : center;
justify-content: center;
a {
color: rgba(255, 255, 255, .65);
}
&:hover {
a {
color: #fff;
}
}
.icon {
font-size: 24px;
}
.iconDashboard {
color: red;
}
}
.logo {
width: 100%;
img {
width : 36px;
margin-right: 8px;
}
h1 {
vertical-align: text-bottom;
font-size : 16px;
text-transform: uppercase;
display : inline-block;
font-weight : 700;
color : @primary-color;
white-space : nowrap;
margin-bottom : 0;
.text-gradient-brand ();
:local {
animation : fadeRightIn 300ms @ease-in-out;
animation-fill-mode: both;
}
}
}
}
.menuContainer {
height : ~"calc(100vh - 120px)";
overflow-x: hidden;
flex : 1;
&::-webkit-scrollbar-thumb {
background-color: transparent;
}
&:hover {
&::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2);
}
}
:global {
.ant-menu-submenu-open,
.ant-menu-submenu-active,
.ant-menu-submenu-title:hover {
color: #fff;
}
.ant-menu-inline {
border-right: none;
}
.has-success.has-feedback .ant-form-item-children-icon {
color : black !important;
animation-name: diffZoomIn1 !important;
}
.ant-layout-sider {
background-color: transparent;
}
.ant-menu-dark,
.ant-menu-dark .ant-menu-sub {
background-color: transparent;
}
.ant-menu-vertical.ant-menu-dark .ant-menu-sub {
background-color: transparent;
}
.ant-menu-item-selected {
opacity : 0.85;
background : rgba(255, 255, 255, 1);
border-radius: 4px;
margin-left : 8px;
text-indent: -8px;
width : ~"calc(100% - 16px)";
.title {
font-weight: 400;
color : rgba(0, 0, 0, 1);
}
}
}
}
.switchTheme {
width : 100%;
height : 48px;
display : flex;
justify-content: space-between;
align-items : center;
padding : 0 16px;
overflow : hidden;
transition : all 0.3s;
span {
white-space: nowrap;
overflow : hidden;
font-size : 12px;
}
:global {
.anticon {
min-width : 14px;
margin-right: 4px;
font-size : 14px;
}
}
}
@keyframes fadeLeftIn {
0% {
transform: translateX(5px);
opacity : 0;
}
100% {
transform: translateX(0);
opacity : 1;
}
}
}
.activeIconFont {
display : inline-block;
margin-left : -29px !important;
width : 72px;
background : rgba(255, 255, 255, 1);
border-radius: 4px;
opacity : 0.84;
color : rgba(0, 0, 0, .65);
}
import React, { PureComponent } from "react";
import { Icon, Switch, Layout } from "antd";
import ScrollBar from "./ScrollBar";
import SiderMenu from "./Menu";
import styles from "./Sider.less";
import IconFont from "@/common/IconFont";
import classnames from "classnames";
class Sider extends PureComponent {
render() {
const {
menus,
theme,
isMobile,
collapsed,
onThemeChange,
onCollapseChange,
companyCode,
siteCode,
onDashboardClick,
} = this.props;
return (
<Layout.Sider
width={200}
theme="dark"
breakpoint="lg"
trigger={null}
collapsible
collapsed={collapsed}
className={styles.sider}
>
<div className={styles.brand}>
<div className={styles.logo}>
{collapsed ? (
<div className={styles.logoOne} >
<a onClick={onDashboardClick}>
<div className={styles.icon}><IconFont type='icon-dashboard1' /></div>
</a>
</div>
) : (
<div className={styles.logoAll}>
<span className={styles.extCni} onClick={onDashboardClick} style={{display:"flex"}}>
<div className={styles.icon}><IconFont type='icon-dashboard1' /></div>
<div className={styles.logoText}>Dashboard</div>
</span>
<div
className={styles.button}
onClick={onCollapseChange.bind(this, !collapsed)}
>
<Icon
className={styles.menuFold}
type={classnames({
"menu-unfold": collapsed,
"menu-fold": !collapsed,
})}
/>
</div>
</div>
)}
</div>
</div>
<div className={styles.menuContainer} id={"styles_sider"}>
<ScrollBar
options={{
// Disabled horizontal scrolling, https://github.com/utatti/perfect-scrollbar#options
suppressScrollX: true,
}}
>
<SiderMenu
companyCode={companyCode}
siteCode={companyCode}
menus={menus}
theme="dark"
isMobile={isMobile}
collapsed={collapsed}
onCollapseChange={onCollapseChange}
/>
</ScrollBar>
</div>
</Layout.Sider>
);
}
}
export default Sider;
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment