mirror of
https://github.com/mindoc-org/mindoc.git
synced 2025-10-20 19:07:25 +08:00
1、实现富文本编辑器
2、实现文档转换为PDF、MOBI、EPUB格式
This commit is contained in:
@@ -3,8 +3,6 @@ package models
|
||||
import (
|
||||
"time"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/astaxie/beego/orm"
|
||||
@@ -24,6 +22,10 @@ type Book struct {
|
||||
OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"`
|
||||
// Description 项目描述.
|
||||
Description string `orm:"column(description);size(2000)" json:"description"`
|
||||
//发行公司
|
||||
Publisher string `orm:"column(publisher);size(500)" json:"publisher"`
|
||||
//是否缓存导出的电子书,如果缓存可能会出现导出的文件不是最新的。 0 为不缓存
|
||||
IsCacheEBook int `orm:"column(is_cache_ebook);type(int);default(0)" json:"is_cache_ebook"`
|
||||
Label string `orm:"column(label);size(500)" json:"label"`
|
||||
// PrivatelyOwned 项目私有: 0 公开/ 1 私有
|
||||
PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"`
|
||||
@@ -354,38 +356,6 @@ func (m *Book) FindForLabelToPager(keyword string, pageIndex, pageSize, member_i
|
||||
}
|
||||
|
||||
|
||||
func (book *Book) ToBookResult() *BookResult {
|
||||
|
||||
m := NewBookResult()
|
||||
|
||||
m.BookId = book.BookId
|
||||
m.BookName = book.BookName
|
||||
m.Identify = book.Identify
|
||||
m.OrderIndex = book.OrderIndex
|
||||
m.Description = strings.Replace(book.Description, "\r\n", "<br/>", -1)
|
||||
m.PrivatelyOwned = book.PrivatelyOwned
|
||||
m.PrivateToken = book.PrivateToken
|
||||
m.DocCount = book.DocCount
|
||||
m.CommentStatus = book.CommentStatus
|
||||
m.CommentCount = book.CommentCount
|
||||
m.CreateTime = book.CreateTime
|
||||
m.ModifyTime = book.ModifyTime
|
||||
m.Cover = book.Cover
|
||||
m.Label = book.Label
|
||||
m.Status = book.Status
|
||||
m.Editor = book.Editor
|
||||
m.Theme = book.Theme
|
||||
m.AutoRelease = book.AutoRelease == 1
|
||||
|
||||
if book.Theme == "" {
|
||||
m.Theme = "default"
|
||||
}
|
||||
if book.Editor == "" {
|
||||
m.Editor = "markdown"
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
//重置文档数量
|
||||
func (m *Book) ResetDocumentNumber(book_id int) {
|
||||
o := orm.NewOrm()
|
||||
|
@@ -2,10 +2,20 @@ package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
"bytes"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/lifei6671/mindoc/conf"
|
||||
"strings"
|
||||
"github.com/lifei6671/mindoc/converter"
|
||||
"strconv"
|
||||
"github.com/russross/blackfriday"
|
||||
"path/filepath"
|
||||
"github.com/astaxie/beego"
|
||||
"os"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/lifei6671/mindoc/utils"
|
||||
)
|
||||
|
||||
type BookResult struct {
|
||||
@@ -14,17 +24,19 @@ type BookResult struct {
|
||||
Identify string `json:"identify"`
|
||||
OrderIndex int `json:"order_index"`
|
||||
Description string `json:"description"`
|
||||
Publisher string `json:"publisher"`
|
||||
IsCacheEBook bool `json:"is_cache_ebook"`
|
||||
PrivatelyOwned int `json:"privately_owned"`
|
||||
PrivateToken string `json:"private_token"`
|
||||
DocCount int `json:"doc_count"`
|
||||
CommentStatus string `json:"comment_status"`
|
||||
CommentCount int `json:"comment_count"`
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
CreateName string `json:"create_name"`
|
||||
CreateName string `json:"create_name"`
|
||||
ModifyTime time.Time `json:"modify_time"`
|
||||
Cover string `json:"cover"`
|
||||
Theme string `json:"theme"`
|
||||
Label string `json:"label"`
|
||||
Theme string `json:"theme"`
|
||||
Label string `json:"label"`
|
||||
MemberId int `json:"member_id"`
|
||||
Editor string `json:"editor"`
|
||||
AutoRelease bool `json:"auto_release"`
|
||||
@@ -79,13 +91,14 @@ func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,
|
||||
return m, err
|
||||
}
|
||||
|
||||
m = book.ToBookResult()
|
||||
m = NewBookResult().ToBookResult(*book)
|
||||
|
||||
m.CreateName = member.Account
|
||||
m.MemberId = relationship.MemberId
|
||||
m.RoleId = relationship.RoleId
|
||||
m.RelationshipId = relationship.RelationshipId
|
||||
|
||||
|
||||
if m.RoleId == conf.BookFounder {
|
||||
m.RoleName = "创始人"
|
||||
} else if m.RoleId == conf.BookAdmin {
|
||||
@@ -134,6 +147,183 @@ func (m *BookResult) FindToPager(pageIndex, pageSize int) (books []*BookResult,t
|
||||
return
|
||||
}
|
||||
|
||||
//实体转换
|
||||
func (m *BookResult) ToBookResult(book Book) *BookResult {
|
||||
|
||||
m.BookId = book.BookId
|
||||
m.BookName = book.BookName
|
||||
m.Identify = book.Identify
|
||||
m.OrderIndex = book.OrderIndex
|
||||
m.Description = strings.Replace(book.Description, "\r\n", "<br/>", -1)
|
||||
m.PrivatelyOwned = book.PrivatelyOwned
|
||||
m.PrivateToken = book.PrivateToken
|
||||
m.DocCount = book.DocCount
|
||||
m.CommentStatus = book.CommentStatus
|
||||
m.CommentCount = book.CommentCount
|
||||
m.CreateTime = book.CreateTime
|
||||
m.ModifyTime = book.ModifyTime
|
||||
m.Cover = book.Cover
|
||||
m.Label = book.Label
|
||||
m.Status = book.Status
|
||||
m.Editor = book.Editor
|
||||
m.Theme = book.Theme
|
||||
m.AutoRelease = book.AutoRelease == 1
|
||||
m.Publisher = book.Publisher
|
||||
m.IsCacheEBook = book.IsCacheEBook == 1
|
||||
|
||||
if book.Theme == "" {
|
||||
m.Theme = "default"
|
||||
}
|
||||
if book.Editor == "" {
|
||||
m.Editor = "markdown"
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
|
||||
|
||||
convertBookResult := ConvertBookResult{}
|
||||
outputPath := filepath.Join(beego.AppConfig.DefaultString("book_output_path","cache"),sessionId,strconv.Itoa(m.BookId))
|
||||
|
||||
if m.IsCacheEBook {
|
||||
outputPath = filepath.Join(beego.AppConfig.DefaultString("book_output_path","cache"),strconv.Itoa(m.BookId))
|
||||
}
|
||||
|
||||
if m.IsCacheEBook {
|
||||
pdfpath := filepath.Join(outputPath,"output","book.pdf")
|
||||
epubpath := filepath.Join(outputPath,"output","book.epub")
|
||||
mobipath := filepath.Join(outputPath,"output","book.mobi")
|
||||
|
||||
if utils.FileExists(pdfpath) && utils.FileExists(epubpath) && utils.FileExists(mobipath){
|
||||
convertBookResult.EpubPath = epubpath
|
||||
convertBookResult.MobiPath = mobipath
|
||||
convertBookResult.PDFPath = pdfpath
|
||||
return convertBookResult,nil
|
||||
}
|
||||
}
|
||||
docs, err := NewDocument().FindListByBookId(m.BookId)
|
||||
if err != nil {
|
||||
return convertBookResult,err
|
||||
}
|
||||
|
||||
tocList := make([]converter.Toc,0)
|
||||
|
||||
for _, item := range docs {
|
||||
if item.ParentId == 0 {
|
||||
toc := converter.Toc{
|
||||
Id: item.DocumentId,
|
||||
Link: strconv.Itoa(item.DocumentId) + ".html",
|
||||
Pid: item.ParentId,
|
||||
Title: item.DocumentName,
|
||||
}
|
||||
|
||||
tocList = append(tocList,toc)
|
||||
}
|
||||
}
|
||||
for _, item := range docs {
|
||||
if item.ParentId != 0 {
|
||||
toc := converter.Toc{
|
||||
Id: item.DocumentId,
|
||||
Link: strconv.Itoa(item.DocumentId) + ".html",
|
||||
Pid: item.ParentId,
|
||||
Title: item.DocumentName,
|
||||
}
|
||||
tocList = append(tocList,toc)
|
||||
}
|
||||
}
|
||||
|
||||
ebookConfig := converter.Config{
|
||||
Charset : "utf-8",
|
||||
Cover : m.Cover,
|
||||
Timestamp : time.Now().Format("2006-01-02 15:04:05"),
|
||||
Description : string(blackfriday.MarkdownBasic([]byte(m.Description))),
|
||||
Footer : "<p style='color:#8E8E8E;font-size:12px;'>本文档使用 <a href='https://www.iminho.me' style='text-decoration:none;color:#1abc9c;font-weight:bold;'>MinDoc</a> 构建 <span style='float:right'>- _PAGENUM_ -</span></p>",
|
||||
Header : "<p style='color:#8E8E8E;font-size:12px;'>_SECTION_</p>",
|
||||
Identifier : "",
|
||||
Language : "zh-CN",
|
||||
Creator : m.CreateName,
|
||||
Publisher : m.Publisher,
|
||||
Contributor : m.Publisher,
|
||||
Title : m.BookName,
|
||||
Format: []string{"epub", "mobi", "pdf"},
|
||||
FontSize : "14",
|
||||
PaperSize : "a4",
|
||||
MarginLeft : "72",
|
||||
MarginRight : "72",
|
||||
MarginTop : "72",
|
||||
MarginBottom : "72",
|
||||
Toc : tocList,
|
||||
More : []string{},
|
||||
|
||||
}
|
||||
|
||||
|
||||
os.MkdirAll(outputPath, 0766)
|
||||
if outputPath, err = filepath.Abs(outputPath); err != nil {
|
||||
beego.Error("导出目录配置错误:" + err.Error())
|
||||
return convertBookResult,err
|
||||
}
|
||||
|
||||
viewPath := beego.BConfig.WebConfig.ViewsPath
|
||||
baseUrl := beego.AppConfig.DefaultString("baseurl","")
|
||||
|
||||
for _,item := range docs {
|
||||
name := strconv.Itoa(item.DocumentId)
|
||||
fpath := filepath.Join(outputPath,name + ".html")
|
||||
|
||||
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0777)
|
||||
if err != nil {
|
||||
return convertBookResult,err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
|
||||
if err := beego.ExecuteViewPathTemplate(&buf,"document/export.tpl",viewPath,map[string]interface{}{"Model": m, "Lists": item, "BaseUrl": baseUrl}); err != nil {
|
||||
return convertBookResult,err
|
||||
}
|
||||
html := buf.String()
|
||||
|
||||
|
||||
if err != nil {
|
||||
|
||||
f.Close()
|
||||
return convertBookResult,err
|
||||
}
|
||||
|
||||
bufio := bytes.NewReader(buf.Bytes())
|
||||
|
||||
doc, err := goquery.NewDocumentFromReader(bufio)
|
||||
doc.Find("img").Each(func(i int, contentSelection *goquery.Selection) {
|
||||
if src, ok := contentSelection.Attr("src"); ok && strings.HasPrefix(src, "/uploads/") {
|
||||
contentSelection.SetAttr("src", baseUrl + src)
|
||||
}
|
||||
})
|
||||
|
||||
html, err = doc.Html()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return convertBookResult,err
|
||||
}
|
||||
|
||||
// html = strings.Replace(html, "<img src=\"/uploads", "<img src=\"" + c.BaseUrl() + "/uploads", -1)
|
||||
|
||||
f.WriteString(html)
|
||||
f.Close()
|
||||
}
|
||||
eBookConverter := &converter.Converter{
|
||||
BasePath : outputPath,
|
||||
Config : ebookConfig,
|
||||
Debug : false,
|
||||
}
|
||||
|
||||
if err := eBookConverter.Convert();err != nil {
|
||||
beego.Error("转换文件错误:" + m.BookName +" => "+ err.Error())
|
||||
return convertBookResult,err
|
||||
}
|
||||
convertBookResult.MobiPath = filepath.Join(outputPath,"output","book.mobi")
|
||||
convertBookResult.PDFPath = filepath.Join(outputPath,"output","book.pdf")
|
||||
convertBookResult.EpubPath = filepath.Join(outputPath,"output","book.epub")
|
||||
return convertBookResult,nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
8
models/convert_book_result.go
Normal file
8
models/convert_book_result.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package models
|
||||
|
||||
// 转换结果
|
||||
type ConvertBookResult struct {
|
||||
PDFPath string
|
||||
EpubPath string
|
||||
MobiPath string
|
||||
}
|
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/lifei6671/mindoc/conf"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Document struct.
|
||||
@@ -137,6 +138,9 @@ func (m *Document) ReleaseContent(book_id int) {
|
||||
if err == nil && len(attach_list) > 0 {
|
||||
content := bytes.NewBufferString("<div class=\"attach-list\"><strong>附件</strong><ul>")
|
||||
for _, attach := range attach_list {
|
||||
if strings.HasPrefix(attach.HttpPath,"/"){
|
||||
attach.HttpPath = strings.TrimSuffix(beego.AppConfig.DefaultString("baseurl",""),"/") + attach.HttpPath
|
||||
}
|
||||
li := fmt.Sprintf("<li><a href=\"%s\" target=\"_blank\" title=\"%s\">%s</a></li>", attach.HttpPath, attach.FileName, attach.FileName)
|
||||
|
||||
content.WriteString(li)
|
||||
|
Reference in New Issue
Block a user