{{define "ruleModal"}} <a-modal id="rule-modal" v-model="ruleModal.visible" :title="ruleModal.title" @ok="ruleModal.ok" :confirm-loading="ruleModal.confirmLoading" :closable="true" :mask-closable="false" :ok-text="ruleModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> <a-form layout="inline"> <table width="100%" class="ant-table-tbody"> <tr> <td style="width: 30%;">Domain Matcher</td> <td> <a-form-item> <a-select v-model="ruleModal.rule.domainMatcher" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select-option v-for="dm in ['','hybrid','linear']" :value="dm">[[ dm ]]</a-select-option> </a-select> </a-form-item> </td> </tr> <tr> <td>Source IPs <a-tooltip> <template slot="title"> <span>{{ i18n "pages.xray.rules.useComma" }}</span> </template> <a-icon type="question-circle"></a-icon> </a-tooltip> </td> <td> <a-form-item> <a-input v-model.trim="ruleModal.rule.source" style="width: 250px"></a-input> </a-form-item> </td> </tr> <tr> <td>Source Port <a-tooltip> <template slot="title"> <span>{{ i18n "pages.xray.rules.useComma" }}</span> </template> <a-icon type="question-circle"></a-icon> </a-tooltip> </td> <td> <a-form-item> <a-input v-model.trim="ruleModal.rule.sourcePort" style="width: 250px"></a-input> </a-form-item> </td> </tr> <tr> <td>Network</td> <td> <a-form-item> <a-select v-model="ruleModal.rule.network" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select-option v-for="x in ['','tcp','tdp','tcp,udp']" :value="x">[[ x ]]</a-select-option> </a-select> </a-form-item> </td> </tr> <tr> <td>Protocol</td> <td> <a-form-item> <a-select v-model="ruleModal.rule.protocol" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select-option v-for="x in ['','http','tls','bittorrent']" :value="x">[[ x ]]</a-select-option> </a-select> </a-form-item> </td> </tr> <tr> <td colspan="2"> <a-form-item> <span>Attributes</span> <a-button size="small" style="margin-left: 10px" @click="ruleModal.rule.attrs.push(['', ''])">+</a-button> <a-input-group compact v-for="(attr,index) in ruleModal.rule.attrs"> <a-input style="width: 50%" v-model="attr[0]" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'> <template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template> </a-input> <a-input style="width: 50%" v-model="attr[1]" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'> <a-button slot="addonAfter" size="small" @click="ruleModal.rule.attrs.splice(index,1)">-</a-button> </a-input> </a-input-group> </a-form-item> </td> </tr> <tr> <td>IP <a-tooltip> <template slot="title"> <span>{{ i18n "pages.xray.rules.useComma" }}</span> </template> <a-icon type="question-circle"></a-icon> </a-tooltip> </td> <td> <a-form-item> <a-input v-model.trim="ruleModal.rule.ip" style="width: 250px"></a-input> </a-form-item> </td> </tr> <tr> <td>Domain <a-tooltip> <template slot="title"> <span>{{ i18n "pages.xray.rules.useComma" }}</span> </template> <a-icon type="question-circle"></a-icon> </a-tooltip> </td> <td> <a-form-item> <a-input v-model.trim="ruleModal.rule.domain" style="width: 250px"></a-input> </a-form-item> </td> </tr> <tr> <td>Port <a-tooltip> <template slot="title"> <span>{{ i18n "pages.xray.rules.useComma" }}</span> </template> <a-icon type="question-circle"></a-icon> </a-tooltip> </td> <td> <a-form-item> <a-input v-model.trim="ruleModal.rule.port" style="width: 250px"></a-input> </a-form-item> </td> </tr> <tr> <td>Inbound Tags</td> <td> <a-form-item> <a-select v-model="ruleModal.rule.inboundTag" mode="multiple" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select-option v-for="tag in ruleModal.inboundTags" :value="tag">[[ tag ]]</a-select-option> </a-select> </a-form-item> </td> </tr> <tr> <td>Outbound Tag</td> <td> <a-form-item> <a-select v-model="ruleModal.rule.outboundTag" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option> </a-select> </a-form-item> </td> </tr> </table> </a-form> </a-modal> <script> const ruleModal = { title: '', visible: false, confirmLoading: false, okText: '{{ i18n "sure" }}', isEdit: false, confirm: null, rule: { type: "field", domainMatcher: "", domain: "", ip: "", port: "", sourcePort: "", network: "", source: "", user: "", inboundTag: [], protocol: [], attrs: [], outboundTag: "", }, inboundTags: [], outboundTags: [], users: [], balancerTag: [], ok() { newRule = ruleModal.getResult(); ObjectUtil.execute(ruleModal.confirm, newRule); }, show({ title='', okText='{{ i18n "sure" }}', rule, confirm=(rule)=>{}, isEdit=false }) { this.title = title; this.okText = okText; this.confirm = confirm; this.visible = true; if(isEdit) { this.rule.domainMatcher = rule.domainMatcher; this.rule.domain = rule.domain ? rule.domain.join(',') : []; this.rule.ip = rule.ip ? rule.ip.join(',') : []; this.rule.port = rule.port; this.rule.sourcePort = rule.sourcePort; this.rule.network = rule.network; this.rule.source = rule.source ? rule.source.join(',') : []; this.rule.user = rule.user ? rule.user.join(',') : []; this.rule.inboundTag = rule.inboundTag; this.rule.protocol = rule.protocol; this.rule.attrs = rule.attrs ? Object.entries(rule.attrs) : []; this.rule.outboundTag = rule.outboundTag; } else { this.rule = { domainMatcher: "", domain: "", ip: "", port: "", sourcePort: "", network: "", source: "", user: "", inboundTag: [], protocol: [], attrs: [], outboundTag: "", } } this.isEdit = isEdit; this.inboundTags = app.templateSettings.inbounds.filter((i) => !ObjectUtil.isEmpty(i.tag)).map(obj => obj.tag); this.inboundTags.push(...app.inboundTags); this.outboundTags = app.templateSettings.outbounds.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag); if(app.templateSettings.reverse){ if(app.templateSettings.reverse.bridges) { this.inboundTags.push(...app.templateSettings.reverse.bridges.map(b => b.tag)); } if(app.templateSettings.reverse.portals) this.outboundTags.push(...app.templateSettings.reverse.portals.map(b => b.tag)); } }, close() { ruleModal.visible = false; ruleModal.loading(false); }, loading(loading) { ruleModal.confirmLoading = loading; }, getResult() { value = ruleModal.rule; rule = {}; newRule = {}; rule.type = "field"; rule.domainMatcher = value.domainMatcher; rule.domain = value.domain.length>0 ? value.domain.split(',') : []; rule.ip = value.ip.length>0 ? value.ip.split(',') : []; rule.port = value.port; rule.sourcePort = value.sourcePort; rule.network = value.network; rule.source = value.source.length>0 ? value.source.split(',') : []; rule.user = value.user.length>0 ? value.user.split(',') : []; rule.inboundTag = value.inboundTag; rule.protocol = value.protocol; rule.attrs = Object.fromEntries(value.attrs); rule.outboundTag = value.outboundTag; for (const [key, value] of Object.entries(rule)) { if ( value !== null && value !== undefined && !(Array.isArray(value) && value.length === 0) && !(typeof value === 'object' && Object.keys(value).length === 0) && value !== '' ) { newRule[key] = value; } } return newRule; } }; new Vue({ delimiters: ['[[', ']]'], el: '#rule-modal', data: { ruleModal: ruleModal, } }); </script> {{end}}