ipEdit.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <el-dialog :title="type === 'Edit' ? '修改IP' : '添加IP'" width="600" v-model="props.open" :close-on-click-modal="false"
  3. :destroy-on-close="true" @close="onCancel" draggable>
  4. <el-form style="height: 128px;" ref="menuDialogFormRef" :rules="dataRules" :model="state.ruleForm" v-loading="loading">
  5. <el-form-item label="" prop="ipType">
  6. <el-radio-group v-model="state.ruleForm.ipType">
  7. <el-radio :value="1">白名单</el-radio>
  8. <el-radio :value="2">黑名单</el-radio>
  9. </el-radio-group>
  10. </el-form-item>
  11. <div class="custom-style">
  12. <el-segmented v-model="state.ruleForm.sourceTypeText" :options="[t('marketingConfig.grouping'), t('marketingConfig.ipSegment')]"
  13. size="default">
  14. <template #default="scope">
  15. <div style="min-width: 50px; line-height: 32px;">
  16. {{ scope.item }}
  17. <el-icon v-if="scope.item === t('marketingConfig.ipSegment')" size="12" style="vertical-align: middle;">
  18. <el-tooltip effect="light" content="输入127.0.0.1/24格式代表网段" placement="top">
  19. <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
  20. <path d="M7 14C8.93298 14 10.683 13.2165 11.9497 11.9497C13.2165 10.683 14 8.93298 14 7C14 5.06702 13.2165 3.31702 11.9497 2.05025C10.683 0.783503 8.93298 0 7 0C5.06702 0 3.31702 0.783503 2.05025 2.05025C0.783503 3.31702 0 5.06702 0 7C0 8.93298 0.783503 10.683 2.05025 11.9497C3.31702 13.2165 5.06702 14 7 14Z" fill="#1B4D88" fill-opacity="0.4"/>
  21. <path fill-rule="evenodd" clip-rule="evenodd" d="M6.99957 1.94434C7.5365 1.94434 7.97179 2.37962 7.97179 2.91656C7.97179 3.4535 7.5365 3.88878 6.99957 3.88878C6.46263 3.88878 6.02734 3.4535 6.02734 2.91656C6.02734 2.37962 6.46263 1.94434 6.99957 1.94434Z" fill="white"/>
  22. <path d="M6.99957 1.94434C7.5365 1.94434 7.97179 2.37962 7.97179 2.91656C7.97179 3.4535 7.5365 3.88878 6.99957 3.88878C6.46263 3.88878 6.02734 3.4535 6.02734 2.91656C6.02734 2.37962 6.46263 1.94434 6.99957 1.94434ZM6.99957 2.33322C6.6774 2.33322 6.41623 2.5944 6.41623 2.91656C6.41623 3.23872 6.6774 3.49989 6.99957 3.49989C7.32173 3.49989 7.5829 3.23872 7.5829 2.91656C7.5829 2.5944 7.32173 2.33322 6.99957 2.33322Z" fill="white"/>
  23. <path d="M7.19477 10.8888V5.44434H6.80588H6.41699" fill="white"/>
  24. <path d="M6.41645 10.8887V6.22206C5.98689 6.22206 5.63867 5.87384 5.63867 5.44428C5.63867 5.01473 5.98689 4.6665 6.41645 4.6665H7.19423L7.27398 4.6703C7.66608 4.71023 7.97201 5.04164 7.97201 5.44428V10.8887C7.97201 11.3183 7.70354 11.3447 7.27398 11.3447C6.84443 11.3447 6.41645 11.3183 6.41645 10.8887Z" fill="white"/>
  25. <path d="M8.55566 10C8.98522 10 9.33344 10.3482 9.33344 10.7778C9.33344 11.2073 8.98522 11.5556 8.55566 11.5556H5.83344C5.40389 11.5556 5.05566 11.2073 5.05566 10.7778C5.05566 10.3482 5.40389 10 5.83344 10H8.55566Z" fill="white"/>
  26. </svg>
  27. </el-tooltip>
  28. </el-icon>
  29. </div>
  30. </template>
  31. </el-segmented>
  32. </div>
  33. <el-form-item label="" prop="groupId" v-if="state.ruleForm.sourceTypeText === t('marketingConfig.grouping')">
  34. <el-select v-model="state.ruleForm.groupId" :placeholder="t('marketingConfig.groupingTip')"
  35. multiple clearable collapse-tags collapse-tags-tooltip :max-collapse-tags="5">
  36. <el-option v-for="item in selectData" :key="item.id" :label="item.groupName" :value="item.id" />
  37. </el-select>
  38. </el-form-item>
  39. <el-form-item label="" prop="ip" v-else>
  40. <el-input v-model="state.ruleForm.ip" type="text" :placeholder="t('marketingConfig.ipTip')"></el-input>
  41. </el-form-item>
  42. </el-form>
  43. <template #footer>
  44. <span class="dialog-footer">
  45. <el-button @click="onCancel">{{ t('common.cancelButtonText') }}</el-button>
  46. <el-button type="primary" @click="onSubmit" :disabled="loading">{{ t('common.confirmButtonText')
  47. }}</el-button>
  48. </span>
  49. </template>
  50. </el-dialog>
  51. </template>
  52. <script setup name="systemMenuDialog" lang="ts">
  53. import { useI18n } from 'vue-i18n';
  54. import { useMessage } from '/@/hooks/message';
  55. import {
  56. pageListIp,
  57. } from '/@/api/marketing/config';
  58. import { ipSplicing } from '/@/utils/ipUpdate';
  59. import { rule } from '/@/utils/validate';
  60. import { parseIpRange } from '/@/utils/ipUpdate';
  61. interface IpItem {
  62. id: Number;
  63. groupId: Number;
  64. groupName: String;
  65. ipMode: Number;
  66. ip: String;
  67. startIp: String;
  68. endIp: String;
  69. sourceType: Number;
  70. list: {
  71. id: Number;
  72. value: String;
  73. }[];
  74. }
  75. // 定义子组件向父组件传值/事件
  76. const emit = defineEmits(['update:open', 'onsuccess']);
  77. const { t } = useI18n();
  78. // 定义变量内容
  79. const loading = ref(false);
  80. const type = ref('add'); // 'add' or 'edit'
  81. const menuDialogFormRef = ref();
  82. const selectData = ref<IpItem[]>([]);
  83. const selectedObjects = ref<IpItem[]>([]);
  84. // 定义需要的数据
  85. const state = reactive({
  86. ruleForm: {
  87. ipType: 1, // 1: 白名单, 2: 黑名单
  88. sourceType: 1,
  89. sourceTypeText: t('marketingConfig.grouping'),
  90. groupId: [] as IpItem[],
  91. ipMode: 1,
  92. groupName:'',
  93. startIp: '',
  94. endIp: '',
  95. ip: '',
  96. },
  97. });
  98. const props = defineProps({
  99. open: {
  100. type: Boolean,
  101. default: false,
  102. },
  103. });
  104. // 表单校验规则
  105. const dataRules = reactive({
  106. groupId: [{ required: true, message: '分组不能为空', trigger: 'blur' }],
  107. ip: [
  108. { required: rule.ip, message: 'IP不能为空', trigger: 'blur' },
  109. { validator: rule.ip, trigger: 'blur' },
  110. ],
  111. });
  112. // 获取ip列表
  113. const getIpData = async () => {
  114. await pageListIp().then((val) => {
  115. selectData.value = val.data.map((item) => {
  116. return {
  117. ...item,
  118. title: item.groupName,
  119. id: item.id,
  120. list: item.ips.map((items) => {
  121. return {
  122. ...items,
  123. id: items.id,
  124. value: ipSplicing(items.startIp, items.endIp),
  125. };
  126. }),
  127. };
  128. });
  129. });
  130. };
  131. watchEffect(() => {
  132. if (props.open) {
  133. state.ruleForm.groupId = [];
  134. state.ruleForm.ip = '';
  135. state.ruleForm.ipType = 1;
  136. getIpData();
  137. }
  138. })
  139. const onCancel = () => {
  140. emit('update:open', false);
  141. };
  142. // 保存数据
  143. const onSubmit = async () => {
  144. const lis = parseIpRange(state.ruleForm.ip);
  145. state.ruleForm.startIp = lis.start;
  146. state.ruleForm.endIp = lis.end;
  147. if (lis.end !== '') {
  148. state.ruleForm.ipMode = 2;
  149. }
  150. state.ruleForm.sourceType = state.ruleForm.sourceTypeText === t('marketingConfig.grouping') ? 1 : 2;
  151. if (state.ruleForm.sourceType == 1 && state.ruleForm.groupId.length == 0) {
  152. return useMessage().error('请选择分组');
  153. } else if (state.ruleForm.sourceType == 2 && state.ruleForm.ip == '') {
  154. return useMessage().error('ip不能为空');
  155. }
  156. try {
  157. loading.value = true;
  158. if (state.ruleForm.sourceTypeText == t('marketingConfig.grouping')) {
  159. selectedObjects.value = [];
  160. selectedObjects.value = selectData.value.filter(item => state.ruleForm.groupId.includes(item.id));
  161. emit('onsuccess', selectedObjects.value, state.ruleForm.sourceType, state.ruleForm.ipType + '');
  162. }else if(state.ruleForm.startIp.length > 0) {
  163. emit('onsuccess', [state.ruleForm], state.ruleForm.sourceType, state.ruleForm.ipType + '');
  164. }
  165. onCancel();
  166. } catch (err) {
  167. console.log(err);
  168. useMessage().error(err.msg);
  169. } finally {
  170. loading.value = false;
  171. }
  172. };
  173. </script>
  174. <style>
  175. .apps-loadmore.el-select-dropdown .el-scrollbar__wrap {
  176. height: 330px !important;
  177. }
  178. .custom-style {
  179. margin-top: 14px;
  180. .el-segmented__item {
  181. border-right: 1px solid rgba(230, 230, 230, 1);
  182. min-width: 72px;
  183. flex: unset;
  184. }
  185. .el-segmented {
  186. border: 1px solid rgba(230, 230, 230, 1);
  187. border-bottom: unset;
  188. --el-segmented-bg-color: #ffffff;
  189. --el-segmented-item-hover-bg-color: rgba(22, 122, 240, 0.1);
  190. --el-segmented-item-selected-color: rgba(22, 122, 240, 1);
  191. --el-segmented-item-hover-color: rgba(22, 122, 240, 1);
  192. --el-segmented-item-selected-bg-color: rgba(22, 122, 240, 0.1);
  193. --el-border-radius-base: 4px 4px 0 0;
  194. --el-segmented-padding: 0;
  195. }
  196. }
  197. </style>