Browse Source

违法通讯录 导入导出 demo 违法信息通报清单调用后端接口逻辑

Luka 1 month ago
parent
commit
e7754cc8eb

+ 25 - 0
src/api/addressBook.ts

@@ -0,0 +1,25 @@
+import request from '@/utils/request';
+
+// 违法联络员状态调整
+export const changeInventoryStatus = (id: string, status: string) => {
+	return request({
+		url: '/api/business/ntlo/changeInventoryStatus',
+		method: 'get',
+		params: {
+			id: id,
+			status: status,
+		},
+	});
+};
+
+// 违法联络员数据上传
+export const importInfo = (data: any) => {
+	return request({
+		url: '/api/business/ntlo/import',
+		headers: {
+			'Content-Type': 'multipart/form-data',
+		},
+		method: 'post',
+		data: data,
+	});
+};

+ 13 - 0
src/api/notificationListManage.ts

@@ -0,0 +1,13 @@
+import request from '@/utils/request';
+
+// 违法事项清单状态调整
+export const changeInventoryStatus = (id: string, status: string) => {
+	return request({
+		url: '/api/business/lonm/changeInventoryStatus',
+		method: 'get',
+		params: {
+			id: id,
+			status: status,
+		},
+	});
+};

+ 84 - 85
src/store/main.ts

@@ -5,97 +5,96 @@
 // paramsType 增删改页面新增项,用来给(特殊)的列表接口刷新页面使用
 
 import {
-    deletePageData,
-    editPageData,
-    getPageListData,
-    newPageData,
-    getPageDetail,
-    getCommon,
+	deletePageData,
+	editPageData,
+	getPageListData,
+	newPageData,
+	getPageDetail,
+	getCommon,
 } from '@/api/main';
 import { defineStore } from 'pinia';
 import cache from '@/plugins/cache';
 import { ElMessage } from 'element-plus';
