Node.js 切近实战(八) 之Excel在线(文件权限)

最近美国又他妈的皮痒了,在南海找事,还说什么中国必须接受南海仲裁结果,我去你大爷的,你以为你是谁啊。说实话只要我们要决一死战的勇气,还管什么华盛顿航母,佛吉尼亚潜艇,大不了大家一起死,不,全世界一起死。怎么个死法,中国惹急了先给俄罗斯来几颗核弹,然后俄罗斯反击中国的同时,也会给欧洲扔几颗核弹,给美国扔很多核弹,然后欧洲英法会给其他国家扔核弹,美国给世界扔核弹,俄罗斯只给北冰洋扔就行了,中国给美国和太平洋扔就行了,这样世界就不复存在了。

今天我们来看一下文件权限管理,这个其实是对共享出去的文件的一个简单的权限管理demo。在上节我写过的界面中,可以查询自己共享出去的文件。

勾选Shared,我们查出自己共享出去的文件。或者我们可以通过点击ToolBar上面的SHARE按钮,实现共享文件。

$(".k-grid-share", "#file_list").bind("click", function (ev) {
    var selIds = [];
    $("#file_list table:eq(1)").find("tr").each(function () {
        var chkElement = $(this).children("td:first").find("input[type=‘checkbox‘]").first();
        if (chkElement.prop(‘checked‘)) {
            selIds.push(chkElement.val());
        }
    });
    
    if (selIds.length == 0) {
        showMsg(‘info‘, ‘Please select at least one file to share!‘);
        return;
    }
    
    sharedUpdate(selIds, true);
});

首先是找到选中的文件的_id,然后调用shareUpdate方法去共享。

function sharedUpdate(selIds, shared) {
    msg = Messenger().post({
        message: "Do you want to " + (shared? ‘share‘:‘unshare‘) + " these file?",
        actions: {
            delete: {
                label: ‘Yes‘,
                delay: 10,
                action: function () {
                    var postData = {
                        ids: selIds,
                        isShared: shared
                    };
                    
                    $.ajax({
                        url: ‘/file/share‘, 
                        type: ‘PUT‘, 
                        dataType: ‘json‘,
                        data: { postData: JSON.stringify(postData) },
                        success: function (res) {
                            if (!res.isSuc) {
                                showMsg(‘error‘, res.msg);
                                return;
                            }
                            
                            getFilelist(selGroupId);
                        }
                    });
                    msg.hide();
                }
            },
            cancel: {
                label: "No",
                action: function () {
                    msg.hide();
                }
            }
        }
    });
}

发送一个ajax请求,去修改传入文件的共享属性,看一下效果

先会弹出确认,点击Yes,调用api file/share去修改共享属性,看一下后台。

router.put(‘/file/share‘, fileRoutes.fileShare);
exports.fileShare = function (req, res) {
    var data = JSON.parse(req.body.postData);
    var idArray = data.ids;
    
    if (!idArray || idArray == 0) {
        res.status(403).json(commonMsgRes.buildJsonErrorRes(‘NoRecord‘));
        return;
    }
    
    fileModel.update({ _id: { $in: idArray } }, { $set: { isshared: data.isShared } }, { multi: true }
, function (error, result) {
        if (error) {
            res.json({ isSuc: false, msg: error.message });
        }
        else {
            res.json({ isSuc: true });
        }
    });
}

在后台,先把json字符串转化成js对象,然后用mongoose提供的update方法去批量更新数据。注意这里的$in,其实是和sqlServer中的in一个意思,$set意思是需要修改的属性,你可以在这里写多个属性进行修改,并不一定只是一个isshared属性,然后最后的multi:true,意思是更新多个doc。所以整个修改的意思就是找到_id在idArray中的file docs,然后将其isshared属性全部修改为传入的值。当然在这里你也可以使用mongoose中的findAndUpdate方法去做批量更新。

文件share好之后,我们看一下共享文件权限设置界面。

查询出数据后,每个文件都可以设置权限,这里很简单的三个,要真做权限,还是买吉日嘎啦的走火入魔权限管理系统好了,自己不要瞎折腾。OK,那么这三个权限使我们mongodb数据库中配置的。

我们在界面可以选择一个或者多个。

选择完成后,点击Save,如果不想修改了,点击cancel,可以回到初始状态,我们来看一下js代码。

$("#file_list").kendoGrid({
    scrollable: true,
    allowCopy: true,
    resizable: false,
    sortable: true,
    height: 800,
    pageable: {
        refresh: true,
        pageSizes: [10, 20, 50, 100],
        buttonCount: 5,
    }, 
    toolbar: [{ name: ‘authSet‘, text: "Batch Setup" , imageClass: ‘k-icon k-i-lock‘ }],
    columns: [{
            template: "<div class=‘center-align-text‘>" +
                "<input id=‘chkId_#=_id#‘ type=‘checkbox‘ class=‘k-checkbox‘ value=‘#=_id#‘ onclick=‘chkHeader_cl
                + "<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: 45,
            sortable: false
        },
        {
            field: "fullname", 
            title: "File Name"
        },
        {
            field: "isshared", 
            title: "Shared" ,
            template: ‘<select id="ddl_auth#=_id#" name="auth" multiple="multiple"></select>‘,
            sortable: false
        }, {
            command: [
                {
                    name: "authUpdate",
                    text: "Save",
                    imageClass: "k-icon k-i-tick",
                    click: updateFileAuth
                }, {
                    name: "authCancel",
                    text: "Cancel",
                    imageClass: "k-icon k-i-undo",
                    click: cancelUpdateFileAuth
                }
            ], 
            width: 230,
            title: "Operation"
        }], dataBound: function (rowBoundEvent) {
        $("#file_list select[name=‘auth‘]").each(function (index, element) {
            $(element).kendoMultiSelect({
                valuePrimitive: true,
                placeholder: "---Please Select---",
                ignoreCase: true,
                dataSource: authArray.length > 0? authArray:dataSource,
                dataTextField: "name",
                dataValueField: "_id",
                headerTemplate: ‘<div class="multi-select-header">‘ 
                            + ‘Choose File Auth Below:</div>‘,
                dataBound: function (e) {
                    var dataItem = $("#file_list").data(‘kendoGrid‘).dataItem($(element).closest("tr"));
                    if (dataItem.auth && dataItem.auth.length > 0) {
                        var authArray = [];
                        dataItem.auth.forEach(function (v) {
                            authArray.push(v._id);
                        });
                        
                        this.value(authArray);
                    }
                    
                }
            });
        });
    }
});

大家注意isShared这一列,是个下拉列表,支持多选,然后在数据绑定完成以后,循环里面的下拉列表,将其渲染成kendoMultiSelect,注意这里的dataSource参数,如果authArray已经取到了,则使用,否则调用后台api获取。

var dataSource = new kendo.data.DataSource({
    transport: {
        read: {
            url: "/file/auth",
            dataType: "json"
        }
    }
});

如果在这里直接使用每次请求的话,会存在很多问题,性能问题,界面渲染也会出现一些重复渲染的问题。因为大家的auth都是一样的,所以我们先取到再说。

var authArray = [];
$.get(‘/file/auth‘, function (result) {
    authArray = result;
});

OK,接下来我们看一下Save功能,在grid的定义中,我们可以看到save调用的是updateFileAuth方法。

function updateFileAuth(e) {
    var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
    var fileId = dataItem._id;
    var authArray = $("#ddl_auth" + dataItem._id).data("kendoMultiSelect").value()
    
    if (!authArray || authArray.length == 0) {
        showMsg(‘info‘, ‘Please select at least one auth!‘);
        return;
    }
    
    var postData = {
        fileId: dataItem._id,
        fileAuth: authArray
    };
    
    $.post(‘/file/auth‘, postData, function (res) {
        if (!res.isSuc) {
            showMsg(‘error‘, res.msg);
            return;
        }
        
        showMsg(‘success‘, ‘Saved successfully!‘);
        $("#btn_searchShared").click();
    });
}

根据当前行拿到id,再根据id拿到下拉选中的值,kendoMultiSelect的value方法返回的就是一个数组。

最后我们将得到的数组传递到api去修改权限,看一下后台。

router.post(‘/file/auth‘, fileAuthRoutes.updateFileAuth);
exports.updateFileAuth = function (req, res) {
    var fileId = req.body.fileId;
    var fileAuth = req.body.fileAuth;
    var fileAuths = [];
    
    fileAuth.forEach(function (v) {
        fileAuths.push(mongoose.Types.ObjectId(v));
    });
    
    fileModel.findByIdAndUpdate(fileId, { ‘$set‘: { auth: fileAuths } }
        , function (error, doc) {
        console.log(error);
        if (error) {
            res.json({ isSuc: false, msg: error.message });
        }
        else {
            res.json({ isSuc: true });
        }
    });
}

在这里我们先将权限的id转化成ObjectId,再根据传入的文件id进行修改,ok,save就说完了。

