AddRules.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <template>
  2. <base-dialog @cancel="cancelDialog">
  3. <div slot="header">{{$t('compute.text_991')}}</div>
  4. <div slot="body">
  5. <a-form
  6. :form="form.fc">
  7. <a-form-item :label="$t('compute.text_990')" v-bind="formItemLayout">
  8. <a-radio-group v-decorator="decorators.direction" @change="decoratorsChange">
  9. <a-radio value="in">{{$t('compute.text_993')}}</a-radio>
  10. <a-radio value="out">{{$t('compute.text_994')}}</a-radio>
  11. </a-radio-group>
  12. </a-form-item>
  13. <a-form-item :label="$t('compute.text_175')" v-bind="formItemLayout">
  14. <a-select
  15. v-decorator="decorators.type"
  16. :disabled="typeDisabled"
  17. :placeholder="$t('compute.text_219')"
  18. @change="typeChange">
  19. <a-select-option v-for="item in typeOptions" :key="item.value" :value="item.value">
  20. {{item.label}}
  21. </a-select-option>
  22. </a-select>
  23. </a-form-item>
  24. <a-form-item v-bind="formItemLayout">
  25. <span slot="label">
  26. {{decLabel}}&nbsp;
  27. <a-tooltip :title="$t('compute.text_995')">
  28. <a-icon type="question-circle-o" />
  29. </a-tooltip>
  30. </span>
  31. <a-input :disabled="IPCheckboxDisabled" v-decorator="decorators.cidr" :placeholder="$t('compute.text_996')" />
  32. <a-checkbox class="right-checkbox" @change="cidrChange">{{$t('compute.text_997')}}</a-checkbox>
  33. </a-form-item>
  34. <a-form-item :label="$t('compute.text_980')" v-bind="formItemLayout">
  35. <a-select v-decorator="decorators.protocol" @change="protocolChange" :disabled="protocolDisabled">
  36. <a-select-option v-for="item in protocolOptions" :key="item.value" :value="item.value">
  37. {{item.label}}
  38. </a-select-option>
  39. </a-select>
  40. </a-form-item>
  41. <a-form-item v-bind="formItemLayout">
  42. <span slot="label">{{$t('compute.text_998')}}<a-tooltip :title="$t('compute.text_999')">
  43. <a-icon type="question-circle-o" />
  44. </a-tooltip>
  45. </span>
  46. <a-input :disabled="portsDisabled" v-decorator="decorators.ports" :placeholder="$t('compute.text_350')" />
  47. <a-checkbox class="right-checkbox" @change="portsChange" :checked="portsChecked" :disabled="portsCheckboxDisabled">{{$t('compute.text_1000')}}</a-checkbox>
  48. </a-form-item>
  49. <a-form-item :label="$t('compute.text_694')" v-bind="formItemLayout">
  50. <a-select v-decorator="decorators.action">
  51. <a-select-option v-for="item in actionOptions" :key="item.value" :value="item.value">
  52. {{item.label}}
  53. </a-select-option>
  54. </a-select>
  55. </a-form-item>
  56. <a-form-item v-bind="formItemLayout">
  57. <span slot="label">{{$t('compute.text_1001')}}<a-tooltip :title="$t('compute.text_1002')">
  58. <a-icon type="question-circle-o" />
  59. </a-tooltip>
  60. </span>
  61. <a-input-number :min="1" :max="100" v-decorator="decorators.priority" />
  62. </a-form-item>
  63. </a-form>
  64. <dialog-selected-tips :name="$t('dictionary.secgroup')" :count="params.data.length" :action="$t('compute.text_991')" />
  65. <dialog-table :data="params.data" :columns="params.columns.slice(0, 3)" />
  66. </div>
  67. <div slot="footer">
  68. <a-button type="primary" @click="handleConfirm" :loading="loading">{{ $t('dialog.ok') }}</a-button>
  69. <a-button @click="cancelDialog">{{ $t('dialog.cancel') }}</a-button>
  70. </div>
  71. </base-dialog>
  72. </template>
  73. <script>
  74. import { validate } from '@/utils/validate'
  75. import DialogMixin from '@/mixins/dialog'
  76. import WindowsMixin from '@/mixins/windows'
  77. export default {
  78. name: 'AddRulesDialog',
  79. mixins: [DialogMixin, WindowsMixin],
  80. data () {
  81. return {
  82. loading: false,
  83. form: {
  84. fc: this.$form.createForm(this),
  85. },
  86. decorators: {
  87. direction: [
  88. 'direction',
  89. {
  90. initialValue: 'in',
  91. },
  92. ],
  93. type: [
  94. 'type',
  95. ],
  96. cidr: [
  97. 'cidr',
  98. {
  99. validateFirst: true,
  100. rules: [
  101. { required: true, message: this.$t('compute.text_996') },
  102. { validator: this.$validate(['cidr', 'IPv4', 'cidr6', 'IPv6'], true, 'some') },
  103. ],
  104. },
  105. ],
  106. protocol: [
  107. 'protocol',
  108. {
  109. initialValue: 'tcp',
  110. },
  111. ],
  112. ports: [
  113. 'ports',
  114. {
  115. rules: [
  116. { required: true, message: this.$t('compute.text_347') },
  117. { validator: this.validatePorts },
  118. ],
  119. },
  120. ],
  121. action: [
  122. 'action',
  123. {
  124. initialValue: 'allow',
  125. rules: [
  126. { required: true },
  127. ],
  128. },
  129. ],
  130. priority: [
  131. 'priority',
  132. {
  133. initialValue: 1,
  134. },
  135. ],
  136. },
  137. formItemLayout: {
  138. wrapperCol: {
  139. span: 8,
  140. },
  141. labelCol: {
  142. span: 3,
  143. },
  144. },
  145. typeOptions: [
  146. { label: this.$t('compute.text_144'), value: 'custom', description: '' },
  147. { label: this.$t('compute.text_1003'), value: 'windows', description: this.$t('compute.text_1004') },
  148. { label: 'SSH (22)', value: 'linux', description: this.$t('compute.text_1005') },
  149. { label: 'HTTP(80)', value: 'http', description: this.$t('compute.text_1006') },
  150. { label: 'HTTPS(443)', value: 'https', description: this.$t('compute.text_1007') },
  151. { label: 'Ping', value: 'ping', description: this.$t('compute.text_1008') },
  152. ],
  153. protocolOptions: [
  154. { label: 'TCP', value: 'tcp' },
  155. { label: 'UDP', value: 'udp' },
  156. { label: 'ICMP', value: 'icmp' },
  157. { label: this.$t('compute.any_protocol.text'), value: 'any' },
  158. ],
  159. actionOptions: [
  160. { label: this.$t('compute.text_976'), value: 'allow' },
  161. { label: this.$t('compute.text_977'), value: 'deny' },
  162. ],
  163. typeDisabled: false,
  164. IPCheckboxDisabled: false,
  165. portsDisabled: false,
  166. portsCheckboxDisabled: false,
  167. portsChecked: false,
  168. protocolDisabled: this.params.title !== 'edit',
  169. decLabel: this.$t('compute.text_979'),
  170. }
  171. },
  172. methods: {
  173. validatePorts (rule, value, callback) {
  174. const ports = value.indexOf(',') !== -1 ? value.split(',') : value.split('-')
  175. if (ports.length > 1) {
  176. const pass = ports.every(function (item, index) {
  177. return +item && item >= 0 && item <= 65535
  178. })
  179. if (!pass) {
  180. if (validate(value, 'ports') === false || validate(value, 'ports').result === false) {
  181. callback(new Error(validate(value, 'ports').msg))
  182. }
  183. callback()
  184. } else {
  185. callback()
  186. }
  187. } else {
  188. if (value === 'ALL') {
  189. callback()
  190. } else {
  191. if (validate(value, 'ports') === false || validate(value, 'ports').result === false) {
  192. callback(new Error(validate(value, 'ports').msg))
  193. }
  194. callback()
  195. }
  196. }
  197. },
  198. typeChange (e) {
  199. if (e === 'windows') {
  200. this.form.fc.setFieldsValue({ ports: '3389' })
  201. this.portsChecked = false
  202. this.portsDisabled = true
  203. this.portsCheckboxDisabled = true
  204. this.protocolDisabled = true
  205. } else if (e === 'linux') {
  206. this.form.fc.setFieldsValue({ ports: '22' })
  207. this.portsChecked = false
  208. this.portsDisabled = true
  209. this.portsCheckboxDisabled = true
  210. this.protocolDisabled = true
  211. } else if (e === 'http') {
  212. this.form.fc.setFieldsValue({ ports: '80' })
  213. this.portsChecked = false
  214. this.portsDisabled = true
  215. this.portsCheckboxDisabled = true
  216. this.protocolDisabled = true
  217. } else if (e === 'https') {
  218. this.form.fc.setFieldsValue({ ports: '443' })
  219. this.portsChecked = false
  220. this.portsDisabled = true
  221. this.portsCheckboxDisabled = true
  222. this.protocolDisabled = true
  223. } else if (e === 'ping') {
  224. this.form.fc.setFieldsValue({ ports: 'ALL', protocol: 'icmp' })
  225. this.portsChecked = true
  226. this.portsDisabled = true
  227. this.portsCheckboxDisabled = true
  228. this.protocolDisabled = true
  229. } else {
  230. this.portsChecked = false
  231. this.portsDisabled = false
  232. this.form.fc.resetFields(['ports'])
  233. this.portsCheckboxDisabled = false
  234. this.protocolDisabled = false
  235. }
  236. },
  237. protocolChange (e) {
  238. if (e === 'icmp') {
  239. this.portsChecked = true
  240. this.portsDisabled = true
  241. this.form.fc.setFieldsValue({ ports: 'ALL' })
  242. this.portsCheckboxDisabled = true
  243. } else {
  244. this.portsCheckboxDisabled = false
  245. }
  246. if (e === 'any') {
  247. this.portsChecked = true
  248. this.form.fc.setFieldsValue({ ports: 'ALL' })
  249. this.form.fc.setFieldsValue({ type: 'custom' })
  250. this.portsCheckboxDisabled = true
  251. this.portsDisabled = true
  252. this.typeDisabled = true
  253. } else {
  254. this.portsCheckboxDisabled = false
  255. this.typeDisabled = false
  256. }
  257. },
  258. decoratorsChange (e) {
  259. if (e.target.value === 'out') {
  260. this.decLabel = this.$t('compute.text_978')
  261. } else {
  262. this.decLabel = this.$t('compute.text_979')
  263. }
  264. this.form.fc.resetFields()
  265. },
  266. cidrChange (e) {
  267. this.IPCheckboxDisabled = !this.IPCheckboxDisabled
  268. if (e.target.checked) {
  269. this.form.fc.setFieldsValue({ cidr: '0.0.0.0/0' })
  270. } else {
  271. this.form.fc.resetFields(['cidr'])
  272. }
  273. },
  274. portsChange (e) {
  275. this.portsChecked = !this.portsChecked
  276. this.portsDisabled = !this.portsDisabled
  277. if (e.target.checked) {
  278. this.form.fc.setFieldsValue({ ports: 'ALL' })
  279. } else {
  280. this.form.fc.resetFields(['ports'])
  281. }
  282. },
  283. doAdd (data) {
  284. const ids = this.params.data.map(v => v.id)
  285. return new this.$Manager('secgroups').batchPerformAction({
  286. action: 'add-rule',
  287. ids,
  288. data,
  289. })
  290. },
  291. async handleConfirm () {
  292. this.loading = true
  293. try {
  294. const values = await this.form.fc.validateFields()
  295. if (values.ports === 'ALL') {
  296. values.ports = ''
  297. }
  298. let description = ''
  299. this.typeOptions.forEach((item) => {
  300. if (item.value === values.type) {
  301. description = item.description
  302. }
  303. })
  304. values.description = description
  305. await this.doAdd(values)
  306. this.loading = false
  307. this.params.refresh()
  308. this.cancelDialog()
  309. } finally {
  310. this.loading = false
  311. }
  312. },
  313. },
  314. }
  315. </script>
  316. <style lang="less" scoped>
  317. .right-checkbox {
  318. width: 100px;
  319. height: 40px;
  320. left: 270px;
  321. font-size: 12px!important;
  322. color: #ccc;
  323. position: absolute;
  324. }
  325. </style>