Node.js 切近實戰(六) 之Excel在線(文件列表)


 

wKioL1d4rXzww-FCAAEXnz2js-A748.png

看到了吧,這就是主界面,首先咱們來看一下My Document的View部分。在看View以前,咱們先看一下Mode的設計。javascript

1css

2html

3java

4正則表達式

5json

6bootstrap

7api

8微信

9app

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

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var authSchema = require('./fileauth.js');

 

require('string.prototype.endswith');

 

var fileSchema = new Schema({

    _id: Schema.Types.ObjectId,

    name: { type: String , trim: true, index: true },

    isshared: { type: Boolean, defaultfalse },

    content: { type: String , trim: true, select: false },

    createuserid: { type: String, index: { sparse: true } },

    createuser: { type: String},

    createdate: { type: Date, default: Date.now, index: { sparse: true } },

    lasteditdate: { type: Date, default: Date.now },

    lastedituserid: String,

    lastedituser: String,

    auth:[{ type: Schema.ObjectId, ref: 'fileauth' }]

}, {

    strict: true ,

    toObject: {

        virtuals: true

    },

    toJSON: {

        virtuals: true

    }

});

 

fileSchema.pre('update'function (next) {

    this.update({}, { $set: { lasteditdate: Date.now() } });

    next();

});

 

var fileSubGroupSchema = new Schema({

    _id: Schema.Types.ObjectId,

    name: { type: String, trim: true , required: true },

    userid: { type: String, required: true , index: true },

    file: [{ type: Schema.ObjectId, ref: 'file' }]

}, {

    strict: true

    toObject: {

        virtuals: true

    },

    toJSON: {

        virtuals: true

    }

});

 

var fileGroupSchema = new Schema({

    userid: { type: String, required: true , index: true },

    name: { type: String, trim: true , required: true },

    file: [{ type: Schema.ObjectId, ref: 'file' }],

    subgroup: [fileSubGroupSchema]

}, {

    strict: true

    toObject: {

        virtuals: true

    },

    toJSON: {

        virtuals: true

    }

});

咱們設計了文件Schema,fileSchema,注意這裏的sparse:true,意思是發散索引,即非彙集索引。

1

2

3

4

fileSchema.pre('update'function (next) {

    this.update({}, { $set: { lasteditdate: Date.now() } });

    next();

});

還有這裏,咱們預約義一個方法,當更新fileModel的時候,會先更新lasteditdate,再更新其餘字段,由於咱們更新的話,最後修改日期確定是當前時間,也不須要用戶每次都去傳,因此這裏預約義仍是頗有用處的。

接下來就是文件組和文件子組,總共兩級,文件組和包含文件和子組,子組只能包含文件,因此這裏設置及的時候,fileGroup中有個subgroup的定義,注意這裏的subgroup它不是一個引用ref,而是嵌入的文檔,是一個總體,可是它對file是隻是一個主鍵的引用。

最後咱們將這些定義好的model模塊化公開出去。

1

2

3

4

5

6

7

8

9

fileGroupSchema.set('collection''filegroups');

fileSchema.set('collection''files');

 

var fileGroupModel = mongoose.model("fileGroup", fileGroupSchema);

var fileModel = mongoose.model("file", fileSchema);

 

 

exports.fileGroupModel = fileGroupModel;

exports.fileModel = fileModel;

 

接下來咱們先看一下View頁面的定義。

1

2

3

4

5

6

7

8

9

#file_tab

  ul

   li View

   li Maintain

  include partial/docview.jade

  include partial/docedit.jade

 

block scripts

  script(type='text/javascript' src='/javascripts/local/doc/docself.js')

在個人文檔咱們包含了兩個頁面,dicview.jade和docedit.jade,看一下docview。

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