-import { log } from 'console';
 
 const useSystemStore = defineStore('system', {
-    state: () => ({
-        pageList: [],
-        pageTotalCount: 0,
-        pageDetailInfo: {},
-        pageOperateType: 'add',
-        deletSign: true,
-        pageInfo: {
-            pageNum: 1,
-            pageSize: 10,
-        },
-        resDate: {} as any,
-        searchObj: {} as any,
-    }),
-    actions: {
-        // 页面的网络请求
-        async getPageListDataAction(pageName: string, queryInfo?: any) {
-            await getPageListData(
-                pageName,
-                queryInfo
-                    ? { ...queryInfo, ...this.pageInfo, ...this.searchObj }
-                    : { ...this.pageInfo, ...this.searchObj }
-            ).then((res: any) => {
-                this.pageList = res.rows;
-                this.pageTotalCount = res.total;
-                this.resDate = res;
-            });
-        },
-        async deletePageDataAction(pageName: string, urlId: any, paramsType?: object) {
-            // 2.删除用户列表数据
-            await deletePageData(pageName, urlId).then((res: any) => {
-                ElMessage.success(res.msg);
-            });
-            this.deletSign = !this.deletSign;
-            await this.getPageListDataAction(pageName, { pageSize: 10, ...paramsType });
-        },
-        async newPageDataAction(pageName: string, pageData: any, paramsType?: object) {
-            let flag = reactive({});
-            // 3.新增用户数据
-            // const res = await newPageData(pageName, pageData);
-            await newPageData(pageName, { ...pageData, ...paramsType }).then((res: any) => {
-                if (res.code === 200) {
-                    ElMessage.success('新增成功');
-                    flag = res;
-                } else {
-                    ElMessage.error(res.msg);
-                    flag = res;
-                }
-            });
-            await this.getPageListDataAction(pageName, { ...this.pageInfo, ...paramsType });
-            return flag;
-        },
-        async editPageDataAction(pageName: string, pageData: any, paramsType?: object) {
-            // 4.修改用户数据
-            await editPageData(pageName, { ...pageData, ...paramsType }).then((res: any) => {
-                if (res.code === 200) {
-                    ElMessage.success('更新成功');
-                } else {
-                    ElMessage.error(res.msg);
-                }
-            });
-            await this.getPageListDataAction(pageName, { ...this.pageInfo, ...paramsType });
-        },
-        async detailPageDataAction(pageName: string, urlId: any) {
-            // 5.获取用户详情数据
-            const res = await getPageDetail(pageName, urlId);
-            this.pageDetailInfo = res.data;
-            cache.local.setJSON('pageDetailInfo', this.pageDetailInfo);
-            return res.data;
-        },
-        // 获取页面详情, 应对特殊情况的详情接口
-        detailPageEval(data: any) {
-            this.pageDetailInfo = data;
-        },
-        // 获取页面操作类型
-        getDetailType(data: string) {
-            this.pageOperateType = data;
-        },
-    },
+	state: () => ({
+		pageList: [],
+		pageTotalCount: 0,
+		pageDetailInfo: {},
+		pageOperateType: 'add',
+		deletSign: true,
+		pageInfo: {
+			pageNum: 1,
+			pageSize: 10,
+		},
+		resDate: {} as any,
+		searchObj: {} as any,
+	}),
+	actions: {
+		// 页面的网络请求
+		async getPageListDataAction(pageName: string, queryInfo?: any) {
+			await getPageListData(
+				pageName,
+				queryInfo
+					? { ...queryInfo, ...this.pageInfo, ...this.searchObj }
+					: { ...this.pageInfo, ...this.searchObj }
+			).then((res: any) => {
+				this.pageList = res.rows;
+				this.pageTotalCount = res.total;
+				this.resDate = res;
+			});
+		},
+		async deletePageDataAction(pageName: string, urlId: any, paramsType?: object) {
+			// 2.删除用户列表数据
+			await deletePageData(pageName, urlId).then((res: any) => {
+				ElMessage.success(res.msg);
+			});
+			this.deletSign = !this.deletSign;
+			await this.getPageListDataAction(pageName, { pageSize: 10, ...paramsType });
+		},
+		async newPageDataAction(pageName: string, pageData: any, paramsType?: object) {
+			let flag = reactive({});
+			// 3.新增用户数据
+			// const res = await newPageData(pageName, pageData);
+			await newPageData(pageName, { ...pageData, ...paramsType }).then((res: any) => {
+				if (res.code === 200) {
+					ElMessage.success('新增成功');
+					flag = res;
+				} else {
+					ElMessage.error(res.msg);
+					flag = res;
+				}
+			});
+			await this.getPageListDataAction(pageName, { ...this.pageInfo, ...paramsType });
+			return flag;
+		},
+		async editPageDataAction(pageName: string, pageData: any, paramsType?: object) {
+			// 4.修改用户数据
+			await editPageData(pageName, { ...pageData, ...paramsType }).then((res: any) => {
+				if (res.code === 200) {
+					ElMessage.success('更新成功');
+				} else {
+					ElMessage.error(res.msg);
+				}
+			});
+			await this.getPageListDataAction(pageName, { ...this.pageInfo, ...paramsType });
+		},
+		async detailPageDataAction(pageName: string, urlId: any) {
+			// 5.获取用户详情数据
+			const res = await getPageDetail(pageName, urlId);
+			this.pageDetailInfo = res.data;
+			cache.local.setJSON('pageDetailInfo', this.pageDetailInfo);
+			return res.data;
+		},
+		// 获取页面详情, 应对特殊情况的详情接口
+		detailPageEval(data: any) {
+			this.pageDetailInfo = data;
+		},
+		// 获取页面操作类型
+		getDetailType(data: string) {
+			this.pageOperateType = data;
+		},
+	},
 });
 
 export default useSystemStore;

+ 33 - 50
src/views/notificationInfoManage/addressBook/components/detail.vue

@@ -80,6 +80,21 @@
 											}}</el-radio>
 										</el-radio-group>
 									</template>
