diff --git a/controllers/account.go b/controllers/account.go index 42fe02de..5ee2175e 100644 --- a/controllers/account.go +++ b/controllers/account.go @@ -1,40 +1,52 @@ package controllers import ( - "time" - "strings" "regexp" + "strconv" + "strings" + "time" "net/smtp" - "github.com/lifei6671/mindoc/conf" - "github.com/lifei6671/mindoc/models" - "github.com/lifei6671/mindoc/utils" + "github.com/astaxie/beego" "github.com/astaxie/beego/logs" "github.com/lifei6671/gocaptcha" - "strconv" + "github.com/lifei6671/mindoc/conf" + "github.com/lifei6671/mindoc/models" + "github.com/lifei6671/mindoc/utils" ) -// AccountController 用户登录与注册. +// AccountController 用户登录与注册 type AccountController struct { BaseController } -// Login 用户登录. -func (c *AccountController) Login() { +// Login 用户登录 +func (c *AccountController) Login() { c.Prepare() c.TplName = "account/login.tpl" - var remember struct { MemberId int ; Account string; Time time.Time} + var remember struct { + MemberId int + Account string + Time time.Time + } - //如果Cookie中存在登录信息 - if cookie,ok := c.GetSecureCookie(conf.GetAppKey(),"login");ok{ + // 显式指定的 URL 参数优先;为了统一处理,将之更新到 Session 中 + turl := c.GetString("turl", "") + if turl != "" { + c.SetSession("turl", turl) + } - if err := utils.Decode(cookie,&remember); err == nil { - if member,err := models.NewMember().Find(remember.MemberId); err == nil { + beego.Info("AccountController.Login(): turl is: " + turl) + + // 如果 Cookie 中存在登录信息 + if cookie, ok := c.GetSecureCookie(conf.GetAppKey(), "login"); ok { + if err := utils.Decode(cookie, &remember); err == nil { + if member, err := models.NewMember().Find(remember.MemberId); err == nil { c.SetMember(*member) - c.Redirect(beego.URLFor("HomeController.Index"), 302) + c.LoggedIn(false) c.StopRun() } } @@ -46,48 +58,72 @@ func (c *AccountController) Login() { captcha := c.GetString("code") is_remember := c.GetString("is_remember") - //如果开启了验证码 - if v,ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v,"true") { - v,ok := c.GetSession(conf.CaptchaSessionName).(string); - if !ok || !strings.EqualFold(v,captcha){ - c.JsonResult(6001,"验证码不正确") + // 如果开启了验证码 + if v, ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") { + v, ok := c.GetSession(conf.CaptchaSessionName).(string) + if !ok || !strings.EqualFold(v, captcha) { + c.JsonResult(6001, "验证码不正确") } } - member,err := models.NewMember().Login(account,password) - //如果没有数据 + member, err := models.NewMember().Login(account, password) if err == nil { member.LastLoginTime = time.Now() member.Update() c.SetMember(*member) - if strings.EqualFold(is_remember,"yes") { + if strings.EqualFold(is_remember, "yes") { remember.MemberId = member.MemberId remember.Account = member.Account remember.Time = time.Now() - v ,err := utils.Encode(remember) + v, err := utils.Encode(remember) if err == nil { - c.SetSecureCookie(conf.GetAppKey(),"login",v) + c.SetSecureCookie(conf.GetAppKey(), "login", v) } - } - c.JsonResult(0,"ok") - }else{ - logs.Error("用户登录 =>",err) - c.JsonResult(500,"账号或密码错误",nil) + data := c.LoggedIn(true) + c.JsonResult(0, "ok", data) + } else { + logs.Error("用户登录 =>", err) + c.JsonResult(500, "账号或密码错误", nil) } - - return } } -//用户注册. -func (c *AccountController) Register() { +// 登录成功后的操作,如重定向到原始请求页面 +func (c *AccountController) LoggedIn(isPost bool) interface{} { + turl := "" + value := c.GetSession("turl") + if value != nil { + turl = value.(string) + } + c.DelSession("turl") + + beego.Info("AccountController.LoggedIn(): turl is: " + turl) + + if !isPost { + // 检查是否存在 turl 参数,如果有则重定向至 turl 处,否则进入 Home 页面 + if turl == "" { + turl = beego.URLFor("HomeController.Index") + } + c.Redirect(turl, 302) + return nil + } else { + var data struct { + TURL string `json:"turl"` + } + data.TURL = turl + return data + } +} + +// 用户注册 +func (c *AccountController) Register() { c.TplName = "account/register.tpl" - //如果没有开启用户注册 - if v,ok := c.Option["ENABLED_REGISTER"]; ok && !strings.EqualFold(v,"true") { + // 如果没有开启用户注册 + if v, ok := c.Option["ENABLED_REGISTER"]; ok && !strings.EqualFold(v, "true") { c.Abort("404") } @@ -98,30 +134,30 @@ func (c *AccountController) Register() { email := c.GetString("email") captcha := c.GetString("code") - if ok,err := regexp.MatchString(conf.RegexpAccount,account); account == "" || !ok || err != nil { - c.JsonResult(6001,"账号只能由英文字母数字组成,且在3-50个字符") + if ok, err := regexp.MatchString(conf.RegexpAccount, account); account == "" || !ok || err != nil { + c.JsonResult(6001, "账号只能由英文字母数字组成,且在3-50个字符") } - if l := strings.Count(password1,"") ; password1 == "" || l > 50 || l < 6{ - c.JsonResult(6002,"密码必须在6-50个字符之间") + if l := strings.Count(password1, ""); password1 == "" || l > 50 || l < 6 { + c.JsonResult(6002, "密码必须在6-50个字符之间") } if password1 != password2 { - c.JsonResult(6003,"确认密码不正确") + c.JsonResult(6003, "确认密码不正确") } - if ok,err := regexp.MatchString(conf.RegexpEmail,email); !ok || err != nil || email == "" { - c.JsonResult(6004,"邮箱格式不正确") + if ok, err := regexp.MatchString(conf.RegexpEmail, email); !ok || err != nil || email == "" { + c.JsonResult(6004, "邮箱格式不正确") } - //如果开启了验证码 - if v,ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v,"true") { - v,ok := c.GetSession(conf.CaptchaSessionName).(string); - if !ok || !strings.EqualFold(v,captcha){ - c.JsonResult(6001,"验证码不正确") + // 如果开启了验证码 + if v, ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") { + v, ok := c.GetSession(conf.CaptchaSessionName).(string) + if !ok || !strings.EqualFold(v, captcha) { + c.JsonResult(6001, "验证码不正确") } } member := models.NewMember() - if _,err := member.FindByAccount(account); err == nil && member.MemberId > 0 { - c.JsonResult(6005,"账号已存在") + if _, err := member.FindByAccount(account); err == nil && member.MemberId > 0 { + c.JsonResult(6005, "账号已存在") } member.Account = account @@ -133,15 +169,15 @@ func (c *AccountController) Register() { member.Status = 0 if err := member.Add(); err != nil { beego.Error(err) - c.JsonResult(6006,"注册失败,请联系系统管理员处理") + c.JsonResult(6006, "注册失败,请联系系统管理员处理") } - c.JsonResult(0,"ok",member) + c.JsonResult(0, "ok", member) } } -//找回密码. -func (c *AccountController) FindPassword() { +// 找回密码 +func (c *AccountController) FindPassword() { c.TplName = "account/find_password_setp1.tpl" mail_conf := conf.GetMailConfig() @@ -151,63 +187,63 @@ func (c *AccountController) FindPassword() { captcha := c.GetString("code") if email == "" { - c.JsonResult(6005,"邮箱地址不能为空") + c.JsonResult(6005, "邮箱地址不能为空") } if !mail_conf.EnableMail { - c.JsonResult(6004,"未启用邮件服务") + c.JsonResult(6004, "未启用邮件服务") } - //如果开启了验证码 - if v,ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v,"true") { - v,ok := c.GetSession(conf.CaptchaSessionName).(string); - if !ok || !strings.EqualFold(v,captcha){ - c.JsonResult(6001,"验证码不正确") + // 如果开启了验证码 + if v, ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") { + v, ok := c.GetSession(conf.CaptchaSessionName).(string) + if !ok || !strings.EqualFold(v, captcha) { + c.JsonResult(6001, "验证码不正确") } } - member ,err := models.NewMember().FindByFieldFirst("email",email) + member, err := models.NewMember().FindByFieldFirst("email", email) if err != nil { - c.JsonResult(6006,"邮箱不存在") + c.JsonResult(6006, "邮箱不存在") } if member.Status != 0 { - c.JsonResult(6007,"账号已被禁用") + c.JsonResult(6007, "账号已被禁用") } if member.AuthMethod == conf.AuthMethodLDAP { - c.JsonResult(6011,"当前用户不支持找回密码") + c.JsonResult(6011, "当前用户不支持找回密码") } - count,err := models.NewMemberToken().FindSendCount(email,time.Now().Add(-1*time.Hour),time.Now()) + count, err := models.NewMemberToken().FindSendCount(email, time.Now().Add(-1*time.Hour), time.Now()) if err != nil { beego.Error(err) - c.JsonResult(6008,"发送邮件失败") + c.JsonResult(6008, "发送邮件失败") } if count > mail_conf.MailNumber { - c.JsonResult(6008,"发送次数太多,请稍候再试") + c.JsonResult(6008, "发送次数太多,请稍候再试") } member_token := models.NewMemberToken() - member_token.Token = string(utils.Krand(32,utils.KC_RAND_KIND_ALL)) + member_token.Token = string(utils.Krand(32, utils.KC_RAND_KIND_ALL)) member_token.Email = email member_token.MemberId = member.MemberId member_token.IsValid = false - if _,err := member_token.InsertOrUpdate(); err != nil { - c.JsonResult(6009,"邮件发送失败") + if _, err := member_token.InsertOrUpdate(); err != nil { + c.JsonResult(6009, "邮件发送失败") } data := map[string]interface{}{ - "SITE_NAME" : c.Option["SITE_NAME"], - "url" : c.BaseUrl() + beego.URLFor("AccountController.FindPassword", "token",member_token.Token,"mail",email), + "SITE_NAME": c.Option["SITE_NAME"], + "url": c.BaseUrl() + beego.URLFor("AccountController.FindPassword", "token", member_token.Token, "mail", email), } - body,err := c.ExecuteViewPathTemplate("account/mail_template.tpl",data) + body, err := c.ExecuteViewPathTemplate("account/mail_template.tpl", data) if err != nil { beego.Error(err) - c.JsonResult(6003,"邮件发送失败") + c.JsonResult(6003, "邮件发送失败") } - go func(mail_conf *conf.SmtpConf,email string,body string) { + go func(mail_conf *conf.SmtpConf, email string, body string) { auth := smtp.PlainAuth( "", mail_conf.SmtpUserName, @@ -215,30 +251,29 @@ func (c *AccountController) FindPassword() { mail_conf.SmtpHost, ) - mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"; + mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" subject := "Subject: 找回密码!\n" err = smtp.SendMail( - mail_conf.SmtpHost + ":" + strconv.Itoa(mail_conf.SmtpPort), + mail_conf.SmtpHost+":"+strconv.Itoa(mail_conf.SmtpPort), auth, mail_conf.FormUserName, - []string{ email }, - []byte(subject + mime +"\n" +body), + []string{email}, + []byte(subject+mime+"\n"+body), ) if err != nil { - beego.Error("邮件发送失败 => ",email,err) + beego.Error("邮件发送失败 => ", email, err) } - }(mail_conf,email,body) + }(mail_conf, email, body) - - c.JsonResult(0,"ok", c.BaseUrl() + beego.URLFor("AccountController.Login")) + c.JsonResult(0, "ok", c.BaseUrl()+beego.URLFor("AccountController.Login")) } token := c.GetString("token") mail := c.GetString("mail") if token != "" && mail != "" { - member_token,err := models.NewMemberToken().FindByFieldFirst("token",token) + member_token, err := models.NewMemberToken().FindByFieldFirst("token", token) if err != nil { beego.Error(err) @@ -248,7 +283,7 @@ func (c *AccountController) FindPassword() { } sub_time := member_token.SendTime.Sub(time.Now()) - if !strings.EqualFold(member_token.Email,mail) || sub_time.Minutes() > float64(mail_conf.MailExpired) || !member_token.ValidTime.IsZero() { + if !strings.EqualFold(member_token.Email, mail) || sub_time.Minutes() > float64(mail_conf.MailExpired) || !member_token.ValidTime.IsZero() { c.Data["ErrorMessage"] = "验证码已过期,请重新操作。" c.TplName = "errors/error.tpl" return @@ -260,7 +295,7 @@ func (c *AccountController) FindPassword() { } } -//校验邮件并修改密码. +// 校验邮件并修改密码 func (c *AccountController) ValidEmail() { c.Prepare() password1 := c.GetString("password1") @@ -270,48 +305,48 @@ func (c *AccountController) ValidEmail() { mail := c.GetString("mail") if password1 == "" { - c.JsonResult(6001,"密码不能为空") + c.JsonResult(6001, "密码不能为空") } - if l := strings.Count(password1,""); l <6 || l > 50{ - c.JsonResult(6001,"密码不能为空且必须在6-50个字符之间") + if l := strings.Count(password1, ""); l < 6 || l > 50 { + c.JsonResult(6001, "密码不能为空且必须在6-50个字符之间") } - if password2 == ""{ - c.JsonResult(6002,"确认密码不能为空") + if password2 == "" { + c.JsonResult(6002, "确认密码不能为空") } if password1 != password2 { - c.JsonResult(6003,"确认密码输入不正确") + c.JsonResult(6003, "确认密码输入不正确") } if captcha == "" { - c.JsonResult(6004,"验证码不能为空") + c.JsonResult(6004, "验证码不能为空") } - v,ok := c.GetSession(conf.CaptchaSessionName).(string); - if !ok || !strings.EqualFold(v,captcha){ - c.JsonResult(6001,"验证码不正确") + v, ok := c.GetSession(conf.CaptchaSessionName).(string) + if !ok || !strings.EqualFold(v, captcha) { + c.JsonResult(6001, "验证码不正确") } mail_conf := conf.GetMailConfig() - member_token,err := models.NewMemberToken().FindByFieldFirst("token",token) + member_token, err := models.NewMemberToken().FindByFieldFirst("token", token) if err != nil { beego.Error(err) - c.JsonResult(6007,"邮件已失效") + c.JsonResult(6007, "邮件已失效") } sub_time := member_token.SendTime.Sub(time.Now()) - if !strings.EqualFold(member_token.Email,mail) || sub_time.Minutes() > float64(mail_conf.MailExpired) || !member_token.ValidTime.IsZero() { + if !strings.EqualFold(member_token.Email, mail) || sub_time.Minutes() > float64(mail_conf.MailExpired) || !member_token.ValidTime.IsZero() { - c.JsonResult(6008,"验证码已过期,请重新操作。") + c.JsonResult(6008, "验证码已过期,请重新操作。") } - member ,err := models.NewMember().Find(member_token.MemberId) - if err != nil{ + member, err := models.NewMember().Find(member_token.MemberId) + if err != nil { beego.Error(err) - c.JsonResult(6005,"用户不存在") + c.JsonResult(6005, "用户不存在") } - hash ,err := utils.PasswordHash(password1); + hash, err := utils.PasswordHash(password1) - if err != nil { + if err != nil { beego.Error(err) - c.JsonResult(6006,"保存密码失败") + c.JsonResult(6006, "保存密码失败") } member.Password = hash @@ -321,25 +356,24 @@ func (c *AccountController) ValidEmail() { member_token.IsValid = true member_token.InsertOrUpdate() - if err != nil { + if err != nil { beego.Error(err) - c.JsonResult(6006,"保存密码失败") + c.JsonResult(6006, "保存密码失败") } - c.JsonResult(0,"ok",c.BaseUrl() + beego.URLFor("AccountController.Login")) + c.JsonResult(0, "ok", c.BaseUrl()+beego.URLFor("AccountController.Login")) } +// Logout 退出登录 +func (c *AccountController) Logout() { + c.SetMember(models.Member{}) -// Logout 退出登录. -func (c *AccountController) Logout(){ - c.SetMember(models.Member{}); + c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600) - c.SetSecureCookie(conf.GetAppKey(),"login","",-3600) - - c.Redirect(beego.URLFor("AccountController.Login"),302) + c.Redirect(beego.URLFor("AccountController.Login"), 302) } -//验证码. -func (c *AccountController) Captcha() { +// 验证码 +func (c *AccountController) Captcha() { c.Prepare() captchaImage, err := gocaptcha.NewCaptchaImage(140, 40, gocaptcha.RandLightColor()) @@ -351,17 +385,16 @@ func (c *AccountController) Captcha() { captchaImage.DrawNoise(gocaptcha.CaptchaComplexLower) - //captchaImage.DrawTextNoise(gocaptcha.CaptchaComplexHigh) + // captchaImage.DrawTextNoise(gocaptcha.CaptchaComplexHigh) txt := gocaptcha.RandText(4) - c.SetSession(conf.CaptchaSessionName,txt) + c.SetSession(conf.CaptchaSessionName, txt) captchaImage.DrawText(txt) - //captchaImage.Drawline(3); + // captchaImage.Drawline(3); captchaImage.DrawBorder(gocaptcha.ColorToRGB(0x17A7A7A)) - //captchaImage.DrawHollowLine() - + // captchaImage.DrawHollowLine() captchaImage.SaveImage(c.Ctx.ResponseWriter, gocaptcha.ImageFormatJpeg) c.StopRun() -} \ No newline at end of file +} diff --git a/controllers/document.go b/controllers/document.go index 172e3c12..9cedddc4 100644 --- a/controllers/document.go +++ b/controllers/document.go @@ -99,6 +99,11 @@ func isUserLoggedIn(c *DocumentController) bool { } func promptUserToLogIn(c *DocumentController) { + beego.Info("Access " + c.Ctx.Request.URL.RequestURI() + " not permitted.") + beego.Info(" Access will be redirected to login page(SessionId: " + c.CruSession.SessionID() + ").") + + c.SetSession("turl", c.Ctx.Request.URL.RequestURI()) + if c.IsAjax() { c.JsonResult(6000, "需要[重]登录。") } else { diff --git a/static/js/markdown.js b/static/js/markdown.js index 3cb575c5..a6b7f0c6 100644 --- a/static/js/markdown.js +++ b/static/js/markdown.js @@ -1,31 +1,32 @@ $(function () { window.addDocumentModalFormHtml = $(this).find("form").html(); window.editor = editormd("docEditor", { - width : "100%", - height : "100%", - path : "/static/editor.md/lib/", - toolbar : true, - placeholder: "本编辑器支持Markdown编辑,左边编写,右边预览", + width: "100%", + height: "100%", + path: "/static/editor.md/lib/", + toolbar: true, + placeholder: "本编辑器支持 Markdown 编辑,左边编写,右边预览。", imageUpload: true, imageFormats: ["jpg", "jpeg", "gif", "png", "JPG", "JPEG", "GIF", "PNG"], - imageUploadURL: window.imageUploadURL , - toolbarModes : "full", + imageUploadURL: window.imageUploadURL, + toolbarModes: "full", fileUpload: true, - fileUploadURL : window.fileUploadURL, - taskList : true, - flowChart : true, - htmlDecode : "style,script,iframe,title,onmouseover,onmouseout,style", - lineNumbers : false, - tocStartLevel : 1, - tocm : true, - saveHTMLToTextarea : true, - onload : function() { + fileUploadURL: window.fileUploadURL, + taskList: true, + flowChart: true, + htmlDecode: "style,script,iframe,title,onmouseover,onmouseout,style", + lineNumbers: false, + tocStartLevel: 1, + tocm: true, + saveHTMLToTextarea: true, + + onload: function() { this.hideToolbar(); var keyMap = { "Ctrl-S": function(cm) { saveDocument(false); }, - "Cmd-S" : function(cm){ + "Cmd-S": function(cm){ saveDocument(false); }, "Ctrl-A": function(cm) { @@ -35,7 +36,7 @@ $(function () { this.addKeyMap(keyMap); var $select_node_id = window.treeCatalog.get_selected(); - if($select_node_id) { + if ($select_node_id) { var $select_node = window.treeCatalog.get_node($select_node_id[0]) if ($select_node) { $select_node.node = { @@ -45,20 +46,21 @@ $(function () { loadDocument($select_node); } } - uploadImage("docEditor",function ($state, $res) { - if($state === "before"){ + + uploadImage("docEditor", function ($state, $res) { + if ($state === "before") { return layer.load(1, { - shade: [0.1,'#fff'] //0.1透明度的白色背景 + shade: [0.1, '#fff'] // 0.1 透明度的白色背景 }); - }else if($state === "success"){ - if($res.errcode === 0) { + } else if ($state === "success") { + if ($res.errcode === 0) { var value = '![](' + $res.url + ')'; window.editor.insertValue(value); } } }); }, - onchange : function () { + onchange: function () { resetEditorChanged(true); } }); @@ -66,62 +68,50 @@ $(function () { /** * 实现标题栏操作 */ - $("#editormd-tools").on("click","a[class!='disabled']",function () { + $("#editormd-tools").on("click", "a[class!='disabled']", function () { var name = $(this).find("i").attr("name"); - if(name === "attachment"){ + if (name === "attachment") { $("#uploadAttachModal").modal("show"); - }else if(name === "history"){ + } else if (name === "history") { window.documentHistory(); - }else if(name === "save"){ + } else if (name === "save") { saveDocument(false); - }else if(name === "template"){ + } else if (name === "template") { $("#documentTemplateModal").modal("show"); - }else if(name === "sidebar"){ - $("#manualCategory").toggle(0,"swing",function () { - + } else if (name === "sidebar") { + $("#manualCategory").toggle(0, "swing", function () { var $then = $("#manualEditorContainer"); var left = parseInt($then.css("left")); - if(left > 0){ + if (left > 0) { window.editorContainerLeft = left; - $then.css("left","0"); - }else{ - $then.css("left",window.editorContainerLeft + "px"); + $then.css("left", "0"); + } else { + $then.css("left", window.editorContainerLeft + "px"); } window.editor.resize(); }); - }else if(name === "release"){ - if(Object.prototype.toString.call(window.documentCategory) === '[object Array]' && window.documentCategory.length > 0){ - if($("#markdown-save").hasClass('change')) { + } else if (name === "release") { + if (Object.prototype.toString.call(window.documentCategory) === '[object Array]' && window.documentCategory.length > 0) { + if ($("#markdown-save").hasClass('change')) { var comfirm_result = confirm("编辑内容未保存,需要保存吗?") - if(comfirm_result) { - saveDocument(); + if (comfirm_result) { + saveDocument(false, releaseBook); + return; } } - $.ajax({ - url : window.releaseURL, - data :{"identify" : window.book.identify }, - type : "post", - dataType : "json", - success : function (res) { - if(res.errcode === 0){ - layer.msg("发布任务已推送到任务队列,稍后将在后台执行。"); - }else{ - layer.msg(res.message); - } - } - }); - }else{ + + releaseBook(); + } else { layer.msg("没有需要发布的文档") } - }else if(name === "tasks") { - //插入GFM任务列表 + } else if (name === "tasks") { + // 插入 GFM 任务列表 var cm = window.editor.cm; var selection = cm.getSelection(); if (selection === "") { cm.replaceSelection("- [x] " + selection); - } - else { + } else { var selectionText = selection.split("\n"); for (var i = 0, len = selectionText.length; i < len; i++) { @@ -129,7 +119,7 @@ $(function () { } cm.replaceSelection(selectionText.join("\n")); } - }else { + } else { var action = window.editor.toolbarHandlers[name]; if (action !== "undefined") { @@ -145,23 +135,23 @@ $(function () { */ window.loadDocument = function($node) { var index = layer.load(1, { - shade: [0.1,'#fff'] //0.1透明度的白色背景 + shade: [0.1, '#fff'] // 0.1 透明度的白色背景 }); $.get(window.editURL + $node.node.id ).done(function (res) { layer.close(index); resetEditor(); - if(res.errcode === 0){ + if (res.errcode === 0) { window.isLoad = true; window.editor.clear(); window.editor.insertValue(res.data.markdown); - window.editor.setCursor({line:0, ch:0}); - var node = { "id" : res.data.doc_id,'parent' : res.data.parent_id === 0 ? '#' : res.data.parent_id ,"text" : res.data.doc_name,"identify" : res.data.identify,"version" : res.data.version}; + window.editor.setCursor({ line : 0, ch : 0 }); + var node = { "id": res.data.doc_id, 'parent': res.data.parent_id === 0 ? '#' : res.data.parent_id, "text": res.data.doc_name, "identify": res.data.identify, "version": res.data.version }; pushDocumentCategory(node); window.selectNode = node; pushVueLists(res.data.attach); - }else{ + } else { layer.msg("文档加载失败"); } }).fail(function () { @@ -174,58 +164,75 @@ $(function () { * 保存文档到服务器 * @param $is_cover 是否强制覆盖 */ - function saveDocument($is_cover,callback) { + function saveDocument($is_cover, callback) { var index = null; var node = window.selectNode; var content = window.editor.getMarkdown(); var html = window.editor.getPreviewedHTML(); var version = ""; - if(!node){ + if (!node) { layer.msg("获取当前文档信息失败"); return; } + var doc_id = parseInt(node.id); - for(var i in window.documentCategory){ + for (var i in window.documentCategory) { var item = window.documentCategory[i]; - if(item.id === doc_id){ + if (item.id === doc_id) { version = item.version; break; } } $.ajax({ - beforeSend : function () { - index = layer.load(1, {shade: [0.1,'#fff'] }); + beforeSend: function () { + index = layer.load(1, { shade: [0.1, '#fff'] }); }, - url : window.editURL, - data : {"identify" : window.book.identify,"doc_id" : doc_id,"markdown" : content,"html" : html,"cover" : $is_cover ? "yes":"no","version": version}, - type :"post", - dataType :"json", - success : function (res) { + url: window.editURL, + data: { "identify": window.book.identify, "doc_id": doc_id, "markdown": content, "html": html, "cover": $is_cover ? "yes" : "no", "version": version }, + type: "post", + dataType: "json", + success: function (res) { layer.close(index); - if(res.errcode === 0){ + if (res.errcode === 0) { resetEditorChanged(false); - for(var i in window.documentCategory){ + for (var i in window.documentCategory) { var item = window.documentCategory[i]; - if(item.id === doc_id){ + if (item.id === doc_id) { window.documentCategory[i].version = res.data.version; break; } } - if(typeof callback === "function"){ + if (typeof callback === "function") { callback(); } - }else if(res.errcode === 6005){ + } else if(res.errcode === 6005) { var confirmIndex = layer.confirm('文档已被其他人修改确定覆盖已存在的文档吗?', { - btn: ['确定','取消'] //按钮 - }, function(){ + btn: ['确定', '取消'] // 按钮 + }, function() { layer.close(confirmIndex); - saveDocument(true,callback); + saveDocument(true, callback); }); - }else{ + } else { + layer.msg(res.message); + } + } + }); + } + + function releaseBook() { + $.ajax({ + url: window.releaseURL, + data: { "identify": window.book.identify }, + type: "post", + dataType: "json", + success: function (res) { + if (res.errcode === 0) { + layer.msg("发布任务已推送到任务队列,稍后将在后台执行。"); + } else { layer.msg(res.message); } } @@ -233,7 +240,6 @@ $(function () { } function resetEditor($node) { - } /** @@ -241,35 +247,34 @@ $(function () { * @param $is_change */ function resetEditorChanged($is_change) { - if($is_change && !window.isLoad ){ + if ($is_change && !window.isLoad) { $("#markdown-save").removeClass('disabled').addClass('change'); - }else{ + } else { $("#markdown-save").removeClass('change').addClass('disabled'); } window.isLoad = false; } + /** * 添加顶级文档 */ $("#addDocumentForm").ajaxForm({ - beforeSubmit : function () { + beforeSubmit: function () { var doc_name = $.trim($("#documentName").val()); - if (doc_name === ""){ - return showError("目录名称不能为空","#add-error-message") + if (doc_name === "") { + return showError("目录名称不能为空", "#add-error-message") } $("#btnSaveDocument").button("loading"); return true; }, - success : function (res) { - if(res.errcode === 0){ - - var data = { "id" : res.data.doc_id,'parent' : res.data.parent_id === 0 ? '#' : res.data.parent_id ,"text" : res.data.doc_name,"identify" : res.data.identify,"version" : res.data.version}; + success: function (res) { + if (res.errcode === 0) { + var data = { "id": res.data.doc_id, 'parent': res.data.parent_id === 0 ? '#' : res.data.parent_id , "text": res.data.doc_name, "identify": res.data.identify, "version": res.data.version }; var node = window.treeCatalog.get_node(data.id); - if(node){ - window.treeCatalog.rename_node({"id":data.id},data.text); - - }else { + if (node) { + window.treeCatalog.rename_node({ "id": data.id }, data.text); + } else { window.treeCatalog.create_node(data.parent, data); window.treeCatalog.deselect_all(); window.treeCatalog.select_node(data); @@ -277,8 +282,8 @@ $(function () { pushDocumentCategory(data); $("#markdown-save").removeClass('change').addClass('disabled'); $("#addDocumentModal").modal('hide'); - }else{ - showError(res.message,"#add-error-message") + } else { + showError(res.message, "#add-error-message"); } $("#btnSaveDocument").button("reset"); } @@ -311,7 +316,6 @@ $(function () { "label": "添加文档", "icon": "fa fa-plus", "action": function (data) { - var inst = $.jstree.reference(data.reference), node = inst.get_node(data.reference); @@ -347,26 +351,26 @@ $(function () { }).on('loaded.jstree', function () { window.treeCatalog = $(this).jstree(); }).on('select_node.jstree', function (node, selected, event) { - if($("#markdown-save").hasClass('change')) { - if(confirm("编辑内容未保存,需要保存吗?")){ - saveDocument(false,function () { + if ($("#markdown-save").hasClass('change')) { + if (confirm("编辑内容未保存,需要保存吗?")) { + saveDocument(false, function () { loadDocument(selected); }); return true; } } + loadDocument(selected); + }).on("move_node.jstree", jstree_save); - }).on("move_node.jstree",jstree_save); - - $("#documentTemplateModal").on("click",".section>a[data-type]",function () { + $("#documentTemplateModal").on("click", ".section>a[data-type]", function () { var $this = $(this).attr("data-type"); var body = $("#template-" + $this).html(); if (body) { window.isLoad = true; window.editor.clear(); window.editor.insertValue(body); - window.editor.setCursor({line: 0, ch: 0}); + window.editor.setCursor({ line: 0, ch: 0 }); resetEditorChanged(true); } $("#documentTemplateModal").modal('hide'); diff --git a/static/js/splitbar.js b/static/js/splitbar.js new file mode 100644 index 00000000..c4effcfa --- /dev/null +++ b/static/js/splitbar.js @@ -0,0 +1,176 @@ +$(function () { + var splitBar = { + // 设置当前屏幕为 840px 时将分割条隐藏 + maxWidth: 840, + + // 父元素选择器 + parentSelector: '.manual-body', + + /** + * 初始化分割条 + */ + init: function () { + var self = this; + $(self.parentSelector) + .append( + $('\ +
\ + \ +
\ + ') + .hover( + function (event) { + event.target.style.background = '#8f949ad8'; + }, + function (event) { + event.target.style.background = ''; + } + ) + ); + + self.loadingHtml(); + + // 设置媒体查询 + mediaMatcher.set(); + }, + + /** + * 加载页面时设置分割条是否显示 + */ + loadingHtml: function () { + var self = this; + var htmlWidth = document.body.clientWidth; + if (htmlWidth <= self.maxWidth) $('#manual-vsplitbar').css('display', 'none'); + }, + + /** + * 在打开关闭菜单事初始化左右窗口和分割条 + */ + reset: function () { + if (isFullScreen) { + // 关闭菜单时,初始化左右窗口 + $('#manual-vsplitbar').css('display', 'none'); + splitBar.inMaxWidthReset(); + $('.manual-left').css('width', '0px'); + } else { + // 打开菜单时,初始化左右窗口 + $('#manual-vsplitbar').css('display', 'block'); + splitBar.outMaxWidthReset(); + } + }, + + /** + * 屏幕小于等于 840px,重置左右窗口 + */ + inMaxWidthReset: function () { + $('#manual-vsplitbar').css('display', 'none'); + $('.m-manual.manual-reader .manual-right').css('left', '0'); + $('.manual-left').css('width', '280px'); + }, + + /** + * 屏幕大于 840px,重置左右窗口 + */ + outMaxWidthReset: function () { + $('.manual-right').css('left', '279px'); + $('.manual-left').css('width', '279px'); + $('#manual-vsplitbar').css('left', '275px').css('display', 'block'); + } + } + + /** + * 设置媒体查询 + * 分割条隐藏 + */ + var mediaMatcher = { + mql: window.matchMedia('(max-width:' + splitBar.maxWidth + 'px)'), + + /** + * 添加媒体查询监听事件 + */ + set: function () { + var self = this; + self.mql.addListener(self.mqCallback); + }, + + /** + * 删除媒体查询监听事件 + */ + remove: function () { + var self = this; + self.mql.removeListener(self.mqCallback); + }, + + /** + * 媒体查询回调函数 + */ + mqCallback: function (event) { + if (event.target.matches) { // 宽度小于等于 840 像素 + $(".m-manual").removeClass('manual-fullscreen-active'); + splitBar.inMaxWidthReset(); + } else { // 宽度大于 840 像素 + splitBar.outMaxWidthReset(); + } + } + } + + // 初始化分割条 + splitBar.init(); + + /** + * 控制菜单宽度 + * 最小为 140px + */ + $('#manual-vsplitbar').on('mousedown', function (e) { + var bodyEle = $('.manual-body')[0]; + + var leftPane = $('.manual-left')[0]; + var splitBar = $('#manual-vsplitbar')[0]; + var rightPane = $('.manual-right')[0]; + + var disX = (e || event).clientX; + + splitBar.left = splitBar.offsetLeft; + + var docMouseMove = document.onmousemove; + var docMouseUp = document.onmouseup; + + document.onmousemove = function (e) { + var curPos = splitBar.left + ((e || event).clientX - disX); + var maxPos = bodyEle.clientWidth - splitBar.offsetWidth; + + curPos > maxPos && (curPos = maxPos); + curPos < 140 && (curPos = 140); + + leftPane.style.width = curPos + "px"; + splitBar.style.left = curPos - 3 + "px"; + rightPane.style.left = curPos + 3 + "px"; + + return false; + } + + document.onmouseup = function () { + document.onmousemove = docMouseMove; + document.onmouseup = docMouseUp; + splitBar.releaseCapture && splitBar.releaseCapture(); + }; + + splitBar.setCapture && splitBar.setCapture(); + return false; + }); + + /** + * 关闭侧边栏时,同步分割条; + */ + $(".manual-fullscreen-switch").on("click", splitBar.reset); +}); diff --git a/views/account/login.tpl b/views/account/login.tpl index f3ded721..12e3a032 100644 --- a/views/account/login.tpl +++ b/views/account/login.tpl @@ -92,60 +92,63 @@ - - - - - + + + + + +