node.js切近实战之excel在线(文件&文件组)

author author     2022-07-31     784

关键词:

最近西安的天气真他妈的热,感觉还是青海的天气美,最高温28度。上周逛了青海湖,感觉还是意犹未尽,其实我还是很喜欢去一趟西藏的,但是考虑到花费也没人陪我,我暂时放弃这个念头。计划去一下重庆或者甘南,也许是现实的。

OK,废话不多说,今天我们来看一下Excel在线部分的文件和文件组。首先我们来看一下页面,调一下胃口。俗话说无图无真相,先看图。

技术分享

没错,还是Telerik Kendo UI,其实我面试的时候当听到别人说自己用的是EasyUI和ExtJs的时候,我就不那么上心,但是如果有人用的是Kendo UI for Html5&JS的话,我就会多关注一点。

先看一下页面整体代码。

技术分享

很简单,还是BootStrap布局,jade模板。注意下最底下的css样式,在jade模板中,如果想要在页面定义css,就要像上面这样写。注意这里我们引用了一个部分页,popup.jade,里面其实就是第一幅图里面New,Rename等按钮弹出的modal页。

技术分享

OK,首先我们看到的是左边的树,这个树叫kendoTreeView,我们来看一下这个树是怎么生成的。

var url = "/filegroup/list/" + userObj.UserID;
var dataSource = new kendo.data.HierarchicalDataSource({
        transport: {
            read: {
                url: url,
                dataType: "json"
            }
        },
        schema: {
            model: {
                id: "_id",
                children: "subgroup",
                expanded: true,
                hasChildren: function (node) {
                    return (node.subgroup && node.subgroup.length > 0);
                },
                spriteCssClass: "folder"
            }
        }
});
    
$("#treeview-filegroup").kendoTreeView({
        dataSource: dataSource,
        dataTextField: ["filecount"],
        dataValueField: ["_id"],
        change: function (e) {
            var tree = e.sender;
            selNode = tree.select();
            var data = tree.dataItem(selNode);
            
            if (data._id) {
                selGroupId = data._id;
                $("#chk_all").prop(‘checked‘, false);
                getFilelist(data._id);
            }
        }
    });

OK,这段代码就是生成树的代码,注意这里的dataSource,当页面加载以后,会请求url,filegroup/list/{0},我们来看一下后台这个api。

router.get(‘/filegroup/list/:userId‘, fileRoutes.fileGroupList);

再看一下fileGroupList方法。

exports.fileGroupList = function (req, res) {
    fileGroupModel.find({ ‘userid‘: req.params.userId }, null, { sort: { name: 1 } } , function (error, fileGroup) {
        res.json(fileGroup);
    });
}

其实就是根据传入的userid查询了一下fileGroup Collection,查出来后,注意这里的schema,它的model定义树节点id是我们mongodb的主键,children是subgroup(上节讲过group和subgroup的model定义,不明白的去上节看),hasChildrenC返回是否有子节点。spriteCssClass设置父节点样式,注意我们第一幅图定义的页面样式就用在这里。OK,接下里我们看树的change事件,当有选中的节点时,将右边列表表头的全选复选框uncheck,并根据选中的_id去mongodb查询group下面的数据,我们来看一下getFilelist方法。

function getFilelist(groupId) {
    if (!groupId) return;
    
    $.get("/filegroup/" + groupId, function (result) {
        var grid = $("#file_list").data("kendoGrid");
        if (result) {
            var dataSource = new kendo.data.DataSource({
                pageSize: 10,
                data: result,
                schema: {
                    parse: function (response) {
                        $.each(response, function (idx, elem) {
                            if (elem.createdate && typeof elem.createdate === "string") {
                                elem.createdate = kendo.parseDate(elem.createdate, "yyyy-MM-ddTHH:mm:ss.fffZ");
                            }
                            
                            if (elem.lasteditdate && typeof elem.lasteditdate === "string") {
                                elem.lasteditdate = kendo.parseDate(elem.lasteditdate, "yyyy-MM-ddTHH:mm:ss.fffZ");
                            }
                        });
                        return response;
                    }
                }
            });
            
            grid.setDataSource(dataSource);
        }
        else {
            grid.dataSource.data([]);
        }
    });
}

直接调用rest api filegroup/{0}查询数据,得到结果以后,构造kendo Grid的dataSource,对日期进行格式化。

