Przeglądaj źródła

Merge pull request #178 from DigitalUnion/master

增加了导出单篇文档为 PDF 的功能。
Minho 7 lat temu
rodzic
commit
4e4035b27a
6 zmienionych plików z 395 dodań i 223 usunięć
  1. 10 0
      TODO
  2. 226 95
      controllers/document.go
  3. 81 82
      routers/router.go
  4. 14 2
      static/css/kancloud.css
  5. 48 43
      static/js/kancloud.js
  6. 16 1
      views/document/default_read.tpl

+ 10 - 0
TODO

@@ -0,0 +1,10 @@
+1、把 log 提取出 dbgout 之类的方法;已改作 beego.Info() 调用;
+2、把源代码里的 TODO 完成;
+3、Export 的两个 URL 应该可以合并,用是否有 :id 来区分;这样 0 号文档输出整个 book 更顺;已完成;
+4、统一代码风格,空格、命名之类的;
+5、美化 PDF 的输出格式;
+6、自动登录新开标签页而且并不能跳转至起始请求页的问题;
+7、用户分组管理;
+8、[自动]展示历史版本;增强历史版本对比显示的能力;
+9、[自动]展示作者信息;也许可以和上一需求合并考虑;
+10、查看了解评论功能;

Plik diff jest za duży
+ 226 - 95
controllers/document.go


+ 81 - 82
routers/router.go

@@ -5,86 +5,85 @@ import (
 	"github.com/lifei6671/mindoc/controllers"
 )
 
