浏览代码

实现项目和文档锁定功能

Minho 7 年之前
父节点
当前提交
de5f7301f0

+ 127 - 30
controllers/DocumentController.go

@@ -54,7 +54,7 @@ func (c *DocumentController) Index() {
 
 	bookResult := isReadable(identify, token, c)
 
-	c.TplName = "document/" + bookResult.Theme + "_read.tpl"
+	c.TplName = fmt.Sprintf("document/%s_read.tpl",bookResult.Theme)
 
 	selected := 0
 
@@ -243,7 +243,7 @@ func (c *DocumentController) Edit() {
 	} else if bookResult.Editor == "html" {
 		c.TplName = "document/new_html_edit_template.tpl"
 	} else {
-		c.TplName = "document/" + bookResult.Editor + "_edit_template.tpl"
+		c.TplName = fmt.Sprintf("document/%s_edit_template.tpl", bookResult.Editor)
 	}
 
 	c.Data["Model"] = bookResult
@@ -260,6 +260,11 @@ func (c *DocumentController) Edit() {
 		beego.Error("FindDocumentTree => ", err)
 	} else {
 		if len(trees) > 0 {
+			for _,tree := range trees {
+				if tree.Type == "lock" {
+					tree.DocumentName = tree.DocumentName + "<span class='lock-text'> [锁定]</span>"
+				}
+			}
 			if jtree, err := json.Marshal(trees); err == nil {
 				c.Data["Result"] = template.JS(string(jtree))
 			}
@@ -297,6 +302,9 @@ func (c *DocumentController) Create() {
 			beego.Error(err)
 			c.JsonResult(6002, "项目不存在或权限不足")
 		}
+		if book.IsLock == 1 {
+			c.JsonResult(6004,"已锁定的项目不能创建文档")
+		}
 
 		bookId = book.BookId
 	} else {
@@ -306,7 +314,9 @@ func (c *DocumentController) Create() {
 			beego.Error("FindByIdentify => ", err)
 			c.JsonResult(6002, "项目不存在或权限不足")
 		}
-
+		if bookResult.IsLock  {
+			c.JsonResult(6004,"已锁定的项目不能创建文档")
+		}
 		bookId = bookResult.BookId
 	}
 
@@ -349,7 +359,7 @@ func (c *DocumentController) Create() {
 // 上传附件或图片
 func (c *DocumentController) Upload() {
 	identify := c.GetString("identify")
-	doc_id, _ := c.GetInt("doc_id")
+	docId, _ := c.GetInt("doc_id")
 	is_attach := true
 
 	if identify == "" {
@@ -402,6 +412,9 @@ func (c *DocumentController) Upload() {
 		if err != nil {
 			c.JsonResult(6006, "文档不存在或权限不足")
 		}
+		if book.IsLock == 1 {
+			c.JsonResult(6004,"已锁定的项目不能上传文件")
+		}
 
 		bookId = book.BookId
 	} else {
@@ -421,11 +434,14 @@ func (c *DocumentController) Upload() {
 			c.JsonResult(6006, "权限不足")
 		}
 
+		if book.IsLock  {
+			c.JsonResult(6004,"已锁定的项目不能上传文件")
+		}
 		bookId = book.BookId
 	}
 
-	if doc_id > 0 {
-		doc, err := models.NewDocument().Find(doc_id)
+	if docId > 0 {
+		doc, err := models.NewDocument().Find(docId)
 		if err != nil {
 			c.JsonResult(6007, "文档不存在")
 		}
@@ -433,6 +449,9 @@ func (c *DocumentController) Upload() {
 		if doc.BookId != bookId {
 			c.JsonResult(6008, "文档不属于指定的项目")
 		}
+		if doc.IsLock == 1 {
+			c.JsonResult(6004,"已锁定的文档不能上传文件")
+		}
 	}
 
 	fileName := "attach_" + strconv.FormatInt(time.Now().UnixNano(), 16)
@@ -456,14 +475,14 @@ func (c *DocumentController) Upload() {
 	attachment.CreateAt = c.Member.MemberId
 	attachment.FileExt = ext
 	attachment.FilePath = strings.TrimPrefix(filePath, conf.WorkingDirectory)
-	attachment.DocumentId = doc_id
+	attachment.DocumentId = docId
 
 	if fileInfo, err := os.Stat(filePath); err == nil {
 		attachment.FileSize = float64(fileInfo.Size())
 	}
 
-	if doc_id > 0 {
-		attachment.DocumentId = doc_id
+	if docId > 0 {
+		attachment.DocumentId = docId
 	}
 
 	if strings.EqualFold(ext, ".jpg") || strings.EqualFold(ext, ".jpeg") || strings.EqualFold(ext, ".png") || strings.EqualFold(ext, ".gif") {
@@ -568,13 +587,13 @@ func (c *DocumentController) DownloadAttachment() {
 // 删除附件
 func (c *DocumentController) RemoveAttachment() {
 	c.Prepare()
-	attach_id, _ := c.GetInt("attach_id")
+	attachId, _ := c.GetInt("attach_id")
 
-	if attach_id <= 0 {
+	if attachId <= 0 {
 		c.JsonResult(6001, "参数错误")
 	}
 
-	attach, err := models.NewAttachment().Find(attach_id)
+	attach, err := models.NewAttachment().Find(attachId)
 
 	if err != nil {
 		beego.Error(err)
@@ -587,8 +606,11 @@ func (c *DocumentController) RemoveAttachment() {
 		beego.Error(err)
 		c.JsonResult(6003, "文档不存在")
 	}
+	if document.IsLockBook(document.DocumentId) {
+		c.JsonResult(6004,"已锁定的项目不能删除附件")
+	}
 	if document.IsLock == 1 {
-		c.JsonResult(6004,"不能编辑已锁定的文档")
+		c.JsonResult(6004,"已锁定的文档不能删除附件")
 	}
 	if c.Member.Role != conf.MemberSuperRole {
 		rel, err := models.NewRelationship().FindByBookIdAndMemberId(document.BookId, c.Member.MemberId)
@@ -737,6 +759,9 @@ func (c *DocumentController) Content() {
 			beego.Info("%d|", version, doc.Version)
 			c.JsonResult(6005, "文档已被修改确定要覆盖吗?")
 		}
+		if doc.IsLock == 1 {
+			c.JsonResult(6003,"锁定的项目不能编辑")
+		}
 
 		history := models.NewDocumentHistory()
 		history.DocumentId = docId
@@ -798,23 +823,6 @@ func (c *DocumentController) Content() {
 
 	c.JsonResult(0, "ok", doc)
 }
-//
-//func (c *DocumentController) GetDocumentById(id string) (doc *models.Document, err error) {
-//	doc = models.NewDocument()
-//	if doc_id, err := strconv.Atoi(id); err == nil {
-//		doc, err = doc.Find(doc_id)
-//		if err != nil {
-//			return nil, err
-//		}
-//	} else {
-//		doc, err = doc.FindByFieldFirst("identify", id)
-//		if err != nil {
-//			return nil, err
-//		}
-//	}
-//
-//	return doc, nil
-//}
 
 // 导出
 func (c *DocumentController) Export() {
@@ -1043,6 +1051,7 @@ func (c *DocumentController) History() {
 	}
 }
 
+//删除文档历史
 func (c *DocumentController) DeleteHistory() {
 	c.Prepare()
 
@@ -1101,6 +1110,7 @@ func (c *DocumentController) DeleteHistory() {
 	c.JsonResult(0, "ok")
 }
 
+//重置文档历史
 func (c *DocumentController) RestoreHistory() {
 	c.Prepare()
 
@@ -1158,6 +1168,7 @@ func (c *DocumentController) RestoreHistory() {
 	c.JsonResult(0, "ok", doc)
 }
 
+//比较文档
 func (c *DocumentController) Compare() {
 	c.Prepare()
 
@@ -1221,6 +1232,92 @@ func (c *DocumentController) Compare() {
 	}
 }
 
+//锁定文档
+func (c *DocumentController) Lock() {
+	docId, _ := c.GetInt("doc_id", 0)
+	identify := c.GetString("identify")
+	// 如果是超级管理员则不判断权限
+	if c.Member.IsAdministrator() {
+		book, err := models.NewBook().FindByFieldFirst("identify", identify)
+		if err != nil {
+			beego.Error(err)
+			c.JsonResult(6002, "项目不存在或权限不足")
+		}
+
+		if book.IsLock == 1 {
+			c.JsonResult(6001,"项目已锁定")
+		}
+	} else {
+		bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
+
+		if err != nil || bookResult.RoleId == conf.BookObserver {
+			beego.Error("FindByIdentify => ", err)
+			c.JsonResult(6002, "项目不存在或权限不足")
+		}
+		if bookResult.IsLock {
+			c.JsonResult(6001,"项目已锁定")
+		}
+	}
+	document, err := models.NewDocument().Find(docId)
+
+	if err != nil {
+		beego.Error("获取文档失败 =>",err)
+		c.JsonResult(6004,"文档不存在")
+	}
+	if document.IsLock == 1 {
+		c.JsonResult(6005,"文档已锁定")
+	}
+	document.IsLock = 1
+	if err := document.InsertOrUpdate();err != nil {
+		beego.Error("锁定文档失败 =>",err)
+		c.JsonResult(6006,"锁定文档失败")
+	}
+	c.JsonResult(0, "文档已锁定", document)
+}
+
+// 解锁文档
+func (c *DocumentController) UnLock()  {
+	docId, _ := c.GetInt("doc_id", 0)
+	identify := c.GetString("identify")
+	// 如果是超级管理员则不判断权限
+	if c.Member.IsAdministrator() {
+		book, err := models.NewBook().FindByFieldFirst("identify", identify)
+		if err != nil {
+			beego.Error(err)
+			c.JsonResult(6002, "项目不存在或权限不足")
+		}
+
+		if book.IsLock == 1 {
+			c.JsonResult(6001,"项目已锁定")
+		}
+	} else {
+		bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
+
+		if err != nil || bookResult.RoleId == conf.BookObserver {
+			beego.Error("FindByIdentify => ", err)
+			c.JsonResult(6002, "项目不存在或权限不足")
+		}
+		if bookResult.IsLock {
+			c.JsonResult(6001,"项目已锁定")
+		}
+	}
+	document, err := models.NewDocument().Find(docId)
+
+	if err != nil {
+		beego.Error("获取文档失败 =>",err)
+		c.JsonResult(6004,"文档不存在")
+	}
+	if document.IsLock == 1 {
+		document.IsLock = 0
+		if err := document.InsertOrUpdate();err != nil {
+			beego.Error("文档解锁失败 =>",err)
+			c.JsonResult(6006,"文档解锁失败")
+		}
+	}
+
+	c.JsonResult(0, "文档已解锁", document)
+}
+
 // 递归生成文档序列数组
 func RecursiveFun(parentId int, prefix, dpath string, c *DocumentController, book *models.BookResult, docs []*models.Document, paths *list.List) {
 	for _, item := range docs {

+ 22 - 0
models/document.go

@@ -216,3 +216,25 @@ func (m *Document) FindListByBookId(bookId int) (docs []*Document, err error) {
 
 	return
 }
+
+//判断项目是否锁定
+func (m *Document) IsLockBook(docId int) bool {
+	document := NewDocument()
+	book := NewBook()
+
+	o := orm.NewOrm()
+
+	err := o.QueryTable(m.TableNameWithPrefix()).Filter("document_id",docId).One(document,"book_id")
+	if err != nil {
+		beego.Error("查询文档失败 =>",err)
+		return false
+	}
+	err = o.QueryTable(book.TableNameWithPrefix()).Filter("book_id",document.BookId).One(book,"is_lock")
+
+	if err != nil {
+		beego.Error("查询项目失败 =>",err)
+		return false
+	}
+
+	return book.IsLock == 1
+}

+ 7 - 1
models/document_tree.go

@@ -18,6 +18,7 @@ type DocumentTree struct {
 	BookIdentify string            `json:"-"`
 	Version      int64             `json:"version"`
 	State        *DocumentSelected `json:"state,omitempty"`
+	Type 		 string 			`json:"type"`
 }
 type DocumentSelected struct {
 	Selected bool `json:"selected"`
@@ -32,7 +33,7 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree, error) {
 
 	var docs []*Document
 
-	count, err := o.QueryTable(m).Filter("book_id", book_id).OrderBy("order_sort", "document_id").Limit(math.MaxInt32).All(&docs, "document_id", "version", "document_name", "parent_id", "identify")
+	count, err := o.QueryTable(m).Filter("book_id", book_id).OrderBy("order_sort", "document_id").Limit(math.MaxInt32).All(&docs, "document_id", "version", "document_name", "parent_id", "identify","is_lock")
 
 	if err != nil {
 		return trees, err
@@ -50,6 +51,11 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree, error) {
 		tree.Identify = item.Identify
 		tree.Version = item.Version
 		tree.BookIdentify = book.Identify
+		if item.IsLock == 1 {
+			tree.Type = "lock"
+		}else{
+			tree.Type = "unlock"
+		}
 		if item.ParentId > 0 {
 			tree.ParentId = item.ParentId
 		} else {

+ 2 - 0
routers/router.go

@@ -68,6 +68,8 @@ func init() {
 	beego.Router("/api/:key/content/?:id", &controllers.DocumentController{}, "*:Content")
 	beego.Router("/api/:key/compare/:id", &controllers.DocumentController{}, "*:Compare")
 	beego.Router("/api/search/user/:key", &controllers.SearchController{}, "*:User")
+	beego.Router("/api/:key/lock", &controllers.DocumentController{}, "*:Lock")
+	beego.Router("/api/:key/unlock", &controllers.DocumentController{}, "*:UnLock")
 
 	beego.Router("/history/get", &controllers.DocumentController{}, "get:History")
 	beego.Router("/history/delete", &controllers.DocumentController{}, "*:DeleteHistory")

+ 5 - 0
static/css/jstree.css

@@ -198,3 +198,8 @@
     line-height: 30px;
     height: 30px;
 }
+
+.jstree .lock-text{
+    color: #c00;
+    font-size: 12px;
+}

+ 50 - 1
static/js/editor.js

@@ -106,7 +106,7 @@ function openDeleteDocumentDialog($node) {
 function openEditCatalogDialog($node) {
     var $then =  $("#addDocumentModal");
     var doc_id = parseInt($node ? $node.id : 0);
-    var text = $node ? $node.text : '';
+    var text = $node ? $node.text.split('<span')[0] : '';
     var parentId = $node && $node.parent !== '#' ? $node.parent : 0;
 
     $then.find("input[name='doc_id']").val(doc_id);
@@ -152,6 +152,55 @@ function pushVueLists($lists) {
     }
 }
 
+/**
+ * 锁定文档
+ * @param $node
+ */
+function lockDocumentAction($node) {
+    var index = layer.load(1, {
+        shade: [0.1, '#fff'] // 0.1 透明度的白色背景
+    });
+
+    $.post(window.lockURL,{"identify" : window.book.identify,"doc_id" : $node.id}).done(function (res) {
+        layer.close(index);
+        if(res.errcode === 0){
+            var node = {"id":$node.id};
+            var name = res.data.doc_name + "<span class='lock-text'> [锁定]</span>";
+            window.treeCatalog.rename_node(node, name);
+            window.treeCatalog.set_type(node,"lock");
+        }else{
+            layer.msg(res.message,{icon : 2})
+        }
+    }).fail(function () {
+        layer.close(index);
+        layer.msg("锁定失败",{icon : 2})
+    });
+}
+/**
+ * 解锁文档
+ * @param $node
+ */
+function unLockDocumentAction($node) {
+    var index = layer.load(1, {
+        shade: [0.1, '#fff'] // 0.1 透明度的白色背景
+    });
+
+    $.post(window.unLockURL,{"identify" : window.book.identify,"doc_id" : $node.id}).done(function (res) {
+        layer.close(index);
+        if(res.errcode === 0){
+            var node = {"id":$node.id};
+            var name = res.data.doc_name;
+            window.treeCatalog.rename_node(node,name);
+            window.treeCatalog.set_type(node,"unlock");
+        }else{
+            layer.msg("解锁失败",{icon : 2})
+        }
+    }).fail(function () {
+        layer.close(index);
+        layer.msg("解锁失败",{icon : 2})
+    });
+}
+
 /**
  * 发布项目
  */

+ 97 - 38
static/js/markdown.js

@@ -75,6 +75,9 @@ $(function () {
      * 实现标题栏操作
      */
     $("#editormd-tools").on("click", "a[class!='disabled']", function () {
+        if($(this).hasClass('disabled')){
+            return false;
+        }
        var name = $(this).find("i").attr("name");
        if (name === "attachment") {
            $("#uploadAttachModal").modal("show");
@@ -148,6 +151,15 @@ $(function () {
             layer.close(index);
 
             if (res.errcode === 0) {
+                var node = { "id": res.data.doc_id, 'parent': res.data.parent_id === 0 ? '#' : res.data.parent_id, "text": res.data.doc_name, "identify": res.data.identify, "version": res.data.version };
+                if(res.data.is_lock){
+                    node.type = "lock";
+                    node.text = node.text + "<span class='lock-text'> [锁定]</span>";
+                    // window.editor.config('readOnly',true);
+                }else{
+                    node.type = "unlock";
+                    window.editor.config('readOnly',false);
+                }
                 window.isLoad = true;
                 try {
                     window.editor.clear();
@@ -156,10 +168,11 @@ $(function () {
                 }catch(e){
                     console.log(e);
                 }
-                var node = { "id": res.data.doc_id, 'parent': res.data.parent_id === 0 ? '#' : res.data.parent_id, "text": res.data.doc_name, "identify": res.data.identify, "version": res.data.version };
+
                 pushDocumentCategory(node);
                 window.selectNode = node;
                 pushVueLists(res.data.attach);
+
             } else {
                 layer.msg("文档加载失败");
             }
@@ -244,6 +257,10 @@ $(function () {
      */
     function resetEditorChanged($is_change) {
         if ($is_change && !window.isLoad) {
+            var type = window.treeCatalog.get_type(window.selectNode);
+            if(type === "lock"){
+                return;
+            }
             $("#markdown-save").removeClass('disabled').addClass('change');
         } else {
             $("#markdown-save").removeClass('change').addClass('disabled');
@@ -265,8 +282,11 @@ $(function () {
         },
         success: function (res) {
             if (res.errcode === 0) {
-                var data = { "id": res.data.doc_id, 'parent': res.data.parent_id === 0 ? '#' : res.data.parent_id , "text": res.data.doc_name, "identify": res.data.identify, "version": res.data.version };
+                var data = { "id": res.data.doc_id, 'parent': res.data.parent_id === 0 ? '#' : res.data.parent_id , "text": res.data.doc_name, "identify": res.data.identify, "version": res.data.version ,"type": res.data.is_lock ? "lock" : "unlock"};
 
+                if(res.data.is_lock){
+                    data.text = data.text + "<span class='lock-text'> [锁定]</span>";
+                }
                 var node = window.treeCatalog.get_node(data.id);
                 if (node) {
                     window.treeCatalog.rename_node({ "id": data.id }, data.text);
@@ -293,6 +313,12 @@ $(function () {
         "types": {
             "default": {
                 "icon": false  // 删除默认图标
+            },
+            "lock" : {
+                "icon" : false
+            },
+            "unlock" : {
+                "icon" : false
             }
         },
         'core': {
@@ -304,45 +330,78 @@ $(function () {
         "contextmenu": {
             show_at_node: false,
             select_node: false,
-            "items": {
-                "添加文档": {
-                    "separator_before": false,
-                    "separator_after": true,
-                    "_disabled": false,
-                    "label": "添加文档",
-                    "icon": "fa fa-plus",
-                    "action": function (data) {
-                        var inst = $.jstree.reference(data.reference),
-                            node = inst.get_node(data.reference);
+            'items' : function(node) {
+                var items = {
+                    "添加文档": {
+                        "separator_before": false,
+                        "separator_after": true,
+                        "_disabled": false,
+                        "label": "添加文档",
+                        "icon": "fa fa-plus",
+                        "action": function (data) {
+                            var inst = $.jstree.reference(data.reference),
+                                node = inst.get_node(data.reference);
 
-                        openCreateCatalogDialog(node);
-                    }
-                },
-                "编辑": {
-                    "separator_before": false,
-                    "separator_after": true,
-                    "_disabled": false,
-                    "label": "编辑",
-                    "icon": "fa fa-edit",
-                    "action": function (data) {
-                        var inst = $.jstree.reference(data.reference);
-                        var node = inst.get_node(data.reference);
-                        openEditCatalogDialog(node);
-                    }
-                },
-                "删除": {
-                    "separator_before": false,
-                    "separator_after": true,
-                    "_disabled": false,
-                    "label": "删除",
-                    "icon": "fa fa-trash-o",
-                    "action": function (data) {
-                        var inst = $.jstree.reference(data.reference);
-                        var node = inst.get_node(data.reference);
-                        openDeleteDocumentDialog(node);
+                            openCreateCatalogDialog(node);
+                        }
+                    },
+                    "编辑": {
+                        "separator_before": false,
+                        "separator_after": true,
+                        "_disabled": false,
+                        "label": "编辑",
+                        "icon": "fa fa-edit",
+                        "action": function (data) {
+                            var inst = $.jstree.reference(data.reference);
+                            var node = inst.get_node(data.reference);
+                            openEditCatalogDialog(node);
+                        }
+                    },
+                    "删除": {
+                        "separator_before": false,
+                        "separator_after": true,
+                        "_disabled": false,
+                        "label": "删除",
+                        "icon": "fa fa-trash-o",
+                        "action": function (data) {
+                            var inst = $.jstree.reference(data.reference);
+                            var node = inst.get_node(data.reference);
+                            openDeleteDocumentDialog(node);
+                        }
+                    },
+                    "unlock" : {
+                        "separator_before": false,
+                        "separator_after": true,
+                        "_disabled": false,
+                        "label": "解锁",
+                        "icon": "fa fa-unlock",
+                        "action": function (data) {
+                            var inst = $.jstree.reference(data.reference);
+                            var node = inst.get_node(data.reference);
+                            unLockDocumentAction(node);
+                        }
+                    },
+                    "lock" : {
+                        "separator_before": false,
+                        "separator_after": true,
+                        "_disabled": false,
+                        "label": "锁定",
+                        "icon": "fa fa-lock",
+                        "action": function (data) {
+                            var inst = $.jstree.reference(data.reference);
+                            var node = inst.get_node(data.reference);
+                            lockDocumentAction(node);
+                        }
                     }
+                };
+                console.log(this.get_type(node));
+                if(this.get_type(node) === "lock") {
+                    delete items.lock;
+                }else{
+                    delete items.unlock;
                 }
-            }
+                return items;
+            },
         }
     }).on('loaded.jstree', function () {
         window.treeCatalog = $(this).jstree();

+ 2 - 0
views/document/markdown_edit_template.tpl

@@ -20,6 +20,8 @@
         window.sortURL = "{{urlfor "BookController.SaveSort" ":key" .Model.Identify}}";
         window.historyURL = "{{urlfor "DocumentController.History"}}";
         window.removeAttachURL = "{{urlfor "DocumentController.RemoveAttachment"}}";
+        window.lockURL = "{{urlfor "DocumentController.Lock" ":key" .Model.Identify}}";
+        window.unLockURL = "{{urlfor "DocumentController.UnLock" ":key" .Model.Identify}}";
     </script>
     <!-- Bootstrap -->
     <link href="{{cdncss "/static/bootstrap/css/bootstrap.min.css"}}" rel="stylesheet">