独书先生 Menu

All items for 7月, 2020

Luckysheet如何一键导入本地Excel

问题

Luckysheet是一款功能很丰富的在线电子表格插件,但是初始版本暂时不支持excel导入导出.笔者结合身边朋友的经验,给出案例供参考.

解决方案

通过sheetJs将导入的excel文件转换成Luckysheet能够支持的数据格式即可

操作步骤

  1. 参照官网教程,先打包源代码,得到Luckysheet核心文件,并在在项目主页引入Luckysheet依赖的js,css,和sheetJs插件xlsx.full.min.js
<link rel="stylesheet" href="./luckysheet/plugins/css/pluginsCss.min.css">

<link rel="stylesheet" href="./luckysheet/plugins/plugins.min.css">

<link rel="stylesheet" href="./luckysheet/css/main.min.css">

<script src="./luckysheet/plugins/js/plugin.min.js"></script>

<script src="./luckysheet/main.min.js"></script>

<script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.2/xlsx.full.min.js"></script>
  1. 页面准备,渲染一个空白的Luckysheet,input file 监听Excel文件上传,通过sheetJs将导入的数据转换成Luckysheet能够识别的格式
// 渲染一个空白的Luckysheet
$(function () {
    luckysheet.create({
        container: 'luckysheet'
    })
})

// 监听文件上传
var input = document.querySelector('input');
input.addEventListener('change', importExcel);
  1. 通过sheetJs将导入的excel数据转换成html table格式数据,使用从luckysheet中抽出来的数据转换方法, 转换为Luckysheet可识别的格式
// 获取excel数据
function importExcel(event) {

    var file = event.target.files[0];
    /* 实例FileReader对象 */
    //other code...
}

// 解析excel数据
function readFile(txtdata) {
    $("#luckysheet-copy-content").html(txtdata);

   //other code...
}

代码参考

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>luckysheet import excel</title>

    <link rel="stylesheet" href="./luckysheet/plugins/css/pluginsCss.min.css">

    <link rel="stylesheet" href="./luckysheet/plugins/plugins.min.css">

    <link rel="stylesheet" href="./luckysheet/css/main.min.css">

    <script src="./luckysheet/plugins/js/plugin.min.js"></script>

    <script src="./luckysheet/main.min.js"></script>

    <script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.2/xlsx.full.min.js"></script>

    <style>
        #container {
            position: relative;
        }
    </style>
</head>

