[v1.1] 新增自动续签并修复了一些 bug

修复后端可能会 panic 的问题
修复前端逻辑问题,新增证书自动续签
This commit is contained in:
0xJacky 2022-01-27 15:04:27 +08:00
parent 27c4b82d54
commit 882fe8c074
121 changed files with 1656 additions and 798 deletions

View file

@ -1,13 +1,14 @@
# Nginx UI # Nginx UI
Yet another Nginx Web UI Yet another Nginx Web UI
Version: 1.0.0 Version: 1.1.0
## 项目特色 ## 项目特色
1. 可在线查看服务器 CPU、内存、load average、磁盘使用率等指标 1. 可在线查看服务器 CPU、内存、load average、磁盘使用率等指标
2. 可一键申请 Let's encrypt 证书 2. 可一键申请 Let's encrypt 证书
3. 在线编辑网站配置文件 3. 可自动续签 Let's encrypt 证书
4. 在线编辑网站配置文件
## 项目预览 ## 项目预览

View file

@ -3,6 +3,8 @@ module.exports = {
"@vue/cli-plugin-babel/preset" "@vue/cli-plugin-babel/preset"
], ],
"plugins": [ "plugins": [
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
["import", {"libraryName": "ant-design-vue", "libraryDirectory": "es", "style": true}, "syntax-dynamic-import"] ["import", {"libraryName": "ant-design-vue", "libraryDirectory": "es", "style": true}, "syntax-dynamic-import"]
], ],
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Before After
Before After

