xray_rule_modal.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. {{define "ruleModal"}}
  2. <a-modal id="rule-modal" v-model="ruleModal.visible" :title="ruleModal.title" @ok="ruleModal.ok"
  3. :confirm-loading="ruleModal.confirmLoading" :closable="true" :mask-closable="false"
  4. :ok-text="ruleModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
  5. <a-form layout="inline">
  6. <table width="100%" class="ant-table-tbody">
  7. <tr>
  8. <td style="width: 30%;">Domain Matcher</td>
  9. <td>
  10. <a-form-item>
  11. <a-select v-model="ruleModal.rule.domainMatcher" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
  12. <a-select-option v-for="dm in ['','hybrid','linear']" :value="dm">[[ dm ]]</a-select-option>
  13. </a-select>
  14. </a-form-item>
  15. </td>
  16. </tr>
  17. <tr>
  18. <td>Source IPs
  19. <a-tooltip>
  20. <template slot="title">
  21. <span>{{ i18n "pages.xray.rules.useComma" }}</span>
  22. </template>
  23. <a-icon type="question-circle"></a-icon>
  24. </a-tooltip>
  25. </td>
  26. <td>
  27. <a-form-item>
  28. <a-input v-model.trim="ruleModal.rule.source" style="width: 250px"></a-input>
  29. </a-form-item>
  30. </td>
  31. </tr>
  32. <tr>
  33. <td>Source Port
  34. <a-tooltip>
  35. <template slot="title">
  36. <span>{{ i18n "pages.xray.rules.useComma" }}</span>
  37. </template>
  38. <a-icon type="question-circle"></a-icon>
  39. </a-tooltip>
  40. </td>
  41. <td>
  42. <a-form-item>
  43. <a-input v-model.trim="ruleModal.rule.sourcePort" style="width: 250px"></a-input>
  44. </a-form-item>
  45. </td>
  46. </tr>
  47. <tr>
  48. <td>Network</td>
  49. <td>
  50. <a-form-item>
  51. <a-select v-model="ruleModal.rule.network" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
  52. <a-select-option v-for="x in ['','tcp','tdp','tcp,udp']" :value="x">[[ x ]]</a-select-option>
  53. </a-select>
  54. </a-form-item>
  55. </td>
  56. </tr>
  57. <tr>
  58. <td>Protocol</td>
  59. <td>
  60. <a-form-item>
  61. <a-select v-model="ruleModal.rule.protocol" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
  62. <a-select-option v-for="x in ['','http','tls','bittorrent']" :value="x">[[ x ]]</a-select-option>
  63. </a-select>
  64. </a-form-item>
  65. </td>
  66. </tr>
  67. <tr>
  68. <td colspan="2">
  69. <a-form-item>
  70. <span>Attributes</span>
  71. <a-button size="small" style="margin-left: 10px" @click="ruleModal.rule.attrs.push(['', ''])">+</a-button>
  72. <a-input-group compact v-for="(attr,index) in ruleModal.rule.attrs">
  73. <a-input style="width: 50%" v-model="attr[0]" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
  74. <template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
  75. </a-input>
  76. <a-input style="width: 50%" v-model="attr[1]" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
  77. <a-button slot="addonAfter" size="small" @click="ruleModal.rule.attrs.splice(index,1)">-</a-button>
  78. </a-input>
  79. </a-input-group>
  80. </a-form-item>
  81. </td>
  82. </tr>
  83. <tr>
  84. <td>IP
  85. <a-tooltip>
  86. <template slot="title">
  87. <span>{{ i18n "pages.xray.rules.useComma" }}</span>
  88. </template>
  89. <a-icon type="question-circle"></a-icon>
  90. </a-tooltip>
  91. </td>
  92. <td>
  93. <a-form-item>
  94. <a-input v-model.trim="ruleModal.rule.ip" style="width: 250px"></a-input>
  95. </a-form-item>
  96. </td>
  97. </tr>
  98. <tr>
  99. <td>Domain
  100. <a-tooltip>
  101. <template slot="title">
  102. <span>{{ i18n "pages.xray.rules.useComma" }}</span>
  103. </template>
  104. <a-icon type="question-circle"></a-icon>
  105. </a-tooltip>
  106. </td>
  107. <td>
  108. <a-form-item>
  109. <a-input v-model.trim="ruleModal.rule.domain" style="width: 250px"></a-input>
  110. </a-form-item>
  111. </td>
  112. </tr>
  113. <tr>
  114. <td>Port
  115. <a-tooltip>
  116. <template slot="title">
  117. <span>{{ i18n "pages.xray.rules.useComma" }}</span>
  118. </template>
  119. <a-icon type="question-circle"></a-icon>
  120. </a-tooltip>
  121. </td>
  122. <td>
  123. <a-form-item>
  124. <a-input v-model.trim="ruleModal.rule.port" style="width: 250px"></a-input>
  125. </a-form-item>
  126. </td>
  127. </tr>
  128. <tr>
  129. <td>Inbound Tags</td>
  130. <td>
  131. <a-form-item>
  132. <a-select v-model="ruleModal.rule.inboundTag" mode="multiple" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
  133. <a-select-option v-for="tag in ruleModal.inboundTags" :value="tag">[[ tag ]]</a-select-option>
  134. </a-select>
  135. </a-form-item>
  136. </td>
  137. </tr>
  138. <tr>
  139. <td>Outbound Tag</td>
  140. <td>
  141. <a-form-item>
  142. <a-select v-model="ruleModal.rule.outboundTag" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
  143. <a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
  144. </a-select>
  145. </a-form-item>
  146. </td>
  147. </tr>
  148. </table>
  149. </a-form>
  150. </a-modal>
  151. <script>
  152. const ruleModal = {
  153. title: '',
  154. visible: false,
  155. confirmLoading: false,
  156. okText: '{{ i18n "sure" }}',
  157. isEdit: false,
  158. confirm: null,
  159. rule: {
  160. type: "field",
  161. domainMatcher: "",
  162. domain: "",
  163. ip: "",
  164. port: "",
  165. sourcePort: "",
  166. network: "",
  167. source: "",
  168. user: "",
  169. inboundTag: [],
  170. protocol: [],
  171. attrs: [],
  172. outboundTag: "",
  173. },
  174. inboundTags: [],
  175. outboundTags: [],
  176. users: [],
  177. balancerTag: [],
  178. ok() {
  179. newRule = ruleModal.getResult();
  180. ObjectUtil.execute(ruleModal.confirm, newRule);
  181. },
  182. show({ title='', okText='{{ i18n "sure" }}', rule, confirm=(rule)=>{}, isEdit=false }) {
  183. this.title = title;
  184. this.okText = okText;
  185. this.confirm = confirm;
  186. this.visible = true;
  187. if(isEdit) {
  188. this.rule.domainMatcher = rule.domainMatcher;
  189. this.rule.domain = rule.domain ? rule.domain.join(',') : [];
  190. this.rule.ip = rule.ip ? rule.ip.join(',') : [];
  191. this.rule.port = rule.port;
  192. this.rule.sourcePort = rule.sourcePort;
  193. this.rule.network = rule.network;
  194. this.rule.source = rule.source ? rule.source.join(',') : [];
  195. this.rule.user = rule.user ? rule.user.join(',') : [];
  196. this.rule.inboundTag = rule.inboundTag;
  197. this.rule.protocol = rule.protocol;
  198. this.rule.attrs = rule.attrs ? Object.entries(rule.attrs) : [];
  199. this.rule.outboundTag = rule.outboundTag;
  200. } else {
  201. this.rule = {
  202. domainMatcher: "",
  203. domain: "",
  204. ip: "",
  205. port: "",
  206. sourcePort: "",
  207. network: "",
  208. source: "",
  209. user: "",
  210. inboundTag: [],
  211. protocol: [],
  212. attrs: [],
  213. outboundTag: "",
  214. }
  215. }
  216. this.isEdit = isEdit;
  217. this.inboundTags = app.templateSettings.inbounds.filter((i) => !ObjectUtil.isEmpty(i.tag)).map(obj => obj.tag);
  218. this.inboundTags.push(...app.inboundTags);
  219. this.outboundTags = app.templateSettings.outbounds.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag);
  220. if(app.templateSettings.reverse){
  221. if(app.templateSettings.reverse.bridges) {
  222. this.inboundTags.push(...app.templateSettings.reverse.bridges.map(b => b.tag));
  223. }
  224. if(app.templateSettings.reverse.portals) this.outboundTags.push(...app.templateSettings.reverse.portals.map(b => b.tag));
  225. }
  226. },
  227. close() {
  228. ruleModal.visible = false;
  229. ruleModal.loading(false);
  230. },
  231. loading(loading) {
  232. ruleModal.confirmLoading = loading;
  233. },
  234. getResult() {
  235. value = ruleModal.rule;
  236. rule = {};
  237. newRule = {};
  238. rule.type = "field";
  239. rule.domainMatcher = value.domainMatcher;
  240. rule.domain = value.domain.length>0 ? value.domain.split(',') : [];
  241. rule.ip = value.ip.length>0 ? value.ip.split(',') : [];
  242. rule.port = value.port;
  243. rule.sourcePort = value.sourcePort;
  244. rule.network = value.network;
  245. rule.source = value.source.length>0 ? value.source.split(',') : [];
  246. rule.user = value.user.length>0 ? value.user.split(',') : [];
  247. rule.inboundTag = value.inboundTag;
  248. rule.protocol = value.protocol;
  249. rule.attrs = Object.fromEntries(value.attrs);
  250. rule.outboundTag = value.outboundTag;
  251. for (const [key, value] of Object.entries(rule)) {
  252. if (
  253. value !== null &&
  254. value !== undefined &&
  255. !(Array.isArray(value) && value.length === 0) &&
  256. !(typeof value === 'object' && Object.keys(value).length === 0) &&
  257. value !== ''
  258. ) {
  259. newRule[key] = value;
  260. }
  261. }
  262. return newRule;
  263. }
  264. };
  265. new Vue({
  266. delimiters: ['[[', ']]'],
  267. el: '#rule-modal',
  268. data: {
  269. ruleModal: ruleModal,
  270. }
  271. });
  272. </script>
  273. {{end}}