DomainEdit.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <template>
  2. <div>
  3. <a-collapse :bordered="false" default-active-key="1">
  4. <a-collapse-panel key="1" :header="name ? '编辑站点:' + name : '添加站点'">
  5. <p>您的配置文件中应当有对应的字段时,下列表单中的设置才能生效,配置文件名称创建后不可修改。</p>
  6. <std-data-entry :data-list="columns" v-model="config" />
  7. <cert-info :domain="name" ref="cert-info" v-if="name"/>
  8. <br/>
  9. <a-space>
  10. <a-button @click="issue_cert" type="primary" ghost>
  11. 自动申请 Let's Encrypt 证书
  12. </a-button>
  13. </a-space>
  14. </a-collapse-panel>
  15. </a-collapse>
  16. <a-card title="配置文件编辑">
  17. <vue-itextarea v-model="configText"/>
  18. </a-card>
  19. <footer-tool-bar>
  20. <a-space>
  21. <a-button @click="$router.go(-1)">返回</a-button>
  22. <a-button type="primary" @click="save">保存</a-button>
  23. </a-space>
  24. </footer-tool-bar>
  25. </div>
  26. </template>
  27. <script>
  28. import StdDataEntry from "@/components/StdDataEntry/StdDataEntry"
  29. import FooterToolBar from "@/components/FooterToolbar/FooterToolBar"
  30. import VueItextarea from "@/components/VueItextarea/VueItextarea"
  31. import columns from "@/views/domain_edit/columns"
  32. import CertInfo from "@/views/domain_edit/CertInfo";
  33. export default {
  34. name: "DomainEdit",
  35. components: {CertInfo, FooterToolBar, StdDataEntry, VueItextarea},
  36. data() {
  37. return {
  38. name: this.$route.params.name,
  39. columns,
  40. config: {
  41. http_listen_port: 80,
  42. https_listen_port: null,
  43. server_name: "",
  44. index: "",
  45. root: "",
  46. ssl_certificate: "",
  47. ssl_certificate_key: "",
  48. support_ssl: false
  49. },
  50. configText: "",
  51. ws: null,
  52. ok: false
  53. }
  54. },
  55. watch: {
  56. '$route'() {
  57. this.init()
  58. },
  59. config: {
  60. handler() {
  61. this.unparse()
  62. },
  63. deep: true
  64. },
  65. 'config.support_ssl'() {
  66. if (this.ok) this.change_support_ssl()
  67. }
  68. },
  69. created() {
  70. this.init()
  71. },
  72. destroyed() {
  73. if (this.ws !== null) {
  74. this.ws.close()
  75. }
  76. },
  77. methods: {
  78. init() {
  79. if (this.name) {
  80. this.$api.domain.get(this.name).then(r => {
  81. this.configText = r.config
  82. this.parse(r).then(()=>{
  83. this.ok = true
  84. })
  85. }).catch(r => {
  86. console.log(r)
  87. this.$message.error("服务器错误")
  88. })
  89. } else {
  90. this.config = {
  91. http_listen_port: 80,
  92. https_listen_port: null,
  93. server_name: "",
  94. index: "",
  95. root: "",
  96. ssl_certificate: "",
  97. ssl_certificate_key: "",
  98. support_ssl: false
  99. }
  100. this.get_template()
  101. }
  102. },
  103. async parse(r) {
  104. const text = r.config
  105. const reg = {
  106. http_listen_port: /listen[\s](.*);/i,
  107. https_listen_port: /listen[\s](.*) ssl/i,
  108. server_name: /server_name[\s](.*);/i,
  109. index: /index[\s](.*);/i,
  110. root: /root[\s](.*);/i,
  111. ssl_certificate: /ssl_certificate[\s](.*);/i,
  112. ssl_certificate_key: /ssl_certificate_key[\s](.*);/i
  113. }
  114. this.config['name'] = r.name
  115. for (let r in reg) {
  116. const match = text.match(reg[r])
  117. // console.log(r, match)
  118. if (match !== null) {
  119. if (match[1] !== undefined) {
  120. this.config[r] = match[1].trim()
  121. } else {
  122. this.config[r] = match[0].trim()
  123. }
  124. }
  125. }
  126. if (this.config.https_listen_port) {
  127. this.config.support_ssl = true
  128. }
  129. },
  130. async unparse() {
  131. let text = this.configText
  132. // http_listen_port: /listen (.*);/i,
  133. // https_listen_port: /listen (.*) ssl/i,
  134. const reg = {
  135. server_name: /server_name[\s](.*);/ig,
  136. index: /index[\s](.*);/i,
  137. root: /root[\s](.*);/i,
  138. ssl_certificate: /ssl_certificate[\s](.*);/i,
  139. ssl_certificate_key: /ssl_certificate_key[\s](.*);/i
  140. }
  141. text = text.replace(/listen[\s](.*);/i, "listen\t"
  142. + this.config['http_listen_port'] + ';')
  143. text = text.replace(/listen[\s](.*) ssl/i, "listen\t"
  144. + this.config['https_listen_port'] + ' ssl')
  145. text = text.replace(/listen(.*):(.*);/i, "listen\t[::]:"
  146. + this.config['http_listen_port'] + ';')
  147. text = text.replace(/listen(.*):(.*) ssl/i, "listen\t[::]:"
  148. + this.config['https_listen_port'] + ' ssl')
  149. for (let k in reg) {
  150. text = text.replace(new RegExp(reg[k]), k + "\t" +
  151. (this.config[k] !== undefined ? this.config[k] : " ") + ";")
  152. }
  153. this.configText = text
  154. },
  155. async get_template() {
  156. if (this.config.support_ssl) {
  157. await this.$api.domain.get_template('https-conf').then(r => {
  158. this.configText = r.template
  159. })
  160. } else {
  161. await this.$api.domain.get_template('http-conf').then(r => {
  162. this.configText = r.template
  163. })
  164. }
  165. await this.unparse()
  166. },
  167. change_support_ssl() {
  168. const that = this
  169. this.$confirm({
  170. title: '您已修改 SSL 支持状态,是否需要更换配置文件模板?',
  171. content: '更换配置文件模板将会丢失自定义配置',
  172. onOk() {
  173. that.get_template()
  174. },
  175. onCancel() {
  176. },
  177. })
  178. },
  179. save() {
  180. this.$api.domain.save(this.name ? this.name : this.config.name, {content: this.configText}).then(r => {
  181. this.parse(r)
  182. this.$message.success("保存成功")
  183. if (this.name) {
  184. this.$refs["cert-info"].get()
  185. }
  186. }).catch(r => {
  187. console.log(r)
  188. this.$message.error("保存错误" + r.message !== undefined ? " " + r.message : null, 10)
  189. })
  190. },
  191. issue_cert() {
  192. this.$message.info("请注意,当前配置中 server_name 必须为需要申请证书的域名,否则无法申请", 15)
  193. this.$message.info("正在申请,请稍后", 15)
  194. this.ws = new WebSocket(this.getWebSocketRoot() + "/cert/issue/" + this.config.server_name
  195. + "?token=" + btoa(this.$store.state.user.token))
  196. this.ws.onopen = () => {
  197. this.ws.send("go")
  198. }
  199. this.ws.onmessage = m => {
  200. const r = JSON.parse(m.data)
  201. switch (r.status) {
  202. case "success":
  203. this.$message.success(r.message, 10)
  204. break
  205. case "info":
  206. this.$message.info(r.message, 10)
  207. break
  208. case "error":
  209. this.$message.error(r.message, 10)
  210. break
  211. }
  212. if (r.status === "success" && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) {
  213. this.config.ssl_certificate = r.ssl_certificate
  214. this.config.ssl_certificate_key = r.ssl_certificate_key
  215. this.$refs["cert-info"].get()
  216. }
  217. }
  218. }
  219. }
  220. }
  221. </script>
  222. <style lang="less">
  223. .ant-collapse {
  224. margin: 10px;
  225. }
  226. .ant-collapse-content-box {
  227. padding: 24px!important;
  228. }
  229. </style>
  230. <style lang="less" scoped>
  231. .ant-card {
  232. margin: 10px;
  233. @media (max-width: 512px) {
  234. margin: 10px 0;
  235. }
  236. }
  237. </style>