BIN
frontend/dist/img/logo.9e691c6b.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -1 +1 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta content="IE=edge" http-equiv="X-UA-Compatible"><meta content="width=device-width,initial-scale=1,user-scalable=0" name="viewport"><link href="/favicon.ico" rel="icon"><title>Nginx UI</title><link href="/js/chunk-006e4cbc.ce4defda.js" rel="prefetch"><link href="/js/chunk-1188de6e.f8e092e0.js" rel="prefetch"><link href="/js/chunk-15551262.4339ed58.js" rel="prefetch"><link href="/js/chunk-1e5147a5.3620bb79.js" rel="prefetch"><link href="/js/chunk-23e3da44.bae4ce87.js" rel="prefetch"><link href="/js/chunk-2b94df79.2bf29671.js" rel="prefetch"><link href="/js/chunk-2d0cf277.c3db42df.js" rel="prefetch"><link href="/js/chunk-32df5a7d.cdbdd8b4.js" rel="prefetch"><link href="/js/chunk-59b694c3.ef41aa76.js" rel="prefetch"><link href="/js/chunk-5f8bd6de.b088830d.js" rel="prefetch"><link href="/js/chunk-680936db.547a4157.js" rel="prefetch"><link href="/js/chunk-7723cf62.c3f452ca.js" rel="prefetch"><link href="/js/chunk-96068e84.05f16d69.js" rel="prefetch"><link href="/js/chunk-ddbf168e.82ea029a.js" rel="prefetch"><link href="/js/chunk-e0ad5fdc.44fe5a47.js" rel="prefetch"><link href="/js/chunk-vendors.b74315d6.js" rel="modulepreload" as="script"><link href="/js/index.fa8b2c24.js" rel="modulepreload" as="script"></head><body><noscript><strong>We're sorry but Nginx UI doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script type="module" src="/js/chunk-vendors.b74315d6.js"></script><script type="module" src="/js/index.fa8b2c24.js"></script><script>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script><script src="/js/chunk-vendors-legacy.b74315d6.js" nomodule></script><script src="/js/index-legacy.e8aba462.js" nomodule></script></body></html> <!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta content="IE=edge" http-equiv="X-UA-Compatible"><meta content="width=device-width,initial-scale=1,user-scalable=0" name="viewport"><link href="/favicon.ico" rel="icon"><title>Nginx UI</title><link href="/js/chunk-00be396e.f6afc813.js" rel="prefetch"><link href="/js/chunk-0393876a.0e2e8183.js" rel="prefetch"><link href="/js/chunk-05148b16.66291bd9.js" rel="prefetch"><link href="/js/chunk-09f0acda.b788b1ae.js" rel="prefetch"><link href="/js/chunk-2881409a.1f853726.js" rel="prefetch"><link href="/js/chunk-2d0cf277.c260d8d5.js" rel="prefetch"><link href="/js/chunk-312c57da.53fa07de.js" rel="prefetch"><link href="/js/chunk-4216c952.f0073bdb.js" rel="prefetch"><link href="/js/chunk-46dcb584.5ee0f4ea.js" rel="prefetch"><link href="/js/chunk-4f82bf3d.8d3be338.js" rel="prefetch"><link href="/js/chunk-5573b71a.92b99af4.js" rel="prefetch"><link href="/js/chunk-5d4d188e.b0ffa164.js" rel="prefetch"><link href="/js/chunk-6a4ca29d.5593b7e1.js" rel="prefetch"><link href="/js/chunk-83d83096.72980dc3.js" rel="prefetch"><link href="/js/chunk-b508de6a.b421b1eb.js" rel="prefetch"><link href="/js/chunk-c8c0a686.85e5c7a1.js" rel="prefetch"><link href="/js/chunk-vendors.731e48fc.js" rel="modulepreload" as="script"><link href="/js/index.62a46eff.js" rel="modulepreload" as="script"></head><body><noscript><strong>We're sorry but Nginx UI doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script type="module" src="/js/chunk-vendors.731e48fc.js"></script><script type="module" src="/js/index.62a46eff.js"></script><script>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script><script src="/js/chunk-vendors-legacy.731e48fc.js" nomodule></script><script src="/js/index-legacy.ec1dfd27.js" nomodule></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-0393876a"],{"0efa":function(t,n,e){"use strict";e.r(n);var a=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("a-card",{attrs:{title:"配置文件编辑"}},[e("vue-itextarea",{model:{value:t.configText,callback:function(n){t.configText=n},expression:"configText"}}),e("footer-tool-bar",[e("a-space",[e("a-button",{on:{click:function(n){return t.$router.go(-1)}}},[t._v("返回")]),e("a-button",{attrs:{type:"primary"},on:{click:t.save}},[t._v("保存")])],1)],1)],1)},o=[],i=(e("b0c0"),e("9c70")),c=e("a002"),s={name:"DomainEdit",components:{FooterToolBar:i["a"],VueItextarea:c["a"]},data:function(){return{name:this.$route.params.name,configText:""}},watch:{$route:function(){this.init()},config:{handler:function(){this.unparse()},deep:!0}},created:function(){this.init()},methods:{init:function(){var t=this;this.name?this.$api.config.get(this.name).then((function(n){t.configText=n.config})).catch((function(n){console.log(n),t.$message.error("服务器错误")})):this.configText=""},save:function(){var t=this;this.$api.config.save(this.name?this.name:this.config.name,{content:this.configText}).then((function(n){t.configText=n.config,t.$message.success("保存成功")})).catch((function(n){console.log(n),t.$message.error("保存错误")}))}}},r=s,f=(e("8f3d"),e("2877")),u=Object(f["a"])(r,a,o,!1,null,"fe43c41a",null);n["default"]=u.exports},1175:function(t,n,e){var a=e("24fb");n=a(!1),n.push([t.i,".ant-card[data-v-fe43c41a]{margin:10px}@media (max-width:512px){.ant-card[data-v-fe43c41a]{margin:10px 0}}",""]),t.exports=n},"48b1":function(t,n,e){var a=e("1175");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[t.i,a,""]]),a.locals&&(t.exports=a.locals);var o=e("499e").default;o("77d6a146",a,!0,{sourceMap:!1,shadowMode:!1})},"8f3d":function(t,n,e){"use strict";e("48b1")}}]);

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-0393876a"],{"0efa":function(t,n,e){"use strict";e.r(n);var a=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("a-card",{attrs:{title:"配置文件编辑"}},[e("vue-itextarea",{model:{value:t.configText,callback:function(n){t.configText=n},expression:"configText"}}),e("footer-tool-bar",[e("a-space",[e("a-button",{on:{click:function(n){return t.$router.go(-1)}}},[t._v("返回")]),e("a-button",{attrs:{type:"primary"},on:{click:t.save}},[t._v("保存")])],1)],1)],1)},o=[],i=(e("b0c0"),e("9c70")),c=e("a002"),s={name:"DomainEdit",components:{FooterToolBar:i["a"],VueItextarea:c["a"]},data:function(){return{name:this.$route.params.name,configText:""}},watch:{$route:function(){this.init()},config:{handler:function(){this.unparse()},deep:!0}},created:function(){this.init()},methods:{init:function(){var t=this;this.name?this.$api.config.get(this.name).then((function(n){t.configText=n.config})).catch((function(n){console.log(n),t.$message.error("服务器错误")})):this.configText=""},save:function(){var t=this;this.$api.config.save(this.name?this.name:this.config.name,{content:this.configText}).then((function(n){t.configText=n.config,t.$message.success("保存成功")})).catch((function(n){console.log(n),t.$message.error("保存错误")}))}}},r=s,f=(e("8f3d"),e("2877")),u=Object(f["a"])(r,a,o,!1,null,"fe43c41a",null);n["default"]=u.exports},1175:function(t,n,e){var a=e("24fb");n=a(!1),n.push([t.i,".ant-card[data-v-fe43c41a]{margin:10px}@media (max-width:512px){.ant-card[data-v-fe43c41a]{margin:10px 0}}",""]),t.exports=n},"48b1":function(t,n,e){var a=e("1175");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[t.i,a,""]]),a.locals&&(t.exports=a.locals);var o=e("499e").default;o("77d6a146",a,!0,{sourceMap:!1,shadowMode:!1})},"8f3d":function(t,n,e){"use strict";e("48b1")}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-09f0acda"],{"0561":function(t,a,e){var o=e("504c");o.__esModule&&(o=o.default),"string"===typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);var i=e("499e").default;i("4267656c",o,!0,{sourceMap:!1,shadowMode:!1})},"1f35":function(t,a,e){"use strict";e.r(a);var o=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"wrapper"},[e("h1",{staticClass:"title"},[t._v(t._s(t.$route.meta.status_code?t.$route.meta.status_code:404))]),e("p",[t._v(t._s(t.$route.meta.error?t.$route.meta.error:"找不到文件"))])])},i=[],c={name:"Error"},r=c,n=(e("629f"),e("2877")),s=Object(n["a"])(r,o,i,!1,null,"0b28b6c0",null);a["default"]=s.exports},"504c":function(t,a,e){var o=e("24fb");a=o(!1),a.push([t.i,"body[data-v-0b28b6c0],div[data-v-0b28b6c0],h1[data-v-0b28b6c0],html[data-v-0b28b6c0]{padding:0;margin:0}body[data-v-0b28b6c0],html[data-v-0b28b6c0]{color:#444;position:relative;font-family:PingFang SC,Helvetica Neue,Helvetica,Arial,CustomFont,Microsoft YaHei UI,Microsoft YaHei,Hiragino Sans GB,sans-serif;background:#fcfcfc;height:100%}h1[data-v-0b28b6c0]{font-size:8em;font-weight:100}a[data-v-0b28b6c0]{color:#4181b9;text-decoration:none;transition:all .3s ease}a[data-v-0b28b6c0]:active,a[data-v-0b28b6c0]:hover{color:#5bb0ed}.wrapper[data-v-0b28b6c0]{position:absolute;top:0;bottom:0;left:0;right:0;font-size:1em;font-weight:400;width:100%;height:30%;line-height:1;margin:auto;text-align:center}",""]),t.exports=a},"629f":function(t,a,e){"use strict";e("0561")}}]);

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-09f0acda"],{"0561":function(t,a,e){var o=e("504c");o.__esModule&&(o=o.default),"string"===typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);var i=e("499e").default;i("4267656c",o,!0,{sourceMap:!1,shadowMode:!1})},"1f35":function(t,a,e){"use strict";e.r(a);var o=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"wrapper"},[e("h1",{staticClass:"title"},[t._v(t._s(t.$route.meta.status_code?t.$route.meta.status_code:404))]),e("p",[t._v(t._s(t.$route.meta.error?t.$route.meta.error:"找不到文件"))])])},i=[],c={name:"Error"},r=c,n=(e("629f"),e("2877")),s=Object(n["a"])(r,o,i,!1,null,"0b28b6c0",null);a["default"]=s.exports},"504c":function(t,a,e){var o=e("24fb");a=o(!1),a.push([t.i,"body[data-v-0b28b6c0],div[data-v-0b28b6c0],h1[data-v-0b28b6c0],html[data-v-0b28b6c0]{padding:0;margin:0}body[data-v-0b28b6c0],html[data-v-0b28b6c0]{color:#444;position:relative;font-family:PingFang SC,Helvetica Neue,Helvetica,Arial,CustomFont,Microsoft YaHei UI,Microsoft YaHei,Hiragino Sans GB,sans-serif;background:#fcfcfc;height:100%}h1[data-v-0b28b6c0]{font-size:8em;font-weight:100}a[data-v-0b28b6c0]{color:#4181b9;text-decoration:none;transition:all .3s ease}a[data-v-0b28b6c0]:active,a[data-v-0b28b6c0]:hover{color:#5bb0ed}.wrapper[data-v-0b28b6c0]{position:absolute;top:0;bottom:0;left:0;right:0;font-size:1em;font-weight:400;width:100%;height:30%;line-height:1;margin:auto;text-align:center}",""]),t.exports=a},"629f":function(t,a,e){"use strict";e("0561")}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1188de6e"],{"8dcc":function(e,t,r){var a=r("bbfd");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[e.i,a,""]]),a.locals&&(e.exports=a.locals);var n=r("499e").default;n("300c9478",a,!0,{sourceMap:!1,shadowMode:!1})},9761:function(e,t,r){"use strict";r.r(t);var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{staticClass:"login-form",attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["email",{rules:[{type:"email",message:"The input is not valid E-mail!"},{required:!0,message:"Please input your E-mail!"}]}],expression:"[\n 'email',\n { rules: [{\n type: 'email',\n message: 'The input is not valid E-mail!',\n },\n {\n required: true,\n message: 'Please input your E-mail!',\n },] },\n ]"}],attrs:{placeholder:"Email"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"mail"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["username",{rules:[{required:!0,message:"Please input your username!"}]}],expression:"[\n 'username',\n { rules: [{ required: true, message: 'Please input your username!' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"Please input your Password!"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: 'Please input your Password!' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 安装 ")])],1)],1),r("footer",[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)},n=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],i=r("1da1"),o=(r("96cf"),{name:"Login",data:function(){return{form:{},lock:!0,thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock&&e.$router.push("/login")}))},methods:{handleSubmit:function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t,a){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:t||r.$api.install.install_nginx_ui(a).then((function(){r.$router.push("/login")})),r.loading=!1;case 2:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),s=o,l=(r("f139"),r("2877")),u=Object(l["a"])(s,a,n,!1,null,null,null);t["default"]=u.exports},bbfd:function(e,t,r){var a=r("24fb");t=a(!1),t.push([e.i,".project-title{margin:50px}.project-title h1{font-size:50px;font-weight:100;text-align:center}.login-form{max-width:500px;margin:0 auto}footer{padding:30px;text-align:center}",""]),e.exports=t},f139:function(e,t,r){"use strict";r("8dcc")}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1188de6e"],{"8dcc":function(e,t,r){var a=r("bbfd");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[e.i,a,""]]),a.locals&&(e.exports=a.locals);var n=r("499e").default;n("300c9478",a,!0,{sourceMap:!1,shadowMode:!1})},9761:function(e,t,r){"use strict";r.r(t);var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{staticClass:"login-form",attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["email",{rules:[{type:"email",message:"The input is not valid E-mail!"},{required:!0,message:"Please input your E-mail!"}]}],expression:"[\n 'email',\n { rules: [{\n type: 'email',\n message: 'The input is not valid E-mail!',\n },\n {\n required: true,\n message: 'Please input your E-mail!',\n },] },\n ]"}],attrs:{placeholder:"Email"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"mail"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["username",{rules:[{required:!0,message:"Please input your username!"}]}],expression:"[\n 'username',\n { rules: [{ required: true, message: 'Please input your username!' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"Please input your Password!"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: 'Please input your Password!' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 安装 ")])],1)],1),r("footer",[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)},n=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],i=r("1da1"),o=(r("96cf"),{name:"Login",data:function(){return{form:{},lock:!0,thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock&&e.$router.push("/login")}))},methods:{handleSubmit:function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t,a){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:t||r.$api.install.install_nginx_ui(a).then((function(){r.$router.push("/login")})),r.loading=!1;case 2:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),s=o,l=(r("f139"),r("2877")),u=Object(l["a"])(s,a,n,!1,null,null,null);t["default"]=u.exports},bbfd:function(e,t,r){var a=r("24fb");t=a(!1),t.push([e.i,".project-title{margin:50px}.project-title h1{font-size:50px;font-weight:100;text-align:center}.login-form{max-width:500px;margin:0 auto}footer{padding:30px;text-align:center}",""]),e.exports=t},f139:function(e,t,r){"use strict";r("8dcc")}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1e5147a5"],{"22e7":function(e,t,r){var n=r("24fb");t=n(!1),t.push([e.i,".project-title{margin:50px}.project-title h1{font-size:50px;font-weight:100;text-align:center}.login-form{max-width:500px;margin:0 auto}footer{padding:30px;text-align:center}",""]),e.exports=t},4871:function(e,t,r){var n=r("22e7");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var a=r("499e").default;a("749337a0",n,!0,{sourceMap:!1,shadowMode:!1})},"4fde":function(e,t,r){"use strict";r("4871")},a55b:function(e,t,r){"use strict";r.r(t);var n=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{staticClass:"login-form",attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["name",{rules:[{required:!0,message:"Please input your username!"}]}],expression:"[\n 'name',\n { rules: [{ required: true, message: 'Please input your username!' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"Please input your Password!"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: 'Please input your Password!' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 登录 ")])],1)],1),r("footer",[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)},a=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],o=r("1da1"),s=(r("96cf"),r("b0c0"),{name:"Login",data:function(){return{form:{},thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock||e.$router.push("/install")})),this.$store.state.user.token&&this.$router.push("/")},methods:{login:function(e){var t=this;return this.$api.auth.login(e.name,e.password).then(Object(o["a"])(regeneratorRuntime.mark((function e(){var r;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,t.$message.success("登录成功",1);case 2:return r=t.$route.query.next?t.$route.query.next:"/",e.next=5,t.$router.push(r);case 5:case"end":return e.stop()}}),e)})))).catch((function(e){var r;console.log(e),t.$message.error(null!==(r=e.message)&&void 0!==r?r:"服务器错误")}))},handleSubmit:function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t,n){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:if(t){e.next=3;break}return e.next=3,r.login(n);case 3:r.loading=!1;case 4:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),i=s,u=(r("4fde"),r("2877")),c=Object(u["a"])(i,n,a,!1,null,null,null);t["default"]=c.exports}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1e5147a5"],{"22e7":function(e,t,r){var n=r("24fb");t=n(!1),t.push([e.i,".project-title{margin:50px}.project-title h1{font-size:50px;font-weight:100;text-align:center}.login-form{max-width:500px;margin:0 auto}footer{padding:30px;text-align:center}",""]),e.exports=t},4871:function(e,t,r){var n=r("22e7");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var a=r("499e").default;a("749337a0",n,!0,{sourceMap:!1,shadowMode:!1})},"4fde":function(e,t,r){"use strict";r("4871")},a55b:function(e,t,r){"use strict";r.r(t);var n=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{staticClass:"login-form",attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["name",{rules:[{required:!0,message:"Please input your username!"}]}],expression:"[\n 'name',\n { rules: [{ required: true, message: 'Please input your username!' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"Please input your Password!"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: 'Please input your Password!' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 登录 ")])],1)],1),r("footer",[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)},a=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],o=r("1da1"),s=(r("96cf"),r("b0c0"),{name:"Login",data:function(){return{form:{},thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock||e.$router.push("/install")})),this.$store.state.user.token&&this.$router.push("/")},methods:{login:function(e){var t=this;return this.$api.auth.login(e.name,e.password).then(Object(o["a"])(regeneratorRuntime.mark((function e(){var r;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,t.$message.success("登录成功",1);case 2:return r=t.$route.query.next?t.$route.query.next:"/",e.next=5,t.$router.push(r);case 5:case"end":return e.stop()}}),e)})))).catch((function(e){var r;console.log(e),t.$message.error(null!==(r=e.message)&&void 0!==r?r:"服务器错误")}))},handleSubmit:function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t,n){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:if(t){e.next=3;break}return e.next=3,r.login(n);case 3:r.loading=!1;case 4:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),i=s,u=(r("4fde"),r("2877")),c=Object(u["a"])(i,n,a,!1,null,null,null);t["default"]=c.exports}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-23e3da44"],{b2cd:function(t,a,e){"use strict";e("e49f")},dda8:function(t,a,e){"use strict";e.r(a);var o=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"wrapper"},[e("h1",{staticClass:"title"},[t._v(t._s(t.$route.meta.status_code?t.$route.meta.status_code:404))]),e("p",[t._v(t._s(t.$route.meta.error?t.$route.meta.error:"找不到文件"))])])},i=[],r={name:"Error"},c=r,n=(e("b2cd"),e("2877")),s=Object(n["a"])(c,o,i,!1,null,"c0697242",null);a["default"]=s.exports},e49f:function(t,a,e){var o=e("fdbe");o.__esModule&&(o=o.default),"string"===typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);var i=e("499e").default;i("6f232624",o,!0,{sourceMap:!1,shadowMode:!1})},fdbe:function(t,a,e){var o=e("24fb");a=o(!1),a.push([t.i,"body[data-v-c0697242],div[data-v-c0697242],h1[data-v-c0697242],html[data-v-c0697242]{padding:0;margin:0}body[data-v-c0697242],html[data-v-c0697242]{color:#444;position:relative;font-family:PingFang SC,Helvetica Neue,Helvetica,Arial,CustomFont,Microsoft YaHei UI,Microsoft YaHei,Hiragino Sans GB,sans-serif;background:#fcfcfc;height:100%}h1[data-v-c0697242]{font-size:8em;font-weight:100}a[data-v-c0697242]{color:#4181b9;text-decoration:none;transition:all .3s ease}a[data-v-c0697242]:active,a[data-v-c0697242]:hover{color:#5bb0ed}.wrapper[data-v-c0697242]{position:absolute;top:0;bottom:0;left:0;right:0;font-size:1em;font-weight:400;width:100%;height:30%;line-height:1;margin:auto;text-align:center}",""]),t.exports=a}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-23e3da44"],{b2cd:function(t,a,e){"use strict";e("e49f")},dda8:function(t,a,e){"use strict";e.r(a);var o=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"wrapper"},[e("h1",{staticClass:"title"},[t._v(t._s(t.$route.meta.status_code?t.$route.meta.status_code:404))]),e("p",[t._v(t._s(t.$route.meta.error?t.$route.meta.error:"找不到文件"))])])},i=[],r={name:"Error"},c=r,n=(e("b2cd"),e("2877")),s=Object(n["a"])(c,o,i,!1,null,"c0697242",null);a["default"]=s.exports},e49f:function(t,a,e){var o=e("fdbe");o.__esModule&&(o=o.default),"string"===typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);var i=e("499e").default;i("6f232624",o,!0,{sourceMap:!1,shadowMode:!1})},fdbe:function(t,a,e){var o=e("24fb");a=o(!1),a.push([t.i,"body[data-v-c0697242],div[data-v-c0697242],h1[data-v-c0697242],html[data-v-c0697242]{padding:0;margin:0}body[data-v-c0697242],html[data-v-c0697242]{color:#444;position:relative;font-family:PingFang SC,Helvetica Neue,Helvetica,Arial,CustomFont,Microsoft YaHei UI,Microsoft YaHei,Hiragino Sans GB,sans-serif;background:#fcfcfc;height:100%}h1[data-v-c0697242]{font-size:8em;font-weight:100}a[data-v-c0697242]{color:#4181b9;text-decoration:none;transition:all .3s ease}a[data-v-c0697242]:active,a[data-v-c0697242]:hover{color:#5bb0ed}.wrapper[data-v-c0697242]{position:absolute;top:0;bottom:0;left:0;right:0;font-size:1em;font-weight:400;width:100%;height:30%;line-height:1;margin:auto;text-align:center}",""]),t.exports=a}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-4216c952"],{3177:function(e,t,r){var n=r("6f0f");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var a=r("499e").default;a("4d98c476",n,!0,{sourceMap:!1,shadowMode:!1})},"6f0f":function(e,t,r){var n=r("24fb");t=n(!1),t.push([e.i,".container{display:flex;align-items:center;justify-content:center;height:100%}.container .login-form{max-width:400px;width:80%}.container .login-form .project-title{margin:50px}.container .login-form .project-title h1{font-size:50px;font-weight:100;text-align:center}.container .login-form .footer{padding:30px;text-align:center}",""]),e.exports=t},b2b2:function(e,t,r){"use strict";r("3177")},bf90:function(e,t,r){"use strict";r.r(t);var n=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"container"},[r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["name",{rules:[{required:!0,message:"请输入用户名"}]}],expression:"[\n 'name',\n { rules: [{ required: true, message: '请输入用户名' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"请输入密码"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: '请输入密码' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 登录 ")])],1)],1),r("div",{staticClass:"footer"},[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)])},a=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],o=r("1da1"),i=(r("96cf"),r("b0c0"),{name:"Login",data:function(){return{form:{},thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock||e.$router.push("/install")})),this.$store.state.user.token&&this.$router.push("/")},methods:{login:function(e){var t=this;return this.$api.auth.login(e.name,e.password).then(Object(o["a"])(regeneratorRuntime.mark((function e(){var r;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,t.$message.success("登录成功",1);case 2:return r=t.$route.query.next?t.$route.query.next:"/",e.next=5,t.$router.push(r);case 5:case"end":return e.stop()}}),e)})))).catch((function(e){var r;console.log(e),t.$message.error(null!==(r=e.message)&&void 0!==r?r:"服务器错误")}))},handleSubmit:function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t,n){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:if(t){e.next=3;break}return e.next=3,r.login(n);case 3:r.loading=!1;case 4:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),s=i,c=(r("b2b2"),r("2877")),u=Object(c["a"])(s,n,a,!1,null,null,null);t["default"]=u.exports}}]);

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-4216c952"],{3177:function(e,t,r){var n=r("6f0f");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var a=r("499e").default;a("4d98c476",n,!0,{sourceMap:!1,shadowMode:!1})},"6f0f":function(e,t,r){var n=r("24fb");t=n(!1),t.push([e.i,".container{display:flex;align-items:center;justify-content:center;height:100%}.container .login-form{max-width:400px;width:80%}.container .login-form .project-title{margin:50px}.container .login-form .project-title h1{font-size:50px;font-weight:100;text-align:center}.container .login-form .footer{padding:30px;text-align:center}",""]),e.exports=t},b2b2:function(e,t,r){"use strict";r("3177")},bf90:function(e,t,r){"use strict";r.r(t);var n=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"container"},[r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["name",{rules:[{required:!0,message:"请输入用户名"}]}],expression:"[\n 'name',\n { rules: [{ required: true, message: '请输入用户名' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"请输入密码"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: '请输入密码' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 登录 ")])],1)],1),r("div",{staticClass:"footer"},[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)])},a=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],o=r("1da1"),i=(r("96cf"),r("b0c0"),{name:"Login",data:function(){return{form:{},thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock||e.$router.push("/install")})),this.$store.state.user.token&&this.$router.push("/")},methods:{login:function(e){var t=this;return this.$api.auth.login(e.name,e.password).then(Object(o["a"])(regeneratorRuntime.mark((function e(){var r;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,t.$message.success("登录成功",1);case 2:return r=t.$route.query.next?t.$route.query.next:"/",e.next=5,t.$router.push(r);case 5:case"end":return e.stop()}}),e)})))).catch((function(e){var r;console.log(e),t.$message.error(null!==(r=e.message)&&void 0!==r?r:"服务器错误")}))},handleSubmit:function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(o["a"])(regeneratorRuntime.mark((function e(t,n){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:if(t){e.next=3;break}return e.next=3,r.login(n);case 3:r.loading=!1;case 4:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),s=i,c=(r("b2b2"),r("2877")),u=Object(c["a"])(s,n,a,!1,null,null,null);t["default"]=u.exports}}]);

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-46dcb584"],{"0125":function(e,t,r){var a=r("24fb");t=a(!1),t.push([e.i,".project-title{margin:50px}.project-title h1{font-size:50px;font-weight:100;text-align:center}.login-form{max-width:500px;margin:0 auto}footer{padding:30px;text-align:center}",""]),e.exports=t},"0f6e":function(e,t,r){"use strict";r("76f8")},"76f8":function(e,t,r){var a=r("0125");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[e.i,a,""]]),a.locals&&(e.exports=a.locals);var n=r("499e").default;n("447bb34c",a,!0,{sourceMap:!1,shadowMode:!1})},c756:function(e,t,r){"use strict";r.r(t);var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{staticClass:"login-form",attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["email",{rules:[{type:"email",message:"The input is not valid E-mail!"},{required:!0,message:"Please input your E-mail!"}]}],expression:"[\n 'email',\n { rules: [{\n type: 'email',\n message: 'The input is not valid E-mail!',\n },\n {\n required: true,\n message: 'Please input your E-mail!',\n },] },\n ]"}],attrs:{placeholder:"Email"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"mail"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["username",{rules:[{required:!0,message:"Please input your username!"}]}],expression:"[\n 'username',\n { rules: [{ required: true, message: 'Please input your username!' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"Please input your Password!"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: 'Please input your Password!' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 安装 ")])],1)],1),r("footer",[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)},n=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],i=r("1da1"),o=(r("96cf"),{name:"Login",data:function(){return{form:{},lock:!0,thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock&&e.$router.push("/login")}))},methods:{handleSubmit:function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t,a){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:t||r.$api.install.install_nginx_ui(a).then((function(){r.$router.push("/login")})),r.loading=!1;case 2:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),s=o,l=(r("0f6e"),r("2877")),u=Object(l["a"])(s,a,n,!1,null,null,null);t["default"]=u.exports}}]);

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-46dcb584"],{"0125":function(e,t,r){var a=r("24fb");t=a(!1),t.push([e.i,".project-title{margin:50px}.project-title h1{font-size:50px;font-weight:100;text-align:center}.login-form{max-width:500px;margin:0 auto}footer{padding:30px;text-align:center}",""]),e.exports=t},"0f6e":function(e,t,r){"use strict";r("76f8")},"76f8":function(e,t,r){var a=r("0125");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[e.i,a,""]]),a.locals&&(e.exports=a.locals);var n=r("499e").default;n("447bb34c",a,!0,{sourceMap:!1,shadowMode:!1})},c756:function(e,t,r){"use strict";r.r(t);var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"login-form"},[e._m(0),r("a-form",{staticClass:"login-form",attrs:{id:"components-form-demo-normal-login",form:e.form},on:{submit:e.handleSubmit}},[r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["email",{rules:[{type:"email",message:"The input is not valid E-mail!"},{required:!0,message:"Please input your E-mail!"}]}],expression:"[\n 'email',\n { rules: [{\n type: 'email',\n message: 'The input is not valid E-mail!',\n },\n {\n required: true,\n message: 'Please input your E-mail!',\n },] },\n ]"}],attrs:{placeholder:"Email"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"mail"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["username",{rules:[{required:!0,message:"Please input your username!"}]}],expression:"[\n 'username',\n { rules: [{ required: true, message: 'Please input your username!' }] },\n ]"}],attrs:{placeholder:"Username"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-input",{directives:[{name:"decorator",rawName:"v-decorator",value:["password",{rules:[{required:!0,message:"Please input your Password!"}]}],expression:"[\n 'password',\n { rules: [{ required: true, message: 'Please input your Password!' }] },\n ]"}],attrs:{type:"password",placeholder:"Password"}},[r("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),r("a-form-item",[r("a-button",{attrs:{type:"primary",block:!0,"html-type":"submit",loading:e.loading}},[e._v(" 安装 ")])],1)],1),r("footer",[e._v(" Copyright © 2020 - "+e._s(e.thisYear)+" 0xJacky ")])],1)},n=[function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"project-title"},[r("h1",[e._v("Nginx UI")])])}],i=r("1da1"),o=(r("96cf"),{name:"Login",data:function(){return{form:{},lock:!0,thisYear:(new Date).getFullYear(),loading:!1}},created:function(){this.form=this.$form.createForm(this)},mounted:function(){var e=this;this.$api.install.get_lock().then((function(t){t.lock&&e.$router.push("/login")}))},methods:{handleSubmit:function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t){var r=this;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return t.preventDefault(),this.loading=!0,e.next=4,this.form.validateFields(function(){var e=Object(i["a"])(regeneratorRuntime.mark((function e(t,a){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:t||r.$api.install.install_nginx_ui(a).then((function(){r.$router.push("/login")})),r.loading=!1;case 2:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}());case 4:case"end":return e.stop()}}),e,this)})));function t(t){return e.apply(this,arguments)}return t}()}}),s=o,l=(r("0f6e"),r("2877")),u=Object(l["a"])(s,a,n,!1,null,null,null);t["default"]=u.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-680936db"],{"37d1":function(t,n,e){"use strict";e("939c")},"939c":function(t,n,e){var a=e("e78d");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[t.i,a,""]]),a.locals&&(t.exports=a.locals);var o=e("499e").default;o("29ba208a",a,!0,{sourceMap:!1,shadowMode:!1})},e33d:function(t,n,e){"use strict";e.r(n);var a=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("a-card",{attrs:{title:"配置文件编辑"}},[e("vue-itextarea",{model:{value:t.configText,callback:function(n){t.configText=n},expression:"configText"}}),e("footer-tool-bar",[e("a-space",[e("a-button",{on:{click:function(n){return t.$router.go(-1)}}},[t._v("返回")]),e("a-button",{attrs:{type:"primary"},on:{click:t.save}},[t._v("保存")])],1)],1)],1)},o=[],i=(e("b0c0"),e("9c70")),c=e("a002"),s={name:"DomainEdit",components:{FooterToolBar:i["a"],VueItextarea:c["a"]},data:function(){return{name:this.$route.params.name,configText:""}},watch:{$route:function(){this.init()},config:{handler:function(){this.unparse()},deep:!0}},created:function(){this.init()},methods:{init:function(){var t=this;this.name?this.$api.config.get(this.name).then((function(n){t.configText=n.config})).catch((function(n){console.log(n),t.$message.error("服务器错误")})):this.configText=""},save:function(){var t=this;this.$api.config.save(this.name?this.name:this.config.name,{content:this.configText}).then((function(n){t.configText=n.config,t.$message.success("保存成功")})).catch((function(n){console.log(n),t.$message.error("保存错误")}))}}},r=s,u=(e("37d1"),e("2877")),f=Object(u["a"])(r,a,o,!1,null,"4076690a",null);n["default"]=f.exports},e78d:function(t,n,e){var a=e("24fb");n=a(!1),n.push([t.i,".ant-card[data-v-4076690a]{margin:10px}@media (max-width:512px){.ant-card[data-v-4076690a]{margin:10px 0}}",""]),t.exports=n}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-680936db"],{"37d1":function(t,n,e){"use strict";e("939c")},"939c":function(t,n,e){var a=e("e78d");a.__esModule&&(a=a.default),"string"===typeof a&&(a=[[t.i,a,""]]),a.locals&&(t.exports=a.locals);var o=e("499e").default;o("29ba208a",a,!0,{sourceMap:!1,shadowMode:!1})},e33d:function(t,n,e){"use strict";e.r(n);var a=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("a-card",{attrs:{title:"配置文件编辑"}},[e("vue-itextarea",{model:{value:t.configText,callback:function(n){t.configText=n},expression:"configText"}}),e("footer-tool-bar",[e("a-space",[e("a-button",{on:{click:function(n){return t.$router.go(-1)}}},[t._v("返回")]),e("a-button",{attrs:{type:"primary"},on:{click:t.save}},[t._v("保存")])],1)],1)],1)},o=[],i=(e("b0c0"),e("9c70")),c=e("a002"),s={name:"DomainEdit",components:{FooterToolBar:i["a"],VueItextarea:c["a"]},data:function(){return{name:this.$route.params.name,configText:""}},watch:{$route:function(){this.init()},config:{handler:function(){this.unparse()},deep:!0}},created:function(){this.init()},methods:{init:function(){var t=this;this.name?this.$api.config.get(this.name).then((function(n){t.configText=n.config})).catch((function(n){console.log(n),t.$message.error("服务器错误")})):this.configText=""},save:function(){var t=this;this.$api.config.save(this.name?this.name:this.config.name,{content:this.configText}).then((function(n){t.configText=n.config,t.$message.success("保存成功")})).catch((function(n){console.log(n),t.$message.error("保存错误")}))}}},r=s,u=(e("37d1"),e("2877")),f=Object(u["a"])(r,a,o,!1,null,"4076690a",null);n["default"]=f.exports},e78d:function(t,n,e){var a=e("24fb");n=a(!1),n.push([t.i,".ant-card[data-v-4076690a]{margin:10px}@media (max-width:512px){.ant-card[data-v-4076690a]{margin:10px 0}}",""]),t.exports=n}}]);

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-6a4ca29d"],{"06de":function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",{staticStyle:{"text-align":"center"}},[a("div",{staticClass:"logo"},[a("img",{attrs:{src:e.logo,alt:"logo"}})]),a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],o=a("1da1"),s=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{logo:a("4ffd"),this_year:t.getFullYear(),version:"1.1.0",build_id:null!==(e="19")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(o["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),c=s,i=(a("a695"),a("2877")),u=Object(i["a"])(c,n,r,!1,null,"bb72cb78",null);t["default"]=u.exports},"0c2d":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".logo img[data-v-bb72cb78]{max-width:120px}.egg[data-v-bb72cb78]{padding:10px 0}.ant-btn[data-v-bb72cb78]{margin:10px 10px 0 0}",""]),e.exports=t},"4ffd":function(e,t,a){e.exports=a.p+"img/logo.9e691c6b.png"},5683:function(e,t,a){var n=a("0c2d");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("fc536a1c",n,!0,{sourceMap:!1,shadowMode:!1})},a695:function(e,t,a){"use strict";a("5683")}}]);

View file

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-6a4ca29d"],{"06de":function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",{staticStyle:{"text-align":"center"}},[a("div",{staticClass:"logo"},[a("img",{attrs:{src:e.logo,alt:"logo"}})]),a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],o=a("1da1"),s=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{logo:a("4ffd"),this_year:t.getFullYear(),version:"1.1.0",build_id:null!==(e="19")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(o["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),c=s,i=(a("a695"),a("2877")),u=Object(i["a"])(c,n,r,!1,null,"bb72cb78",null);t["default"]=u.exports},"0c2d":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".logo img[data-v-bb72cb78]{max-width:120px}.egg[data-v-bb72cb78]{padding:10px 0}.ant-btn[data-v-bb72cb78]{margin:10px 10px 0 0}",""]),e.exports=t},"4ffd":function(e,t,a){e.exports=a.p+"img/logo.9e691c6b.png"},5683:function(e,t,a){var n=a("0c2d");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("fc536a1c",n,!0,{sourceMap:!1,shadowMode:!1})},a695:function(e,t,a){"use strict";a("5683")}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-96068e84"],{"0d92":function(e,t,a){"use strict";a("e6a6")},"7c22":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".egg[data-v-0db462a3]{padding:10px 0}.ant-btn[data-v-0db462a3]{margin:10px 10px 0 0}",""]),e.exports=t},e6a6:function(e,t,a){var n=a("7c22");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("1fb1813a",n,!0,{sourceMap:!1,shadowMode:!1})},f820:function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",[a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],s=a("1da1"),i=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{this_year:t.getFullYear(),version:"1.0.0",build_id:null!==(e="16")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),o=i,c=(a("0d92"),a("2877")),u=Object(c["a"])(o,n,r,!1,null,"0db462a3",null);t["default"]=u.exports}}]);

View file

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-96068e84"],{"0d92":function(e,t,a){"use strict";a("e6a6")},"7c22":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".egg[data-v-0db462a3]{padding:10px 0}.ant-btn[data-v-0db462a3]{margin:10px 10px 0 0}",""]),e.exports=t},e6a6:function(e,t,a){var n=a("7c22");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("1fb1813a",n,!0,{sourceMap:!1,shadowMode:!1})},f820:function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",[a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],s=a("1da1"),i=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{this_year:t.getFullYear(),version:"1.0.0",build_id:null!==(e="16")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),o=i,c=(a("0d92"),a("2877")),u=Object(c["a"])(o,n,r,!1,null,"0db462a3",null);t["default"]=u.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
frontend/dist/js/index.62a46eff.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"version":"1.0.0","build_id":12,"total_build":16} {"version":"1.1.0","build_id":2,"total_build":19}

View file

@ -1,6 +1,6 @@
{ {
"name": "nginx-ui-frontend", "name": "nginx-ui-frontend",
"version": "1.0.0", "version": "1.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
@ -51,6 +51,7 @@
"sass-loader": "^10", "sass-loader": "^10",
"vue-cli-plugin-generate-build-id": "^0.2.0", "vue-cli-plugin-generate-build-id": "^0.2.0",
"vue-cropper": "^0.5.6", "vue-cropper": "^0.5.6",
"vue-template-babel-compiler": "^1.1.2",
"vue-template-compiler": "^2.6.11" "vue-template-compiler": "^2.6.11"
}, },
"eslintConfig": { "eslintConfig": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Before After
Before After

View file

@ -33,6 +33,14 @@ const domain = {
cert_info(domain) { cert_info(domain) {
return http.get('cert/' + domain + '/info') return http.get('cert/' + domain + '/info')
},
add_auto_cert(domain) {
return http.post('cert/' + domain)
},
remove_auto_cert(domain) {
return http.delete('cert/' + domain)
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -1,5 +1,6 @@
<template> <template>
<div class="logo"> <div class="logo">
<img :src="logo" alt="logo" />
<p class="text">Nginx UI</p> <p class="text">Nginx UI</p>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
@ -7,7 +8,12 @@
<script> <script>
export default { export default {
name: 'Logo' name: 'Logo',
data() {
return {
logo: require('@/assets/img/logo.png')
}
}
} }
</script> </script>
@ -31,7 +37,7 @@ export default {
font-size: 23px; font-size: 23px;
line-height: 48px; line-height: 48px;
height: 48px; height: 48px;
text-align: center; padding-left: 52px;
} }
} }
</style> </style>

View file

@ -0,0 +1,53 @@
<template>
<div>
<a-checkbox-group v-model="checkedList" :options="options" @change="onChange"/>
<template v-if="allowOther&&checkedList.indexOf('其他')>0">
<a-form-item label="其他">
<a-input v-model="other" @change="onChangeOther"/>
</a-form-item>
</template>
</div>
</template>
<script>
export default {
name: 'StdCheckGroup',
props: {
options: Array,
allowOther: Boolean,
data: {
type: Object,
default() {
return {
checkedList: [],
other: ''
}
}
}
},
model: {
prop: 'data',
event: 'changeData'
},
watch: {
data() {
this.checkedList = this.data.checkedList
this.other = this.data.other
}
},
data() {
return {
checkedList: this.data.checkedList,
other: this.data.other
}
},
methods: {
onChange(checkedList) {
this.checkedList = checkedList
this.$emit('changeData', this.$data)
},
onChangeOther() {
this.$emit('changeData', this.$data)
}
},
}
</script>

View file

@ -14,13 +14,14 @@
<script> <script>
export default { export default {
name: "StdCheckTag", name: 'StdCheckTag',
data() { data() {
return { return {
selectedTag: '', selectedTag: '',
} }
}, },
props: { props: {
disabled: [Boolean],
value: [Number, String, Boolean], value: [Number, String, Boolean],
options: [Array, Object], options: [Array, Object],
keyType: { keyType: {
@ -36,9 +37,11 @@ export default {
}, },
methods: { methods: {
handleChange(tag) { handleChange(tag) {
if (!this.disabled) {
this.selectedTag = tag this.selectedTag = tag
this.$emit('change', isNaN(parseInt(tag)) || this.keyType === 'string' ? tag : parseInt(tag)) this.$emit('change', isNaN(parseInt(tag)) || this.keyType === 'string' ? tag : parseInt(tag))
} }
}
}, },
watch: { watch: {
value() { value() {
@ -55,6 +58,7 @@ export default {
.ant-tag { .ant-tag {
background-color: rgba(0, 0, 0, 0.05); background-color: rgba(0, 0, 0, 0.05);
} }
.ant-tag-checkable-checked { .ant-tag-checkable-checked {
background-color: #1890ff; background-color: #1890ff;
} }

View file

@ -7,7 +7,12 @@
:validate-status="error[d.dataIndex] ? 'error' :'success'" :validate-status="error[d.dataIndex] ? 'error' :'success'"
:wrapperCol="d.edit.wrapperCol" :wrapperCol="d.edit.wrapperCol"
> >
<a-input v-if="d.edit.type==='input'" v-model="dataSource[d.dataIndex]" :placeholder="d.edit.placeholder" /> <p v-if="d.description" v-html="d.description+'<br/>'"/>
<a-input
v-if="d.edit.type==='input'"
v-model="dataSource[d.dataIndex]"
:placeholder="getInputPlaceholder(d, dataSource)"
/>
<a-textarea v-else-if="d.edit.type==='textarea'" v-model="dataSource[d.dataIndex]" <a-textarea v-else-if="d.edit.type==='textarea'" v-model="dataSource[d.dataIndex]"
:rows="d.edit.row?d.edit.row:5"/> :rows="d.edit.row?d.edit.row:5"/>
<std-select-option <std-select-option
@ -24,13 +29,21 @@
:options="d.mask" :options="d.mask"
/> />
<std-multi-check-tag
v-else-if="d.edit.type==='multi-check-tag'"
v-model="temp[d.dataIndex]"
:data-object="temp"
:options="d.mask"
/>
<std-selector <std-selector
v-else-if="d.edit.type==='selector'" v-model="temp[d.dataIndex]" :api="d.edit.api" v-else-if="d.edit.type==='selector'" v-model="temp[d.dataIndex]" :api="d.edit.api"
:columns="d.edit.columns" :columns="d.edit.columns"
:data_key="d.edit.data_key" :data_key="d.edit.data_key"
:disable_search="d.edit.disable_search" :pagination_method="d.edit.pagination_method" :disable_search="d.edit.disable_search" :pagination_method="d.edit.pagination_method"
:record-value-index="d.edit.recordValueIndex" :value="fn(temp, d.edit.valueIndex)" :record-value-index="d.edit.recordValueIndex" :value="fn(temp, d.edit.valueIndex)"
:get_params="{...d.edit.get_params, ...bindModel(d.edit.bind, temp)}" :get_params="get_params_fn(d)"
:description="d.edit.description"
selection-type="radio" selection-type="radio"
/> />
@ -45,8 +58,7 @@
:crop="d.edit.crop" :crop="d.edit.crop"
:auto-upload="d.edit.auto_upload" :auto-upload="d.edit.auto_upload"
:crop-options="d.edit.cropOptions" :type="d.edit.upload_type ? d.edit.upload_type : 'img'" :crop-options="d.edit.cropOptions" :type="d.edit.upload_type ? d.edit.upload_type : 'img'"
@changeFileUrl="url => {$emit('change_'+d.dataIndex, url)}" @uploaded="url => {$emit('uploaded', url)}"
@uploaded="url => {$emit(d.dataIndex+'Uploaded', url)}"
/> />
<std-date-picker v-else-if="d.edit.type==='date_picker'" v-model="temp[d.dataIndex]" <std-date-picker v-else-if="d.edit.type==='date_picker'" v-model="temp[d.dataIndex]"
@ -72,6 +84,20 @@
{{ d.text }} {{ d.text }}
</a-checkbox> </a-checkbox>
<std-check-group
v-else-if="d.edit.type==='check-group'"
v-model="temp[d.dataIndex]"
:options="d.options"
:allow-other="d.edit.allow_other"
/>
<std-radio-group
v-else-if="d.edit.type==='radio-group'"
v-model="temp[d.dataIndex]"
:options="d.options"
:key-type="d.edit.key_type"
/>
<std-transfer <std-transfer
v-else-if="d.edit.type==='transfer'" v-else-if="d.edit.type==='transfer'"
v-model="temp[d.dataIndex]" v-model="temp[d.dataIndex]"
@ -79,14 +105,15 @@
:data-key="d.edit.dataKey" :data-key="d.edit.dataKey"
/> />
<rich-text-editor v-else-if="d.edit.type==='rich-text'" v-model="temp[d.dataIndex]" /> <rich-text-editor v-else-if="d.edit.type==='rich-text'" v-model="temp[d.dataIndex]"/>
<p v-else-if="d.edit.type==='readonly'"> <p v-else-if="d.edit.type==='readonly'">
{{ d.mask ? d.mask[fn(temp, d.dataIndex)] : fn(temp, d.dataIndex) }} {{ d.mask ? d.mask[fn(temp, d.dataIndex)] : fn(temp, d.dataIndex) }}
</p> </p>
<p v-else>{{ "edit.type 参数非法 " + d.edit.type }}</p> <p v-else>{{ 'edit.type 参数非法 ' + d.edit.type }}</p>
<p v-if="!dataSource[d.dataIndex] && d.empty_description" v-html="d.empty_description"/>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<slot name="supplement"/> <slot name="supplement"/>
@ -101,12 +128,18 @@ import StdSelector from './StdSelector'
import StdUpload from './StdUpload' import StdUpload from './StdUpload'
import StdDatePicker from './StdDatePicker' import StdDatePicker from './StdDatePicker'
import StdTransfer from './StdTransfer' import StdTransfer from './StdTransfer'
import RichTextEditor from "@/components/RichText/RichTextEditor"; import RichTextEditor from '@/components/RichText/RichTextEditor'
import StdCheckTag from "@/components/StdDataEntry/StdCheckTag"; import StdCheckTag from '@/components/StdDataEntry/StdCheckTag'
import StdMultiCheckTag from '@/components/StdDataEntry/StdMultiCheckTag'
import StdCheckGroup from '@/components/StdDataEntry/StdCheckGroup'
import StdRadioGroup from '@/components/StdDataEntry/StdRadioGroup'
export default { export default {
name: 'StdDataEntry', name: 'StdDataEntry',
components: { components: {
StdRadioGroup,
StdCheckGroup,
StdMultiCheckTag,
StdCheckTag, StdCheckTag,
RichTextEditor, RichTextEditor,
StdTransfer, StdTransfer,
@ -144,14 +177,14 @@ export default {
}, },
watch: { watch: {
dataSource() { dataSource() {
this.temp = this.dataSource this.temp = this.dataSource ?? []
}, },
dataList() { dataList() {
this.M_dataList = this.editableColumns(this.dataList) this.M_dataList = this.editableColumns(this.dataList ?? [])
} }
}, },
created() { created() {
this.temp = this.dataSource this.temp = this.dataSource ?? []
if (this.layout === 'horizontal') { if (this.layout === 'horizontal') {
this.labelCol = {span: 4} this.labelCol = {span: 4}
this.wrapperCol = {span: 18} this.wrapperCol = {span: 18}
@ -159,11 +192,14 @@ export default {
this.M_dataList = this.editableColumns(this.dataList) this.M_dataList = this.editableColumns(this.dataList)
}, },
methods: { methods: {
get_params_fn(d) {
return {...d.edit.get_params, ...this.bindModel(d.edit.bind, this.temp)}
},
fn: (obj, desc) => { fn: (obj, desc) => {
const arr = desc.split('.') const arr = desc.split('.')
while (arr.length) { while (arr.length) {
const top = obj[arr.shift()] const top = obj[arr.shift()]
if (!top) { if (top === undefined) {
return null return null
} }
obj = top obj = top
@ -186,6 +222,15 @@ export default {
} }
} }
return object return object
},
getInputPlaceholder(d, dataSource) {
// edit
if (dataSource.id) {
return d.edit.placeholder?.edit ?? d.edit.placeholder
} else {
// add
return d.edit.placeholder?.add ?? d.edit.placeholder
}
} }
} }
} }

View file

@ -0,0 +1,75 @@
<template>
<div>
<template v-for="(v,k) in options">
<a-checkable-tag
:key="k"
:checked="selectedTags.indexOf(k) > -1"
@change="checked => handleChange(k, checked)"
>
{{ v }}
</a-checkable-tag>
</template>
</div>
</template>
<script>
export default {
name: 'StdMultiCheckTag',
data() {
return {
selectedTags: [],
}
},
props: {
disabled: [Boolean],
value: [Array],
dataObject: [Object],
options: {
type: Object,
default() {
return {}
}
},
},
model: {
prop: 'value',
event: 'change'
},
methods: {
handleChange(tag, checked) {
const {selectedTags} = this
this.selectedTags = checked
? [...selectedTags, tag]
: selectedTags.filter(t => t !== tag)
this.$emit('change', this.selectedTags)
},
loadData() {
for (const [k] of Object.entries(this.options)) {
if (this.dataObject[k] === 1) {
if (this.selectedTags.indexOf(k) === -1)
this.selectedTags.push(k)
}
}
}
},
watch: {
value() {
this.selectedTag = this.value ?? []
},
},
created() {
this.selectedTag = this.value ?? []
this.loadData()
},
}
</script>
<style lang="less" scoped>
.ant-tag {
background-color: rgba(0, 0, 0, 0.05);
}
.ant-tag-checkable-checked {
background-color: #1890ff;
}
</style>

View file

@ -7,8 +7,19 @@
:file-list="uploadList" :file-list="uploadList"
:remove="remove" :remove="remove"
> >
<a-button :disabled="disabled"><a-icon type="upload"/>选择文件</a-button> <a-button :disabled="disabled">
<a-icon type="upload"/>
选择文件
</a-button>
</a-upload> </a-upload>
<a-progress
v-if="show_progress"
:stroke-color="{
from: '#108ee9',
to: '#87d068',
}"
:percent="progress"
/>
<a-button <a-button
type="primary" type="primary"
:disabled="uploadList.length === 0 && !id" :disabled="uploadList.length === 0 && !id"
@ -37,7 +48,7 @@
<script> <script>
export default { export default {
name: "StdMultiFilesUpload", name: 'StdMultiFilesUpload',
props: { props: {
api: Function, api: Function,
id: { id: {
@ -67,11 +78,13 @@ export default {
}, },
data() { data() {
return { return {
show_progress: false,
uploadList: [], uploadList: [],
uploaded: this.fileList, uploaded: this.fileList,
lastFileTime: 0, lastFileTime: 0,
server: process.env["VUE_APP_API_UPLOAD_ROOT"], server: process.env['VUE_APP_API_UPLOAD_ROOT'],
uploading: false, uploading: false,
progress: 0
} }
}, },
model: { model: {
@ -82,14 +95,25 @@ export default {
async upload() { async upload() {
if (this.uploadList.length) { if (this.uploadList.length) {
this.uploading = true this.uploading = true
this.show_progress = true
this.progress = 0
let formData = new FormData() let formData = new FormData()
while (this.uploadList.length) { this.uploadList.forEach(v => {
formData.append('file[]', this.uploadList.shift()) formData.append('file[]', v)
} })
this.visible = false this.visible = false
this.uploading = true this.uploading = true
this.$message.info('正在上传附件, 请不要关闭本页') this.$message.info('正在上传附件, 请不要关闭本页')
return this.api(this.id, formData).then(r => { let config = {
onUploadProgress: (progressEvent) => {
// 使 progress
if (progressEvent.lengthComputable) {
this.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100) // 使 UI
}
}
}
return this.api(this.id, formData, config).then(r => {
this.uploadList = []
this.uploaded = [...this.uploaded, ...r] this.uploaded = [...this.uploaded, ...r]
this.uploading = false this.uploading = false
this.$emit('uploaded', r) this.$emit('uploaded', r)
@ -112,7 +136,7 @@ export default {
}, },
getFileName(path) { getFileName(path) {
// 15 // 15
const idx = path.indexOf("/", 15) const idx = path.indexOf('/', 15)
return path.substring(idx + 1) return path.substring(idx + 1)
}, },
remove(r) { remove(r) {

View file

@ -0,0 +1,49 @@
<template>
<a-radio-group name="radioGroup" v-model="data" @change="onChange">
<a-radio :value="k" v-for="(v,k) in options" :key="k">
{{ v }}
</a-radio>
</a-radio-group>
</template>
<script>
export default {
name: 'StdRadioGroup',
props: {
options: [Object,Array],
value: {
type: [String, Number]
},
keyType: String
},
model: {
prop: 'value',
event: 'changeValue'
},
data() {
return {
data: this.value?.toString() ?? '',
}
},
watch: {
value() {
this.data = this.value.toString()
}
},
methods: {
onChange(e) {
if (this.keyType === 'int') {
this.data = e.target.value
this.$emit('changeValue', parseInt(e.target.value))
} else {
this.$emit('changeValue', e.target.value)
}
}
}
}
</script>
<style scoped>
</style>

View file

@ -1,10 +1,9 @@
<template> <template>
<div class="std-selector" @click="visible=true"> <div class="std-selector" @click="show()">
<a-input v-model="_key" disabled hidden/> <a-input v-model="_key" disabled hidden/>
<a-input <div class="value">
v-model="M_value" <p>{{ M_value }}</p>
disabled </div>
/>
<a-modal <a-modal
:mask="false" :mask="false"
:visible="visible" :visible="visible"
@ -16,6 +15,7 @@
:width="600" :width="600"
destroyOnClose destroyOnClose
> >
{{ description }}
<std-table <std-table
:api="api" :api="api"
:columns="columns" :columns="columns"
@ -24,8 +24,9 @@
:pithy="true" :pithy="true"
:get_params="get_params" :get_params="get_params"
:selectionType="selectionType" :selectionType="selectionType"
:disable_query_params="true"
@selected="onSelect" @selected="onSelect"
@selectedRecord="r => {record = r}" @selectedRecord="onSelectedRecord"
/> />
</a-modal> </a-modal>
</div> </div>
@ -61,7 +62,8 @@ export default {
default() { default() {
return {} return {}
} }
} },
description: String
}, },
model: { model: {
prop: '_key', prop: '_key',
@ -86,9 +88,15 @@ export default {
} }
}, },
methods: { methods: {
show() {
this.visible = true
},
onSelect(selected) { onSelect(selected) {
this.selected = selected this.selected = selected
}, },
onSelectedRecord(r) {
this.record = r
},
ok() { ok() {
this.visible = false this.visible = false
let selected = this.selected let selected = this.selected
@ -102,15 +110,47 @@ export default {
} }
</script> </script>
<style scoped>
.ant-form-inline .std-selector {
height: 40px;
}
</style>
<style lang="less" scoped> <style lang="less" scoped>
.std-selector { .std-selector {
.ant-input { height: 38px;
min-width: 180px;
position: relative;
.value {
box-sizing: border-box;
font-variant: tabular-nums;
list-style: none;
font-feature-settings: 'tnum';
position: absolute;
top: 50%;
bottom: 50%;
left: 50%;
-webkit-transform: translateX(-50%) translateY(-50%);
display: inline-block;
width: 100%;
height: 32px;
padding: 4px 11px;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
line-height: 1.5;
background-color: #fff;
background-image: none;
border: 1px solid #d9d9d9;
border-radius: 4px;
transition: all 0.3s;
margin: 0 10px 0 0; margin: 0 10px 0 0;
cursor: pointer; cursor: pointer;
@media (prefers-color-scheme: dark) {
background-color: #1e1f20;
border: 1px solid #666666;
color: rgba(255, 255, 255, 0.99);
} }
.ant-input-disabled {
background: unset;
color: unset;
} }
} }
</style> </style>

View file

@ -3,21 +3,29 @@
<a-upload <a-upload
:before-upload="beforeUpload" :before-upload="beforeUpload"
:multiple="false" :multiple="false"
:show-upload-list="true"
:file-list="uploadList" :file-list="uploadList"
:remove="remove"
> >
<a-button :disabled="disabled"><a-icon type="upload"/>上传</a-button> <a-button :disabled="disabled">
<a-icon type="upload"/>
上传
</a-button>
</a-upload> </a-upload>
<a-progress
v-if="show_progress"
:stroke-color="{from: '#108ee9',to: '#87d068'}"
:percent="progress"
/>
<p style="margin: 15px 0" v-show="fileUrl"> <p style="margin: 15px 0" v-show="fileUrl">
<a-icon type="paper-clip" style="margin-right: 5px"/> <a-icon type="paper-clip" style="margin-right: 5px"/>
<a :href="server + '/' + fileUrl" target="_blank" @click="()=>{}">{{ fileUrl }}</a> <a :href="server + '/' + fileUrl" target="_blank" @click="()=>{}">下载附件</a>
</p> </p>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: "StdSingleFileUpload", name: 'StdSingleFileUpload',
props: { props: {
api: Function, api: Function,
id: { id: {
@ -39,7 +47,9 @@ export default {
data() { data() {
return { return {
uploadList: [], uploadList: [],
server: process.env["VUE_APP_API_UPLOAD_ROOT"], server: process.env['VUE_APP_API_UPLOAD_ROOT'],
progress: 0,
show_progress: false,
} }
}, },
model: { model: {
@ -47,15 +57,27 @@ export default {
event: 'changeFileUrl' event: 'changeFileUrl'
}, },
methods: { methods: {
remove() {
this.uploadList.shift()
},
async upload() { async upload() {
if (this.uploadList.length) { if (this.uploadList.length) {
this.show_progress = true
this.progress = 0
const formData = new FormData() const formData = new FormData()
formData.append('file', this.uploadList.shift()) formData.append('file', this.uploadList.shift())
this.visible = false this.visible = false
this.uploading = true this.uploading = true
this.$message.info('正在上传附件, 请不要关闭本页') this.$message.info('正在上传附件, 请不要关闭本页')
let config = {
return this.api(this.id, formData).then(r => { onUploadProgress: (progressEvent) => {
// 使 progress
if (progressEvent.lengthComputable) {
this.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100)
}
}
}
return this.api(this.id, formData, config).then(r => {
this.$emit('uploaded', r.url) this.$emit('uploaded', r.url)
this.$emit('changeFileUrl', r.url) this.$emit('changeFileUrl', r.url)
this.uploading = false this.uploading = false

View file

@ -50,6 +50,7 @@
:api="api" :api="api"
:auto-upload="autoUpload" :auto-upload="autoUpload"
@changeFileUrl="url => {$emit('changeFileUrl', url)}" @changeFileUrl="url => {$emit('changeFileUrl', url)}"
@uploaded="url => {$emit('uploaded', url)}"
:disabled="disabled" :disabled="disabled"
ref="single-file" ref="single-file"
/> />
@ -63,6 +64,7 @@
:auto-upload="autoUpload" :auto-upload="autoUpload"
:api_delete="api_delete" :api_delete="api_delete"
@changeFileUrl="url => {$emit('changeFileUrl', url)}" @changeFileUrl="url => {$emit('changeFileUrl', url)}"
@uploaded="url => {$emit('uploaded', url)}"
:disabled="disabled" :disabled="disabled"
ref="multi-file" ref="multi-file"
/> />
@ -73,9 +75,9 @@
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import VueCropper from 'vue-cropper' import VueCropper from 'vue-cropper'
import StdSingleFileUpload from "@/components/StdDataEntry/StdSingleFileUpload"; import StdSingleFileUpload from '@/components/StdDataEntry/StdSingleFileUpload'
import StdMultiFilesUpload from "@/components/StdDataEntry/StdMultiFilesUpload"; import StdMultiFilesUpload from '@/components/StdDataEntry/StdMultiFilesUpload'
import { v4 as uuidv4 } from 'uuid'; import {v4 as uuidv4} from 'uuid'
Vue.use(VueCropper) Vue.use(VueCropper)
@ -134,7 +136,7 @@ export default {
visible: false, visible: false,
fileList: [], fileList: [],
M_list: this.list, M_list: this.list,
server: process.env["VUE_APP_API_UPLOAD_ROOT"] server: process.env['VUE_APP_API_UPLOAD_ROOT']
} }
}, },
created() { created() {
@ -151,18 +153,18 @@ export default {
}, },
methods: { methods: {
getFileUrl() { getFileUrl() {
return this.fileUrl.substring(0,5) === 'data:' ? this.fileUrl : return this.fileUrl.substring(0, 5) === 'data:' ? this.fileUrl :
this.server + '/' + this.fileUrl this.server + '/' + this.fileUrl
}, },
async upload() { async upload() {
if (this.type === 'multi-file') { if (this.type === 'multi-file') {
return await this.$refs["multi-file"].upload() return await this.$refs['multi-file'].upload()
} }
if (this.orig && this.fileUrl !== this.orig) { if (this.orig && this.fileUrl !== this.orig) {
return this.handleSingleUpload() return this.handleSingleUpload()
} }
if (this.$refs['single-file']) { if (this.$refs['single-file']) {
return await this.$refs["single-file"].upload() return await this.$refs['single-file'].upload()
} }
}, },
handleSingleUpload() { handleSingleUpload() {
@ -193,6 +195,10 @@ export default {
file.thumbUrl = e.target.result file.thumbUrl = e.target.result
this.$emit('changeFileUrl', e.target.result) this.$emit('changeFileUrl', e.target.result)
} }
if (this.autoUpload) {
this.handleSingleUpload()
return false
}
} else { } else {
this.$emit('changeFileUrl', file.name) this.$emit('changeFileUrl', file.name)
} }

View file

@ -14,7 +14,7 @@ export const routes = [
children: [ children: [
{ {
path: 'dashboard', path: 'dashboard',
component: () => import('@/views/DashBoard'), component: () => import('@/views/doashboard/DashBoard'),
name: '仪表盘', name: '仪表盘',
meta: { meta: {
//hiddenHeaderContent: true, //hiddenHeaderContent: true,
@ -24,7 +24,7 @@ export const routes = [
{ {
path: 'user', path: 'user',
name: '用户管理', name: '用户管理',
component: () => import('@/views/User.vue'), component: () => import('@/views/user/User.vue'),
meta: { meta: {
icon: 'user' icon: 'user'
}, },
@ -40,15 +40,15 @@ export const routes = [
children: [{ children: [{
path: 'list', path: 'list',
name: '网站列表', name: '网站列表',
component: () => import('@/views/Domain.vue'), component: () => import('@/views/domain/DomainList.vue'),
}, { }, {
path: 'add', path: 'add',
name: '添加站点', name: '添加站点',
component: () => import('@/views/domain_edit/DomainEdit.vue'), component: () => import('@/views/domain/DomainAdd.vue'),
}, { }, {
path: ':name', path: ':name',
name: '编辑站点', name: '编辑站点',
component: () => import('@/views/domain_edit/DomainEdit.vue'), component: () => import('@/views/domain/DomainEdit.vue'),
meta: { meta: {
hiddenInSidebar: true hiddenInSidebar: true
} }
@ -57,7 +57,7 @@ export const routes = [
{ {
path: 'config', path: 'config',
name: '配置管理', name: '配置管理',
component: () => import('@/views/Config.vue'), component: () => import('@/views/config/Config.vue'),
meta: { meta: {
icon: 'file' icon: 'file'
}, },
@ -65,7 +65,7 @@ export const routes = [
{ {
path: 'config/:name', path: 'config/:name',
name: '配置编辑', name: '配置编辑',
component: () => import('@/views/ConfigEdit.vue'), component: () => import('@/views/config/ConfigEdit.vue'),
meta: { meta: {
hiddenInSidebar: true hiddenInSidebar: true
}, },
@ -73,7 +73,7 @@ export const routes = [
{ {
path: 'about', path: 'about',
name: '关于', name: '关于',
component: () => import('@/views/About.vue'), component: () => import('@/views/other/About.vue'),
meta: { meta: {
icon: 'info-circle' icon: 'info-circle'
} }
@ -83,19 +83,19 @@ export const routes = [
{ {
path: '/install', path: '/install',
name: '安装', name: '安装',
component: () => import('@/views/Install'), component: () => import('@/views/other/Install'),
meta: {noAuth: true} meta: {noAuth: true}
}, },
{ {
path: '/login', path: '/login',
name: '登录', name: '登录',
component: () => import('@/views/Login'), component: () => import('@/views/other/Login'),
meta: {noAuth: true} meta: {noAuth: true}
}, },
{ {
path: '/404', path: '/404',
name: '404 Not Found', name: '404 Not Found',
component: () => import('@/views/Error'), component: () => import('@/views/other/Error'),
meta: {noAuth: true, status_code: 404, error: 'Not Found'} meta: {noAuth: true, status_code: 404, error: 'Not Found'}
}, },
{ {

View file

@ -1,119 +0,0 @@
<template>
<div class="login-form">
<div class="project-title">
<h1>Nginx UI</h1>
</div>
<a-form
id="components-form-demo-normal-login"
:form="form"
class="login-form"
@submit="handleSubmit"
>
<a-form-item>
<a-input
v-decorator="[
'name',
{ rules: [{ required: true, message: 'Please input your username!' }] },
]"
placeholder="Username"
>
<a-icon slot="prefix" type="user" style="color: rgba(0,0,0,.25)"/>
</a-input>
</a-form-item>
<a-form-item>
<a-input
v-decorator="[
'password',
{ rules: [{ required: true, message: 'Please input your Password!' }] },
]"
type="password"
placeholder="Password"
>
<a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)"/>
</a-input>
</a-form-item>
<a-form-item>
<a-button type="primary" :block="true" html-type="submit" :loading="loading">
登录
</a-button>
</a-form-item>
</a-form>
<footer>
Copyright © 2020 - {{ thisYear }} 0xJacky
</footer>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
form: {},
thisYear: new Date().getFullYear(),
loading: false
}
},
created() {
this.form = this.$form.createForm(this)
},
mounted() {
this.$api.install.get_lock().then(r=>{
if (!r.lock) {
this.$router.push('/install')
}
})
if (this.$store.state.user.token) {
this.$router.push('/')
}
},
methods: {
login(values) {
return this.$api.auth.login(values.name, values.password).then(async () => {
await this.$message.success('登录成功', 1)
const next = this.$route.query.next ? this.$route.query.next : '/'
await this.$router.push(next)
}).catch(r => {
console.log(r)
this.$message.error(r.message ?? '服务器错误')
})
},
handleSubmit: async function (e) {
e.preventDefault()
this.loading = true
await this.form.validateFields(async (err, values) => {
if (!err) {
await this.login(values)
}
this.loading = false
})
},
},
};
</script>
<style lang="less">
.project-title {
margin: 50px;
h1 {
font-size: 50px;
font-weight: 100;
text-align: center;
}
}
.login-form {
max-width: 500px;
margin: 0 auto;
}
.login-form-button {
}
footer {
padding: 30px;
text-align: center;
}
</style>

View file

@ -50,6 +50,6 @@ export default {
} }
</script> </script>
<style scoped> <style lang="less" scoped>
</style> </style>

View file

@ -0,0 +1,65 @@
<template>
<a-card title="添加站点">
<p>在这里添加站点添加完成后进入域名配置编辑页面即可配置 SSL</p>
<std-data-entry :data-list="columns" :data-source="config"/>
<footer-tool-bar>
<a-button
type="primary"
@click="save"
>
完成
</a-button>
</footer-tool-bar>
</a-card>
</template>
<script>
import FooterToolBar from "@/components/FooterToolbar/FooterToolBar"
import StdDataEntry from "@/components/StdDataEntry/StdDataEntry"
import {columns} from "@/views/domain/columns"
import {unparse} from "@/views/domain/methods"
export default {
name: "DomainAdd",
components: {StdDataEntry, FooterToolBar},
data() {
return {
config: {},
columns: columns.slice(0, -1) // SSL
}
},
beforeCreate() {
},
methods: {
save() {
this.$api.domain.get_template('http-conf').then(r => {
let text = unparse(r.template, this.config)
this.$api.domain.save(this.config.name, {content: text, enabled: true}).then(() => {
this.$message.success("保存成功")
this.$api.domain.enable(this.config.name).then(() => {
this.$message.success("启用成功")
this.$router.push('/domain/' + this.config.name)
}).catch(r => {
console.log(r)
this.$message.error(r.message ?? '启用失败', 10)
})
}).catch(r => {
console.log(r)
this.$message.error(r.message ?? '保存错误', 10)
})
})
}
}
}
</script>
<style lang="less" scoped>
.ant-steps {
padding: 10px 0 20px 0;
}
</style>

View file

@ -3,14 +3,18 @@
<a-collapse :bordered="false" default-active-key="1"> <a-collapse :bordered="false" default-active-key="1">
<a-collapse-panel key="1" :header="name ? '编辑站点:' + name : '添加站点'"> <a-collapse-panel key="1" :header="name ? '编辑站点:' + name : '添加站点'">
<p>您的配置文件中应当有对应的字段时下列表单中的设置才能生效配置文件名称创建后不可修改</p> <p>您的配置文件中应当有对应的字段时下列表单中的设置才能生效配置文件名称创建后不可修改</p>
<std-data-entry :data-list="columns" v-model="config" /> <std-data-entry :data-list="columns" v-model="config"/>
<template v-if="config.support_ssl">
<cert-info :domain="name" ref="cert-info" v-if="name"/> <cert-info :domain="name" ref="cert-info" v-if="name"/>
<br/> <br/>
<a-space>
<a-button @click="issue_cert" type="primary" ghost> <a-button @click="issue_cert" type="primary" ghost>
自动申请 Let's Encrypt 证书 自动申请 Let's Encrypt 证书
</a-button> </a-button>
</a-space> <p><br/>点击自动申请证书将会从 Let's Encrypt 获得签发证书
在获取签发证书前请确保配置文件中已为
<code>/.well-known</code> 目录反向代理到后端的
<code>HTTPChallengePort (default:9180)</code></p>
</template>
</a-collapse-panel> </a-collapse-panel>
</a-collapse> </a-collapse>
@ -20,7 +24,7 @@
<footer-tool-bar> <footer-tool-bar>
<a-space> <a-space>
<a-button @click="$router.go(-1)">返回</a-button> <a-button @click="$router.push('/domain/list')">返回</a-button>
<a-button type="primary" @click="save">保存</a-button> <a-button type="primary" @click="save">保存</a-button>
</a-space> </a-space>
</footer-tool-bar> </footer-tool-bar>
@ -32,16 +36,16 @@
import StdDataEntry from "@/components/StdDataEntry/StdDataEntry" import StdDataEntry from "@/components/StdDataEntry/StdDataEntry"
import FooterToolBar from "@/components/FooterToolbar/FooterToolBar" import FooterToolBar from "@/components/FooterToolbar/FooterToolBar"
import VueItextarea from "@/components/VueItextarea/VueItextarea" import VueItextarea from "@/components/VueItextarea/VueItextarea"
import columns from "@/views/domain_edit/columns" import {columns, columnsSSL} from "@/views/domain/columns"
import CertInfo from "@/views/domain_edit/CertInfo"; import {unparse} from "@/views/domain/methods"
import CertInfo from "@/views/domain/CertInfo"
export default { export default {
name: "DomainEdit", name: "DomainEdit",
components: {CertInfo, FooterToolBar, StdDataEntry, VueItextarea}, components: {CertInfo, FooterToolBar, StdDataEntry, VueItextarea},
data() { data() {
return { return {
name: this.$route.params.name, name: this.$route.params.name.toString(),
columns,
config: { config: {
http_listen_port: 80, http_listen_port: 80,
https_listen_port: null, https_listen_port: null,
@ -50,7 +54,8 @@ export default {
root: "", root: "",
ssl_certificate: "", ssl_certificate: "",
ssl_certificate_key: "", ssl_certificate_key: "",
support_ssl: false support_ssl: false,
auto_cert: false
}, },
configText: "", configText: "",
ws: null, ws: null,
@ -68,7 +73,14 @@ export default {
deep: true deep: true
}, },
'config.support_ssl'() { 'config.support_ssl'() {
if (this.ok) this.change_support_ssl() if (this.ok) {
this.change_support_ssl()
}
},
'config.auto_cert'() {
if (this.ok) {
this.change_auto_cert()
}
} }
}, },
created() { created() {
@ -84,7 +96,8 @@ export default {
if (this.name) { if (this.name) {
this.$api.domain.get(this.name).then(r => { this.$api.domain.get(this.name).then(r => {
this.configText = r.config this.configText = r.config
this.parse(r).then(()=>{ this.config.auto_cert = r.auto_cert
this.parse(r).then(() => {
this.ok = true this.ok = true
}) })
}).catch(r => { }).catch(r => {
@ -100,7 +113,8 @@ export default {
root: "", root: "",
ssl_certificate: "", ssl_certificate: "",
ssl_certificate_key: "", ssl_certificate_key: "",
support_ssl: false support_ssl: false,
auto_cert: false,
} }
this.get_template() this.get_template()
} }
@ -133,32 +147,7 @@ export default {
} }
}, },
async unparse() { async unparse() {
let text = this.configText this.configText = unparse(this.configText, this.config)
// http_listen_port: /listen (.*);/i,
// https_listen_port: /listen (.*) ssl/i,
const reg = {
server_name: /server_name[\s](.*);/ig,
index: /index[\s](.*);/i,
root: /root[\s](.*);/i,
ssl_certificate: /ssl_certificate[\s](.*);/i,
ssl_certificate_key: /ssl_certificate_key[\s](.*);/i
}
text = text.replace(/listen[\s](.*);/i, "listen\t"
+ this.config['http_listen_port'] + ';')
text = text.replace(/listen[\s](.*) ssl/i, "listen\t"
+ this.config['https_listen_port'] + ' ssl')
text = text.replace(/listen(.*):(.*);/i, "listen\t[::]:"
+ this.config['http_listen_port'] + ';')
text = text.replace(/listen(.*):(.*) ssl/i, "listen\t[::]:"
+ this.config['https_listen_port'] + ' ssl')
for (let k in reg) {
text = text.replace(new RegExp(reg[k]), k + "\t" +
(this.config[k] !== undefined ? this.config[k] : " ") + ";")
}
this.configText = text
}, },
async get_template() { async get_template() {
if (this.config.support_ssl) { if (this.config.support_ssl) {
@ -185,11 +174,11 @@ export default {
}) })
}, },
save() { save() {
this.$api.domain.save(this.name ? this.name : this.config.name, {content: this.configText}).then(r => { this.$api.domain.save(this.name, {content: this.configText}).then(r => {
this.parse(r) this.parse(r)
this.$message.success("保存成功") this.$message.success("保存成功")
if (this.name) { if (this.name) {
this.$refs["cert-info"].get() if (this.$refs["cert-info"]) this.$refs["cert-info"].get()
} }
}).catch(r => { }).catch(r => {
console.log(r) console.log(r)
@ -223,10 +212,35 @@ export default {
if (r.status === "success" && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) { if (r.status === "success" && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) {
this.config.ssl_certificate = r.ssl_certificate this.config.ssl_certificate = r.ssl_certificate
this.config.ssl_certificate_key = r.ssl_certificate_key this.config.ssl_certificate_key = r.ssl_certificate_key
this.$refs["cert-info"].get() if (this.$refs["cert-info"]) this.$refs["cert-info"].get()
}
}
},
change_auto_cert() {
if (this.config.auto_cert) {
this.$api.domain.add_auto_cert(this.name).then(() => {
this.$message.success(this.name + ' 加入自动续签列表成功')
}).catch(e => {
this.$message.error(e.message ?? this.name + ' 加入自动续签列表失败')
})
} else {
this.$api.domain.remove_auto_cert(this.name).then(() => {
this.$message.success('从自动续签列表中删除 ' + this.name + ' 成功')
}).catch(e => {
this.$message.error(e.message ?? '从自动续签列表中删除 ' + this.name + ' 失败')
})
}
}
},
computed: {
columns: {
get() {
if (this.config.support_ssl) {
return [...columns, ...columnsSSL]
} else {
return [...columns]
} }
} }
} }
} }
} }
@ -234,16 +248,21 @@ export default {
<style lang="less"> <style lang="less">
.ant-collapse { .ant-collapse {
margin: 10px; margin-bottom: 20px;
.ant-collapse-item {
border-bottom: unset;
}
} }
.ant-collapse-content-box { .ant-collapse-content-box {
padding: 24px!important; padding: 24px !important;
} }
</style> </style>
<style lang="less" scoped> <style lang="less" scoped>
.ant-card { .ant-card {
margin: 10px; // margin: 10px;
@media (max-width: 512px) { @media (max-width: 512px) {
margin: 10px 0; margin: 10px 0;
} }

View file

@ -24,7 +24,7 @@
import StdTable from "@/components/StdDataDisplay/StdTable" import StdTable from "@/components/StdDataDisplay/StdTable"
const columns = [{ const columns = [{
title: "名称", title: "配置名称",
dataIndex: "name", dataIndex: "name",
scopedSlots: {customRender: "名称"}, scopedSlots: {customRender: "名称"},
sorter: true, sorter: true,

View file

@ -36,6 +36,18 @@ const columns = [{
type: "switch", type: "switch",
event: "change_support_ssl" event: "change_support_ssl"
} }
}]
const columnsSSL = [{
title: "自动续签",
dataIndex: "auto_cert",
edit: {
type: "switch",
event: "change_auto_cert"
},
description: '启用自动续签后,系统将会每小时检测一次该域名证书的信息,' +
'如果距离上次签发已超过1个月则将执行自动续签。' +
'<br/>启用前先点击下方「自动申请 Let\'s Encrypt 证书」即可获得证书路径。'
}, { }, {
title: "https 监听端口", title: "https 监听端口",
dataIndex: "https_listen_port", dataIndex: "https_listen_port",
@ -57,4 +69,4 @@ const columns = [{
} }
}] }]
export default columns export {columns, columnsSSL}

View file

@ -0,0 +1,29 @@
const unparse = (text, config) => {
// http_listen_port: /listen (.*);/i,
// https_listen_port: /listen (.*) ssl/i,
const reg = {
server_name: /server_name[\s](.*);/ig,
index: /index[\s](.*);/i,
root: /root[\s](.*);/i,
ssl_certificate: /ssl_certificate[\s](.*);/i,
ssl_certificate_key: /ssl_certificate_key[\s](.*);/i
}
text = text.replace(/listen[\s](.*);/i, "listen\t"
+ config['http_listen_port'] + ';')
text = text.replace(/listen[\s](.*) ssl/i, "listen\t"
+ config['https_listen_port'] + ' ssl')
text = text.replace(/listen(.*):(.*);/i, "listen\t[::]:"
+ config['http_listen_port'] + ';')
text = text.replace(/listen(.*):(.*) ssl/i, "listen\t[::]:"
+ config['https_listen_port'] + ' ssl')
for (let k in reg) {
text = text.replace(new RegExp(reg[k]), k + "\t" +
(config[k] !== undefined ? config[k] : " ") + ";")
}
return text
}
export {unparse}

View file

@ -1,5 +1,8 @@
<template> <template>
<a-card> <a-card style="text-align: center">
<div class="logo">
<img :src="logo" alt="logo" />
</div>
<h2>Nginx UI</h2> <h2>Nginx UI</h2>
<p>Yet another WebUI for Nginx</p> <p>Yet another WebUI for Nginx</p>
<p>Version: {{ version }} ({{ build_id }})</p> <p>Version: {{ version }} ({{ build_id }})</p>
@ -22,6 +25,7 @@ export default {
data() { data() {
const date = new Date() const date = new Date()
return { return {
logo: require('@/assets/img/logo.png'),
this_year: date.getFullYear(), this_year: date.getFullYear(),
version: process.env.VUE_APP_VERSION, version: process.env.VUE_APP_VERSION,
build_id: process.env.VUE_APP_TOTAL_BUILD ?? '开发模式', build_id: process.env.VUE_APP_TOTAL_BUILD ?? '开发模式',
@ -39,6 +43,12 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.logo {
img {
max-width: 120px
}
}
.egg { .egg {
padding: 10px 0; padding: 10px 0;
} }

View file

@ -0,0 +1,125 @@
<template>
<div class="container">
<div class="login-form">
<div class="project-title">
<h1>Nginx UI</h1>
</div>
<a-form
id="components-form-demo-normal-login"
:form="form"
@submit="handleSubmit"
>
<a-form-item>
<a-input
v-decorator="[
'name',
{ rules: [{ required: true, message: '请输入用户名' }] },
]"
placeholder="Username"
>
<a-icon slot="prefix" type="user" style="color: rgba(0,0,0,.25)"/>
</a-input>
</a-form-item>
<a-form-item>
<a-input
v-decorator="[
'password',
{ rules: [{ required: true, message: '请输入密码' }] },
]"
type="password"
placeholder="Password"
>
<a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)"/>
</a-input>
</a-form-item>
<a-form-item>
<a-button type="primary" :block="true" html-type="submit" :loading="loading">
登录
</a-button>
</a-form-item>
</a-form>
<div class="footer">
Copyright © 2020 - {{ thisYear }} 0xJacky
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
form: {},
thisYear: new Date().getFullYear(),
loading: false
}
},
created() {
this.form = this.$form.createForm(this)
},
mounted() {
this.$api.install.get_lock().then(r => {
if (!r.lock) {
this.$router.push('/install')
}
})
if (this.$store.state.user.token) {
this.$router.push('/')
}
},
methods: {
login(values) {
return this.$api.auth.login(values.name, values.password).then(async () => {
await this.$message.success('登录成功', 1)
const next = this.$route.query.next ? this.$route.query.next : '/'
await this.$router.push(next)
}).catch(r => {
console.log(r)
this.$message.error(r.message ?? '服务器错误')
})
},
handleSubmit: async function (e) {
e.preventDefault()
this.loading = true
await this.form.validateFields(async (err, values) => {
if (!err) {
await this.login(values)
}
this.loading = false
})
},
},
};
</script>
<style lang="less">
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
.login-form {
max-width: 400px;
width: 80%;
.project-title {
margin: 50px;
h1 {
font-size: 50px;
font-weight: 100;
text-align: center;
}
}
.login-form-button {
}
.footer {
padding: 30px;
text-align: center;
}
}
}
</style>

View file

@ -1 +1 @@
{"version":"1.0.0","build_id":12,"total_build":16} {"version":"1.1.0","build_id":2,"total_build":19}

Some files were not shown because too many files have changed in this diff Show more