#view

  .row-margin-large

  label(style='font-size:17px') Owned Documents:

  span#div_ownTotal

  .line-height-30(style='width:100%')

    div(style='width:50%;float:left')   

      label Date:   

      input#dp_ownStart(onkeydown='return false;')   

      input#dp_ownEnd(onkeydown='return false;')   

    div(style='width:30%;float:left')   

      label File Name:   

      input#txt_ownFileName(type='text')   

    div(style='width:20%;float:left;text-align:center')   

      button#btn_searchOwn.k-button.k-primary Search

  .clear-float

  .row-margin 

  hr.panel-line  

  #div_own(style='min-height:350px')  

    div#div_retriveOwn(style='top:10%;left:45%;position:relative;display:none')  

      img(src='/stylesheets/images/loading-large.gif')  

      label(style='color:#666666') retriving......  

  .row-margin-large.clear-float

  #own_pager

  br   

  .row-margin-large

   label(style='font-size:17px') Shared Documents:

   span#div_sharedTotal

   .line-height-30(style='width:100%')

     div(style='width:50%;float:left')   

      label Date:  

      input#dp_shareStart(onkeydown='return false;')  

      input#dp_shareEnd(onkeydown='return false;')  

     div(style='width:30%;float:left')   

      label File Name: 

      input#txt_sharedFileName(type='text') 

     div(style='width:20%;float:left;text-align:center')   

      button#btn_searchShared.k-button.k-primary Search

   .clear-float

   .row-margin 

   hr.panel-line 

   #div_share(style='min-height:350px;margin-bottom:10px') 

     div#div_retriveShared(style='top:10%;left:45%;position:relative;display:none') 

       img(src='/stylesheets/images/loading-large.gif') 

       label(style='color:#666666') retriving......

   #shared_pager

這個頁面包含一個Owned Document和Shared Document,咱們看一下js部分。

1

2

3

4

5

6

7

8

9

10

11

 $("#txt_ownFileName").keydown(function (e) {

        if (e.keyCode == 13) {

            $("#btn_searchOwn").click();

        }

    });

     

    $("#btn_searchOwn").click(function () {

        getOwnedFileList();

    });

     

    $("#btn_searchOwn").click();

頁面load完成後,直接查詢。

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

function getOwnedFileList() {

        var fileName = $.trim($("#txt_ownFileName").val());

        var startDate = $("#dp_ownStart").data("kendoDatePicker").value();

        var endDate = $("#dp_ownEnd").data("kendoDatePicker").value();

         

        var postData = {

            fileName: fileName,

            startDate: startDate,

            endDate: endDate,

            pageIndex: $("#own_pager").data('kendoPager').page() - 1 < 0? 0:$("#own_pager").data('kendoPager').page() - 1,

            pageSize: $("#own_pager").data('kendoPager').pageSize(),

            userId: userObj.UserID

        };

         

        isOwnSearch = true;

        $("#div_retriveOwn").show();

        $.post('/file/owned/retrieve', { data: JSON.stringify(postData) } , function (data) {

            $("#div_retriveOwn").hide();

             

            var tempSource = [];

            for (var i = 0; i < data.totalCount; i++) {

                tempSource.push(i);

            }

             

            var dataSource = new kendo.data.DataSource({

                data: tempSource,

                pageSize: $("#own_pager").data('kendoPager').pageSize()

            });

             

             

            $("#own_pager").data('kendoPager').setDataSource(dataSource);

            $("#own_pager").data('kendoPager').page(postData.pageIndex + 1);

             

            $("#div_own").html('');

            $("#div_ownTotal").css('color''red').html('(0)');

            if (data.totalCount && data.totalCount > 0) {

                $("#div_ownTotal").css({ 'color''red' 'font-weight''bold' }).html("(" + data.totalCount + ")");

                for (var i = 0; i < data.files.length; i++) {

                    if (i % 10 == 0) {

                        $("#div_own").append('<div class="clear-float"/>');

                    }

                    $("#div_own").append('<div style="width:10%;float:left">' 

                    '<div class="row-margin center-align-text">' 

                    '<a href="javascript:void(0)" style="text-decoration: none;color:#666666">' 

                    '<img id="' + data.files[i]._id + '" class="excel-img" src="/images/excel.png"/></a>' 

                    '<div style="word-break: break-word; width:90px">' + data.files[i].name + '</div>' 

                    '</div></div>');

                }

                 

                $("#div_own img").each(function () {

                    $(this).dblclick(function () {

                        window.location.href = '/index?file_id=' + $(this).attr('id');

                    });

                });

            }

        });

    }

