|
@@ -1,6 +1,27 @@
|
|
|
<template>
|
|
|
<div class="w-full ml-[-8px] mt-5">
|
|
|
<div class="px-4 rounded overflow-y-auto w-full" style="max-height: calc(100vh - 350px)">
|
|
|
+ <div class="flex items-start">
|
|
|
+ <label class="w-[65px] leading-8 text-right">地区</label>
|
|
|
+ <div class="flex gap-2 ml-2 flex-wrap w-57vw]">
|
|
|
+ <el-tag
|
|
|
+ v-for="(tag, index) in regionData"
|
|
|
+ :key="index"
|
|
|
+ size="large"
|
|
|
+ closable
|
|
|
+ :disable-transitions="false"
|
|
|
+ @close="handleClose(tag, 'region')"
|
|
|
+ >
|
|
|
+ {{ tag.state ? `${tag.country} - ${tag.state}` : tag.country }}
|
|
|
+ </el-tag>
|
|
|
+ <ChineseRegionSelector v-if="regionInputVisible" v-model="regionData" @update:modelValue="handleRegionDataUpdate" />
|
|
|
+ <el-button v-else class="button-new-tag" @click="showRegionInput"> 添加地区</el-button>
|
|
|
+ <!-- 注册隐藏的表单项以启用校验 -->
|
|
|
+ <el-form-item prop="region" style="display: none"></el-form-item>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="px-4 rounded overflow-y-auto w-full" style="max-height: calc(100vh - 350px)">
|
|
|
<div class="flex items-start">
|
|
|
<label class="w-[65px] leading-8 text-right">IP</label>
|
|
|
<div class="flex gap-2 ml-2 flex-wrap w-57vw]">
|
|
@@ -16,11 +37,10 @@
|
|
|
@blur="handleInputConfirm('ip')"
|
|
|
/>
|
|
|
<el-button v-else class="button-new-tag" @click="showIpInput"> 添加IP</el-button>
|
|
|
- <!-- 注册隐藏的表单项以启用校验 -->
|
|
|
<el-form-item prop="ip" style="display: none"></el-form-item>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </div> -->
|
|
|
|
|
|
<div class="px-4 rounded overflow-y-auto mt-4 w-full" style="max-height: calc(100vh - 350px)">
|
|
|
<div class="flex items-start">
|
|
@@ -48,6 +68,11 @@
|
|
|
<el-form-item label="主动推送" prop="autoPush" class="w-full">
|
|
|
<el-switch v-model="formData.autoPush" class="mr-2" />
|
|
|
</el-form-item>
|
|
|
+ <el-form-item label="推送应用" prop="appId" class="w-1/2">
|
|
|
+ <el-select v-model="formData.appId" placeholder="请选择推送方式" :props="{ multiple: true }" class="w-full">
|
|
|
+ <el-option v-for="item in appOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
<el-form-item label="推送方式" prop="action" class="w-1/2">
|
|
|
<JDictSelect v-model:value="formData.action" placeholder="请选择推送方式" dictType="pushMode" :styleClass="'w-full'" />
|
|
|
</el-form-item>
|
|
@@ -76,7 +101,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup name="Edit" lang="ts">
|
|
|
-import { saveRule } from '/@/api/marketing/config';
|
|
|
+import { saveRule, getAppList } from '/@/api/marketing/config';
|
|
|
import { useI18n } from 'vue-i18n';
|
|
|
import { useMessage } from '/@/hooks/message';
|
|
|
let baseURL = import.meta.env.VITE_API_URL;
|
|
@@ -103,6 +128,7 @@ const success = (val: string) => {
|
|
|
// 引入组件
|
|
|
const JDictSelect = defineAsyncComponent(() => import('/@/components/JDictSelect/index.vue'));
|
|
|
const Image = defineAsyncComponent(() => import('/@/components/Upload/Image.vue'));
|
|
|
+const ChineseRegionSelector = defineAsyncComponent(() => import('/@/components/common/ChineseRegionSelector.vue'));
|
|
|
const { t } = useI18n();
|
|
|
// 定义变量内容
|
|
|
|
|
@@ -122,6 +148,18 @@ const formData = ref<any>({
|
|
|
delayPush: '',
|
|
|
autoPush: false,
|
|
|
});
|
|
|
+const appOptions = ref<any[]>([]);
|
|
|
+const getAppListData = async() => {
|
|
|
+ const res = await getAppList()
|
|
|
+ const data = res.data
|
|
|
+ appOptions.value = data.map((item: any) => {
|
|
|
+ return {
|
|
|
+ label: item.appName,
|
|
|
+ value: item.appId,
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
|
|
|
// // 表单校验规则
|
|
|
const dataRules = reactive({
|
|
@@ -152,6 +190,18 @@ const dataRules = reactive({
|
|
|
trigger: 'blur',
|
|
|
},
|
|
|
],
|
|
|
+ region: [
|
|
|
+ {
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ if (!regionData.value || regionData.value.length === 0) {
|
|
|
+ callback(new Error('地区不能为空'));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ trigger: 'blur',
|
|
|
+ },
|
|
|
+ ],
|
|
|
pushFrequency: [
|
|
|
{ required: true, message: '推送频率不能为空', trigger: 'blur' },
|
|
|
{
|
|
@@ -166,15 +216,19 @@ const dataRules = reactive({
|
|
|
|
|
|
const ipInputValue = ref('');
|
|
|
const domainInputValue = ref('');
|
|
|
+const regionInputValue = ref('');
|
|
|
|
|
|
const ipInputVisible = ref(false);
|
|
|
const domainInputVisible = ref(false);
|
|
|
+const regionInputVisible = ref(false);
|
|
|
|
|
|
const ipInputRef = ref();
|
|
|
const domainInputRef = ref();
|
|
|
+const regionInputRef = ref();
|
|
|
|
|
|
const ipData = ref<string[]>([]);
|
|
|
const domainData = ref<string[]>([]);
|
|
|
+const regionData = ref<any[]>([]);
|
|
|
|
|
|
const showIpInput = () => {
|
|
|
ipInputVisible.value = true;
|
|
@@ -188,9 +242,17 @@ const showDomainInput = () => {
|
|
|
domainInputRef.value!.input!.focus();
|
|
|
});
|
|
|
};
|
|
|
-const handleClose = (tag: string, type: string) => {
|
|
|
+const showRegionInput = () => {
|
|
|
+ regionInputVisible.value = true;
|
|
|
+ nextTick(() => {
|
|
|
+ regionInputRef.value?.focus();
|
|
|
+ });
|
|
|
+};
|
|
|
+const handleClose = (tag: any, type: string) => {
|
|
|
if (type === 'ip') {
|
|
|
ipData.value = ipData.value.filter((item: string) => item !== tag);
|
|
|
+ } else if (type === 'region') {
|
|
|
+ regionData.value = regionData.value.filter((item: any) => item !== tag);
|
|
|
} else if (type === 'domain') {
|
|
|
domainData.value = domainData.value.filter((item: string) => item !== tag);
|
|
|
}
|
|
@@ -347,6 +409,10 @@ const validateDomain = (domain: string): boolean => {
|
|
|
const handleInputConfirm = (type: string) => {
|
|
|
if (type === 'ip') {
|
|
|
if (ipInputValue.value) {
|
|
|
+ if (regionData.value.includes(ipInputValue.value)) {
|
|
|
+ useMessage().error('该地区已存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
// 校验IP格式
|
|
|
if (validateIP(ipInputValue.value)) {
|
|
|
// 检查IP冲突
|
|
@@ -364,6 +430,10 @@ const handleInputConfirm = (type: string) => {
|
|
|
ipInputValue.value = '';
|
|
|
} else if (type === 'domain') {
|
|
|
if (domainInputValue.value) {
|
|
|
+ if (regionData.value.includes(domainInputValue.value)) {
|
|
|
+ useMessage().error('该地区已存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
// 校验域名格式
|
|
|
if (validateDomain(domainInputValue.value)) {
|
|
|
domainData.value.push(domainInputValue.value);
|
|
@@ -374,8 +444,20 @@ const handleInputConfirm = (type: string) => {
|
|
|
}
|
|
|
domainInputVisible.value = false;
|
|
|
domainInputValue.value = '';
|
|
|
+ } else if (type === 'region') {
|
|
|
+ if (regionInputValue.value) {
|
|
|
+ regionData.value.push(regionInputValue.value);
|
|
|
+ }
|
|
|
+ regionInputVisible.value = false;
|
|
|
+ regionInputValue.value = '';
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+// 地区数据更新处理
|
|
|
+const handleRegionDataUpdate = (newRegionData: any[]) => {
|
|
|
+ regionData.value = newRegionData;
|
|
|
+ regionInputVisible.value = false;
|
|
|
+};
|
|
|
const getpushContent = () => {
|
|
|
if (formData.value.pushContent && formData.value.pushType) {
|
|
|
return formData.value.pushContent.includes('http') ? formData.value.pushContent : baseURL + formData.value.pushContent;
|
|
@@ -403,9 +485,10 @@ const onSubmit = async () => {
|
|
|
...formData.value,
|
|
|
ip: ipData.value,
|
|
|
domain: domainData.value,
|
|
|
+ region: regionData.value,
|
|
|
pushContent: getpushContent(),
|
|
|
pushType: formData.value.pushType || false,
|
|
|
-
|
|
|
+ pushFrequency: pushFrequency.toString(),
|
|
|
};
|
|
|
|
|
|
if (!formData.value.pushContent) {
|
|
@@ -416,7 +499,7 @@ const onSubmit = async () => {
|
|
|
|
|
|
await saveRule({
|
|
|
...formData.value,
|
|
|
- pushFrequency: pushFrequency.toString(),
|
|
|
+ pushFrequency: pushFrequency.toString(),
|
|
|
});
|
|
|
useMessage().success(t('common.editSuccessText'));
|
|
|
emit('onsuccess');
|
|
@@ -448,7 +531,9 @@ watch(
|
|
|
};
|
|
|
ipData.value = props.rowData.ip || [];
|
|
|
domainData.value = props.rowData.domain || [];
|
|
|
+ regionData.value = props.rowData.region || [];
|
|
|
oldUrl.value = props.rowData.pushContent;
|
|
|
+ getAppListData()
|
|
|
}
|
|
|
}
|
|
|
);
|