mirror of
https://github.com/mindoc-org/mindoc.git
synced 2026-02-27 17:03:57 +08:00
实现导出pdf
This commit is contained in:
@@ -60,4 +60,8 @@ smtp_port=25
|
|||||||
#发送邮件的显示名称
|
#发送邮件的显示名称
|
||||||
form_user_name=admin@iminho.me
|
form_user_name=admin@iminho.me
|
||||||
#邮件有效期30分钟
|
#邮件有效期30分钟
|
||||||
mail_expired=30
|
mail_expired=30
|
||||||
|
|
||||||
|
|
||||||
|
###############配置PDF生成工具地址###################
|
||||||
|
wkhtmltopdf=D:/Program Files/wkhtmltopdf/bin/wkhtmltopdf.exe
|
||||||
@@ -10,11 +10,13 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"container/list"
|
||||||
|
|
||||||
"github.com/lifei6671/godoc/models"
|
"github.com/lifei6671/godoc/models"
|
||||||
"github.com/lifei6671/godoc/conf"
|
"github.com/lifei6671/godoc/conf"
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
|
"github.com/lifei6671/godoc/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
//DocumentController struct.
|
//DocumentController struct.
|
||||||
@@ -558,10 +560,109 @@ func (c *DocumentController) Content() {
|
|||||||
c.JsonResult(0,"ok",doc)
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
_ "github.com/lifei6671/godoc/routers"
|
_ "github.com/lifei6671/godoc/routers"
|
||||||
_ "github.com/astaxie/beego/session/redis"
|
_ "github.com/astaxie/beego/session/redis"
|
||||||
_ "github.com/astaxie/beego/session/memcache"
|
_ "github.com/astaxie/beego/session/memcache"
|
||||||
_ "github.com/astaxie/beego/session/mysql"
|
_ "github.com/astaxie/beego/session/mysql"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/lifei6671/godoc/commands"
|
"github.com/lifei6671/godoc/commands"
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"github.com/lifei6671/godoc/controllers"
|
"github.com/lifei6671/godoc/controllers"
|
||||||
"github.com/lifei6671/godoc/conf"
|
"github.com/lifei6671/godoc/conf"
|
||||||
"github.com/lifei6671/godoc/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -37,7 +38,6 @@ func main() {
|
|||||||
|
|
||||||
beego.ErrorController(&controllers.ErrorController{})
|
beego.ErrorController(&controllers.ErrorController{})
|
||||||
|
|
||||||
utils.ConverterPdf("a.pdf",nil)
|
|
||||||
beego.Run()
|
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
|
pid = p
|
||||||
}
|
}
|
||||||
if pid == parent_id {
|
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 := ""
|
selected := ""
|
||||||
if item.DocumentId == selected_id {
|
if item.DocumentId == selected_id {
|
||||||
selected = ` class="jstree-clicked"`
|
selected = ` class="jstree-clicked"`
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ func init() {
|
|||||||
|
|
||||||
beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index")
|
beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index")
|
||||||
beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read")
|
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")
|
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 {
|
func setDefault(po *PageOptions, totalpages int) *PageOptions {
|
||||||
if len(po.FirstPageText) <= 0 {
|
if len(po.FirstPageText) <= 0 {
|
||||||
po.FirstPageText = "首页"
|
po.FirstPageText = "«"
|
||||||
}
|
}
|
||||||
if len(po.LastPageText) <= 0 {
|
if len(po.LastPageText) <= 0 {
|
||||||
po.LastPageText = "尾页"
|
po.LastPageText = "»"
|
||||||
}
|
}
|
||||||
if len(po.PrePageText) <= 0 {
|
if len(po.PrePageText) <= 0 {
|
||||||
po.PrePageText = "上一页"
|
po.PrePageText = "‹"
|
||||||
}
|
}
|
||||||
if len(po.NextPageText) <= 0 {
|
if len(po.NextPageText) <= 0 {
|
||||||
po.NextPageText = "下一页"
|
po.NextPageText = "›"
|
||||||
}
|
}
|
||||||
if po.CurrentPage >= totalpages {
|
if po.CurrentPage >= totalpages {
|
||||||
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
|
|
||||||
}
|
|
||||||
77
utils/pdf_windows.go
Normal file
77
utils/pdf_windows.go
Normal file
@@ -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>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="pull-right">
|
<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">
|
<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>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|||||||
45
views/document/export.tpl
Normal file
45
views/document/export.tpl
Normal file
@@ -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>
|
||||||
Reference in New Issue
Block a user