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

本文介绍了一个文件权限管理的实现方案,包括文件共享、权限设置等功能。通过前端界面操作,利用AJAX请求与后端交互,实现文件的共享状态更改及权限分配。

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

wKiom1d_uvjwLs_IAABtoZkX9S0247.png

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

$(".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方法去共享。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

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请求,去修改传入文件的共享属性,看一下效果

wKiom1d_vNvTamX7AAASDfy2Q4A040.png

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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好之后,我们看一下共享文件权限设置界面。

wKioL1d_wjHQRRJAAACeCc0GwYw849.png

 

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

wKiom1d_wtPiluekAABhd0NeFyQ395.png

 

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

wKioL1d_wwayubJzAABALF21hNg124.png

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

$("#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获取。

1

2

3

4

5

6

7

8

var dataSource = new kendo.data.DataSource({

    transport: {

        read: {

            url: "/file/auth",

            dataType: "json"

        }

    }

});

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

1

2

3

4

var authArray = [];

$.get('/file/auth'function (result) {

    authArray = result;

});

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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去修改权限,看一下后台。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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再赋给下拉列表。

1

2

3

4

5

6

7

8

9

10

11

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,我们先看页面的代码。

wKiom1d_yLTx06NTAACSmsMSEe0041.png

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

1

2

3

fileAuthSchemas.authModel.find({}, function (error, doc) {

    res.render('authorization/docauth', { authArray: doc });

});

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

wKioL1d_yk7SDrZWAAAZgiCtUAQ554.png

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

$("#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代码。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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 });

        }

    });

}

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

wKioL1d_y36AsYJMAACdV_6SYNc024.png

 

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

原文转自:乐搏学院http://www.learnbo.com/front/article/cmsIndex

先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值