<body>
    <div id="container">
        <input type="file" />
        <div id="luckysheet"
            style="margin:0px;padding:0px;position:absolute;width:100%;height:100%;left: 0px;top: 30px;"></div>
    </div>

    <script>
        document.querySelector('#container').style.height = window.innerHeight + 'px';

        // 渲染一个空白的Luckysheet
        $(function () {

            luckysheet.create({
                container: 'luckysheet'
            })
        })

        // 监听文件上传
        var input = document.querySelector('input');
        input.addEventListener('change', importExcel);

        // 获取excel数据
        function importExcel(event) {

            var file = event.target.files[0];
            /* 实例FileReader对象 */
            var reader = new FileReader();
            reader.onload = function (e) {
                /* Parse data */
                var bstr = e.target.result;
                var wb = XLSX.read(bstr, { type: 'binary' });
                /* 获取第一个工作表*/
                var wsname = wb.SheetNames[0];
                var ws = wb.Sheets[wsname];
                /* 将工作表对象转换为JSON对象数组*/
                // var dataArr = XLSX.utils.sheet_to_json(ws, { header: 1 });
                /* 生成HTML输出 */
                var data = XLSX.utils.sheet_to_html(ws);
                /* 调用数据转换方法将数据格式转换成Luckysheet格式*/
                readFile(data);
            };
            /*将文件内容读取为原始二进制字符串*/
            reader.readAsBinaryString(file);
        }

        // 解析excel数据
        function readFile(txtdata) {
            $("#luckysheet-copy-content").html(txtdata);

            var data = new Array($("#luckysheet-copy-content").find("table tr").length);
            var colLen = 0;
            $("#luckysheet-copy-content").find("table tr").eq(0).find("td").each(function () {
                var colspan = parseInt($(this).attr("colspan"));
                if (isNaN(colspan)) {
                    colspan = 1;
                }
                colLen += colspan;
            });

            for (var i = 0; i < data.length; i++) {
                data[i] = new Array(colLen);
            }

            var r = 0;
            var borderInfo = {};
            var luckysheet_select_save = luckysheet.getluckysheet_select_save();

            $("#luckysheet-copy-content").find("table tr").each(function () {
                var $tr = $(this);
                var c = 0;
                $tr.find("td").each(function () {
                    var $td = $(this);
                    var cell = {};
                    var txt = $td.text();

                    if ($.trim(txt).length == 0) {
                        cell.v = null;
                        cell.m = "";
                    }
                    else {
                        var mask = luckysheet.mask.genarate($td.text());
                        cell.v = mask[2];
                        cell.ct = mask[1];
                        cell.m = mask[0];
                    }

                    var bg = $td.css("background-color");
                    if (bg == "rgba(0, 0, 0, 0)") {
                        bg = "rgba(255,255,255)";
                    }

                    cell.bg = bg;

                    var bl = $td.css("font-weight");
                    if (bl == 400 || bl == "normal") {
                        cell.bl = 0;
                    }
                    else {
                        cell.bl = 1;
                    }

                    var it = $td.css("font-style");
                    if (it == "normal") {
                        cell.it = 0;
                    }
                    else {
                        cell.it = 1;
                    }

                    var ff = $td.css("font-family");
                    var ffs = ff.split(",");
                    for (var i = 0; i < ffs.length; i++) {
                        var fa = $.trim(ffs[i].toLowerCase());
                        fa = luckysheet.menuButton.fontjson[fa];
                        if (fa == null) {
                            cell.ff = 0;
                        }
                        else {
                            cell.ff = fa;
                            break;
                        }
                    }

                    var fs = Math.floor(parseInt($td.css("font-size")) * 72 / luckysheet.dpi_y) + 1;
                    cell.fs = fs;

                    var fc = $td.css("color");

                    cell.fc = fc;

                    var ht = $td.css("text-align");
                    if (ht == "center") {
                        cell.ht = 0;
                    }
                    else if (ht == "right") {
                        cell.ht = 2;
                    }
                    else {
                        cell.ht = 1;
                    }

                    var vt = $td.css("vertical-align");
                    if (vt == "middle") {
                        cell.vt = 0;
                    }
                    else if (vt == "top" || vt == "text-top") {
                        cell.vt = 1;
                    }
                    else {
                        cell.vt = 2;
                    }

                    while (c < colLen && data[r] != null) {
                        c++;
                    }

                    if (c == colLen) {
                        return true;
                    }

                    if (data[r] == null) {
                        data[r] = cell;
                        var rowspan = parseInt($td.attr("rowspan"));
                        var colspan = parseInt($td.attr("colspan"));

                        if (isNaN(rowspan)) {
                            rowspan = 1;
                        }

                        if (isNaN(colspan)) {
                            colspan = 1;
                        }


                        var r_ab = luckysheet_select_save[0]["row"][0] + r;
                        var c_ab = luckysheet_select_save[0]["column"][0] + c;
                        for (var rp = 0; rp < rowspan; rp++) {
                            for (var cp = 0; cp < colspan; cp++) {
                                if (rp == 0) {
                                    var bt = $td.css("border-top");
                                    if (bt != null && bt.length > 0 && bt.substr(0, 3).toLowerCase() != "0px") {
                                        var width = $td.css("border-top-width");
                                        var type = $td.css("border-top-style");
                                        var color = $td.css("border-top-color");
                                        var borderconfig = luckysheet.menuButton.getQKBorder(width, type, color);

                                        if (borderInfo[(r + rp) + "_" + (c + cp)] == null) {
                                            borderInfo[(r + rp) + "_" + (c + cp)] = {};
                                        }

                                        borderInfo[(r + rp) + "_" + (c + cp)].t = { "style": borderconfig[0], "color": borderconfig[1] };
                                    }
                                }

                                if (rp == rowspan - 1) {
                                    var bb = $td.css("border-bottom");
                                    if (bb != null && bb.length > 0 && bb.substr(0, 3).toLowerCase() != "0px") {
                                        var width = $td.css("border-bottom-width");
                                        var type = $td.css("border-bottom-style");
                                        var color = $td.css("border-bottom-color");
                                        var borderconfig = luckysheet.menuButton.getQKBorder(width, type, color);

                                        if (borderInfo[(r + rp) + "_" + (c + cp)] == null) {
                                            borderInfo[(r + rp) + "_" + (c + cp)] = {};
                                        }

                                        borderInfo[(r + rp) + "_" + (c + cp)].b = { "style": borderconfig[0], "color": borderconfig[1] };
                                    }
                                }

                                if (cp == 0) {
                                    var bl = $td.css("border-left");
                                    if (bl != null && bl.length > 0 && bl.substr(0, 3).toLowerCase() != "0px") {
                                        var width = $td.css("border-left-width");
                                        var type = $td.css("border-left-style");
                                        var color = $td.css("border-left-color");
                                        var borderconfig = luckysheet.menuButton.getQKBorder(width, type, color);

                                        if (borderInfo[(r + rp) + "_" + (c + cp)] == null) {
                                            borderInfo[(r + rp) + "_" + (c + cp)] = {};
                                        }

                                        borderInfo[(r + rp) + "_" + (c + cp)].l = { "style": borderconfig[0], "color": borderconfig[1] };
                                    }
                                }

                                if (cp == colspan - 1) {
                                    var br = $td.css("border-right");
                                    if (br != null && br.length > 0 && br.substr(0, 3).toLowerCase() != "0px") {
                                        var width = $td.css("border-right-width");
                                        var type = $td.css("border-right-style");
                                        var color = $td.css("border-right-color");
                                        var borderconfig = luckysheet.menuButton.getQKBorder(width, type, color);

                                        if (borderInfo[(r + rp) + "_" + (c + cp)] == null) {
                                            borderInfo[(r + rp) + "_" + (c + cp)] = {};
                                        }

                                        borderInfo[(r + rp) + "_" + (c + cp)].r = { "style": borderconfig[0], "color": borderconfig[1] };
                                    }
                                }

                                if (rp == 0 && cp == 0) {
                                    continue;
                                }
                                data[r + rp] = { "mc": { "r": r_ab, "c": c_ab } };
                            }
                        }

                        if (rowspan > 1 || colspan > 1) {
                            var first = { "rs": rowspan, "cs": colspan, "r": r_ab, "c": c_ab };
                            data[r].mc = first;
                        }
                    }

                    c++;

                    if (c == colLen) {
                        return true;
                    }
                });

                r++;
            });

            var index = luckysheet.sheetmanage.getSheetIndex(luckysheet.currentSheetIndex);
            var file = luckysheet.getluckysheetfile()[index];
            var luckysheet_selection_range = file["luckysheet_selection_range"];

            luckysheet_selection_range = [];
            luckysheet.selection.pasteHandler(data, borderInfo);
            $("#luckysheet-copy-content").empty();
        }

    </script>
