mirror of https://github.com/mindoc-org/mindoc.git
实现导出pdf
parent
a438b8104d
commit
9c99e8ea3d
|
@ -61,3 +61,7 @@ smtp_port=25
|
|||
form_user_name=admin@iminho.me
|
||||
#邮件有效期30分钟
|
||||
mail_expired=30
|
||||
|
||||
|
||||
###############配置PDF生成工具地址###################
|
||||
wkhtmltopdf=D:/Program Files/wkhtmltopdf/bin/wkhtmltopdf.exe
|
|
@ -10,11 +10,13 @@ import (
|
|||
"path/filepath"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"container/list"
|
||||
|
||||
"github.com/lifei6671/godoc/models"
|
||||
"github.com/lifei6671/godoc/conf"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/lifei6671/godoc/utils"
|
||||
)
|
||||
|
||||
//DocumentController struct.
|
||||
|
@ -558,10 +560,109 @@ func (c *DocumentController) Content() {
|
|||
c.JsonResult(0,"ok",doc)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//导出文件
|
||||
func (c *DocumentController) Export() {
|
||||
c.Prepare()
|
||||
c.TplName = "document/export.tpl"
|
||||
|
||||
identify := c.Ctx.Input.Param(":key")
|
||||
// token := c.GetString("token")
|
||||
output := c.GetString("output")
|
||||
//id, _ := c.GetInt(":id")
|
||||
token := c.GetString("token")
|
||||
|
||||
if identify == "" {
|
||||
c.Abort("404")
|
||||
}
|
||||
//如果没有开启你们访问则跳转到登录
|
||||
if !c.EnableAnonymous && c.Member == nil {
|
||||
c.Redirect(beego.URLFor("AccountController.Login"),302)
|
||||
return
|
||||
}
|
||||
book := isReadable(identify,token,c)
|
||||
|
||||
if book.PrivatelyOwned == 1 {
|
||||
|
||||
}
|
||||
|
||||
docs, err := models.NewDocument().FindListByBookId(book.BookId)
|
||||
|
||||
if err != nil {
|
||||
beego.Error(err)
|
||||
c.Abort("500")
|
||||
}
|
||||
|
||||
if output == "pdf" {
|
||||
dpath := "cache/" + book.Identify
|
||||
|
||||
os.MkdirAll(dpath, 0766)
|
||||
|
||||
pathList := list.New()
|
||||
|
||||
RecursiveFun(0, "", dpath, c, book, docs, pathList)
|
||||
|
||||
defer os.RemoveAll(dpath)
|
||||
|
||||
os.MkdirAll("./cache", 0766)
|
||||
pdfpath := "cache/" + identify + ".pdf"
|
||||
|
||||
paths := make([]string, len(docs))
|
||||
index := 0
|
||||
for e := pathList.Front(); e != nil; e = e.Next() {
|
||||
paths[index] = e.Value.(string)
|
||||
index ++
|
||||
}
|
||||
|
||||
beego.Info(paths)
|
||||
|
||||
utils.ConverterHtmlToPdf(paths, pdfpath)
|
||||
|
||||
|
||||
|
||||
c.Ctx.Output.Download(pdfpath, identify + ".pdf")
|
||||
|
||||
defer os.Remove(pdfpath)
|
||||
|
||||
c.StopRun()
|
||||
}
|
||||
|
||||
c.StopRun()
|
||||
}
|
||||
|
||||
|
||||
func RecursiveFun(parent_id int,prefix,dpath string,c *DocumentController,book *models.BookResult,docs []*models.Document,paths *list.List) {
|
||||
for _, item := range docs {
|
||||
if item.ParentId == parent_id {
|
||||
name := prefix + strconv.Itoa(item.ParentId) + strconv.Itoa(item.OrderSort) + strconv.Itoa(item.DocumentId)
|
||||
fpath := dpath + "/" + name + ".html"
|
||||
paths.PushBack(fpath)
|
||||
|
||||
|
||||
f, err := os.OpenFile(fpath, os.O_CREATE, 0666)
|
||||
|
||||
if err != nil {
|
||||
beego.Error(err)
|
||||
c.Abort("500")
|
||||
}
|
||||
|
||||
html, err := c.ExecuteViewPathTemplate("document/export.tpl", map[string]interface{}{"Model" : book, "Lists":item,"BaseUrl" : c.BaseUrl()})
|
||||
if err != nil {
|
||||
f.Close()
|
||||
beego.Error(err)
|
||||
c.Abort("500")
|
||||
}
|
||||
f.WriteString(html)
|
||||
f.Close()
|
||||
|
||||
for _, sub := range docs {
|
||||
if sub.ParentId == item.DocumentId {
|
||||
RecursiveFun(item.DocumentId,name,dpath,c,book,docs,paths)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
8
main.go
8
main.go
|
@ -1,18 +1,19 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/lifei6671/godoc/routers"
|
||||
_ "github.com/astaxie/beego/session/redis"
|
||||
_ "github.com/astaxie/beego/session/memcache"
|
||||
_ "github.com/astaxie/beego/session/mysql"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/lifei6671/godoc/commands"
|
||||
"fmt"
|
||||
"os"
|
||||
"github.com/lifei6671/godoc/controllers"
|
||||
"github.com/lifei6671/godoc/conf"
|
||||
"github.com/lifei6671/godoc/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -37,7 +38,6 @@ func main() {
|
|||
|
||||
beego.ErrorController(&controllers.ErrorController{})
|
||||
|
||||
utils.ConverterPdf("a.pdf",nil)
|
||||
beego.Run()
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,13 @@ func (m *Document) ReleaseContent(book_id int) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
func (m *Document) FindListByBookId(book_id int) (docs []*Document,err error) {
|
||||
o := orm.NewOrm()
|
||||
|
||||
_,err = o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).All(&docs)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -100,19 +100,7 @@ func getDocumentTree(array []*DocumentTree,parent_id int,selected_id int,selecte
|
|||
pid = p
|
||||
}
|
||||
if pid == parent_id {
|
||||
/**
|
||||
$selected = $item['doc_id'] == $selected_id ? ' class="jstree-clicked"' : '';
|
||||
$selected_li = $item['doc_id'] == $selected_parent_id ? ' class="jstree-open"' : '';
|
||||
|
||||
$menu .= '<li id="'.$item['doc_id'].'"'.$selected_li.'><a href="'. route('document.show',['doc_id'=> $item['doc_id']]) .'" title="' . htmlspecialchars($item['doc_name']) . '"'.$selected.'>' . $item['doc_name'] .'</a>';
|
||||
|
||||
$key = array_search($item['doc_id'], array_column($array, 'parent_id'));
|
||||
|
||||
if ($key !== false) {
|
||||
self::createTree($item['doc_id'], $array,$selected_id,$selected_parent_id);
|
||||
}
|
||||
$menu .= '</li>';
|
||||
*/
|
||||
selected := ""
|
||||
if item.DocumentId == selected_id {
|
||||
selected = ` class="jstree-clicked"`
|
||||
|
|
|
@ -58,6 +58,7 @@ func init() {
|
|||
|
||||
beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index")
|
||||
beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read")
|
||||
beego.Router("/export/:key", &controllers.DocumentController{},"*:Export")
|
||||
|
||||
beego.Router("/attach_files/:key/:attach_id",&controllers.DocumentController{},"get:DownloadAttachment")
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -287,16 +287,16 @@ func getFooter(po *PageOptions, totalpages int) string {
|
|||
*/
|
||||
func setDefault(po *PageOptions, totalpages int) *PageOptions {
|
||||
if len(po.FirstPageText) <= 0 {
|
||||
po.FirstPageText = "首页"
|
||||
po.FirstPageText = "«"
|
||||
}
|
||||
if len(po.LastPageText) <= 0 {
|
||||
po.LastPageText = "尾页"
|
||||
po.LastPageText = "»"
|
||||
}
|
||||
if len(po.PrePageText) <= 0 {
|
||||
po.PrePageText = "上一页"
|
||||
po.PrePageText = "‹"
|
||||
}
|
||||
if len(po.NextPageText) <= 0 {
|
||||
po.NextPageText = "下一页"
|
||||
po.NextPageText = "›"
|
||||
}
|
||||
if po.CurrentPage >= totalpages {
|
||||
po.CurrentPage = totalpages
|
||||
|
|
22
utils/pdf.go
22
utils/pdf.go
|
@ -1,22 +0,0 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"github.com/jung-kurt/gofpdf"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
func ConverterPdf(output string,htmlList map[string]string) error {
|
||||
|
||||
pdf := gofpdf.New("P", "mm", "A4", "./static/pdf-fonts/msyh.ttf")
|
||||
|
||||
pdf.AddPage()
|
||||
|
||||
pdf.SetFont("微软雅黑","B",14)
|
||||
pdf.Cell(40, 10, "Hello, world")
|
||||
err := pdf.OutputFileAndClose("hello.pdf")
|
||||
|
||||
if err != nil {
|
||||
beego.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"fmt"
|
||||
"bufio"
|
||||
"github.com/axgle/mahonia"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
// 中文说明:http://www.jianshu.com/p/4d65857ffe5e#
|
||||
func ConverterHtmlToPdf(uri []string,path string) {
|
||||
|
||||
exe := beego.AppConfig.String("wkhtmltopdf")
|
||||
|
||||
if exe == "" {
|
||||
panic("wkhtmltopdf not exist.")
|
||||
}
|
||||
|
||||
params := []string{"/C",exe,"--margin-bottom","25"}
|
||||
|
||||
params = append(params,uri...)
|
||||
params = append(params,path)
|
||||
|
||||
cmd := exec.Command("cmd",params...)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("StdoutPipe: " + err.Error())
|
||||
return
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
fmt.Println("StderrPipe: ", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
fmt.Println("Start: ", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(stdout)
|
||||
enc := mahonia.NewDecoder("gbk")
|
||||
|
||||
//实时循环读取输出流中的一行内容
|
||||
for {
|
||||
line ,err2 := reader.ReadString('\n')
|
||||
|
||||
if err2 != nil || io.EOF == err2 {
|
||||
break
|
||||
}
|
||||
|
||||
beego.Error(enc.ConvertString(line))
|
||||
}
|
||||
|
||||
bytesErr, err := ioutil.ReadAll(stderr)
|
||||
|
||||
if err == nil {
|
||||
beego.Error(enc.ConvertString(string(bytesErr)))
|
||||
}else{
|
||||
beego.Error("Error: Stderr => " + err.Error())
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
|
||||
beego.Error("Error: ", err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
return
|
||||
|
||||
}
|
|
@ -58,9 +58,9 @@
|
|||
</a>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<a :href="'{{urlfor "DocumentController.Index" ":key" ""}}' + item.identify" title="查看文档" data-toggle="tooltip"><i class="fa fa-eye"></i> 查看文档</a>
|
||||
<a :href="'{{urlfor "DocumentController.Index" ":key" ""}}' + item.identify" title="查看文档" data-toggle="tooltip" target="_blank"><i class="fa fa-eye"></i> 查看文档</a>
|
||||
<template v-if="item.role_id != 3">
|
||||
<a :href="'/api/' + item.identify + '/edit'" title="编辑文档" data-toggle="tooltip"><i class="fa fa-edit" aria-hidden="true"></i> 编辑文档</a>
|
||||
<a :href="'/api/' + item.identify + '/edit'" title="编辑文档" data-toggle="tooltip" target="_blank"><i class="fa fa-edit" aria-hidden="true"></i> 编辑文档</a>
|
||||
</template>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>{{.Model.BookName}} - Powered by MinDoc</title>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link href="{{.BaseUrl}}/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="{{.BaseUrl}}/static/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="{{.BaseUrl}}/static/jstree/3.3.4/themes/default/style.min.css" rel="stylesheet">
|
||||
|
||||
<link href="{{.BaseUrl}}/static/nprogress/nprogress.css" rel="stylesheet">
|
||||
<link href="{{.BaseUrl}}/static/css/kancloud.css" rel="stylesheet">
|
||||
<link href="{{.BaseUrl}}/static/css/jstree.css" rel="stylesheet">
|
||||
{{if eq .Model.Editor "markdown"}}
|
||||
<link href="{{.BaseUrl}}/static/editor.md/css/editormd.preview.css" rel="stylesheet">
|
||||
{{else}}
|
||||
<link href="{{.BaseUrl}}/static/highlight/styles/zenburn.css" rel="stylesheet">
|
||||
{{end}}
|
||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="{{.BaseUrl}}/static/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="{{.BaseUrl}}/static/respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<div class="m-manual manual-reader">
|
||||
<div class="container-fluid manual-body">
|
||||
|
||||
<div class="manual-article">
|
||||
<div class="article-content">
|
||||
<h1 id="article-title">{{.Lists.DocumentName}}</h1>
|
||||
<div class="article-body {{if eq $.Model.Editor "markdown"}}markdown-body editormd-preview-container{{else}}editor-content{{end}}" id="page-content">
|
||||
{{str2html .Lists.Release}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue