writing.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. <html lang="zh-CN">
  2. <head>
  3. <meta charset="utf-8">
  4. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <meta name="author" content="jie">
  7. <title>backup-x</title>
  8. <!-- Bootstrap CSS -->
  9. <link rel="stylesheet" href="/static/bootstrap.min.css">
  10. <link rel="stylesheet" href="/static/common.css">
  11. <script src="/static/jquery-3.5.1.min.js"></script>
  12. <script src="/static/bootstrap.min.js"></script>
  13. </head>
  14. <body>
  15. <header>
  16. <div class="navbar navbar-dark bg-dark shadow-sm">
  17. <div class="container d-flex justify-content-between">
  18. <a href="/" class="navbar-brand d-flex align-items-center">
  19. <strong>backup-x</strong>
  20. </a>
  21. </div>
  22. </div>
  23. </header>
  24. <main role="main" style="margin-top: 30px">
  25. <div class="row">
  26. <div class="col-md-6 offset-md-3">
  27. <form>
  28. <button class="btn btn-primary submit_btn" style="margin-bottom: 15px;">Save</button>
  29. <button class="btn btn-warning submit_btn_backupNow" style="margin-bottom: 15px;margin-left: 15px;">Save & Backup Now</button>
  30. <div class="alert" style="display: none;">
  31. <strong id="resultMsg"></strong>
  32. </div>
  33. <div class="portlet">
  34. <h5 class="portlet__head">备份设置</h5>
  35. <div class="portlet__body">
  36. <nav>
  37. <div class="nav nav-tabs" id="nav-tab" role="tablist">
  38. {{range $i, $v := .BackupConfig}}
  39. <a class="nav-item nav-link {{if eq $i 0}}active{{end}}" id="id_{{$i}}" data-toggle="tab" href="#content_{{$i}}" role="tab">
  40. {{if eq $v.ProjectName ""}}
  41. {{$i}}
  42. {{else}}
  43. {{$v.ProjectName}}
  44. {{end}}
  45. </a>
  46. {{end}}
  47. </div>
  48. </nav>
  49. <div class="tab-content" id="nav-tabContent">
  50. {{range $i, $v := .BackupConfig}}
  51. <div class="tab-pane fade {{if eq $i 0}}show active{{end}}" id="content_{{$i}}" role="tabpanel">
  52. <br/>
  53. <div class="form-group row">
  54. <label for="ProjectName_{{$i}}" class="col-sm-2 col-form-label">项目名称</label>
  55. <div class="col-sm-10">
  56. <input class="form-control" name="ProjectName" id="ProjectName_{{$i}}" rows="3" value="{{$v.ProjectName}}" onchange="projectNameChange(this)" aria-describedby="ProjectName_help">
  57. <small id="ProjectName_help" class="form-text text-muted">请输入项目名称,一般取数据库名称,并确保名称不重复</small>
  58. </div>
  59. </div>
  60. <div class="form-group row">
  61. <label for="Command_{{$i}}" class="col-sm-2 col-form-label">备份脚本</label>
  62. <div class="col-sm-10">
  63. <textarea class="form-control" name="Command" id="Command_{{$i}}" rows="3" aria-describedby="Command_help">{{$v.Command}}</textarea>
  64. <small id="Command_help" class="form-text text-muted">
  65. 须包含#{DATE}变量, #{PWD}为下方的密码变量 <a target="blank" href="https://github.com/jeessy2/backup-x#备份脚本参考">备份脚本参考</a>
  66. <br/>例:mysqldump -h192.168.1.11 -uroot -p#{PWD} db-name > #{DATE}.sql
  67. </small>
  68. </div>
  69. </div>
  70. <div class="form-group row">
  71. <label for="Pwd_{{$i}}" class="col-sm-2 col-form-label">密码变量</label>
  72. <div class="col-sm-10">
  73. <input type="password" class="form-control" name="Pwd" id="Pwd_{{$i}}" value="{{$v.Pwd}}">
  74. </div>
  75. </div>
  76. <div class="form-group row">
  77. <label for="SaveDays_{{$i}}" class="col-sm-2 col-form-label">本地保存(天)</label>
  78. <div class="col-sm-4">
  79. <input type="number" class="form-control" name="SaveDays" id="SaveDays_{{$i}}" value="{{$v.SaveDays}}" min="1">
  80. </div>
  81. <label for="SaveDaysS3_{{$i}}" class="col-sm-2 col-form-label">对象存储保存(天)</label>
  82. <div class="col-sm-4">
  83. <input type="number" class="form-control" name="SaveDaysS3" id="SaveDaysS3_{{$i}}" value="{{$v.SaveDaysS3}}" min="1">
  84. </div>
  85. </div>
  86. <div class="form-group row">
  87. <label for="StartTime_{{$i}}" class="col-sm-2 col-form-label">备份起始时间</label>
  88. <div class="col-sm-10">
  89. <select class="form-control" name="StartTime" id="StartTime_{{$i}}" value="{{$v.StartTime}}">
  90. <option value="0" {{if eq $v.StartTime 0}}selected{{end}}>0:00</option>
  91. <option value="1" {{if eq $v.StartTime 1}}selected{{end}}>1:00</option>
  92. <option value="2" {{if eq $v.StartTime 2}}selected{{end}}>2:00</option>
  93. <option value="3" {{if eq $v.StartTime 3}}selected{{end}}>3:00</option>
  94. <option value="4" {{if eq $v.StartTime 4}}selected{{end}}>4:00</option>
  95. <option value="5" {{if eq $v.StartTime 5}}selected{{end}}>5:00</option>
  96. <option value="6" {{if eq $v.StartTime 6}}selected{{end}}>6:00</option>
  97. <option value="7" {{if eq $v.StartTime 7}}selected{{end}}>7:00</option>
  98. <option value="8" {{if eq $v.StartTime 8}}selected{{end}}>8:00</option>
  99. <option value="9" {{if eq $v.StartTime 9}}selected{{end}}>9:00</option>
  100. <option value="10" {{if eq $v.StartTime 10}}selected{{end}}>10:00</option>
  101. <option value="11" {{if eq $v.StartTime 11}}selected{{end}}>11:00</option>
  102. <option value="12" {{if eq $v.StartTime 12}}selected{{end}}>12:00</option>
  103. <option value="13" {{if eq $v.StartTime 13}}selected{{end}}>13:00</option>
  104. <option value="14" {{if eq $v.StartTime 14}}selected{{end}}>14:00</option>
  105. <option value="15" {{if eq $v.StartTime 15}}selected{{end}}>15:00</option>
  106. <option value="16" {{if eq $v.StartTime 16}}selected{{end}}>16:00</option>
  107. <option value="17" {{if eq $v.StartTime 17}}selected{{end}}>17:00</option>
  108. <option value="18" {{if eq $v.StartTime 18}}selected{{end}}>18:00</option>
  109. <option value="19" {{if eq $v.StartTime 19}}selected{{end}}>19:00</option>
  110. <option value="20" {{if eq $v.StartTime 20}}selected{{end}}>20:00</option>
  111. <option value="21" {{if eq $v.StartTime 21}}selected{{end}}>21:00</option>
  112. <option value="22" {{if eq $v.StartTime 22}}selected{{end}}>22:00</option>
  113. <option value="23" {{if eq $v.StartTime 23}}selected{{end}}>23:00</option>
  114. </select>
  115. </div>
  116. </div>
  117. <div class="form-group row">
  118. <label for="Period_{{$i}}" class="col-sm-2 col-form-label">备份周期(分钟)</label>
  119. <div class="col-sm-10">
  120. <input type="number" class="form-control" name="Period" id="Period_{{$i}}" value="{{$v.Period}}" min="1">
  121. </div>
  122. </div>
  123. </div>
  124. {{end}}
  125. </div>
  126. </div>
  127. </div>
  128. <div class="portlet">
  129. <h5 class="portlet__head">服务配置</h5>
  130. <div class="portlet__body">
  131. <div class="form-group row">
  132. <label for="Username" class="col-sm-2 col-form-label">登录用户名</label>
  133. <div class="col-sm-10">
  134. <input class="form-control" name="Username" id="Username" value="{{.Username}}" aria-describedby="Username_help" required>
  135. <small id="Username_help" class="form-text text-muted">必须输入</small>
  136. </div>
  137. </div>
  138. <div class="form-group row">
  139. <label for="Password" class="col-sm-2 col-form-label">登录密码</label>
  140. <div class="col-sm-10">
  141. <input class="form-control" type="password" name="Password" id="Password" value="{{.Password}}" aria-describedby="password_help" required>
  142. <small id="password_help" class="form-text text-muted">必须输入</small>
  143. </div>
  144. </div>
  145. </div>
  146. </div>
  147. <div class="portlet">
  148. <h5 class="portlet__head">Webhook通知</h5>
  149. <div class="portlet__body">
  150. <div class="form-group row">
  151. <label for="WebhookURL" class="col-sm-2 col-form-label">URL</label>
  152. <div class="col-sm-10">
  153. <input class="form-control" name="WebhookURL" id="WebhookURL" value="{{.WebhookURL}}" aria-describedby="WebhookURL_help">
  154. <small id="WebhookURL_help" class="form-text text-muted">
  155. <a target="blank" href="https://github.com/jeessy2/backup-x#webhook">点击参考官方Webhook说明</a><br/>
  156. 支持的变量#{projectName}, #{fileName}, #{fileSize}, #{result},
  157. </small>
  158. </div>
  159. </div>
  160. <div class="form-group row">
  161. <label for="WebhookRequestBody" class="col-sm-2 col-form-label">RequestBody</label>
  162. <div class="col-sm-10">
  163. <textarea class="form-control" id="WebhookRequestBody" name="WebhookRequestBody" rows="3" aria-describedby="WebhookRequestBody_help">
  164. {{- .WebhookRequestBody -}}
  165. </textarea>
  166. <small id="WebhookRequestBody_help" class="form-text text-muted">
  167. RequestBody为空GET请求,不为空POST请求。支持的变量同上
  168. </small>
  169. </div>
  170. </div>
  171. <div class="form-group row">
  172. <label class="col-sm-2 col-form-label"></label>
  173. <div class="col-sm-10">
  174. <button class="btn btn-primary btn-sm" id="webhookTestBtn" aria-describedby="webhookTestBtn_help">模拟测试Webhook</button>
  175. <small id="webhookTestBtn_help" class="form-text text-muted"></small>
  176. </div>
  177. </div>
  178. </div>
  179. </div>
  180. <div class="portlet">
  181. <h5 class="portlet__head">对象存储配置</h5>
  182. <div class="portlet__body">
  183. <div class="form-group row">
  184. <label for="Endpoint" class="col-sm-2 col-form-label">Endpoint</label>
  185. <div class="col-sm-10">
  186. <input class="form-control" name="Endpoint" id="Endpoint" value="{{.Endpoint}}" aria-describedby="Endpoint_help">
  187. </div>
  188. </div>
  189. <div class="form-group row">
  190. <label for="AccessKey" class="col-sm-2 col-form-label">AccessKey</label>
  191. <div class="col-sm-10">
  192. <input class="form-control" name="AccessKey" id="AccessKey" value="{{.AccessKey}}" aria-describedby="AccessKey_help">
  193. </div>
  194. </div>
  195. <div class="form-group row">
  196. <label for="SecretKey" class="col-sm-2 col-form-label">SecretKey</label>
  197. <div class="col-sm-10">
  198. <input class="form-control" type="password" name="SecretKey" id="SecretKey" value="{{.SecretKey}}" aria-describedby="SecretKey_help">
  199. </div>
  200. </div>
  201. <div class="form-group row">
  202. <label for="BucketName" class="col-sm-2 col-form-label">BucketName</label>
  203. <div class="col-sm-10">
  204. <input class="form-control" name="BucketName" id="BucketName" value="{{.BucketName}}" aria-describedby="BucketName_help">
  205. </div>
  206. </div>
  207. </div>
  208. </div>
  209. <button class="btn btn-primary submit_btn" style="margin-bottom: 15px;">Save</button>
  210. <button class="btn btn-warning submit_btn_backupNow" style="margin-bottom: 15px;margin-left: 15px;">Save & Backup Now</button>
  211. </form>
  212. </div>
  213. <div class="col-md-3">
  214. <p class="font-weight-light text-break" style="margin-top: 115px;font-size: 13px;" id="logs"></p>
  215. <button type="button" class="btn btn-outline-primary btn-sm" id="clearLogBtn">清空日志</button>
  216. </div>
  217. </div>
  218. </main>
  219. <script>
  220. $(function(){
  221. $(".submit_btn,.submit_btn_backupNow").on('click',function(e) {
  222. e.preventDefault();
  223. $('body').animate({ scrollTop: 0 }, 300);
  224. $.ajax({
  225. method: "POST",
  226. url: "/save?backupNow=" + e.target.classList.contains("submit_btn_backupNow"),
  227. data: $('form').serialize(),
  228. success: function (result) {
  229. $('.alert').css("display", "block");
  230. if (result !== "ok") {
  231. $('.alert').addClass("alert-danger").removeClass("alert-success")
  232. $('#resultMsg').html(result)
  233. } else {
  234. // ok
  235. $('.alert').addClass("alert-success").removeClass("alert-danger")
  236. $('#resultMsg').html("保存成功")
  237. setTimeout(function(){
  238. $('.alert').css("display", "none");
  239. }, 3000)
  240. }
  241. },
  242. error: function(jqXHR) {
  243. alert(jqXHR.statusText);
  244. }
  245. })
  246. })
  247. })
  248. // projectNameChange
  249. function projectNameChange(that) {
  250. let id = $(that).attr("id").split("_")[1]
  251. console.log($(that).val())
  252. $("#id_"+id).html($(that).val())
  253. }
  254. </script>
  255. <script>
  256. function getLogs() {
  257. $.get("/logs", function(result){
  258. $("#logs").html(result)
  259. })
  260. }
  261. getLogs()
  262. setInterval(getLogs, 5 * 1000)
  263. $(function(){
  264. $("#clearLogBtn").on("click", function(e) {
  265. e.preventDefault();
  266. $.ajax({
  267. method: "GET",
  268. url: "/clearLog",
  269. success: function() {
  270. getLogs()
  271. },
  272. error: function(jqXHR) {
  273. alert(jqXHR.statusText);
  274. }
  275. })
  276. })
  277. })
  278. </script>
  279. <script>
  280. $(function(){
  281. $("#webhookTestBtn").on("click", function(e) {
  282. e.preventDefault();
  283. $.ajax({
  284. method: "POST",
  285. url: "/webhookTest",
  286. data: {"URL": $("#WebhookURL").val(), "RequestBody": $("#WebhookRequestBody").val()},
  287. success: function() {
  288. $("#webhookTestBtn_help").text("提交模拟测试成功, 如修改记得保存配置")
  289. setTimeout(function(){
  290. $("#webhookTestBtn_help").text("")
  291. }, 5000)
  292. },
  293. error: function(jqXHR) {
  294. alert(jqXHR.statusText);
  295. }
  296. })
  297. })
  298. })
  299. </script>
  300. </html>