router.get(‘/filegroup/:id‘, fileRoutes.fileGroup);
exports.fileGroup = function (req, res) {
    var groupId = req.params.id;
    fileGroupModel.findById(groupId).populate(‘file‘).exec(function (error, doc) {
        if (!doc || doc.length == 0) {
            fileGroupModel.findOne({ ‘subgroup._id‘: groupId })
            .populate(‘subgroup‘)
            .populate(‘subgroup.file‘)
            .exec(function (error, docs) {
                if (docs) {
                    var subGroupIndex = -1;
                    docs.subgroup.forEach(function (element, index, arra) {
                        if (subGroupIndex > -1) return;
                        
                        if (element._id == groupId) {
                            subGroupIndex = index;
                        }
                    });
                    
                    if (subGroupIndex > -1) {
                        res.json(docs.subgroup[subGroupIndex].file);
                    }
                }
            });
        }
        else {
            res.json(doc.file);
        }
    });
}

这里要注意,首先我们也不知道这里传入的是groupId还是subgroupId,所以我们先拿groupId查询,如果查到了,就返回数据,如果没查到,就拿_id去查subgroup,查询subgroup,注意这里要使用subgroup._id作为查询条件,因为subgroup是嵌入在group中的,是一个整体。查完之后注意这里的两个populate,如果没有populate的话,意味着这些嵌入的subgroup以及引用的file都不会被包含在查询结果中,我们来看一下查询的结果,在后台加一句console.log(docs)即可。有两个subgroup,两个下面都有文件。

技术分享

我们用robomongo也许看的更清晰一些,两个group,一个下面有7个文件,一个有2个文件。

技术分享

此时这个结果的话,我们还得找到我们页面传递的_id对应的subgroup下面的file。所以在代码中又有了循环匹配id确定subgroup索引下标的过程,找到后,直接根据索引拿出file。是不是很麻烦,如果你有什么好的办法,可以给我留言。

接下来我们来看一下kendo grid,首先看一下这个全选。

$("#chk_all").click(function () {
    var isChecked = $(this).prop("checked");
    $("#file_list table:eq(1)").find("tr").each(function () {
        $(this).children("td:first").find("input[type=‘checkbox‘]").first().prop(‘checked‘, isChecked);
    });
});

看起来很简单,找到第一个table找到所有tr,再找到第一个td,锁定checkbox让它选中或者不选中。

$("#file_list").kendoGrid({
        scrollable: true,
        selectable: true,
        allowCopy: true,
        resizable: false,
        sortable: true,
        pageable: {
            refresh: true,
            pageSizes: [10, 20, 50, 100],
            buttonCount: 5
        },
        toolbar: [
            { name: ‘share‘, imageClass: ‘glyphicon glyphicon-share-alt‘ },
            { name: ‘unshare‘, imageClass: ‘glyphicon glyphicon-lock‘ },
            { name: ‘batch_delete‘, text: "Delete" , imageClass: ‘glyphicon glyphicon-trash‘ }, 
            { name: ‘export‘, imageClass: ‘k-icon k-i-excel‘ }],
        columns: [{
                template: "<div class=‘center-align-text‘>" +
                    "<input id=‘chkId_#=_id#‘ type=‘checkbox‘ class=‘k-checkbox‘ value=‘#=_id#‘ onclick=‘chkHeader_click‘/>" 
                    + "<label class=‘k-checkbox-label‘ for=‘chkId_#=_id#‘></label></div>",
                field: "",
                title: "<div class=‘center-align-text‘>" +
                    "<input type=‘checkbox‘ class=‘k-checkbox‘ id=‘chk_all‘/>" 
                    + "<label class=‘k-checkbox-label‘ for=‘chk_all‘></label></div>",
                width: 40
            },
            {
                field: "fullname", 
                title: "File Name"
            }, {
                field: "isshared", 
                title: "Shared" ,
                width: 85, 
                template: "<div><input type=‘checkbox‘ class=‘k-checkbox‘ value=‘#=isshared#‘ #=isshared ? "checked=‘checked‘":"" # />" 
                + "<label class=‘k-checkbox-label‘></label></div>",
                sortable: false
            },
            {
                command: [
                    {
                        name: "preview",
                        text: "", 
                        imageClass: ‘glyphicon glyphicon-search‘,
                        click: showDetails
                    }, {
                        name: "delete",
                        text: "", 
                        imageClass: ‘glyphicon glyphicon-trash‘,
                        click: confirmFileDelete
                    }, {
                        name: "rename",
                        text: "",
                        imageClass: ‘glyphicon glyphicon-list-alt‘,
                        click: fileRename
                    }, {
                        name: "edits", 
                        text: "", 
                        imageClass: ‘glyphicon glyphicon-pencil‘,
                        click: viewfile
                    }
                ], 
                width: 310,
                title: "Operation"
            }]
    });

