jcq 2 dni temu
rodzic
commit
75ad2a9959

+ 7 - 0
package-lock.json

@@ -19,6 +19,7 @@
 				"child_process": "^1.0.2",
 				"china-area-data": "^5.0.1",
 				"codemirror": "5.65.18",
+				"country-state-city": "^3.2.1",
 				"crypto-js": "4.2.0",
 				"dayjs": "^1.11.13",
 				"dotenv": "^17.2.1",
@@ -2725,6 +2726,12 @@
 				"url": "https://github.com/sponsors/mesqueeb"
 			}
 		},
+		"node_modules/country-state-city": {
+			"version": "3.2.1",
+			"resolved": "https://registry.npmjs.org/country-state-city/-/country-state-city-3.2.1.tgz",
+			"integrity": "sha512-kxbanqMc6izjhc/EHkGPCTabSPZ2G6eG4/97akAYHJUN4stzzFEvQPZoF8oXDQ+10gM/O/yUmISCR1ZVxyb6EA==",
+			"license": "GPL-3.0"
+		},
 		"node_modules/cpu-features": {
 			"version": "0.0.10",
 			"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz",

+ 1 - 0
package.json

@@ -26,6 +26,7 @@
 		"child_process": "^1.0.2",
 		"china-area-data": "^5.0.1",
 		"codemirror": "5.65.18",
+		"country-state-city": "^3.2.1",
 		"crypto-js": "4.2.0",
 		"dayjs": "^1.11.13",
 		"dotenv": "^17.2.1",

+ 7 - 0
src/api/marketing/config.ts

@@ -125,6 +125,13 @@ export const getRule = (params?: Object) => {
 		params,
 	});
 };
+//获取app列表
+export const getAppList = () => {
+	return request({
+		url: '/marketing/app/list',
+		method: 'get',
+	});
+};
 //保存主动推送
 export const saveRule = (data?: Object) => {
 	return request({

+ 1 - 0
src/views/count/user/versionDistribution/i18n/zh-cn.ts

@@ -8,3 +8,4 @@ export default {
 		versionComparison:'版本对比'
 	},
 };
+

+ 91 - 6
src/views/marketing/config/components/push.vue

@@ -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()
 		}
 	}
 );