+
+									<!-- 单位名称 -->
+									<template v-if="item.type === 'unitName'">
+										<el-tree-select
+											v-model="formData[item.prop]"
+											:data="unitOptions"
+											node-key="id"
+											filterable
+											check-strictly="true"
+											:placeholder="item.placeholder"
+											style="width: 100%"
+										/>
+									</template>
+
+									<!-- 联络人姓名  -->
 									<template v-if="item.type === 'contactName'">
 										<el-select
 											:disabled="item.disabled"
@@ -101,17 +116,8 @@
 											/>
 										</el-select>
 									</template>
-									<template v-if="item.type === 'unitName'">
-										<el-tree-select
-											v-model="formData[item.prop]"
-											:data="unitOptions"
-											node-key="id"
-											filterable
-											check-strictly="true"
-											:placeholder="item.placeholder"
-											style="width: 100%"
-										/>
-									</template>
+
+									<!-- 所属部门 -->
 									<template v-if="item.type === 'belongsDept'">
 										<el-input
 											:readonly="item.disabled"
@@ -181,28 +187,20 @@ interface userNameListItem {
 	value: string;
 	label: string;
 }
-const allOptions = ref<userNameListItem[]>([]);
-allOptions.value = [
-	{ label: '综合办公室-张三', value: 'Alabama' },
-	{ label: '科技信息处-李四', value: 'Alaska' },
-	{ label: '综合办公室-王五', value: 'Arizona' },
-	{ label: '科技信息处-赵六', value: 'California' },
-];
-
+const alluserNameOptions = ref<userNameListItem[]>([]);
 const userLoading = ref(false);
-
 const userNameOptions = ref<userNameListItem[]>([]);
 const remoteuserNameMethod = (query: string) => {
 	if (query) {
 		userLoading.value = true;
 		setTimeout(() => {
 			userLoading.value = false;
-			userNameOptions.value = allOptions.value.filter(item => {
+			userNameOptions.value = alluserNameOptions.value.filter(item => {
 				return item.label.toLowerCase().includes(query.toLowerCase());
 			});
 		}, 200);
 	} else {
-		userNameOptions.value = allOptions.value;
+		userNameOptions.value = alluserNameOptions.value;
 	}
 };
 
@@ -269,34 +267,6 @@ async function setDialogVisible(isNew: boolean = true, check: boolean = false) {
 	isEdit.value = !isNew;
 }
 
-watch(
-	() => formData.value.unitName,
-	(newVal, oldVal) => {
-		console.log(newVal, oldVal);
-	}
-);
-
-/**
- * 根据 id 查找节点并返回其 children
- * @param tree 树形结构数据
- * @param targetId 目标 id
- * @returns 匹配的节点的 children,未找到返回 undefined
- */
-function getChildrenById(tree: TreeOptions[], targetId: string): TreeOptions[] | undefined {
-	for (const node of tree) {
-		if (node.id === targetId) {
-			return node.children;
-		}
-		if (node.children && node.children.length > 0) {
-			const result = getChildrenById(node.children, targetId);
-			if (result !== undefined) {
-				return result;
-			}
-		}
-	}
-	return undefined;
-}
-
 // 点击确定
 function handleConfirmClick(formEl: FormInstance | undefined) {
 	if (!formEl) return;
@@ -331,6 +301,19 @@ function onPageDetail(urlId: number | [] | string) {
 	systemStore.detailPageDataAction(props.modalConfig.pageName, urlId);
 }
 
+watch(
+	() => formData.value,
+	(newVal, oldVal) => {
+		if (newVal?.unitName !== oldVal?.unitName) {
+			console.log('unitName:', newVal.unitName, oldVal?.unitName);
+		}
+		if (newVal?.contactName !== oldVal?.contactName) {
+			console.log('contactName:', newVal.contactName, oldVal?.contactName);
+		}
+	},
+	{ deep: true }
+);
+
 defineExpose({
 	setDialogVisible,
 	onPageDetail,

+ 89 - 0
src/views/notificationInfoManage/addressBook/components/import.vue

@@ -0,0 +1,89 @@
+<script setup lang="ts">
+import { importInfo } from '@/api/addressBook';
+
+const props = defineProps({
+	isVisible: {
+		type: Boolean,
+		default: false,
+	},
+	title: {
+		type: String,
+		default: '',
+	},
+	user: {
+		type: String,
+		default: '',
+	},
+});
+type Emit = {
+	(e: 'update:isVisible', isVisible: boolean): void;
+	(e: 'refresh-table'): void;
+};
+const emit = defineEmits<Emit>();
+
+const onSubmit = () => {
+	importInfo({
+		file: flieDb,
+		user: props.user,
+	})
+		.then(() => {
+			ElMessage.success('导入成功');
+			emit('refresh-table');
+			onCancel();
+		})
+		.catch(() => {
+			return;
+		});
+};
+const onCancel = () => {
+	fileList.value = [];
+	flieDb = null;
+	emit('update:isVisible', false);
+};
+
+const fileList = ref([]); // 用于存储已选择的文件列表
+let flieDb = reactive<any>(null);
+const handleChange = (file: any) => {
+	console.log(file.name);
+	const isCSV = file.type === 'text/csv' || file.name.endsWith('.csv');
+	if (!isCSV) {
+		ElMessage.error('只能上传 CSV 文件');
+		fileList.value = [];
+		return false;
+	}
+	flieDb = file.raw; // 获取文件对象
+};
+
+const handleExceed = () => {
+	ElMessage.warning(`当前限制选择 1 个文件哦`);
+};
+</script>
+
+<template>
+	<el-dialog :model-value="isVisible" :title="title" width="60%" append-to-body @close="onCancel">
+		<el-upload
+			class="upload-demo"
+			drag
+			:on-change="handleChange"
+			:file-list="fileList"
+			multiple
+			:limit="1"
+			:on-exceed="handleExceed"
+			:auto-upload="false"
+			accept=".csv"
+		>
+			<el-icon class="el-icon--upload"><upload-filled /></el-icon>
+			<div class="el-upload__text">Drop file here or <em>click to upload</em></div>
+			<template #tip>
+				<div class="el-upload__tip">仅限csv格式的文件</div>
+			</template>
+		</el-upload>
+		<!-- 弹窗底部操作按钮 -->
+		<template #footer>
+			<div class="dialog-footer">
+				<el-button type="primary" @click="onSubmit">确 定</el-button>
+				<el-button @click="onCancel">取 消</el-button>
+			</div>
+		</template>
+	</el-dialog>
+</template>

+ 112 - 5
src/views/notificationInfoManage/addressBook/index.vue

@@ -38,8 +38,8 @@
 							</template>
 						</template>
 						<template #button>
-							<el-button type="primary" @click="onImport()">导入</el-button>
-							<el-button type="primary" @click="onImport()">下载模版</el-button>
+							<el-button type="primary" @click="handleImportShow()">导入</el-button>
+							<el-button type="primary" @click="onImportTemplate()">下载模版</el-button>
 							<el-button type="primary" @click="onAdd()">新增</el-button>
 							<el-button type="primary" @click="onExport()">导出</el-button>
 						</template>
@@ -50,7 +50,9 @@
 								<el-button type="danger" link @click="onDelete(scope.row)"> 删除 </el-button>
 							</template>
 							<template v-esle>
-								<el-button type="primary" link @click="onDelete(scope.row)"> 启用 </el-button>
+								<el-button type="primary" link @click="handleStatus(scope.row, '启用', '1')">
+									启用
+								</el-button>
 							</template>
 						</template>
 					</pageContent>
@@ -60,6 +62,11 @@
 	</el-tabs>
 	<pageDetail :modalConfig="activeTab === '1' ? detailConfig : detailNonIndustryConfig" ref="modalRef">
 	</pageDetail>
+	<pageImport
+		v-model:isVisible="importDialog.isvisible"
+		:title="importDialog.title"
+		@refresh-table="handleQuery()"
+	/>
 </template>
 
 <script setup lang="ts">
@@ -72,10 +79,12 @@ import pageSearch from '@/components/components/pageSearch.vue';
 import detailConfig from './config/detail.config';
 import detailNonIndustryConfig from './config/detail.nonIndustry.config';
 import pageDetail from './components/detail.vue';
+import pageImport from './components/import.vue';
 import useSystemStore from '@/store/main';
 import TreeSelect from './components/treeSelect.vue';
 import { type TabsPaneContext } from 'element-plus';
 import { outTypeList } from '@/libs/commonMeth';
+import { changeInventoryStatus } from '@/api/addressBook';
 
 const bj_msg_recipient = outTypeList('bj_msg_recipient'); //短信接收人
 const bj_ab_status: any = outTypeList('bj_ab_status'); //通讯录状态
@@ -86,7 +95,7 @@ const { pageDetailInfo, searchObj } = storeToRefs(systemStore);
 const total = ref(0);
 const pageSize = ref([10, 20, 30]);
 const tableData = ref([]);
-const tableListRef = ref<InstanceType<typeof pageContent>>();
+const tableListRef: any = ref<InstanceType<typeof pageContent>>();
 
 const tabs = reactive([
 	{
@@ -122,6 +131,20 @@ const getTreeCheck = async data => {
 	}
 	searchTableRef.value[0].handleQueryClick();
 };
+
+const handleQuery = async () => {
+	loading.value = true;
+	setTimeout(() => {
+		if (treeSelectdRef.value) {
+			treeSelectdRef.value[0].handleReset(false);
+		}
+		if (searchTableRef.value) {
+			searchTableRef.value[0].handleResetClick();
+		}
+		loading.value = false;
+	}, 500);
+};
+
 const treeSelectdRef = ref<InstanceType<typeof TreeSelect>>();
 const loading = ref(false);
 const handleClick = async (tab: TabsPaneContext) => {
@@ -137,6 +160,15 @@ const handleClick = async (tab: TabsPaneContext) => {
 	}, 500);
 };
 
+const importDialog = reactive({
+	isvisible: false,
+	title: '通报联络员数据导入',
+});
+
+function handleImportShow() {
+	importDialog.isvisible = true;
+}
+
 const handleEdit = async (id: string) => {
 	await handlePageDetail(id);
 	await handleEditDataClick();
@@ -151,7 +183,7 @@ const handleCheck = async (id: string) => {
 const onAdd = () => {
 	handleNewDataClick();
 };
-const onImport = () => {
+const onImportTemplate = () => {
 	const link = document.createElement('a');
 	link.href = `/assets/address-book.xlsx`;
 	link.download = '违法信息通报通讯录人员导入模板.xlsx'; // 指定下载后的文件名
@@ -182,6 +214,81 @@ function onDelete(row: any) {
 		});
 }
 
+// 状态按钮
+function handleStatus(row: any, status: string, str: string) {
+	ElMessageBox.confirm(`是否${str}联络人“${row.contactName}”条条目信息吗?`, '状态提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+	})
+		.then(async () => {
+			const postData: any = await changeInventoryStatus(row.liaisonId, status);
+			if (postData.code === 200) {
+				tableListRef.value[0].fetchPageListData({ industryType: activeTab.value });
+				ElMessage.success('操作成功!');
+			} else {
+				ElMessage.error('操作失败!');
+			}
+		})
+		.catch(() => {
+			ElMessage({
+				type: 'info',
+				message: '取消操作',
+			});
+		});
+}
+
+// 联络员导出
+const handleDownload = async () => {
+	ElMessageBox.confirm(`确定要导出所选数据信息?`, '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		distinguishCancelAndClose: true,
+	})
+		.then(async () => {
+			const isLoading = ElLoading.service({
+				lock: true,
+				text: 'Loading',
+				background: 'rgba(0, 0, 0, 0.7)',
+			});
+			let data: any = {};
+			// 获取表格数据
+			// data = cfgSelection.value;
+			try {
+				// 创建 Blob 对象
+				const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
+				// 获取列名
+				const headers = [
+					{ key: 'uuid', label: '目标设备码' },
+					{ key: 'client_ip', label: '目标设备IP' },
+					{ key: 'type', label: '适用平台' },
+					{ key: 'remark', label: '目标设备名称' },
+				];
+				const headerRow = headers.map(header => header.label).join(',');
+				// 构造 CSV 内容
+				const csvContent = [
+					headerRow,
+					...data.map((row: any) => headers.map(header => row[header.key]).join(',')),
+				].join('\n');
+
+				// 构造文件名
+				const filename = `${timestamp}.csv`; // 指定下载文件的名称;
+				// 创建 Blob 对象
+				const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8' });
+				// 创建下载链接
+				const url = URL.createObjectURL(blob);
+				const a = document.createElement('a');
+				a.href = url;
+				a.download = filename;
+				a.click();
+				URL.revokeObjectURL(url); // 释放 URL 对象
+			} finally {
+				isLoading.close();
+			}
+		})
+		.catch(() => {});
+};
+
 // 筛选-状态赋值 bj_notification_status
 async function searchItem() {
 	searchConfig.formItems.forEach(item => {

+ 7 - 7
src/views/notificationInfoManage/notificationListManage/config/detail.config.ts

@@ -59,13 +59,13 @@ const modalConfig = {
 			span: 8,
 			placeholder: '请选择通报事项类别',
 		},
-		{
-			label: '事项编号',
-			prop: 'mattersListCode',
-			type: 'input',
-			span: 8,
-			placeholder: '请输入事项编号',
-		},
+		// {
+		// 	label: '事项编号',
+		// 	prop: 'mattersListCode',
+		// 	type: 'input',
+		// 	span: 8,
+		// 	placeholder: '请输入事项编号',
+		// },
 		{
 			label: '通报事项',
 			prop: 'notificationMatters',

+ 16 - 3
src/views/notificationInfoManage/notificationListManage/index.vue

@@ -56,7 +56,7 @@
 				</template>
 			</template>
 			<template #operate="scope">
-				<el-button type="primary" link @click="handleEdit(scope.row.notifiedMattersId)"> 查看 </el-button>
+				<el-button type="primary" link @click="handleCheck(scope.row.notifiedMattersId)"> 查看 </el-button>
 				<!-- 待提交 -->
 				<template v-if="scope.row.releaseStatus == '3'">
 					<el-button type="primary" link @click="handleEdit(scope.row.notifiedMattersId)"> 编辑 </el-button>
@@ -88,6 +88,8 @@ import searchConfig from './config/search.config';
 import pageSearch from '@/components/components/pageSearch.vue';
 import detailConfig from './config/detail.config';
 import pageDetail from './components/detail.vue';
+import { changeInventoryStatus } from '@/api/notificationListManage';
+
 import useSystemStore from '@/store/main';
 import { outTypeList, outDeptTree } from '@/libs/commonMeth';
 import { TreeOptions } from '@/types/global';
@@ -124,6 +126,11 @@ const handleEdit = async (id: string) => {
 	await handleEditDataClick();
 };
 
+const handleCheck = async (id: string) => {
+	await handlePageDetail(id);
+	await handleCheckDataClick();
+};
+
 const onMessageChange = (scope, newVal) => {
 	scope.onInput(newVal);
 };
@@ -140,8 +147,14 @@ function handleStatus(value: string, status: string, str: string) {
 		cancelButtonText: '取消',
 		type: 'warning',
 	})
-		.then(() => {
-			// systemStore.deletePageDataAction(contentConfig.pageName, value);
+		.then(async () => {
+			const postData: any = await changeInventoryStatus(value, status);
+			if (postData.code === 200) {
+				tableListRef.value[0].fetchPageListData();
+				ElMessage.success('操作成功!');
+			} else {
+				ElMessage.error('操作失败!');
+			}
 		})
 		.catch(() => {
 			ElMessage({

+ 1 - 1
vite.config.ts

@@ -18,7 +18,7 @@ export default defineConfig(({ mode, command }) => {
 			proxy: {
 				// https://cn.vitejs.dev/config/#server-proxy
 				'/dev-api': {
-					target: 'http://localhost:8080',
+					target: 'http://u68b4f5c.natappfree.cc/',
 					changeOrigin: true,
 					rewrite: p => p.replace(/^\/dev-api/, ''),
 				},