注意grid中的Shared列,使用的是kendo的模板#=#这种写法。最后我们再看一下command列,这个列的话其实就是定义一些按钮,每个按钮都定义好了click事件。就看第一个showDetails,看看js代码

function showDetails(e) {
    var wnd = $("#wd_details").kendoWindow({
        title: "File Detail Info",
        modal: true,
        visible: false,
        resizable: false,
        minWidth: 300
    }).data("kendoWindow");
    
    var detailsTemplate = kendo.template($("#popup_detail").html());
    e.preventDefault();
    
    var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
    wnd.content(detailsTemplate(dataItem));
    wnd.center().open();
}

在这里其实就是弹出一个kendo window,这个弹出页中又加载了kendo 模板popup_detail,我们来看一下这个template。

script#popup_detail(type="text/x-kendo-template")
 dl
  dt
   label File Name:
  dd #=fullname#
  dt
   label Shared:
  dd #=isshared#
  dt
   label CreateDate:
  dd #=kendo.toString(createdate,‘MM/dd/yyyy HH:mm tt‘)#
  dt
   label LastEditUser:
  dd #=lastedituser#
  dt
   label LastEditDate:
  dd #=kendo.toString(lasteditdate,‘MM/dd/yyyy HH:mm tt‘)#

只要我们将一个对象给模板,模板就会自己替换对应的内容。在这里我们会先拿到点击行的对象,然后通过.content赋给模板,最后弹出modal页。

技术分享

就是这么简单,点击重命名按钮,就会弹出重命名页面。

技术分享

rename功能其实很简单,看看前台和后台。

$("#btn_fileRename").click(function () {
    var fileName = $.trim($("#new_fileName").val());
    if (!fileName) {
        showMsg("info", "Please input new file name!");
        return;
    }
    
    var postData = {
        id: $("#hfd_fileId").val(),
        filename: fileName
    };
    
    $.ajax({
        url: ‘/file/rename‘, 
        type: ‘PUT‘, 
        dataType: ‘json‘,
        data: { postData: JSON.stringify(postData) },
        success: function (res) {
            if (!res.isSuc) {
                showMsg(‘error‘, res.msg);
                return;
            }
            
            $("#wd_fileRename").data("kendoWindow").close();
            getFilelist(selGroupId);
        }
    });
});
router.put(‘/file/rename‘, fileRoutes.fileRename);
exports.fileRename = function (req, res) {
    var data = JSON.parse(req.body.postData);
    fileModel.findByIdAndUpdate(data.id, { $set: { name: data.filename, lasteditdate: Date.now() } }
        , function (error, result) {
        if (error) {
            res.json({ isSuc: false, msg: error.message });
        }
        else {
            res.json({ isSuc: true });
        }
    });
}

nodejs,用起来就是这么爽,好了今天就到这里,明天我们继续会讲剩下的group&subgroup创建,文件删除,共享设置等功能,敬请期待。

本文出自 “技术创造价值” 博客,请务必保留此出处http://leelei.blog.51cto.com/856755/1795764

node.js切近实战之linux部署

