Ver código fonte

Merge branch 'dev-cmn' into dev-ly

cmy 1 semana atrás
pai
commit
66262efc75

+ 17 - 12
src/api/marketing/apps.ts

@@ -1,14 +1,15 @@
 import request from '/@/utils/request';
 
-// export const getDetail = (params?: Object) => {
-// 	return request({
-// 		url: '/marketing/apps/edit',
-// 		// url: 'https://m1.apifoxmock.com/m1/6687089-6396408-default/marketing/apps/edit',
-// 		method: 'get',
-// 		params,
-// 	});
-// };
-
+/**
+ * 分页查询应用列表
+ * @param size	每页显示条数
+ * @param current	当前页
+ * @param appId	应用ID
+ * @param appName	应用名称
+ * @param domainType	应用类型
+ * @param remark	备注
+ * @returns 
+ */
 export const pageList = (params?: Object) => {
 	return request({
 		url: '/marketing/app/page',
@@ -18,10 +19,14 @@ export const pageList = (params?: Object) => {
 	});
 };
 
-export const delAppById = (params?: Object) => {
+/**
+ * 根据id拉黑应用
+ * @param id 应用ID
+ * @returns 
+ */
+export const delAppById = (id?: String|Number) => {
 	return request({
-		url: '/marketing/app/del/{id}',
+		url: '/marketing/app/del/' + id,
 		method: 'get',
-		params,
 	});
 };

+ 28 - 15
src/views/marketing/apps/components/domainCell.vue

@@ -1,7 +1,13 @@
 <template>
-  <div class="flex">
-    <div class="item" v-for="item in list.slice(0, 4)" :key="item">{{item}};</div>
-    <el-link type="info" @click="handleEdit" >查看详情</el-link>
+  <div class="cell">
+    <div class="flex">
+      <div class="item" v-for="item in list.slice(0, 4)" :key="item">{{item}}</div>
+    </div>
+    <div class="action" :style="{ textAlign: list.length > 0 ? 'left' : 'center'}">
+      <el-link type="info" @click="handleEdit" style="color: #167AF0; line-height: 18px;">
+        {{ list.length > 0 ? '查看详情' : '添加域名'}}
+      </el-link>
+    </div>
   </div>
   <DomainForm ref="DomainFormRef" />
 </template>
@@ -35,17 +41,24 @@ const handleEdit = () => {
   DomainFormRef.value.openDialog(props.domainList);
 };
 </script>
-<style scoped>
-.flex {
-  display: flex;
-  flex-wrap: wrap;
-}
-.item {
-  box-sizing: border-box;
-  padding: 4px 0;
-  text-align: left;
-  margin-right: 20px;
-  color: #666666;
-  line-height: 18px;
+<style scoped lang="scss">
+.cell {
+  padding: 10px 0;
+  .flex {
+    display: flex;
+    flex-wrap: wrap;
+    margin-bottom: 5px;
+  }
+  .item {
+    box-sizing: border-box;
+    padding: 4px 0;
+    text-align: left;
+    margin-right: 15px;
+    color: #646464;
+    line-height: 14px;
+  }
+  .action {
+    width: 100%;
+  }
 }
 </style>

+ 10 - 4
src/views/marketing/apps/components/domainCollapse.vue

@@ -26,10 +26,13 @@
             </template>
           </el-popover>
         </template>
+        <div class="text-gray-400" v-if="domains.length <= 0">
+          --
+        </div>
       </div>
     </template>
   </JCollapse>
-  <DomainEdit v-model:open="domainEditOpen" />
+  <DomainEdit v-model:open="domainEditOpen" @onsuccess="addDomain" />
 </template>
 
 <script setup lang="ts" name="domainCollapse">
@@ -56,12 +59,10 @@ const domains = ref<DomianItem[]>([]);
 const domainDeletable = ref(false);// 控制域名列表项是否可删除
 const domainEditOpen = ref(false);
 
-watchEffect(() => {
+watch(props.data, ()=>{
   if (props.data) {
     domains.value = props.data;
   }
-  console.log('domains', domains.value);
-
 })
 
 const getDomainList = (detail: DomianItem) => {
@@ -76,6 +77,11 @@ const handleDeleteDomain = (deleteItem: DomianItem) => {
   domains.value = domains.value.filter((item: any) => item.id != deleteItem.id);
 }
 
+const addDomain = (data: DomianItem[]) => {
+  console.log(data);
+  domains.value = [...domains.value, ...data];
+}
+
 </script>
 <style lang="scss">
 .el-collapse-item__content {

+ 34 - 34
src/views/marketing/apps/components/domainEdit.vue

@@ -12,9 +12,9 @@
 				</el-segmented>
 			</div>
 			<el-form-item label="" prop="grouping" v-if="activeName === t('marketingConfig.grouping')">
-				<el-select v-model="state.ruleForm.groupingTip" :placeholder="t('marketingConfig.groupingTip')"
-					clearable>
-					<el-option v-for="item in listSelect" :key="item.value" :label="item.label" :value="item.value" />
+				<el-select multiple collapse-tags collapse-tags-tooltip :max-collapse-tags="5"
+					v-model="state.ruleForm.selectedIds" :placeholder="t('marketingConfig.groupingTip')" clearable>
+					<el-option v-for="item in listSelect" :key="item.id" :label="item.groupName" :value="item.id" />
 				</el-select>
 			</el-form-item>
 			<el-form-item label="" prop="domain" v-else>
@@ -32,49 +32,35 @@
 	</el-dialog>
 </template>
 
-<script setup name="systemMenuDialog">
+<script setup lang="ts" name="systemMenuDialog">
 import { useI18n } from 'vue-i18n';
-import { info, getAppList, save } from '/@/api/marketing/config';
+import { pageListDomain } from '/@/api/marketing/config';
 import { useMessage } from '/@/hooks/message';
 
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['update:open', 'onsuccess']);
 const { t } = useI18n();
 
+interface DomainItem {
+	domains: String[];
+	groupName: String;
+	id: String;
+}
+
 // 定义变量内容
 const loading = ref(false);
 const type = ref('add'); // 'add' or 'edit'
 const activeName = ref(t('marketingConfig.grouping'));
 const dialogFormRef = ref();
-const listSelect = ref([
-	{
-		value: 'group1',
-		label: '分组1',
-	},
-	{
-		value: 'group2',
-		label: '分组2',
-	},
-	{
-		value: 'group3',
-		label: '分组3',
-	},
-]);
+const listSelect = ref<DomainItem[]>([]);
+const selectedObjects = ref<DomainItem[]>([]);
+
 // 定义需要的数据
 const state = reactive({
 	ruleForm: {
-		list: [''],
-		https: [''], // 域名集合
-		ips: [''], // ip集合
-		// {
-		//   id: '1',
-		//   ip: '美国',
-		//   appId: '1',
-		//   appUrl: 'www.baidu.com',
-		//   appName: 'adsa'
-		// },
+		selectedIds: [] as String[], // 选中域名分组
+		domain: [],
 	},
-	appList: [], // 应用下拉框列表
 });
 
 const props = defineProps({
@@ -83,7 +69,8 @@ const props = defineProps({
 		default: false,
 	},
 });
-// // 表单校验规则
+
+// 表单校验规则
 const dataRules = reactive({
 	domain: [
 		{ required: true, message: '域名不能为空', trigger: 'blur' }
@@ -94,11 +81,14 @@ const onCancel = () => {
 };
 // 保存数据
 const onSubmit = async () => {
+	selectedObjects.value = [];
 	try {
 		loading.value = true;
-		// await save(state.ruleForm);
-		useMessage().success(t(state.ruleForm.id ? 'common.editSuccessText' : 'common.addSuccessText'));
-		emit('onsuccess');
+		console.log(state.ruleForm.selectedIds);
+		selectedObjects.value = listSelect.value.filter(item=>state.ruleForm.selectedIds.includes(item.id));
+		console.log(selectedObjects.value);
+		useMessage().success(t('common.addSuccessText'));
+		emit('onsuccess', selectedObjects.value);
 		onCancel();
 	} catch (err) {
 		useMessage().error(err.msg);
@@ -106,6 +96,16 @@ const onSubmit = async () => {
 		loading.value = false;
 	}
 };
+
+const getDomainList = async ()=>{
+	const data = await pageListDomain();
+	listSelect.value = data.data;
+}
+
+onMounted(()=>{
+	getDomainList();
+})
+
 </script>
 <style scoped>
 .apps-loadmore.el-select-dropdown .el-scrollbar__wrap {

+ 48 - 24
src/views/marketing/apps/components/ipCell.vue

@@ -1,13 +1,15 @@
 <template>
-  <div style="text-align: left;">白名单:</div>
-  <div class="flex">
-    <div class="item" v-for="item in whitelist.slice(0, 4)" :key="item">{{item}};</div>
-    <el-link type="info" @click="handleEdit">查看详情</el-link>
-  </div>
-  <div style="text-align: left; margin-top: 10px;">黑名单:</div>
-  <div class="flex">
-    <div class="item" v-for="item in blacklist.slice(0, 4)" :key="item">{{item}};</div>
-    <el-link type="info" @click="handleEdit">查看详情</el-link>
+  <div class="cell">
+    <div class="ellipsis" style="width: 100%; text-align: left;" v-for="(list, index) in [whitelist, blacklist]">
+      <span class="title">{{ index == 0 ? '白名单:' : '黑名单:' }}</span>
+      <span class="item" v-for="item in list" :key="item">{{item}}</span>
+      <span class="item" v-if="list.length <= 0">--</span>
+    </div>
+    <div class="action">
+      <el-link type="info" @click="handleEdit" style="color: #167AF0; line-height: 18px;" >
+        {{ blacklist.length > 0 ? '查看详情' : '添加IP'}}
+      </el-link>
+    </div>
   </div>
   <IpForm ref="IpFormRef" />
 </template>
@@ -35,8 +37,6 @@ watch(
       }
       item.ipType == 1 ? blacklist.value.push(temp) : whitelist.value.push(temp);
     });
-    console.log(blacklist);
-    console.log(whitelist);
   },
   { immediate: true }
 );
@@ -46,18 +46,42 @@ const handleEdit = () => {
   IpFormRef.value.openDialog(props.ipList);
 };
 </script>
-<style scoped>
-.flex {
-  display: flex;
-  flex-wrap: wrap;
-}
-.item {
-  width: auto;
-  box-sizing: border-box;
-  padding: 4px 0;
-  text-align: left;
-  margin-right: 20px;
-  color: #666666;
-  line-height: 18px;
+<style scoped lang="scss">
+.cell {
+  padding: 10px 0;
+  .flex {
+    display: flex;
+    flex-wrap: wrap;
+    margin-bottom: 5px;
+  }
+  .title {
+    text-align: left;
+    line-height: 14px;
+    height: 14px;
+    margin-right: 15px;
+    padding: 4px 0;
+  }
+  .item {
+    width: auto;
+    box-sizing: border-box;
+    padding: 4px 0;
+    text-align: left;
+    margin-right: 15px;
+    color: #646464;
+    line-height: 14px;
+  }
+  .action {
+    width: 100%;
+    text-align: left;
+  }
+
+  .ellipsis {
+    display: -webkit-box;          /* 使用弹性盒子布局 */
+    -webkit-box-orient: vertical;  /* 垂直方向排列 */
+    -webkit-line-clamp: 2;         /* 限制显示的行数 */
+    overflow: hidden;              /* 隐藏超出部分 */
+    text-overflow: ellipsis;       /* 超出时显示省略号 */
+    word-break: break-word;        /* 允许单词断行(可选) */
+  }
 }
 </style>

+ 9 - 29
src/views/marketing/apps/components/ipCollapse.vue

@@ -5,10 +5,10 @@
     :deleteText="ipDeletable ? '取消' : t('marketingConfig.deleteText')" :updateText="'新增'"
     :activeNames="['1']">
     <template #default>
-      <div class="border-b p-2 items-center flex flex-wrap collapse-group">
-        <div class="collapse-group-name">白名单:</div>
-        <div class="tag-content">
-          <template v-for="item in ips.whitelist" :key="item.id">
+      <div class="border-b p-2 items-center flex flex-wrap collapse-group min-h-[40px]" v-for="(list, index) in [ips.whitelist, ips.blacklist]" :key="index">
+        <div class="collapse-group-name">{{ index == 0 ? '白名单' : '黑名单'}}:</div>
+        <div class="tag-content" v-if="list.length > 0">
+          <template v-for="item in list" :key="item.id">
             <!-- 具体IP(段) -->
             <el-tag v-if="item.sourceType == 2" effect="light" :closable="ipDeletable" @close="handleDeleteIp(item)"
               color="#f4f4f4" round class="ml-1 cursor-pointer" style="margin-bottom: 4px;">
@@ -16,43 +16,23 @@
             </el-tag>
             <!-- 分组 -->
             <el-popover v-else width="200" trigger="hover" placement="top">
-              <div class="flex flex-wrap">
+              <div class="flex flex-wrap break-all">
                 {{ item.groupName }}
               </div>
               <template #reference>
                 <el-tag @click="getIpList(item)" effect="light" :closable="ipDeletable" @close="handleDeleteIp(item)"
                   color="#f4f4f4" round class="ml-1 cursor-pointer" style="margin-bottom: 4px;">
-                  {{ item.groupName }}
+                  {{ item.groupName.length > 30 ? item.groupName.substring(0, 30) + '...' : item.groupName}}
                 </el-tag>
               </template>
             </el-popover>
           </template>
         </div>
-      </div>
-      <div class="p-2 items-center flex flex-wrap collapse-group">
-        <div class="collapse-group-name">黑名单:</div>
-        <div class="tag-content">
-          <template v-for="item in ips.blacklist" :key="item.id">
-            <!-- 具体IP(段) -->
-            <el-tag v-if="item.sourceType == 2" effect="light" :closable="ipDeletable" @close="handleDeleteIp(item)"
-              color="#f4f4f4" round class="ml-1 cursor-pointer" style="margin-bottom: 4px;">
-              {{ item.startIp }}{{ item.ipMode == 2 ? (' / ' + item.endIp.split('.').pop()) : '' }}
-            </el-tag>
-            <!-- 分组 -->
-            <el-popover v-else width="200" trigger="hover" placement="top">
-              <div class="flex flex-wrap">
-                {{ item.groupName }}
-              </div>
-              <template #reference>
-                <el-tag @click="getIpList(item)" effect="light" :closable="ipDeletable" @close="handleDeleteIp(item)"
-                  color="#f4f4f4" round class="ml-1 cursor-pointer" style="margin-bottom: 4px;">
-                  {{ item.groupName }}
-                </el-tag>
-              </template>
-            </el-popover>
-          </template>
+        <div class="text-gray-400" v-else>
+          --
         </div>
       </div>
+
     </template>
   </JCollapse>
   <IpEdit v-model:open="listEditOpen" />

+ 27 - 12
src/views/marketing/apps/index.vue

@@ -10,10 +10,9 @@
           <el-form-item :label="'应用ID'" prop="appId">
             <el-input :placeholder="'请输入应用ID'" clearable v-model="state.queryForm.appId" />
           </el-form-item>
-          <el-form-item :label="'应用类型'" prop="appType">
-            <el-select placeholder="请选择应用类型" v-model="state.queryForm.appType">
-              <el-option :key="''" :label="'全部'" :value="''" />
-              <el-option v-for="item in appTypes" :key="item.value" :label="item.description" :value="item.value" />
+          <el-form-item :label="'应用类型'" prop="domainSelected">
+            <el-select placeholder="请选择应用类型" v-model="state.queryForm.domainSelected">
+              <el-option v-for="item in domainTypeOptions" :key="item.value" :label="item.description" :value="item.value" />
             </el-select>
           </el-form-item>
           <el-form-item :label="'备注'" prop="remark">
@@ -52,7 +51,7 @@
         </el-table-column>
         <el-table-column :label="t('marketingApps.appImg')" prop="appImg" width="150" show-overflow-tooltip>
           <template #default="{ row }" style="display: flex; align-self: center;">
-            <el-image style="width: 80px; height: 80px" :src="row.appImg" :fit="fit" />
+            <el-image style="width: 80px; height: 80px; border-radius: 10px;" :src="row.appImg" :fit="fit" />
           </template>
         </el-table-column>
         <el-table-column :label="t('marketingApps.name')" prop="appName" width="150" show-overflow-tooltip>
@@ -63,7 +62,7 @@
         <el-table-column :label="t('marketingApps.appType')" prop="domainType" width="110" show-overflow-tooltip>
           <template #default="{ row }">
             <el-select @change="handleChange(row)" :disabled="activeName === 'tab2'" v-model="row.domainType" placeholder="" style="width: 80px">
-              <el-option v-for="item in appTypes" :key="item.value" :label="item.description" :value="item.value" />
+              <el-option v-for="item in domainTypeOptions" :key="item.value" :label="item.description" :value="item.value" />
             </el-select>
           </template>
         </el-table-column>
@@ -191,22 +190,31 @@ const selectObjs = ref([]) as any;
 const multiple = ref(true);
 const state: BasicTableProps = reactive<BasicTableProps>({
   pageList: pageList,
+  createdIsNeed: false,
   queryForm: {
-    domain: '',
-    appType: '',
     appId: '',
+    appName: '',
+    domainSelected: '0',
+    domainType: '',
     remark: '',
   }
 });
 
-const appTypes = ref([]) as any;
-const getAppTypes = async () => {
+const domainTypeOptions = ref([]) as any;
+const getDomianTypeList = async () => {
   const { data } = await fetchItemList({
     dictType: 'DomianType'
   });
-  appTypes.value = data?.records || [];
+  domainTypeOptions.value = data?.records || [];
+  domainTypeOptions.value.map((item)=>{
+    item.value = Number(item.value);
+  })
+  domainTypeOptions.value.unshift({
+    description: '全部',
+    value: '0'
+  })
 }
-getAppTypes();
+getDomianTypeList();
 
 const triggerRules = [
   {
@@ -224,6 +232,7 @@ const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTa
 // 搜索事件
 const query = () => {
   state.dataList = [];
+  state.queryForm.domainType = state.queryForm.domainSelected == 0 ? '' : state.queryForm.domainSelected;
   getDataList();
 };
 
@@ -275,6 +284,8 @@ const handleDelete = async (row: any) => {
 	try {
     if(activeName.value == 'tab1'){
       await useMessageBox().confirm('是否确认拉黑该应用');
+      await delAppById(row.id);
+      ElMessage.success('拉黑成功!');
     }else{
       ElMessage.success('还原成功!');
     }
@@ -292,6 +303,10 @@ const handleDelete = async (row: any) => {
   query();
 };
 
+onMounted(()=>{
+  query();
+})
+
 </script>
 <style scoped lang="scss">
 :deep(.el-link__inner) {