</body>

</html>

探讨

仅前端文件导入是不带单元格样式的,但是从excel复制单元格到Luckysheet是带单元格样式的.可以从 在线demo 尝试下.

目前Luckysheet功能正在完善中,可以逐步关注.

The operation was rejected by your operating system.

问题

npm install报错:

The operation was rejected by your operating system.
npm ERR! It's possible that the file was already in use (by a text editor or antivirus),
npm ERR! or that you lack permissions to access it.
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.

解决

  1. 查看是否有程序占用项目文件夹,比如:
    • git bash打开了项目
    • github desktop打开了项目
    • 另外的cmd窗口打开了此文件夹/项目文件夹
    • 开启了本地服务器/vscode等编辑器软件打开了项目
  2. 在项目中已管理员身份运行cmd(如何以管理员身份运行cmd)

node-gyp node-sass安装指南

问题

npm install --global --production windows-build-tools报错

MSI (s) (14:10) [20:36:04:711]: Product: Python 2.7.15 (64-bit) -- Installation failed.

MSI (s) (14:10) [20:36:04:712]: Windows Installer 已安装产品。产品名称: Python 2.7.15 (64-bit)。产品版本: 2.7.15150。产品语言: 1033。制造商: Python Software Foundation。安装成功或错误状态: 1603。