拼好查詢json對象後,post到api去查詢,而後根據返回的數據去構造kendoPager,最後咱們去構造文件列表,每一個文件在雙擊的時候,都會跳轉到index界面讀取文件的內容展現在kendospread sheet上。咱們看一下效果。

wKioL1d4tOLiAYAPAACOsn1Oj7g429.png

分頁,點擊2到第二頁

wKiom1d4tZvgUw6BAABRm97Ogr0127.png

分頁是沒有問題的,美觀大方。OK,對於Shared Document的js代碼,和上面的基本同樣。

wKiom1d4tzKy-U-HAABZ-kqq4Do613.png

看上去只是多了個tooltip的說明,其實這個效果是bootstrap提供的,咱們只須要寫以下的代碼便可。

1

2

3

4

5

6

7

8

 $("#div_share").append('<div style="width:10%;float:left">' 

                     '<div class="row-margin center-align-text tooltip-options" data-toggle="tooltip" data-placement="bottom" title="' + tooltipTemplate + '">' 

                     '<a href="javascript:void(0)" style="text-decoration: none;color:#666666">' 

                     '<img id="' + data.files[i]._id + '" class="excel-img" src="/images/excel_share.png"/></a>' 

                     '<div style="word-break: break-word;width:90px">' + data.files[i].name + '</div>' 

                     '</div></div>');

 

$("#div_share .tooltip-options").tooltip({ html : true });

OK最後咱們看一下rest api。

1

2

3

var fileRoutes = require('../controller/filemng.js');

router.post('/file/owned/retrieve', fileRoutes.getOwnedFileList);

router.post('/file/shared/retrieve', fileRoutes.getSharedFileList);

根據url咱們知道方法在filemng.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

exports.getOwnedFileList = function (req, res) {

    var data = JSON.parse(req.body.data);

    var fileName = data.fileName;

    var startDate = data.startDate;

    var endDate = data.endDate;

    var pageIndex = data.pageIndex;

    var pageSize = data.pageSize;

    var userId = data.userId;

     

    var query = fileModel.find({});

    query = query.where('createuserid', userId);

     

    if (fileName) {

        var regex = new RegExp(fileName, 'i');

        query = query.where('name', regex);

    }

     

    if (startDate && endDate) {

        query = query.where('createdate').gte(startDate).lte(endDate);

    }

     

    query.count().exec(function (error, count) {

        query.limit(pageSize).skip(pageIndex * pageSize).sort('-createdate')

        .exec("find"function (error, docs) {

            res.json({ files: docs, totalCount: count });

        });

    });

}

注意這裏的查詢,對於filename的模糊查詢,用正則表達式。對於日期的查詢,咱們用gte和lte,大於和小於。最後咱們先算出總數,再拿到分頁的數據,將數據拼成json對象輸出到客戶端。

用robomongo查了一下,確實也是22條數據

wKioL1d4uGDw_RgoAAFE11Sp7Pc490.png

共享的文件也只有2個

wKioL1d4uPnxBi_AAACYMwvjVdw149.png

OK,今天就到這裏,若是你們想要源碼,估計要到實戰15之後了,慢慢等吧。

 

結束語

 

免費學習更多精品課程,登陸樂搏學院官網http://h.learnbo.cn/

或關注咱們的官方微博微信,還有更多驚喜哦~

 

本文出自 「技術創造價值」 博客,請務必保留此出處http://leelei.blog.51cto.com/856755/1795164

相關文章
相關標籤/搜索