xray_rule_modal.html 10 KB

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