之前的话我们的项目都是跑在windows上,今天我们要将我们的程序跑到linxu机器上。在看linux部署之前,我们先看一下node.js类似于asp.netmvc的过滤器或者叫拦截器。在app.js中我们加入如下代码var beforeRequest = function (req... 查看详情

node.js实战之node多进程与jxcore打包深入运用(代码片段)

@[toc]JXcore打包Jxcore是一个支持多线程JS发布版本的节点,基本上不需要对现有代码进行任何更改,可以直接在多线程中运行,具有线程安全性。本文主要介绍jxcore的封装功能。下载jxcore安装包并解压缩。解压目录中提供了JX二进... 查看详情

云原生之docker实战使用docker部署zfile在线文件目录程序

【云原生之Docker实战】使用Docker部署zfile在线文件目录程序一、Zfile介绍1.Zfile简介2.Zfile特点二、检查docker状态1.检查docker版本2.检查docker状态三、安装docker-compose1.下载docker-compose二进制包2.给文件增加执行权限3.检查docker-compose版... 查看详情

node读写excel操作

目支持写Excel的node.js模块:node-xlsx:基于Node.js解析excel文件数据及生成excel文件;excel-parser:基于Node.js解析excel文件数据,支持xls及xlsx格式文件;excel-export:基于Node.js将数据生成导出excel文件,生成文件格式为xlsx;node-xlrd:基于node.js... 查看详情

node.js之文件下载(代码片段)

Node.js之文件下载,主要最近解决我的一个需求。需求描述:如何将腾讯云上传的文件存储到本地某个目录下,如果用js来实现,纯JavaScript没有这样的功能(也许有),正好我这个项目用node.js比较多,正好可以利用node.js丰富的API实现... 查看详情

node.js学习笔记之写文件

node.js之写文件//---------------optfile.js------------------var fs= require(‘fs‘);module.exports={  writefile:function(path,data){  //异步方式    fs.writeFile 查看详情

es实战之数据导出成csv文件

...数据生成文件并下载本篇主要是将第二步,第一步在《es实战之查询大量数据》中已讲述。csvvsexcelexcel2003不能超过65536,excel2007及以上版本支持1048576条数据。excel支持的数据量有限,并且生生成文件的速度比较慢。csv具有支持写... 查看详情

使用nodejs处理excel文件

参考技术Anode-xlsx:基于Node.js解析excel文件数据及生成excel文件;excel-parser:基于Node.js解析excel文件数据,支持xls及xlsx格式文件;excel-export:基于Node.js将数据生成导出excel文件,生成文件格式为xlsx;node-xlrd:基于node.js从excel文件中提取... 查看详情

实战系列之node.js玩转java

这些年以来,Node.js的兴起,JavaScript已经从当年的“世界最被误解的语言”变成了“世界最流行的语言”。且其发展之势,从语言本身的进化,库和包的增长,工具支持的完善,star项目和领域解决方案的涌现,平台... 查看详情

node.js之读取csv文件

varfs=require("fs");fs.readFile(‘123.csv‘,function(err,data){vartable=newArray();if(err){console.log(err.stack);return;}ConvertToTable(data,function(table){console.log(table);})});console.log("程序执行完毕" 查看详情

如何使用 HTML 输入文件导入 excel 文件并在 Node.js 中读取文件内容(如何将完整路径发送到 Node.js)

】如何使用HTML输入文件导入excel文件并在Node.js中读取文件内容(如何将完整路径发送到Node.js)【英文标题】:HowtoimportexcelfileusingHTMLInputfileandreadthefilecontentsinNode.js(HowtosendthefullpathtoNode.js)【发布时间】:2020-11-0600:15:08【问题描述... 查看详情

如何使用 node.js 将 EXCEL 文件数据读取到 json

】如何使用node.js将EXCEL文件数据读取到json【英文标题】:HowtoreadEXCELfiledatatojsonusingnode.js【发布时间】:2017-07-1201:17:42【问题描述】:如何使用node.js将EXCEL文件数据读入json文件夹的路径在服务器之外即,计算机中的任何位置,例... 查看详情

node.js学习笔记之读文件

 直接读硬盘上aa.txt内容var  http  =  require(‘http‘);var  optfile  =  require(‘./models/optfile‘);http.createServer(function  (reques 查看详情

使用 Node JS 连接到在线托管的 PostgreSQL

】使用NodeJS连接到在线托管的PostgreSQL【英文标题】:ConnectingtoPostgresSQLhostedonlineusingNodeJS【发布时间】:2021-11-1311:49:57【问题描述】:我目前正在尝试从数据库创建一个功能查询以将其发布到创建的csv文件中,但是我无法以编程... 查看详情

node.js之文件及文件流(fs,path,buffer,stream)(代码片段)

文件操作1文件模块fsfs模块---》操作文件---》io----》node的特长fs模块是node非常重要的模块,能体现出node的优势fs.readFile()读文件fs.writeFile()写文件fs.appendFile()在文件的内部去追加写一些内容fs.mkdir()创建文件夹fs.readdir()读文件... 查看详情

如何从 node.js 服务器提供 word、excel、ppt 和 pdf 文件

】如何从node.js服务器提供word、excel、ppt和pdf文件【英文标题】:Howtoserveword,excel,pptandpdffilesfromnode.jsserver【发布时间】:2021-10-1905:26:08【问题描述】:我已成功将文件从mongoDB上传到我的node.js服务器屏幕截图如下:clickheretoseeScreen... 查看详情

node.js读写文件之批量替换图片

  问题:文件夹A中有大量图片文件,需要用另外一个图片替换掉A中图片,但是命名保持不变。  手工的做法如下:  1)浏览器打开图片->2)另存为->3)目标文件夹->4)找到一个图片->5)替换->6)... 查看详情

在node.js中使用ejsexcel输出excel文件

1、背景在Nodejs应用程序中输出Excel,第一印象想到的一般是node-xlsx,这类插件不仅需要我们通过JS写入数据,还需要通过JS进行EXCEL显示样式的管理。这是个大问题,不仅代码冗余,而且非常不易于维护,假设业务需要合并一个单... 查看详情