diff --git a/README.md b/README.md index 286a2b0d..1cbd48d2 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,11 @@ go build -ldflags "-w" -o mindoc main.go bee run ``` +## 旧版本运行 可更新部分数据库配置 +```base +./mindoc update +``` + MinDoc 如果使用MySQL储存数据,则编码必须是`utf8mb4_general_ci`。请在安装前,把数据库配置填充到项目目录下的 `conf/app.conf` 中。 如果使用 `SQLite` 数据库,则直接在配置文件中配置数据库路径即可. @@ -189,39 +194,44 @@ docker run -p 8181:8181 --name mindoc -e DB_ADAPTER=mysql -e MYSQL_PORT_3306_TCP **创建项目** -![创建项目](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501204438.png) +![创建项目](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/create.png?raw=true) **项目列表** -![项目列表](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501203542.png) +![项目列表](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/project_list.png?raw=true) **项目概述** -![项目概述](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501203619.png) +![项目概述](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/intro.png?raw=true) **项目成员** -![项目成员](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501203637.png) +![项目成员](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/member.png?raw=true) **项目设置** -![项目设置](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501203656.png) +![项目设置](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/project_setting.png?raw=true) **基于Editor.md开发的Markdown编辑器** -![基于Editor.md开发的Markdown编辑器](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501203854.png) +![基于Editor.md开发的Markdown编辑器](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/editor_md.png?raw=true) **基于wangEditor开发的富文本编辑器** -![基于wangEditor开发的富文本编辑器](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501204651.png) +![基于wangEditor开发的富文本编辑器](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/wang_editor.png?raw=true) + + +**基于cherryMarkdown开发的编辑器** + +![基于cherry-markdown开发的编辑器](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/cheery-markdown.png?raw=true) **项目预览** -![项目预览](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501204609.png) +![项目预览](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/preview.png?raw=true) **超级管理员后台** -![超级管理员后台](https://raw.githubusercontent.com/lifei6671/mindoc/master/uploads/20170501204710.png) +![超级管理员后台](https://github.com/mindoc-org/mindoc/blob/master/uploads/docs/admin.png?raw=true) # 使用的技术(TODO: 最新技术栈整理中,使用的第三方库升级中) @@ -229,6 +239,7 @@ docker run -p 8181:8181 --name mindoc -e DB_ADAPTER=mysql -e MYSQL_PORT_3306_TCP - [Beego](https://github.com/beego/beego) ~~1.10.0~~ - MySQL 5.6 - [editor.md](https://github.com/pandao/editor.md) Markdown 编辑器 +- [cherry-markdown](https://github.com/Tencent/cherry-markdown) Cherry Markdown Writer - [Bootstrap](https://github.com/twbs/bootstrap) 3.2 - [jQuery](https://github.com/jquery/jquery) 库 - [WebUploader](https://github.com/fex-team/webuploader) 文件上传框架 @@ -250,13 +261,13 @@ docker run -p 8181:8181 --name mindoc -e DB_ADAPTER=mysql -e MYSQL_PORT_3306_TCP # 主要功能 -- 项目管理,可以对项目进行编辑更改,成员添加等。 +- 项目管理,可以对项目进行编辑更改,成员添加, 项目排序等。 - 文档管理,添加和删除文档等。 - 评论管理,可以管理文档评论和自己发布的评论。 - 用户管理,添加和禁用用户,个人资料更改等。 - 用户权限管理 , 实现用户角色的变更。 - 项目加密,可以设置项目公开状态,私有项目需要通过Token访问。 -- 站点配置,可开启匿名访问、验证码等。 +- 站点配置,多语言切换, 可开启匿名访问、验证码等。 # 参与开发 diff --git a/commands/command.go b/commands/command.go index b22396c7..dbe2b9c9 100644 --- a/commands/command.go +++ b/commands/command.go @@ -234,6 +234,9 @@ func RegisterCommand() { } else if len(os.Args) >= 2 && os.Args[1] == "version" { CheckUpdate() os.Exit(0) + } else if len(os.Args) >= 2 && os.Args[1] == "update" { + Update() + os.Exit(0) } } diff --git a/commands/update.go b/commands/update.go index 205d39cb..ae2f99e6 100644 --- a/commands/update.go +++ b/commands/update.go @@ -3,15 +3,17 @@ package commands import ( "encoding/json" "fmt" + "github.com/mindoc-org/mindoc/models" "io/ioutil" "net/http" "os" + "github.com/beego/beego/v2/client/orm" "github.com/beego/beego/v2/core/logs" "github.com/mindoc-org/mindoc/conf" ) -//检查最新版本. +// 检查最新版本. func CheckUpdate() { fmt.Println("MinDoc current version => ", conf.VERSION) @@ -47,3 +49,23 @@ func CheckUpdate() { os.Exit(0) } + +func Update() { + fmt.Println("Update...") + RegisterDataBase() + RegisterModel() + err := orm.RunSyncdb("default", false, true) + if err == nil { + UpdateInitialization() + } else { + panic(err.Error()) + } + fmt.Println("Update Successfully!") + os.Exit(0) +} +func UpdateInitialization() { + err := models.NewOption().Update() + if err != nil { + panic(err.Error()) + } +} diff --git a/conf/lang/en-us.ini b/conf/lang/en-us.ini index fcd9a765..b5935cb6 100644 --- a/conf/lang/en-us.ini +++ b/conf/lang/en-us.ini @@ -502,6 +502,9 @@ edit_user = Edit User pwd_tips = Please leave it blank if you do not change the password, only local users can change the password [mgr] +language = Default Language +zh_cn = 简体中文 +en_us = English dashboard_menu = Dashboard user_menu = User team_menu = Team diff --git a/conf/lang/zh-cn.ini b/conf/lang/zh-cn.ini index 388fe510..d44b2c3c 100644 --- a/conf/lang/zh-cn.ini +++ b/conf/lang/zh-cn.ini @@ -502,6 +502,9 @@ edit_user = 编辑用户 pwd_tips = 不修改密码请留空,只支持本地用户修改密码 [mgr] +language = 默认语言 +zh_cn = 简体中文 +en_us = English dashboard_menu = 仪表盘 user_menu = 用户管理 team_menu = 团队管理 diff --git a/controllers/BaseController.go b/controllers/BaseController.go index 4d7d27dc..0b8451d1 100644 --- a/controllers/BaseController.go +++ b/controllers/BaseController.go @@ -83,7 +83,7 @@ func (c *BaseController) Prepare() { c.SetLang() } -//判断用户是否登录. +// 判断用户是否登录. func (c *BaseController) isUserLoggedIn() bool { return c.Member != nil && c.Member.MemberId > 0 } @@ -127,7 +127,7 @@ func (c *BaseController) JsonResult(errCode int, errMsg string, data ...interfac c.StopRun() } -//如果错误不为空,则响应错误信息到浏览器. +// 如果错误不为空,则响应错误信息到浏览器. func (c *BaseController) CheckJsonError(code int, err error) { if err == nil { @@ -182,7 +182,7 @@ func (c *BaseController) BaseUrl() string { return baseUrl } -//显示错误信息页面. +// 显示错误信息页面. func (c *BaseController) ShowErrorPage(errCode int, errMsg string) { c.TplName = "errors/error.tpl" @@ -217,7 +217,11 @@ func (c *BaseController) SetLang() { } if len(lang) == 0 || !i18n.IsExist(lang) { - lang, _ = web.AppConfig.String("default_lang") + if c.Data["language"] != nil { + lang = c.Data["language"].(string) + } else { + lang, _ = web.AppConfig.String("default_lang") + } } if !hasCookie { c.Ctx.SetCookie("lang", lang, 1<<31-1, "/") diff --git a/controllers/ManagerController.go b/controllers/ManagerController.go index 8a065775..3abc43d0 100644 --- a/controllers/ManagerController.go +++ b/controllers/ManagerController.go @@ -133,7 +133,7 @@ func (c *ManagerController) CreateMember() { c.JsonResult(0, "ok", member) } -//更新用户状态. +// 更新用户状态. func (c *ManagerController) UpdateMemberStatus() { c.Prepare() @@ -166,7 +166,7 @@ func (c *ManagerController) UpdateMemberStatus() { c.JsonResult(0, "ok", member) } -//变更用户权限. +// 变更用户权限. func (c *ManagerController) ChangeMemberRole() { c.Prepare() @@ -199,7 +199,7 @@ func (c *ManagerController) ChangeMemberRole() { c.JsonResult(0, "ok", member) } -//编辑用户信息. +// 编辑用户信息. func (c *ManagerController) EditMember() { c.Prepare() c.TplName = "manager/edit_users.tpl" @@ -251,7 +251,7 @@ func (c *ManagerController) EditMember() { c.Data["Model"] = member } -//删除一个用户,并将该用户的所有信息转移到超级管理员上. +// 删除一个用户,并将该用户的所有信息转移到超级管理员上. func (c *ManagerController) DeleteMember() { c.Prepare() member_id, _ := c.GetInt("id", 0) @@ -283,7 +283,7 @@ func (c *ManagerController) DeleteMember() { c.JsonResult(0, "ok") } -//项目列表. +// 项目列表. func (c *ManagerController) Books() { c.Prepare() c.TplName = "manager/books.tpl" @@ -313,7 +313,7 @@ func (c *ManagerController) Books() { c.Data["Lists"] = books } -//编辑项目. +// 编辑项目. func (c *ManagerController) EditBook() { c.Prepare() @@ -460,7 +460,7 @@ func (c *ManagerController) CreateToken() { } } -//项目设置. +// 项目设置. func (c *ManagerController) Setting() { c.Prepare() c.TplName = "manager/setting.tpl" @@ -541,7 +541,7 @@ func (c *ManagerController) Comments() { } -//DeleteComment 标记评论为已删除 +// DeleteComment 标记评论为已删除 func (c *ManagerController) DeleteComment() { c.Prepare() @@ -565,7 +565,7 @@ func (c *ManagerController) DeleteComment() { c.JsonResult(0, "ok", comment) } -//设置项目私有状态. +// 设置项目私有状态. func (c *ManagerController) PrivatelyOwned() { c.Prepare() status := c.GetString("status") @@ -603,7 +603,7 @@ func (c *ManagerController) PrivatelyOwned() { c.JsonResult(0, "ok") } -//附件列表. +// 附件列表. func (c *ManagerController) AttachList() { c.Prepare() c.TplName = "manager/attach_list.tpl" @@ -634,7 +634,7 @@ func (c *ManagerController) AttachList() { c.Data["Lists"] = attachList } -//附件清理. +// 附件清理. func (c *ManagerController) AttachClean() { c.Prepare() @@ -669,7 +669,7 @@ func (c *ManagerController) AttachClean() { c.JsonResult(0, "ok") } -//附件详情. +// 附件详情. func (c *ManagerController) AttachDetailed() { c.Prepare() c.TplName = "manager/attach_detailed.tpl" @@ -698,7 +698,7 @@ func (c *ManagerController) AttachDetailed() { c.Data["Model"] = attach } -//删除附件. +// 删除附件. func (c *ManagerController) AttachDelete() { c.Prepare() attachId, _ := c.GetInt("attach_id") @@ -721,7 +721,7 @@ func (c *ManagerController) AttachDelete() { c.JsonResult(0, "ok") } -//标签列表 +// 标签列表 func (c *ManagerController) LabelList() { c.Prepare() c.TplName = "manager/label_list.tpl" @@ -743,7 +743,7 @@ func (c *ManagerController) LabelList() { c.Data["Lists"] = labels } -//删除标签 +// 删除标签 func (c *ManagerController) LabelDelete() { labelId, err := strconv.Atoi(c.Ctx.Input.Param(":id")) if err != nil { @@ -936,7 +936,7 @@ func (c *ManagerController) TeamMemberList() { } } -//搜索团队用户. +// 搜索团队用户. func (c *ManagerController) TeamSearchMember() { c.Prepare() @@ -1015,7 +1015,7 @@ func (c *ManagerController) TeamChangeMemberRole() { } -//团队项目列表. +// 团队项目列表. func (c *ManagerController) TeamBookList() { c.Prepare() c.TplName = "manager/team_book_list.tpl" @@ -1062,7 +1062,7 @@ func (c *ManagerController) TeamBookList() { } } -//给团队增加项目. +// 给团队增加项目. func (c *ManagerController) TeamBookAdd() { c.Prepare() @@ -1086,7 +1086,7 @@ func (c *ManagerController) TeamBookAdd() { } } -//搜索未参与的项目. +// 搜索未参与的项目. func (c *ManagerController) TeamSearchBook() { c.Prepare() @@ -1106,7 +1106,7 @@ func (c *ManagerController) TeamSearchBook() { } -//删除团队项目. +// 删除团队项目. func (c *ManagerController) TeamBookDelete() { c.Prepare() teamRelationshipId, _ := c.GetInt("teamRelId") @@ -1123,7 +1123,7 @@ func (c *ManagerController) TeamBookDelete() { c.JsonResult(0, "OK") } -//项目空间列表. +// 项目空间列表. func (c *ManagerController) Itemsets() { c.Prepare() c.TplName = "manager/itemsets.tpl" @@ -1151,7 +1151,7 @@ func (c *ManagerController) Itemsets() { c.Data["Lists"] = items } -//编辑或添加项目空间. +// 编辑或添加项目空间. func (c *ManagerController) ItemsetsEdit() { c.Prepare() itemId, _ := c.GetInt("itemId") @@ -1186,7 +1186,7 @@ func (c *ManagerController) ItemsetsEdit() { c.JsonResult(0, "OK") } -//删除项目空间. +// 删除项目空间. func (c *ManagerController) ItemsetsDelete() { c.Prepare() itemId, _ := c.GetInt("itemId") diff --git a/models/Options.go b/models/Options.go index 8673b9ff..4c337767 100644 --- a/models/Options.go +++ b/models/Options.go @@ -164,5 +164,30 @@ func (m *Option) Init() error { } } + if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name", "language").Exist() { + option := NewOption() + option.OptionValue = "zh-cn" + option.OptionName = "language" + option.OptionTitle = "站点语言" + if _, err := o.Insert(option); err != nil { + return err + } + } + + return nil +} + +func (m *Option) Update() error { + o := orm.NewOrm() + + if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name", "language").Exist() { + option := NewOption() + option.OptionValue = "zh-cn" + option.OptionName = "language" + option.OptionTitle = "站点语言" + if _, err := o.Insert(option); err != nil { + return err + } + } return nil } diff --git a/static/cherry/cherry-markdown.css b/static/cherry/cherry-markdown.css index 69be091e..01db3f42 100644 --- a/static/cherry/cherry-markdown.css +++ b/static/cherry/cherry-markdown.css @@ -1961,6 +1961,15 @@ div[data-type=codeBlock] .token.inserted { transform: rotate(-2deg); } +.whole-article-wrap > div { + display: flex; + flex-direction: column; +} + +.whole-article-wrap > div > .markdown-article { + width: calc(100% - 260px); +} + [data-code-block-theme=coy] div[data-type=codeBlock] pre[class*=language-]:after { right: 0.75em; left: auto; @@ -3194,7 +3203,8 @@ div[data-type=codeBlock] .token.inserted { } .cherry-editor .cm-s-default .cm-url { - background: #4b4b4b; + background: #f8fafb; + color: #3582fb; font-family: "Menlo", "Liberation Mono", "Consolas", "DejaVu Sans Mono", "Ubuntu Mono", "Courier New", "andale mono", "lucida console", monospace; font-size: 0.9em; } diff --git a/static/cherry/cherry-markdown.js b/static/cherry/cherry-markdown.js index 847d987d..98b38c63 100644 --- a/static/cherry/cherry-markdown.js +++ b/static/cherry/cherry-markdown.js @@ -54950,7 +54950,7 @@ style: ['position: absolute', 'bottom: 30px', 'top: 30px', 'left: 0', 'right: 0', 'overflow: hidden'].join(';') }); this.foot = createElement('div', 'cherry-dialog--foot', { - style: ['height: 30px', 'line-height: 30px', 'padding-left: 10px', 'padding-right: 10px', 'position: absolute', 'bottom: 0', 'left: 0', 'right: 0'].join(';') + style: ['height: 30px', 'line-height: 18px', 'padding-left: 10px', 'padding-right: 10px', 'position: absolute', 'bottom: 0', 'left: 0', 'right: 0'].join(';') }); this.headTitle = createElement('span', 'cherry-dialog--title', { style: 'user-select:none;' diff --git a/static/cherry/drawio_demo/EditorUi.js b/static/cherry/drawio_demo/EditorUi.js index 61ac7631..3a0fa1b9 100644 --- a/static/cherry/drawio_demo/EditorUi.js +++ b/static/cherry/drawio_demo/EditorUi.js @@ -5745,7 +5745,7 @@ EditorUi.prototype.convertImages = function (svgRoot, callback, imageCache, conv for (var i = 0; i < images.length; i++) { (mxUtils.bind(this, function (img) { var src = converter.convert(img.getAttribute(srcAttr)); - + console.log(src) // Data URIs are pass-through if (src != null && src.substring(0, 5) != 'data:') { var tmp = cache[src]; @@ -6059,6 +6059,21 @@ EditorUi.prototype.getBaseFilename = function () { }; +EditorUi.prototype.convertImageToDataUri = function (src, call) { + let img = new Image(); + img.src = src; + img.onload = function() { + let canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + let ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + let base64 = canvas.toDataURL('image/png'); + call(base64) + }; +} + + EditorUi.prototype.createImageDataUri = function (canvas, xml, format) { var data = canvas.toDataURL('image/' + format); diff --git a/static/css/markdown.css b/static/css/markdown.css index 3bd1b285..c0e45bc9 100644 --- a/static/css/markdown.css +++ b/static/css/markdown.css @@ -545,18 +545,20 @@ iframe.cherry-dialog-iframe { .manual-article.cherry-markdown .toc { position: fixed; - right: 0; - width: 200px; - margin-top: -70px; + right: 50px; + width: 260px; + font-size: 12px; overflow: auto; - margin-right: 50px; + border: 1px solid #e8e8e8; + padding: 10px; + border-radius: 6px; } -@media screen and (min-width: 840px) { - .markdown-article { - margin-right: 200px !important; - } -} +/*@media screen and (min-width: 840px) {*/ +/* .markdown-article {*/ +/* margin-right: 200px !important;*/ +/* }*/ +/*}*/ .markdown-article-head { width: unset !important; diff --git a/static/css/markdown.preview.css b/static/css/markdown.preview.css index bf23a4ff..2c96303f 100644 --- a/static/css/markdown.preview.css +++ b/static/css/markdown.preview.css @@ -56,6 +56,20 @@ flex-direction: column; } +/*.content > .whole-article-wrap {*/ +/* flex-direction: row-reverse;*/ +/*}*/ + +.content > .whole-article-wrap > .markdown-toc { + right: 30px; + margin-left: 10px; + max-height: 550px; +} + +.content > .whole-article-wrap > .markdown-article { + width: 100%; +} + .article-body .markdown-toc{ position: fixed; right: 50px; @@ -90,7 +104,7 @@ /*margin-right: 250px;*/ } .article-body.content .markdown-toc{ - position: relative; + position: fixed; margin-top: 0; } .article-body.content .markdown-article{ diff --git a/static/js/cherry_markdown.js b/static/js/cherry_markdown.js index b8fc9602..ce20da0f 100644 --- a/static/js/cherry_markdown.js +++ b/static/js/cherry_markdown.js @@ -630,10 +630,11 @@ function myFileUpload(file, callback) { }, success: function (data) { layer.close(layerIndex); - if (data[0].errcode !== 0) { - layer.msg(data[0].message); + // 验证data是否为数组 + if (data.errcode !== 0) { + layer.msg(data.message); } else { - callback(data[0].url); // 假设返回的 JSON 中包含上传文件的 URL,调用回调函数并传入 URL + callback(data.url); // 假设返回的 JSON 中包含上传文件的 URL,调用回调函数并传入 URL } } }); diff --git a/static/js/kancloud.js b/static/js/kancloud.js index 97422bb1..d6ebd370 100644 --- a/static/js/kancloud.js +++ b/static/js/kancloud.js @@ -141,6 +141,7 @@ function renderPage($data) { $("#article-info").text($data.doc_info); $("#view_count").text("阅读次数:" + $data.view_count); $("#doc_id").val($data.doc_id); + checkMarkdownTocElement(); if ($data.page) { loadComment($data.page, $data.doc_id); } else { @@ -154,7 +155,7 @@ function renderPage($data) { $("#view_container").removeClass("theme__dark theme__green theme__light theme__red theme__default") $("#view_container").addClass($data.markdown_theme) } - checkMarkdownTocElement(); + } /*** @@ -442,6 +443,9 @@ function loadCopySnippets() { function checkMarkdownTocElement() { let toc = $(".markdown-toc-list"); + if ($(".toc").length) { + toc = $(".toc"); + } let articleComment = $("#articleComment"); if (toc.length) { $(".wiki-bottom-left").css("width", "calc(100% - 260px)"); diff --git a/uploads/docs/admin.png b/uploads/docs/admin.png new file mode 100644 index 00000000..1ef25c5b Binary files /dev/null and b/uploads/docs/admin.png differ diff --git a/uploads/docs/cheery-markdown.png b/uploads/docs/cheery-markdown.png new file mode 100644 index 00000000..f6ec4d9a Binary files /dev/null and b/uploads/docs/cheery-markdown.png differ diff --git a/uploads/docs/create.png b/uploads/docs/create.png new file mode 100644 index 00000000..0c43b60f Binary files /dev/null and b/uploads/docs/create.png differ diff --git a/uploads/docs/editor_md.png b/uploads/docs/editor_md.png new file mode 100644 index 00000000..37e1cb9d Binary files /dev/null and b/uploads/docs/editor_md.png differ diff --git a/uploads/docs/intro.png b/uploads/docs/intro.png new file mode 100644 index 00000000..f1f51996 Binary files /dev/null and b/uploads/docs/intro.png differ diff --git a/uploads/docs/member.png b/uploads/docs/member.png new file mode 100644 index 00000000..9b721fa0 Binary files /dev/null and b/uploads/docs/member.png differ diff --git a/uploads/docs/preview.png b/uploads/docs/preview.png new file mode 100644 index 00000000..38ee1819 Binary files /dev/null and b/uploads/docs/preview.png differ diff --git a/uploads/docs/project_list.png b/uploads/docs/project_list.png new file mode 100644 index 00000000..5bfd020b Binary files /dev/null and b/uploads/docs/project_list.png differ diff --git a/uploads/docs/project_setting.png b/uploads/docs/project_setting.png new file mode 100644 index 00000000..22b527ca Binary files /dev/null and b/uploads/docs/project_setting.png differ diff --git a/uploads/docs/wang_editor.png b/uploads/docs/wang_editor.png new file mode 100644 index 00000000..a45e6cd5 Binary files /dev/null and b/uploads/docs/wang_editor.png differ diff --git a/views/manager/setting.tpl b/views/manager/setting.tpl index 479fbb9f..c54ca01c 100644 --- a/views/manager/setting.tpl +++ b/views/manager/setting.tpl @@ -44,6 +44,13 @@
{{i18n .Lang "mgr.site_desc_tips"}}
+ +