安装时发生严重错误
C:\Users\14145\.windows-build-tools\python-2.7.15.amd64.msi

解决

1.自行下载python2.7.15版本的重装
淘宝镜像站快速下载地址:https://npm.taobao.org/mirrors/python/2.7.15/

2.设置多python
https://blog.csdn.net/qq_27474589/article/details/72583014

3.重新 npm install --global --production windows-build-tools

可能搭配的命令

  1. npm config set msvs_version 2012 --global
  2. npm config set msvs_version 2017
  3. npm install node-pre-gyp -g
  4. 有的依赖比较大,但是国内的网络环境收到了限制,可以参考此篇教程采用更科学的方式
    > 强烈推荐:彻底解决npm下载问题

其他解决思路

一、重新安装
1. npm cache clean --force
2. 删除项目中的 node_modules (如何快速删除node_modules)
3. 删除 package-lock.jsona
4. 重新 npm install

二、node-sass换成sass
1.先卸载node-sass: npm uninstall node-sass -g
2.再安装sass: npm install sass -g

node-gyp

教程链接:https://github.com/nodejs/node-gyp

wordpress搬家备份迁移

1. 使用插件All-in-One WP Migration导入导出

aliyun无法连接FTP服务器

2. 增大上传文件大小限制

html目录下,即wp-content同级目录,修改.htaccess文件,修改(没有就增加):

php_value upload_max_filesize 128M
php_value post_max_size 128M
php_value memory_limit 256M
php_value max_execution_time 300
php_value max_input_time 300

即可增加最大上传文件大小为128M

3. 您的PHP似乎没有安装运行WordPress所必需的MySQL扩展(centos 7)

  • yum -y install mariadb-server php-mysql
  • sudo systemctl restart httpd

参考

http://www.auiou.com/relevant/00001477.jsp

git commit规范

依赖安装

1. 生成commit信息

npm install --save-dev commitizen

npx commitizen init cz-conventional-changelog --save-dev --save-exact

package.json

"scripts": {
   "commit": "git-cz"
}

2. commit校验

npm install --save-dev @commitlint/config-conventional @commitlint/cli

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
修改文件commitlint.config.js为正常格式

3. 更新版本、生成changelog、打tag

npm i --save-dev standard-version

package.json

 "scripts": {
    "release": "standard-version"
  }

commit使用步骤

提交代码

git pull
git add .
npm run commit
npm run release -- --prerelease
git push --follow-tags origin master

commit规范

npm run commit后根据交互提示编写
1. type

type为必填项,用于指定commit的类型
# 主要type
feat:     增加新功能
fix:      修复bug

# 特殊type
docs:     只改动了文档相关的内容
style:    不影响代码含义的改动,例如去掉空格、改变缩进、增删分号
build:    构造工具的或者外部依赖的改动,例如webpack,npm
refactor: 代码重构时使用
revert:   执行git revert打印的message

# 不常使用type
test:     添加测试或者修改现有测试
perf:     提高性能的改动
ci:       与CI(持续集成服务)有关的改动
chore:    不修改src或者test的其余修改,例如构建过程或辅助工具的变动
复制代码当一次改动包括主要type与特殊type时,统一采用主要type。
  1. scope

scope也为必填项,用于描述改动的范围,例如在业务项目中可以依据菜单或者功能模块划分,如果是组件库开发,则可以依据组件划分

  1. subject

subject是commit的简短描述

  1. body

commit的详细描述,说明代码提交的详细说明。主要描述改动之前的情况及修改动机,对于小的修改不作要求,但是重大需求、更新等必须添加body来作说明。

  1. break changes

break changes指明是否产生了破坏性修改,涉及break changes的改动必须指明该项,类似版本升级、接口参数减少、接口删除、迁移等。

  1. affect issues

affect issues指明是否影响了某个问题。格式为: fix #{issue_id}
例如:

re #2
fix #14

发布版本

在多次commit之后,可能需要发布一个新版本,以下命令会自动更新版本号

npm run release -- --prerelease
git push --follow-tags origin master 

详细使用:https://github.com/conventional-changelog/standard-version

参考

  • https://juejin.im/post/5cea2c4bf265da1b6836993f
  • https://juejin.im/post/5cc4694a6fb9a03238106eb9
  • https://juejin.im/post/5d0b3f8c6fb9a07ec07fc5d0

阿里云无法连接FTP服务器

问题

在安装wordpress插件的时候,无法连接FTP服务器,发现阿里云ECS默认是没有安装ftp服务的

解决

参考官网教程安装vsftpd

步骤

1. root登录aliyun ssh

2. yum安装vsftpd

yum install -y vsftpd

3. 设置FTP服务开机自启动

systemctl enable vsftpd.service

4. 启动ftp服务

systemctl start vsftpd.service

5. 设定用户

-d指向目录/home/ftpuser,-g创建用户组ftp,-s /sbin/nologin禁止ftpuser用户登录SSH

useradd -d /home/ftpuser -g ftp -s /sbin/nologin ftpuser

为ftpuser设置密码

passwd ftpuser

更改/var/www目录的拥有者为ftpuser。

chown -R ftpuser:ftp /var/www

6. 修改vsftpd.conf

vim /etc/vsftpd/vsftpd.conf
#除下面提及的参数外,其他参数保持默认值即可。

#修改下列参数的值
#禁止匿名登录FTP服务器
anonymous_enable=NO
#允许本地用户登录FTP服务器
local_enable=YES
#监听IPv4 sockets
listen=YES
#在行首添加#注释掉以下参数,关闭监听IPv6 sockets
#listen_ipv6=YES

#添加下列参数
#设置本地用户登录后所在目录
local_root=/var/www
#全部用户被限制在主目录
chroot_local_user=YES
#启用例外用户名单
chroot_list_enable=YES
#指定例外用户列表文件,列表中用户不被锁定在主目录
chroot_list_file=/etc/vsftpd/chroot_list
#开启被动模式
pasv_enable=YES
allow_writeable_chroot=YES
#本教程中为Linux实例公网IP
pasv_address=<FTP服务器公网IP地址>
#设置被动模式下,建立数据传输可使用的端口范围的最小值
pasv_min_port=50000
#设置被动模式下,建立数据传输可使用的端口范围的最大值
pasv_max_port=60000

7. 添加 root为例外

vim /etc/vsftpd/chroot_list # 

8. 重启

systemctl restart vsftpd.service

9. 添加安全组

自定义TCP, 21/21, 0.0.0.0/0
自定义TCP, 50000/60000, 0.0.0.0/0
  1. 谷歌浏览器访问:ftp://<FTP服务器公网IP地址>:21验证

FAQ

1. 外网无法访问可能为防火墙问题

ftp默认的端口为21,centos默认没有开启,则修改iptables文件

vi /etc/sysconfig/iptables

新增:

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 21 -j ACCEPT

保存和关闭文件,重启防火墙:

service iptables restart

2. 登录后无法返回目录和上传文件,可能要设置selinux

查看selinux状态

getsebool -a | grep ftp

如果出现:

getsebool:  SELinux is disabled

则需要先开启SELinux

出现allow_ftpd_full_access off或者ftp_home_dir off即没有开启外网访问
执行

setsebool -P allow_ftpd_full_access 1   

setsebool -P ftp_home_dir off 1

重启vsftpd

systemctl restart vsftpd.service
  1. 文件开启权限
chmod 777 /var/www
  1. 偶现不成功,请在评论区讨论

参考

https://help.aliyun.com/document_detail/92048.html
https://www.kancloud.cn/chandler/bc-linux/52710

python目录和文件名转换成小写或大写

需求

linux服务器有大小写的区分,如果有静态文件的路径为驼峰命名MainStatic/FeatureJs.js,那么只能通过 MainStatic/FeatureJs.js访问,而无法通过mainstatic/featurejs.js访问,那么如何让这两个地址都可以访问呢?

思路

先使用带lua模块的nginx镜像:nginx-lua来托管我们的静态文件,能够实现大写的请求转发到小写上,然后再使用python脚本把静态文件全部改成小写的形式.

操作步骤

1.环境准备

docker, git, node, python3安装

centos下安装 docker, git, node, python环境

2. nginx-lua安装

docker run --name master_nginx_2 \
-v /etc/localtime:/etc/localtime \
-v /software/nginx/cert:/etc/nginx/cert \
-v /software/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v /software/nginx/conf.d:/etc/nginx/conf.d \
-v /software/nginx/html:/usr/share/nginx/html \
-v /software/nginx/logs:/var/log/nginx \
--restart=always \
-p 80:80 -p 443:443 \
-d firesh/nginx-lua

3. nginx.conf配置

user nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 2;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_min_length 1k;
    gzip_types text/plain text/css application/octet-stream application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png application/x-httpd-php application/vnd.ms-fontobject application/x-font-ttf font/ttf font/opentype font/x-woff image/svg+xml image/x-icon;
    include /etc/nginx/conf.d/*.conf;
}

FAQ

4. nginx配置转发

conf.d目录下,自己的配置文件增加lua转发规则
比如我的conf.d/01_www.lwebapp.com.conf

server {
    listen 80;
    server_name www.lwebapp.com lwebapp.com;   #域名
    rewrite ^(.*)$  https://$host$1 permanent;  #将所有http请求通过rewrite重定向到https
}
server {
    listen 443 ssl;   #SSL协议访问端口号为443。此处如未添加ssl,可能会造成Nginx无法启动
    server_name www.lwebapp.com lwebapp.com;  # 要解析进来的域名

    ssl_certificate       /etc/nginx/cert/3114423_lwebapp.com.pem;
    ssl_certificate_key   /etc/nginx/cert/3114423_lwebapp.com.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;  #使用此加密套件
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;   #使用该协议进行配置
    ssl_prefer_server_ciphers on; 

    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 2;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_min_length 1k;
    gzip_types text/plain text/css application/octet-stream application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png application/x-httpd-php application/vnd.ms-fontobject application/x-font-ttf font/ttf font/opentype font/x-woff image/svg+xml image/x-icon;

    location / {
        root   /usr/share/nginx/html/vue-demo;
        index  index.html index.htm;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

5. python脚本

python目录和文件名转换成小写或大写conver.py,放置在nginx/html下,后续html下会放置各个项目的静态文件,所以使用conver.py统一使用脚本处理

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os, sys


def convert(rootdir, optype='l'):
    """
    目录/文件名转换成小写或大写
    :param rootdir: 要转换的根目录路径
    :param optype: 操作类型(小写/大写)  小写:optype = 'l'  大写:optype = 'u',默认转换成小写
    :return:
    """
    dirlist = os.listdir(rootdir)
    for index, onedir in enumerate(dirlist):
        if optype == 'l':
            cdir = onedir.lower()
        elif optype == 'u':
            cdir = onedir.upper()
        subdir = os.path.join(rootdir, onedir)

        if onedir != cdir:      # 子目录或文件名不全为小写或大写
            subcdir = os.path.join(rootdir, cdir)
            os.rename(subdir, subcdir)          # 把大写的目录或文件名命名成小写或大写
            dirlist[index] = cdir
            subdir = subcdir

        # print(subdir)
        if os.path.isdir(subdir):
            convert(subdir, optype)

def help():
    print("use: python convert.py 'rootDirPath' {optype:'l'/'u'}")

def main():
    if len(sys.argv) == 2:
        convert(sys.argv[1])
    elif len(sys.argv) == 3:
        convert(sys.argv[1], sys.argv[2])
    else:
        help()
        exit(400)


if __name__ == '__main__':
    main()

6. 项目初始化

前置条件,安装node

# 进入/software/vue-demo/repository 目录
cd /
mkdir -p /software/vue-demo/repository
cd /software/vue-demo/repository

# 拉取初始代码
git clone https://github.com/Dushusir/vue-demo.git

# 进入vue-demo目并安装项目依赖
cd vue-demo
npm install
# 打包
npm run build

# 新建vue-demo
cd ../../../nginx/html
mkdir vue-demo

# 复制到托管目录
cd ../../vue-demo
yes | cp -r repository/vue-demo/dist/* ../nginx/html/vue-demo

7. 一键更新脚本

后续github上传代码后,在服务器任意位置使用 cd / && cd software/vue-demo && sh deploy_vue_demo.sh一键更新发布

#!/bin/bash
# 一键更新部署脚本,目录在:/software/vue-demo/下
# pull下来的网站代码仓库目录
input="repository/vue-demo"
# 挂载到容器的代码目录
output="../nginx/html/vue-demo"
cd $input

# 忽略本地,强制从线上更新下来
git fetch --all
git reset --hard origin/master 
git pull

# 打包
npm run build

# 备份
cd ../../$output && yes | cp -r * ../../../back/vue-demo
# 清空发布目录
rm -rf *
# 复制到发布目录
cd / && cd software/vue-demo && yes | cp -r $input/dist/* $output

# 文件名大写转小写
cd / && cd software/nginx/html && python3 conver.py "endoc" "l"

8. 一键回退脚本

cd / && cd software/vue-demo && sh back_deploy_vue_demo.sh

#!/bin/bash
# 一键回退脚本,目录在:/software/vue-demo/下
# 挂载html代码目录
output="../nginx/html/vue-demo"
# 清空发布目录
cd $output && rm -rf *
# 复制备份到发布目录
cd / && cd software/back/vue-demo && yes | cp -r * ../$output

参考

centos下安装 docker, git, node, python环境

1. git

yum install git

2. docker

centos下

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

或者参考docker-ce安装

3. node

1. install latest nvm

wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

if no any response,try curl:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

v0.35.3 is latest version currently i use, change the version if you need.learn more aboutnvm

if you get error

curl: (7) Failed connect to raw.githubusercontent.com:443; Connection reset by peer

just try open the https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh in browser,download install.sh file manually, then upload to your server, tap sudo bash install.sh manually.

2. solve commond not found

source ~/.nvm/nvm.sh

3. install node v12.X latest version

nvm install 12

4. check node version

node -v

4. python 3

udo yum install yum-utils
sudo yum-builddep python
curl -O https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz
tar xf Python-3.8.3.tgz
cd Python-3.8.3
./configure
make
sudo make install
alias python='/usr/local/bin/python3.8' #edit python command python3

windows docker 部署gogs / mysql / yapi / mongo

windows docker 部署gogs / mysql / yapi / mongo

environment

  1. docker for windows desktop
  2. docker configuration
{
  "registry-mirrors": [
    "http://hub-mirror.c.163.com",
    "https://registry.docker-cn.com"
  ],
  "insecure-registries": [],
  "debug": true,
  "experimental": false
}

gogs and mysql service

gogs and mysql network

docker network create --subnet 172.21.0.0/16 gogs_network

mysql

docker run --name my-mysql -p 3306:3306 -v C:/software/mysql:/var/lib/mysql --net gogs_network --ip 172.21.0.3 -e MYSQL_DATABASE=gogsdb -e MYSQL_USER=gogsuser -e MYSQL_PASSWORD=gogspwd -e MYSQL_ROOT_PASSWORD=gogspwd -e MYSQL_ALLOW_EMPTY_PASSWORD='yes' -d mysql

gogs

docker run --name my-gogs -p 1001:22 -p 1002:3000 -v C:/software/gogs/data:/data --net gogs_network --ip 172.21.0.2 gogs/gogs

yapi and mongo service

yapi and mongo network

docker network create --subnet 172.22.0.0/16 yapi_network

start mongo

docker volume create --name mongodata
docker volume create --name mongoconfigdb

docker run --name my-mongo -p 27017:27017 -v mongodata:/data/db -v mongoconfigdb:/data/configdb --net yapi_network --ip 172.22.0.3 -d mongo:4 --auth

mongo setting

# into mongo container
docker exec -it my-mongo mongo admin

# set admin user (root)
db.createUser({ user: 'admin', pwd: 'admin123456', roles: [ { role: "root", db: "admin" } ] });

# auth admin user
db.auth("admin", "admin123456")

# restart mongo
docker restart my-mongo

# into mongo container again
docker exec -it my-mongo mongo -u admin -p admin123456 --authenticationDatabase admin

# create yapi database
use yapi

# set yapi user
db.createUser({ 
    user: 'yapi', 
    pwd: 'yapi123456', 
    roles: [
        { role: "dbAdmin", db: "yapi" },
        { role: "readWrite", db: "yapi" } 
    ]
});

# auth yapi user
db.auth("yapi", "yapi123456")

yapi

docker build -t yapi .
docker run --name my-yapi -p 1003:3000 -p 1004:9090 -v C:/software/yapi/my-yapi:/my-yapi --net yapi_network --ip 172.22.0.2 -d yapi sh -c "yapi server"

deploy

open http://localhost:1004/ to deploy,get account:”admin@admin.com”, password:”ymfe.org”

change command restart serve

docker stop my-yapi
docker rm my-yapi
docker run --name my-yapi -p 1003:3000 -p 1004:9090 -v C:/software/yapi/my-yapi:/my-yapi --net yapi_network --ip 172.22.0.2 -d yapi sh -c "node my-yapi/vendors/server/app.js"

open http://localhost:1003/ to use

refer

https://hub.docker.com/_/mongo
https://www.cnblogs.com/woshimrf/p/docker-install-yapi.html
https://github.com/Ryan-Miao/docker-yapi
https://www.cnblogs.com/lori/p/7897003.html
https://segmentfault.com/q/1010000006128749

win10 网络发现局域网共享无效

win10发现不了同一网络的其他电脑 可以通过输入ping ip来进入别人的电脑,网络发现,网络共享都已启用,无效

问题

win10发现不了同一网络的其他电脑
可以通过输入ping ip来进入别人的电脑,网络发现,网络共享都已启用,无效

分析

问题在于新设备与旧设备关于5261SMB共享协议版本问题,新设备4102启用smb2.0,1709会默认关闭1653smb1.0功能,旧设备默认打开的

解决

打开控制面板——程序与功能——启用或关闭windows功能——smb1.0/cifs 文件共享支持,打上勾,重启解决

参考

https://zhidao.baidu.com/question/268187104464614965.html