|
@@ -5,21 +5,23 @@
|
|
<Title class="ml-4" :title="t('marketingConfig.ipList')" />
|
|
<Title class="ml-4" :title="t('marketingConfig.ipList')" />
|
|
<div class="p-4 rounded">
|
|
<div class="p-4 rounded">
|
|
<el-button type="primary" @click="onClickAdd('ip')">{{ t('marketingConfig.addIpList') }}</el-button>
|
|
<el-button type="primary" @click="onClickAdd('ip')">{{ t('marketingConfig.addIpList') }}</el-button>
|
|
- <JCollapse
|
|
|
|
- @update="(item) => onClickEdit(item, 'ip')"
|
|
|
|
- @delete="(item) => onOpenDelete(item, 'ip')"
|
|
|
|
- :data="ipData"
|
|
|
|
- :activeNames="ipActiveId"
|
|
|
|
- :deleteText="t('marketingConfig.deleteListText')"
|
|
|
|
- :updateText="t('marketingConfig.updateText')"
|
|
|
|
- />
|
|
|
|
|
|
+ <div v-if="ipData.length > 0" class="overflow-y-auto mt-2" style="height: calc(100vh - 250px)">
|
|
|
|
+ <JCollapse
|
|
|
|
+ @update="(item) => onClickEdit(item, 'ip')"
|
|
|
|
+ @delete="(item) => onOpenDelete(item, 'ip')"
|
|
|
|
+ :data="ipData"
|
|
|
|
+ :activeNames="ipActiveId"
|
|
|
|
+ :deleteText="t('marketingConfig.deleteListText')"
|
|
|
|
+ :updateText="t('marketingConfig.updateText')"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</el-tab-pane>
|
|
</el-tab-pane>
|
|
<el-tab-pane :label="t('marketingConfig.domainList')" name="域名分组" class="layout-padding-auto layout-padding-view">
|
|
<el-tab-pane :label="t('marketingConfig.domainList')" name="域名分组" class="layout-padding-auto layout-padding-view">
|
|
<Title class="ml-4" :title="t('marketingConfig.domainList')" />
|
|
<Title class="ml-4" :title="t('marketingConfig.domainList')" />
|
|
<div class="p-4 rounded">
|
|
<div class="p-4 rounded">
|
|
<el-button type="primary" @click="onClickAdd('domain')">{{ t('marketingConfig.addDomainList') }}</el-button>
|
|
<el-button type="primary" @click="onClickAdd('domain')">{{ t('marketingConfig.addDomainList') }}</el-button>
|
|
- <div v-if="domainData.length > 0">
|
|
|
|
|
|
+ <div v-if="domainData.length > 0" class="overflow-y-auto mt-2" style="height: calc(100vh - 250px)">
|
|
<JCollapse
|
|
<JCollapse
|
|
@update="(item) => onClickEdit(item, 'domain')"
|
|
@update="(item) => onClickEdit(item, 'domain')"
|
|
:data="domainData"
|
|
:data="domainData"
|
|
@@ -34,7 +36,7 @@
|
|
</el-tab-pane>
|
|
</el-tab-pane>
|
|
<el-tab-pane :label="t('marketingConfig.disposition')" name="全局配置" class="layout-padding-auto layout-padding-view">
|
|
<el-tab-pane :label="t('marketingConfig.disposition')" name="全局配置" class="layout-padding-auto layout-padding-view">
|
|
<Title class="ml-4" :title="t('marketingConfig.disposition')" />
|
|
<Title class="ml-4" :title="t('marketingConfig.disposition')" />
|
|
- <div class="p-4 rounded">
|
|
|
|
|
|
+ <div class="p-4 rounded overflow-y-auto" style="max-height: calc(100vh - 350px)">
|
|
<JCollapse
|
|
<JCollapse
|
|
:data="[{ title: 'IP集合', id: '1' }]"
|
|
:data="[{ title: 'IP集合', id: '1' }]"
|
|
:activeNames="['1']"
|
|
:activeNames="['1']"
|
|
@@ -82,7 +84,7 @@
|
|
</div>
|
|
</div>
|
|
<div class="p-2 items-center flex flex-wrap">
|
|
<div class="p-2 items-center flex flex-wrap">
|
|
<span class="mr-2">黑名单</span>
|
|
<span class="mr-2">黑名单</span>
|
|
-
|
|
|
|
|
|
+
|
|
<span v-for="item in ipBlackList" :key="item.id">
|
|
<span v-for="item in ipBlackList" :key="item.id">
|
|
<el-popover v-if="item?.sourceType === 1" width="280" @show="onLoadDetail(item, ipList)" trigger="hover" placement="top">
|
|
<el-popover v-if="item?.sourceType === 1" width="280" @show="onLoadDetail(item, ipList)" trigger="hover" placement="top">
|
|
<div v-if="item.list.length > 0" class="flex flex-wrap">
|
|
<div v-if="item.list.length > 0" class="flex flex-wrap">
|
|
@@ -119,13 +121,12 @@
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
</JCollapse>
|
|
</JCollapse>
|
|
-
|
|
|
|
<JCollapse
|
|
<JCollapse
|
|
class="mt-4"
|
|
class="mt-4"
|
|
:data="[{ title: '域名集合', id: '1' }]"
|
|
:data="[{ title: '域名集合', id: '1' }]"
|
|
:activeNames="['1']"
|
|
:activeNames="['1']"
|
|
- @update="(item) => (domainEditOpen = true)"
|
|
|
|
- @delete="(item) => (closeDomainTags = !closeDomainTags)"
|
|
|
|
|
|
+ @update="() => (domainEditOpen = true)"
|
|
|
|
+ @delete="() => (closeDomainTags = !closeDomainTags)"
|
|
:deleteText="closeDomainTags ? t('marketingConfig.cancel') : t('marketingConfig.deleteDomain')"
|
|
:deleteText="closeDomainTags ? t('marketingConfig.cancel') : t('marketingConfig.deleteDomain')"
|
|
:updateText="t('marketingConfig.addDomain')"
|
|
:updateText="t('marketingConfig.addDomain')"
|
|
>
|
|
>
|
|
@@ -172,41 +173,49 @@
|
|
</JCollapse>
|
|
</JCollapse>
|
|
</div>
|
|
</div>
|
|
<div class="w-[66%] ml-[-8px] mt-5">
|
|
<div class="w-[66%] ml-[-8px] mt-5">
|
|
- <el-form ref="menuDialogFormRef" :model="formData" :rules="dataRules" label-width="90px" class="flex flex-wrap">
|
|
|
|
- <el-form-item :label="t('marketingConfig.jumpMode')" prop="jumpMode" class="w-1/3">
|
|
|
|
- <el-select v-model="formData.jumpMode" :placeholder="t('marketingConfig.jumpModeTip')">
|
|
|
|
- <el-option v-for="item in listSelect" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
|
- </el-select>
|
|
|
|
|
|
+ <el-form ref="ruleFormRef" :model="formData" :rules="dataRules" label-width="90px" class="flex flex-wrap">
|
|
|
|
+ <el-form-item :label="t('marketingConfig.jumpMode')" prop="triggerMode" class="w-1/3">
|
|
|
|
+ <JDictSelect
|
|
|
|
+ v-model:value="formData.triggerMode"
|
|
|
|
+ :placeholder="t('marketingConfig.jumpModeTip')"
|
|
|
|
+ :dictType="'triggerMode'"
|
|
|
|
+ :selectFirst="true"
|
|
|
|
+ :styleClass="'w-full'"
|
|
|
|
+ />
|
|
</el-form-item>
|
|
</el-form-item>
|
|
- <el-form-item :label="t('marketingConfig.triggerType')" prop="triggerType" class="w-1/3">
|
|
|
|
- <el-select v-model="formData.triggerType" :placeholder="t('marketingConfig.triggerTypeTip')">
|
|
|
|
- <el-option v-for="item in triggerSelect" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
|
- </el-select>
|
|
|
|
|
|
+ <el-form-item :label="t('marketingConfig.triggerType')" prop="triggerRule" class="w-1/3">
|
|
|
|
+ <JDictSelect
|
|
|
|
+ v-model:value="formData.triggerRule"
|
|
|
|
+ :placeholder="t('marketingConfig.triggerTypeTip')"
|
|
|
|
+ :dictType="'triggerRule'"
|
|
|
|
+ :selectFirst="true"
|
|
|
|
+ :styleClass="'w-full'"
|
|
|
|
+ />
|
|
</el-form-item>
|
|
</el-form-item>
|
|
- <el-form-item :label="t('marketingConfig.triggerFrequency')" prop="triggerFrequency" class="w-1/3">
|
|
|
|
- <el-input v-model="formData.triggerFrequency" type="text" :placeholder="t('marketingConfig.triggerFrequencyTip')" />
|
|
|
|
|
|
+ <el-form-item :label="t('marketingConfig.triggerFrequency')" prop="triggerNum" class="w-1/3">
|
|
|
|
+ <el-input v-model="formData.triggerNum" type="text" :placeholder="t('marketingConfig.triggerFrequencyTip')" />
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
|
<div class="w-full mb-[18px]">
|
|
<div class="w-full mb-[18px]">
|
|
<el-form-item
|
|
<el-form-item
|
|
- v-if="formData.jumpMode == '2' || formData.jumpMode == '3'"
|
|
|
|
|
|
+ v-if="formData.triggerMode == '2' || formData.triggerMode == '3'"
|
|
:label="t('marketingConfig.prompt')"
|
|
:label="t('marketingConfig.prompt')"
|
|
- prop="prompt"
|
|
|
|
|
|
+ prop="promptMsg"
|
|
class="w-1/3"
|
|
class="w-1/3"
|
|
>
|
|
>
|
|
- <el-input v-model="formData.prompt" type="text" :placeholder="t('marketingConfig.promptTip')"></el-input>
|
|
|
|
|
|
+ <el-input v-model="formData.promptMsg" type="text" :placeholder="t('marketingConfig.promptTip')"></el-input>
|
|
</el-form-item>
|
|
</el-form-item>
|
|
<el-form-item
|
|
<el-form-item
|
|
- v-if="formData.jumpMode == '1' || formData.jumpMode == '3'"
|
|
|
|
|
|
+ v-if="formData.triggerMode == '1' || formData.triggerMode == '3'"
|
|
:label="t('marketingConfig.jumpLink')"
|
|
:label="t('marketingConfig.jumpLink')"
|
|
- prop="jumpLink"
|
|
|
|
|
|
+ prop="url"
|
|
class="w-1/3"
|
|
class="w-1/3"
|
|
>
|
|
>
|
|
- <el-input v-model="formData.jumpLink" type="text" :placeholder="t('marketingConfig.jumpLinkTip')"></el-input>
|
|
|
|
|
|
+ <el-input v-model="formData.url" type="text" :placeholder="t('marketingConfig.jumpLinkTip')"></el-input>
|
|
</el-form-item>
|
|
</el-form-item>
|
|
</div>
|
|
</div>
|
|
<div class="w-full">
|
|
<div class="w-full">
|
|
- <el-button type="primary" @click="onSubmit" class="w-[80px] ml-5">{{ t('common.saveBtn') }}</el-button>
|
|
|
|
|
|
+ <el-button type="primary" @click="onSubmit(ruleFormRef)" class="w-[80px] ml-5">{{ t('common.saveBtn') }}</el-button>
|
|
</div>
|
|
</div>
|
|
</el-form>
|
|
</el-form>
|
|
</div>
|
|
</div>
|
|
@@ -238,11 +247,14 @@ import {
|
|
delIpList,
|
|
delIpList,
|
|
delDomainList,
|
|
delDomainList,
|
|
getGroupDetail,
|
|
getGroupDetail,
|
|
|
|
+ getConfigDetail,
|
|
|
|
+ saveConfigDetail,
|
|
} from '/@/api/marketing/config';
|
|
} from '/@/api/marketing/config';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useMessage } from '/@/hooks/message';
|
|
import { useMessage } from '/@/hooks/message';
|
|
import { rule } from '/@/utils/validate';
|
|
import { rule } from '/@/utils/validate';
|
|
import { ipSplicing } from '/@/utils/ipUpdate';
|
|
import { ipSplicing } from '/@/utils/ipUpdate';
|
|
|
|
+import type { FormInstance } from 'element-plus';
|
|
|
|
|
|
// 引入组件
|
|
// 引入组件
|
|
const JCollapse = defineAsyncComponent(() => import('/@/components/JCollapse/index.vue'));
|
|
const JCollapse = defineAsyncComponent(() => import('/@/components/JCollapse/index.vue'));
|
|
@@ -251,9 +263,10 @@ const DomainEdit = defineAsyncComponent(() => import('./components/domainEdit.vu
|
|
const ListEdit = defineAsyncComponent(() => import('./components/listEdit.vue'));
|
|
const ListEdit = defineAsyncComponent(() => import('./components/listEdit.vue'));
|
|
const GroupingEdit = defineAsyncComponent(() => import('./components/ipGroupingEdit.vue'));
|
|
const GroupingEdit = defineAsyncComponent(() => import('./components/ipGroupingEdit.vue'));
|
|
const IpListEdit = defineAsyncComponent(() => import('./components/ipListEdit.vue'));
|
|
const IpListEdit = defineAsyncComponent(() => import('./components/ipListEdit.vue'));
|
|
|
|
+const JDictSelect = defineAsyncComponent(() => import('/@/components/JDictSelect/index.vue'));
|
|
const { t } = useI18n();
|
|
const { t } = useI18n();
|
|
// 定义变量内容
|
|
// 定义变量内容
|
|
-const activeName = ref('全局配置');
|
|
|
|
|
|
+const activeName = ref('IP分组');
|
|
//关闭或打开tabs的关闭按钮
|
|
//关闭或打开tabs的关闭按钮
|
|
const closeDomainTags = ref(false);
|
|
const closeDomainTags = ref(false);
|
|
const closeIpTags = ref(false);
|
|
const closeIpTags = ref(false);
|
|
@@ -277,38 +290,13 @@ const openType = ref('ip'); // 'ip' or 'domain'
|
|
const ipWhiteList = ref([]); // ip白名单
|
|
const ipWhiteList = ref([]); // ip白名单
|
|
const ipBlackList = ref([]); // ip黑名单
|
|
const ipBlackList = ref([]); // ip黑名单
|
|
const domainList = ref([]);
|
|
const domainList = ref([]);
|
|
-
|
|
|
|
-const listSelect = ref([
|
|
|
|
- {
|
|
|
|
- value: '1',
|
|
|
|
- label: '跳转链接',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '2',
|
|
|
|
- label: '提示信息',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '3',
|
|
|
|
- label: '提示并跳转',
|
|
|
|
- },
|
|
|
|
-]);
|
|
|
|
-const triggerSelect = ref([
|
|
|
|
- {
|
|
|
|
- value: '1',
|
|
|
|
- label: '仅一次跳转',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '2',
|
|
|
|
- label: '多次跳转',
|
|
|
|
- },
|
|
|
|
-]);
|
|
|
|
-
|
|
|
|
|
|
+const ruleFormRef = ref();
|
|
const formData = ref({
|
|
const formData = ref({
|
|
- jumpMode: '1',
|
|
|
|
- triggerType: '',
|
|
|
|
- jumpLink: '',
|
|
|
|
- triggerFrequency: '',
|
|
|
|
- prompt: '',
|
|
|
|
|
|
+ promptMsg: '',
|
|
|
|
+ triggerMode: '',
|
|
|
|
+ triggerRule: '',
|
|
|
|
+ url: '',
|
|
|
|
+ triggerNum: '',
|
|
});
|
|
});
|
|
const onOpenDelete = (item: any, type: any) => {
|
|
const onOpenDelete = (item: any, type: any) => {
|
|
console.log(item);
|
|
console.log(item);
|
|
@@ -322,22 +310,22 @@ const getData = () => {
|
|
openType.value === 'ip' ? getIpData() : getDomainData();
|
|
openType.value === 'ip' ? getIpData() : getDomainData();
|
|
};
|
|
};
|
|
const onLoadDetail = async (item: any) => {
|
|
const onLoadDetail = async (item: any) => {
|
|
- if(item.list.length !== 0) return;
|
|
|
|
|
|
+ if (item.list.length !== 0) return;
|
|
await getGroupDetail({ id: item.groupId }).then((val) => {
|
|
await getGroupDetail({ id: item.groupId }).then((val) => {
|
|
- item.list = val.data.ips.map((item)=>{
|
|
|
|
- return ipSplicing(item.startIp, item.endIp)
|
|
|
|
|
|
+ item.list = val.data.ips.map((item) => {
|
|
|
|
+ return ipSplicing(item.startIp, item.endIp);
|
|
});
|
|
});
|
|
- });
|
|
|
|
|
|
+ });
|
|
};
|
|
};
|
|
|
|
|
|
// // 表单校验规则
|
|
// // 表单校验规则
|
|
const dataRules = reactive({
|
|
const dataRules = reactive({
|
|
- jumpLink: [
|
|
|
|
|
|
+ url: [
|
|
{ required: true, message: '跳转连接不能为空', trigger: 'blur' },
|
|
{ required: true, message: '跳转连接不能为空', trigger: 'blur' },
|
|
{ validator: rule.url, trigger: 'blur' },
|
|
{ validator: rule.url, trigger: 'blur' },
|
|
],
|
|
],
|
|
- triggerFrequency: [
|
|
|
|
- { required: true, message: '域名不能为空', trigger: 'blur' },
|
|
|
|
|
|
+ triggerNum: [
|
|
|
|
+ { required: true, message: '触发频率不能为空', trigger: 'blur' },
|
|
{
|
|
{
|
|
pattern: /^(10000|[1-9]\d{0,3}|0)$|^(100%|[1-9]?\d%|0%)$/,
|
|
pattern: /^(10000|[1-9]\d{0,3}|0)$|^(100%|[1-9]?\d%|0%)$/,
|
|
message: '请输入 0-10000 的正整数或 0%-100% 的百分比',
|
|
message: '请输入 0-10000 的正整数或 0%-100% 的百分比',
|
|
@@ -346,8 +334,29 @@ const dataRules = reactive({
|
|
],
|
|
],
|
|
});
|
|
});
|
|
|
|
|
|
-const onSubmit = () => {
|
|
|
|
- useMessage().success(t(formData.value ? 'common.editSuccessText' : 'common.addSuccessText'));
|
|
|
|
|
|
+const onSubmit = async () => {
|
|
|
|
+ let isValid = true;
|
|
|
|
+ if (formData.value.triggerMode === '1' || formData.value.triggerMode === '3') {
|
|
|
|
+ try {
|
|
|
|
+ await ruleFormRef.value.validateField('url');
|
|
|
|
+ } catch (error) {
|
|
|
|
+ // 验证失败,阻止后续逻辑执行
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 如果验证失败,直接返回,不执行后续逻辑
|
|
|
|
+ if (!isValid) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ loading.value = true;
|
|
|
|
+ await saveConfigDetail(formData.value);
|
|
|
|
+ useMessage().success(t('common.editSuccessText'));
|
|
|
|
+ } catch (err) {
|
|
|
|
+ useMessage().error(err.msg);
|
|
|
|
+ } finally {
|
|
|
|
+ getConfig();
|
|
|
|
+ }
|
|
};
|
|
};
|
|
const handleClick = (data: any) => {
|
|
const handleClick = (data: any) => {
|
|
if (data.props.label === 'IP分组') {
|
|
if (data.props.label === 'IP分组') {
|
|
@@ -416,6 +425,7 @@ const onOpenEditMenu = (type: string, row: any) => {
|
|
const getConfig = () => {
|
|
const getConfig = () => {
|
|
configIp();
|
|
configIp();
|
|
configDomain();
|
|
configDomain();
|
|
|
|
+ getConfigDetail();
|
|
};
|
|
};
|
|
const configDomain = async () => {
|
|
const configDomain = async () => {
|
|
await getConfigDomainList().then((val) => {
|
|
await getConfigDomainList().then((val) => {
|
|
@@ -434,11 +444,11 @@ const configIp = async () => {
|
|
.map((item) => {
|
|
.map((item) => {
|
|
return { ...item, list: [] };
|
|
return { ...item, list: [] };
|
|
});
|
|
});
|
|
- ipBlackList.value = val.data.filter((item) => item.ipType === 2).map((item) => {
|
|
|
|
|
|
+ ipBlackList.value = val.data
|
|
|
|
+ .filter((item) => item.ipType === 2)
|
|
|
|
+ .map((item) => {
|
|
return { ...item, list: [] };
|
|
return { ...item, list: [] };
|
|
- });;
|
|
|
|
- console.log(ipBlackList.value);
|
|
|
|
-
|
|
|
|
|
|
+ });
|
|
});
|
|
});
|
|
};
|
|
};
|
|
const getDomainData = async () => {
|
|
const getDomainData = async () => {
|
|
@@ -480,6 +490,18 @@ const getIpData = async () => {
|
|
};
|
|
};
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+ await getConfigDetail().then((val) => {
|
|
|
|
+ formData.value = {
|
|
|
|
+ promptMsg: '',
|
|
|
|
+ triggerMode: '',
|
|
|
|
+ triggerRule: '',
|
|
|
|
+ url: '',
|
|
|
|
+ triggerNum: '',
|
|
|
|
+ };
|
|
|
|
+ formData.value = { ...val.data, triggerMode: val.data?.triggerMode.toString(), triggerRule: val.data?.triggerRule.toString() };
|
|
|
|
+ console.log(val);
|
|
|
|
+ });
|
|
};
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|