再看一下cancel,其实就是将该行的权限id再赋给下拉列表。

function cancelUpdateFileAuth(e) {
    var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
    var fileId = dataItem._id;
    var authArray = [];
    if (dataItem != null && dataItem.auth.length > 0) {
        dataItem.auth.forEach(function (v) {
            authArray.push(v._id);
        });
    }
    $("#ddl_auth" + dataItem._id).data("kendoMultiSelect").value(authArray);
}

ok,最后就是batch批量设置,勾选数据,点击ToolBar上的BATCH SETUP,我们先看页面的代码。

这里的fileAuth_Window就是批量设置界面,在这里大家发现了一个循环的写法,不错,这就是jade模板中的语法,类似于razor视图引擎一样。看到这样的循环,我们在后台必须有代码要给页面这些值,类似于asp.net mvc中页面绑定的Model。

fileAuthSchemas.authModel.find({}, function (error, doc) {
    res.render(‘authorization/docauth‘, { authArray: doc });
});

看到了吧,在向客户端输出页面时,同时传了一个对象,对象中的authArray的值为doc。这样的话,我们就可以在页面直接使用这个变量authArray。

我们选择三个,点击SETUP,AJAX调用后台api批量设置。

$("#btn_setup").click(function () {
    var selAuthIdArray = getSelAuthId();
    if (selAuthIdArray.length == 0) {
        showMsg(‘info‘, ‘Please select at least one auth!‘);
        return;
    }
    
    var selIds = getSelFileId();
    if (selIds.length == 0) {
        showMsg(‘info‘, ‘Please select at least one file to setup!‘);
        return;
    }
    
    showConfirm(updateFileAuthBatch);
});

function updateFileAuthBatch() {
    var selIds = getSelFileId();
    if (selIds.length == 0) {
        showMsg(‘info‘, ‘Please select at least one file to setup!‘);
        return;
    }
    
    var postBody = {
        fileIdArray: selIds,
        fileAuth: getSelAuthId()
    };
    
    $.post(‘/file/auth/batch‘, postBody, function (result) {
        if (!result.isSuc) {
            showMsg(‘error‘, result.msg);
            return;
        }

        fileAuthWindow.data("kendoWindow").close();
        $("#btn_searchShared").click();
    });
}

function showConfirm(action) {
    msg = Messenger().post({
        message: "Do you want to setup?",
        actions: {
            save: {
                label: ‘Yes‘,
                delay: 10,
                action: function () {
                    action();
                    msg.hide();
                }
            },
            cancel: {
                label: "No",
                action: function () {
                    msg.hide();
                }
            }
        }
    });
}

上面这段代码有没有很像C#中的委托呢?有点。最后我们看一下后台的批量设置api代码。

exports.batchUpdateFileAuth = function (req, res) {
    var fileIdArray = req.body.fileIdArray;
    var fileAuth = req.body.fileAuth;
    var fileAuths = [];
    
    if (!fileIdArray || fileIdArray.length == 0) {
        res.json(commonMsgRes.buildJsonErrorRes(‘NoRecord‘));
        return;
    }
    
    fileAuth.forEach(function (v) {
        fileAuths.push(mongoose.Types.ObjectId(v));
    });
    
    fileModel.update({ _id: { $in: fileIdArray } }, { $set: { auth: fileAuths } }, { multi: true }
        , function (error, doc) {
        if (error) {
            res.json({ isSuc: false, msg: error.message });
        }
        else {
            res.json({ isSuc: true });
        }
    });
}

这样就设置成功了,我们来看一下效果。

好了,下节进入我们的关键点,Excel在线保存,编辑。

学习Telerik Kendo UI:http://demos.telerik.com/kendo-ui/grid/index

时间: 2025-01-16 08:32:42

Node.js 切近实战(八) 之Excel在线(文件权限)的相关文章

Node.js 切近实战(七) 之Excel在线(文件&文件组)

最近西安的天气真他妈的热,感觉还是青海的天气美,最高温28度.上周逛了青海湖,感觉还是意犹未尽,其实我还是很喜欢去一趟西藏的,但是考虑到花费也没人陪我,我暂时放弃这个念头.计划去一下重庆或者甘南,也许是现实的. OK,废话不多说,今天我们来看一下Excel在线部分的文件和文件组.首先我们来看一下页面,调一下胃口.俗话说无图无真相,先看图. 没错,还是Telerik Kendo UI,其实我面试的时候当听到别人说自己用的是EasyUI和ExtJs的时候,我就不那么上心,但是如果有人用的是Kendo

Node.js 切近实战(九) 之Excel在线(在线编辑)

最近实在是太想去西藏了,我自己总是喜欢人少的旅游地,喜欢一望无垠,喜欢蓝天白云大草原. 之前有一节我给大家讲过文件列表,如下,今天我们要讲的就是Excel在线编辑. 当我们双击文件图标的时候会跳转到一个Excel修改界面,如下. ok,这里我们使用的依然是Telerik Kendo UI中的SpreadSheet,看一下这个Spread Sheet是如何用的. 我们定义一个spreadsheet的div,我们看一下这个div怎么生成sheet. $("#spreadsheet").ke

Node.js 切近实战(十) 之Excel在线(共享文件)

本篇文章我就不罗嗦了,主要讲的是共享文件列表,主要功能就是查看别人共享的文件. 打开该界面,用户可以在左侧看到共享文件的人员的信息,点击该人可以查看该人共享了哪些文件.在Grid里面有查看文件修改记录,编辑,标记为星标文件等功能.OK,我们先看一下UI代码. div(style='padding:5px;')  include ../common/search.jade .row-margin  hr.panel-line   #splitter(style='height:750px;')  

Node.js 切近实战(六) 之Excel在线

终于如愿以偿的去了趟青海湖,感觉美美的.我想着老了(50岁),去那里帮牧民看牦牛,放羊.看着蓝天白云,一望无际碧绿的湖水,想想写程序的这些年,想想城市生活,想想人的一生到底是为了什么,人的一生难道只是为了比别人有钱,比别人赚更多的钱.万一想不通,就去塔尔寺面试,当个和尚喇嘛什么的.如果人家不收我,就在寺庙朝拜10万次,靠着虔诚的心我也能积攒些许功德.

Node.js 切近实战(二) 之图书管理系统

上一篇Node.Js切近实战讲述了如何在VS上搭建Node.Js开发环境,相信看过那篇博客的同学,你已经对Node.Js有了好感,多了解些技术还是很有必要的.所谓实战见真功,还是要实战才行.我看博客园上一些专家荣誉的人写的博客,全是理论,没有实战,没有实战就没有发言权.熟能生巧,实战出理论. 我们看一下项目结构 典型的NodeJs三层架构,controller,model,view,这里每个部分什么职能,我就不多说了. 首先我们看一下登录界面,先上图,我看博客的时候,会首先看博客中有没有图,比如

Node.js 切近实战(十一) 之实时通讯

曾经在幽幽暗暗反反复复中追问,才知道平平淡淡从从容容才是真,听着歌曲,写博客,感觉就来了. 今天我们主要看一下Socket.IO实时通讯,先看一下界面. .row  .col-md-9   .panel.panel-primary    .panel-heading     h3.panel-title(style='font-size:13px;') Chat Message    .panel-body#div_msgbody(style='min-height:590px;max-heig

Node.js 切近实战(一) 之环境搭建

哥们先来吐槽一下,最近面试别人的一些经历.有的小伙干了五年,这五年干的是同样的活,三层架构,ASP.NET MVC,Jquery.看简历还能用,结果面试中才知道这五年自己没写过泛型类,泛型方法,委托自定义事件也都没用过,还说抽象类中必须都是抽象方法才可以.还有一小伙,干了十年,泛型委托一概不清楚.最近有个干了9年的,也呆过几家外企,感觉还挺牛,来了之后果然牛,敲着个二郎腿,声音比我还大,搞得好像他在面试我.9年了,只会最常用的一些东西,asp.net mvc,asp.net webforms,W

Node.js 切近实战(十二) 之Linux部署

之前的话我们的项目都是跑在windows上,今天我们要将我们的程序跑到linxu机器上.在看linux部署之前,我们先看一下node.js类似于asp.net mvc的过滤器或者叫拦截器.在app.js中我们加入如下代码 var beforeRequest = function (req, res, next) {     if (req.originalUrl == '/'          || req.originalUrl == '/login'          || req.orig

Node.js 切近实战(二) 之图书管理系统(图书信息录入)

上一节我们讲了图书管理系统的登录,相信大家对jade模板和angular js也有了了解,今天的话我们来看一下图书信息录入.在这里我们准备使用Nosql数据库,本篇博客中使用的是MongoDB.OK.Mongo DB的安装我就不多说了,那么Node.Js平台使用mongoDB我们使用什么扩展包好呢,我觉得还是mongoose比较合适,封装了好多针对mongodb的方法,简单易用. 首先我们来看一下图书model的设计bookInfo.js. var mongoose = require('mon