-func init()  {
-	beego.Router("/",&controllers.HomeController{},"*:Index")
-
-	beego.Router("/login", &controllers.AccountController{},"*:Login")
-	beego.Router("/logout", &controllers.AccountController{},"*:Logout")
-	beego.Router("/register", &controllers.AccountController{},"*:Register")
-	beego.Router("/find_password", &controllers.AccountController{},"*:FindPassword")
-	beego.Router("/valid_email", &controllers.AccountController{},"post:ValidEmail")
-	beego.Router("/captcha", &controllers.AccountController{},"*:Captcha")
-
-	beego.Router("/manager", &controllers.ManagerController{},"*:Index")
-	beego.Router("/manager/users", &controllers.ManagerController{},"*:Users")
-	beego.Router("/manager/users/edit/:id", &controllers.ManagerController{},"*:EditMember")
-	beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember")
-	beego.Router("/manager/member/delete", &controllers.ManagerController{},"post:DeleteMember")
-	beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus")
-	beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole")
-	beego.Router("/manager/books", &controllers.ManagerController{},"*:Books")
-	beego.Router("/manager/books/edit/:key", &controllers.ManagerController{},"*:EditBook")
-	beego.Router("/manager/books/delete", &controllers.ManagerController{},"*:DeleteBook")
-	beego.Router("/manager/comments", &controllers.ManagerController{},"*:Comments")
-	beego.Router("/manager/books/token", &controllers.ManagerController{},"post:CreateToken")
-	beego.Router("/manager/setting",&controllers.ManagerController{},"*:Setting")
-	beego.Router("/manager/books/transfer", &controllers.ManagerController{},"post:Transfer")
-	beego.Router("/manager/books/open", &controllers.ManagerController{},"post:PrivatelyOwned")
-	beego.Router("/manager/attach/list", &controllers.ManagerController{},"*:AttachList")
-	beego.Router("/manager/attach/detailed/:id", &controllers.ManagerController{},"*:AttachDetailed")
-	beego.Router("/manager/attach/delete", &controllers.ManagerController{},"post:AttachDelete")
-
-
-	beego.Router("/setting", &controllers.SettingController{},"*:Index")
-	beego.Router("/setting/password", &controllers.SettingController{},"*:Password")
-	beego.Router("/setting/upload", &controllers.SettingController{},"*:Upload")
-
-	beego.Router("/book", &controllers.BookController{},"*:Index")
-	beego.Router("/book/:key/dashboard", &controllers.BookController{},"*:Dashboard")
-	beego.Router("/book/:key/setting", &controllers.BookController{},"*:Setting")
-	beego.Router("/book/:key/users", &controllers.BookController{},"*:Users")
-	beego.Router("/book/:key/release", &controllers.BookController{},"post:Release")
-	beego.Router("/book/:key/sort", &controllers.BookController{},"post:SaveSort")
-
-	beego.Router("/book/create", &controllers.BookController{},"*:Create")
-	beego.Router("/book/users/create", &controllers.BookMemberController{},"post:AddMember")
-	beego.Router("/book/users/change", &controllers.BookMemberController{},"post:ChangeRole")
-	beego.Router("/book/users/delete", &controllers.BookMemberController{},"post:RemoveMember")
-
-	beego.Router("/book/setting/save", &controllers.BookController{},"post:SaveBook")
-	beego.Router("/book/setting/open", &controllers.BookController{},"post:PrivatelyOwned")
-	beego.Router("/book/setting/transfer", &controllers.BookController{},"post:Transfer")
-	beego.Router("/book/setting/upload", &controllers.BookController{},"post:UploadCover")
-	beego.Router("/book/setting/token", &controllers.BookController{},"post:CreateToken")
-	beego.Router("/book/setting/delete", &controllers.BookController{},"post:Delete")
-
-	beego.Router("/api/attach/remove/", &controllers.DocumentController{},"post:RemoveAttachment")
-	beego.Router("/api/:key/edit/?:id", &controllers.DocumentController{},"*:Edit")
-	beego.Router("/api/upload",&controllers.DocumentController{},"post:Upload")
-	beego.Router("/api/:key/create",&controllers.DocumentController{},"post:Create")
-	beego.Router("/api/:key/delete", &controllers.DocumentController{},"post:Delete")
-	beego.Router("/api/:key/content/?:id",&controllers.DocumentController{},"*:Content")
-	beego.Router("/api/:key/compare/:id", &controllers.DocumentController{},"*:Compare")
-
-	beego.Router("/history/get", &controllers.DocumentController{},"get:History")
-	beego.Router("/history/delete", &controllers.DocumentController{},"*:DeleteHistory")
-	beego.Router("/history/restore", &controllers.DocumentController{},"*:RestoreHistory")
-
-	beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index")
-	beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read")
-	beego.Router("/docs/:key/search", &controllers.DocumentController{},"post:Search")
-	beego.Router("/export/:key", &controllers.DocumentController{},"*:Export")
-	beego.Router("/qrcode/:key.png",&controllers.DocumentController{},"get:QrCode")
-
-	beego.Router("/attach_files/:key/:attach_id",&controllers.DocumentController{},"get:DownloadAttachment")
-
-	beego.Router("/comment/create", &controllers.CommentController{},"post:Create")
-	beego.Router("/comment/lists", &controllers.CommentController{},"get:Lists")
-	beego.Router("/comment/index", &controllers.CommentController{},"*:Index")
-
-	beego.Router("/search",&controllers.SearchController{},"get:Index")
-
-	beego.Router("/tag/:key", &controllers.LabelController{},"get:Index")
-	beego.Router("/tags", &controllers.LabelController{},"get:List")
+func init() {
+	beego.Router("/", &controllers.HomeController{}, "*:Index")
+
+	beego.Router("/login", &controllers.AccountController{}, "*:Login")
+	beego.Router("/logout", &controllers.AccountController{}, "*:Logout")
+	beego.Router("/register", &controllers.AccountController{}, "*:Register")
+	beego.Router("/find_password", &controllers.AccountController{}, "*:FindPassword")
+	beego.Router("/valid_email", &controllers.AccountController{}, "post:ValidEmail")
+	beego.Router("/captcha", &controllers.AccountController{}, "*:Captcha")
+
+	beego.Router("/manager", &controllers.ManagerController{}, "*:Index")
+	beego.Router("/manager/users", &controllers.ManagerController{}, "*:Users")
+	beego.Router("/manager/users/edit/:id", &controllers.ManagerController{}, "*:EditMember")
+	beego.Router("/manager/member/create", &controllers.ManagerController{}, "post:CreateMember")
+	beego.Router("/manager/member/delete", &controllers.ManagerController{}, "post:DeleteMember")
+	beego.Router("/manager/member/update-member-status", &controllers.ManagerController{}, "post:UpdateMemberStatus")
+	beego.Router("/manager/member/change-member-role", &controllers.ManagerController{}, "post:ChangeMemberRole")
+	beego.Router("/manager/books", &controllers.ManagerController{}, "*:Books")
+	beego.Router("/manager/books/edit/:key", &controllers.ManagerController{}, "*:EditBook")
+	beego.Router("/manager/books/delete", &controllers.ManagerController{}, "*:DeleteBook")
+	beego.Router("/manager/comments", &controllers.ManagerController{}, "*:Comments")
+	beego.Router("/manager/books/token", &controllers.ManagerController{}, "post:CreateToken")
+	beego.Router("/manager/setting", &controllers.ManagerController{}, "*:Setting")
+	beego.Router("/manager/books/transfer", &controllers.ManagerController{}, "post:Transfer")
+	beego.Router("/manager/books/open", &controllers.ManagerController{}, "post:PrivatelyOwned")
+	beego.Router("/manager/attach/list", &controllers.ManagerController{}, "*:AttachList")
+	beego.Router("/manager/attach/detailed/:id", &controllers.ManagerController{}, "*:AttachDetailed")
+	beego.Router("/manager/attach/delete", &controllers.ManagerController{}, "post:AttachDelete")
+
+	beego.Router("/setting", &controllers.SettingController{}, "*:Index")
+	beego.Router("/setting/password", &controllers.SettingController{}, "*:Password")
+	beego.Router("/setting/upload", &controllers.SettingController{}, "*:Upload")
+
+	beego.Router("/book", &controllers.BookController{}, "*:Index")
+	beego.Router("/book/:key/dashboard", &controllers.BookController{}, "*:Dashboard")
+	beego.Router("/book/:key/setting", &controllers.BookController{}, "*:Setting")
+	beego.Router("/book/:key/users", &controllers.BookController{}, "*:Users")
+	beego.Router("/book/:key/release", &controllers.BookController{}, "post:Release")
+	beego.Router("/book/:key/sort", &controllers.BookController{}, "post:SaveSort")
+
+	beego.Router("/book/create", &controllers.BookController{}, "*:Create")
+	beego.Router("/book/users/create", &controllers.BookMemberController{}, "post:AddMember")
+	beego.Router("/book/users/change", &controllers.BookMemberController{}, "post:ChangeRole")
+	beego.Router("/book/users/delete", &controllers.BookMemberController{}, "post:RemoveMember")
+
+	beego.Router("/book/setting/save", &controllers.BookController{}, "post:SaveBook")
+	beego.Router("/book/setting/open", &controllers.BookController{}, "post:PrivatelyOwned")
+	beego.Router("/book/setting/transfer", &controllers.BookController{}, "post:Transfer")
+	beego.Router("/book/setting/upload", &controllers.BookController{}, "post:UploadCover")
+	beego.Router("/book/setting/token", &controllers.BookController{}, "post:CreateToken")
+	beego.Router("/book/setting/delete", &controllers.BookController{}, "post:Delete")
+
+	beego.Router("/api/attach/remove/", &controllers.DocumentController{}, "post:RemoveAttachment")
+	beego.Router("/api/:key/edit/?:id", &controllers.DocumentController{}, "*:Edit")
+	beego.Router("/api/upload", &controllers.DocumentController{}, "post:Upload")
+	beego.Router("/api/:key/create", &controllers.DocumentController{}, "post:Create")
+	beego.Router("/api/:key/delete", &controllers.DocumentController{}, "post:Delete")
+	beego.Router("/api/:key/content/?:id", &controllers.DocumentController{}, "*:Content")
+	beego.Router("/api/:key/compare/:id", &controllers.DocumentController{}, "*:Compare")
+
+	beego.Router("/history/get", &controllers.DocumentController{}, "get:History")
+	beego.Router("/history/delete", &controllers.DocumentController{}, "*:DeleteHistory")
+	beego.Router("/history/restore", &controllers.DocumentController{}, "*:RestoreHistory")
+
+	beego.Router("/docs/:key", &controllers.DocumentController{}, "*:Index")
+	beego.Router("/docs/:key/:id", &controllers.DocumentController{}, "*:Read")
+	beego.Router("/docs/:key/search", &controllers.DocumentController{}, "post:Search")
+	beego.Router("/export/:key", &controllers.DocumentController{}, "*:ExportBook")
+	beego.Router("/export/:key/:id", &controllers.DocumentController{}, "*:ExportDoc")
+	beego.Router("/qrcode/:key.png", &controllers.DocumentController{}, "get:QrCode")
+
+	beego.Router("/attach_files/:key/:attach_id", &controllers.DocumentController{}, "get:DownloadAttachment")
+
+	beego.Router("/comment/create", &controllers.CommentController{}, "post:Create")
+	beego.Router("/comment/lists", &controllers.CommentController{}, "get:Lists")
+	beego.Router("/comment/index", &controllers.CommentController{}, "*:Index")
+
+	beego.Router("/search", &controllers.SearchController{}, "get:Index")
+
+	beego.Router("/tag/:key", &controllers.LabelController{}, "get:Index")
+	beego.Router("/tags", &controllers.LabelController{}, "get:List")
 }
-

+ 14 - 2
static/css/kancloud.css

@@ -417,7 +417,8 @@ table>tbody>tr:hover{
 }
 .manual-article .article-head {
     position: relative;
-    zoom:1;padding: 10px 20px
+    zoom: 1;
+    padding: 10px 20px
 }
 .manual-reader .book-title{
     color: #333333;
@@ -430,7 +431,7 @@ table>tbody>tr:hover{
 .manual-article .article-head h1 {
     margin: 0;
     font-size: 20px;
-    font-weight: 200;
+    font-weight: 300;
     text-align: center;
     line-height: 30px;
     overflow: hidden;
@@ -438,6 +439,17 @@ table>tbody>tr:hover{
     white-space: nowrap;
     color: #444
 }
+.manual-article .article-head h3 {
+    margin: 0;
+    font-size: 12px;
+    font-weight: 200;
+    text-align: center;
+    line-height: 18px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    color: #444
+}
 .manual-article .article-content{
     min-width: 980px;
     max-width: 98%;

+ 48 - 43
static/js/kancloud.js

@@ -4,51 +4,58 @@
  * @param $id
  * @param $callback
  */
-function loadDocument($url,$id,$callback) {
+function loadDocument($url, $id, $callback) {
     $.ajax({
         url : $url,
         type : "GET",
-        beforeSend :function (xhr) {
+        beforeSend : function (xhr) {
             var body = events.data('body_' + $id);
             var title = events.data('title_' + $id);
             var doc_title = events.data('doc_title_' + $id);
+            var doc_info = events.data('doc_info_' + $id);
 
-            if(body && title && doc_title){
-
+            if (body && title && doc_title) {
                 if (typeof $callback === "function") {
                     body = $callback(body);
                 }
+
                 $("#page-content").html(body);
                 $("title").text(title);
                 $("#article-title").text(doc_title);
+                $("#article-info").text(doc_info);
 
-                events.trigger('article.open',{ $url : $url, $init : false , $id : $id });
+                events.trigger('article.open', { $url : $url, $init : false, $id : $id });
 
                 return false;
             }
             NProgress.start();
         },
         success : function (res) {
-            if(res.errcode === 0){
+            if (res.errcode === 0) {
                 var body = res.data.body;
                 var doc_title = res.data.doc_title;
                 var title = res.data.title;
+                var doc_info = res.data.doc_info;
 
                 $body = body;
-                if (typeof $callback === "function" ){
+                if (typeof $callback === "function" ) {
                     $body = $callback(body);
                 }
+
                 $("#page-content").html($body);
                 $("title").text(title);
                 $("#article-title").text(doc_title);
+                $("#article-info").text(doc_info);
 
-                events.data('body_' + $id,body);
-                events.data('title_' + $id,title);
-                events.data('doc_title_' + $id,doc_title);
-
-                events.trigger('article.open',{ $url : $url, $init : true, $id : $id });
+                events.data('body_' + $id, body);
+                events.data('title_' + $id, title);
+                events.data('doc_title_' + $id, doc_title);
+                events.data('doc_info_' + $id, doc_info);
 
-            }else{
+                events.trigger('article.open', { $url : $url, $init : true, $id : $id });
+            } else if (res.errcode === 6000) {
+                window.location.href = "/";
+            } else {
                 layer.msg("加载失败");
             }
         },
@@ -74,9 +81,9 @@ $(function () {
     });
     $(".manual-right").scroll(function () {
         var top = $(".manual-right").scrollTop();
-        if(top > 100){
+        if (top > 100) {
             $(".view-backtop").addClass("active");
-        }else{
+        } else {
             $(".view-backtop").removeClass("active");
         }
     });
@@ -85,7 +92,7 @@ $(function () {
     initHighlighting();
 
     window.jsTree = $("#sidebar").jstree({
-        'plugins':["wholerow","types"],
+        'plugins' : ["wholerow", "types"],
         "types": {
             "default" : {
                 "icon" : false  // 删除默认图标
@@ -93,31 +100,31 @@ $(function () {
         },
         'core' : {
             'check_callback' : true,
-            "multiple" : false ,
+            "multiple" : false,
             'animation' : 0
         }
-    }).on('select_node.jstree',function (node,selected,event) {
+    }).on('select_node.jstree', function (node, selected, event) {
         $(".m-manual").removeClass('manual-mobile-show-left');
         var url = selected.node.a_attr.href;
 
-        if(url === window.location.href){
+        if (url === window.location.href) {
             return false;
         }
-        loadDocument(url,selected.node.id);
 
+        loadDocument(url, selected.node.id);
     });
 
-    $("#slidebar").on("click",function () {
+    $("#slidebar").on("click", function () {
         $(".m-manual").addClass('manual-mobile-show-left');
     });
-    $(".manual-mask").on("click",function () {
+    $(".manual-mask").on("click", function () {
         $(".m-manual").removeClass('manual-mobile-show-left');
     });
 
     /**
      * 关闭侧边栏
      */
-    $(".manual-fullscreen-switch").on("click",function () {
+    $(".manual-fullscreen-switch").on("click", function () {
         isFullScreen = !isFullScreen;
         if (isFullScreen) {
             $(".m-manual").addClass('manual-fullscreen-active');
@@ -126,24 +133,23 @@ $(function () {
         }
     });
 
-    //处理打开事件
+    // 处理打开事件
     events.on('article.open', function (event, $param) {
-
         if ('pushState' in history) {
             if ($param.$init === false) {
-                window.history.replaceState($param , $param.$id , $param.$url);
+                window.history.replaceState($param, $param.$id, $param.$url);
             } else {
-                window.history.pushState($param, $param.$id , $param.$url);
+                window.history.pushState($param, $param.$id, $param.$url);
             }
-
         } else {
             window.location.hash = $param.$url;
         }
+
         initHighlighting();
         $(".manual-right").scrollTop(0);
     });
 
-    $(".navg-item[data-mode]").on("click",function () {
+    $(".navg-item[data-mode]").on("click", function () {
         var mode = $(this).data('mode');
         $(this).siblings().removeClass('active').end().addClass('active');
         $(".m-manual").removeClass("manual-mode-view manual-mode-collect manual-mode-search").addClass("manual-mode-" + mode);
@@ -155,25 +161,25 @@ $(function () {
     $("#searchForm").ajaxForm({
         beforeSubmit : function () {
             var keyword = $.trim($("#searchForm").find("input[name='keyword']").val());
-            if(keyword === ""){
+            if (keyword === "") {
                 $(".search-empty").show();
                 $("#searchList").html("");
                 return false;
             }
-            $("#btnSearch").attr("disabled","disabled").find("i").removeClass("fa-search").addClass("loading");
+            $("#btnSearch").attr("disabled", "disabled").find("i").removeClass("fa-search").addClass("loading");
             window.keyword = keyword;
         },
-        success :function (res) {
+        success : function (res) {
             var html = "";
-            if(res.errcode === 0){
-                for(var i in res.data){
+            if (res.errcode === 0) {
+                for(var i in res.data) {
                     var item = res.data[i];
-                    html += '<li><a href="javascript:;" title="'+ item.doc_name +'" data-id="'+ item.doc_id+'"> '+ item.doc_name +' </a></li>';
+                    html += '<li><a href="javascript:;" title="' + item.doc_name + '" data-id="' + item.doc_id + '"> ' + item.doc_name + ' </a></li>';
                 }
             }
-            if(html !== ""){
+            if (html !== "") {
                 $(".search-empty").hide();
-            }else{
+            } else {
                 $(".search-empty").show();
             }
             $("#searchList").html(html);
@@ -184,7 +190,6 @@ $(function () {
     });
 
     window.onpopstate = function (e) {
-
         var $param = e.state;
         console.log($param);
         if($param.hasOwnProperty("$url")) {
@@ -192,18 +197,18 @@ $(function () {
 
             window.jsTree.jstree().select_node({ id : $param.$id });
             $param.$init = false;
-            //events.trigger('article.open', $param );
-        }else{
+            // events.trigger('article.open', $param);
+        } else {
             console.log($param);
         }
     };
     try {
         var $node = window.jsTree.jstree().get_selected();
         if (typeof $node === "object") {
-            $node = window.jsTree.jstree().get_node({id: $node[0]});
-            events.trigger('article.open', {$url: $node.a_attr.href, $init: true, $id: $node.a_attr.id});
+            $node = window.jsTree.jstree().get_node({ id: $node[0] });
+            events.trigger('article.open', { $url: $node.a_attr.href, $init: true, $id: $node.a_attr.id });
         }
-    }catch (e){
+    } catch (e) {
         console.log(e);
     }
 });

+ 16 - 1
views/document/default_read.tpl

@@ -58,7 +58,8 @@
                         {{if eq .Model.PrivatelyOwned 0}}
                         <li><a href="javascript:" data-toggle="modal" data-target="#shareProject">项目分享</a> </li>
                         <li role="presentation" class="divider"></li>
-                        <li><a href="{{urlfor "DocumentController.Export" ":key" .Model.Identify "output" "pdf"}}" target="_blank">项目导出PDF</a> </li>
+                        <li><a href="javascript:void(0);" onclick="ExportPdfDoc()">文档导出为 PDF</a> </li>
+                        <li><a href="{{urlfor "DocumentController.ExportBook" ":key" .Model.Identify "output" "pdf"}}" target="_blank">项目导出为 PDF</a> </li>
                         {{end}}
 
                         <li><a href="{{urlfor "HomeController.Index"}}" title="返回首页">返回首页</a> </li>
@@ -127,6 +128,7 @@
                             </div>
                             <div class="col-md-8 text-center">
                                 <h1 id="article-title">{{.Title}}</h1>
+                                <h3 id="article-info">{{.Info}}</h3>
                             </div>
                             <div class="col-md-2">
                             </div>
@@ -234,6 +236,13 @@
 <script type="text/javascript" src="/static/js/jquery.highlight.js"></script>
 <script type="text/javascript" src="/static/js/kancloud.js"></script>
 <script type="text/javascript">
+active_book_id = {{.Model.Identify}};
+active_doc_id = {{.DocumentId}};
+$(function () {
+    $("body").on('article.open', function (event, $param) {
+        active_doc_id = $param.$id;
+    });
+});
 $(function () {
     $("#searchList").on("click","a",function () {
         var id = $(this).attr("data-id");
@@ -245,6 +254,12 @@ $(function () {
         });
     });
 });
+function ExportPdfDoc() {
+    var id = active_book_id;
+    if(active_doc_id != "0")
+        id += "/" + active_doc_id;
+    window.location.href = "/export/" + id + "?output=pdf";
+}
 </script>
 </body>
 </html>

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików