feat: 添加编码查询日志导出

This commit is contained in:
皓月归尘 2025-02-18 02:03:59 +08:00
parent 2a93ad5b87
commit 9cf28df363
8 changed files with 399 additions and 32 deletions

View File

@ -39,6 +39,8 @@ buttons:Linked: Linked
buttons:More: More buttons:More: More
buttons:Deselect: Deselect buttons:Deselect: Deselect
buttons:DeleteInBatches: Delete In Batches buttons:DeleteInBatches: Delete In Batches
buttons:ExportInBatches: Export In Batches
buttons:ExportAll: Export All
buttons:UploadAvatar: Upload Avatar buttons:UploadAvatar: Upload Avatar
buttons:ResetPassword: Reset Password buttons:ResetPassword: Reset Password
buttons:RoleAllocation: Role Allocation buttons:RoleAllocation: Role Allocation

View File

@ -39,6 +39,8 @@ buttons:Linked: 联动
buttons:More: 更多 buttons:More: 更多
buttons:Deselect: 取消选择 buttons:Deselect: 取消选择
buttons:DeleteInBatches: 批量删除 buttons:DeleteInBatches: 批量删除
buttons:ExportInBatches: 批量导出
buttons:ExportAll: 全部导出
buttons:UploadAvatar: 上传头像 buttons:UploadAvatar: 上传头像
buttons:ResetPassword: 重置密码 buttons:ResetPassword: 重置密码
buttons:RoleAllocation: 角色分配 buttons:RoleAllocation: 角色分配

View File

@ -128,3 +128,17 @@ export const getCodeLogListAPI = (params: {
export const getCodeLogInfoAPI = (id: string) => { export const getCodeLogInfoAPI = (id: string) => {
return http.request<QueryCodeLogInfo>("get", `/api/code/logInfo/${id}`); return http.request<QueryCodeLogInfo>("get", `/api/code/logInfo/${id}`);
}; };
/**获取所有查询编码列表 */
export const getCodeLogListAllAPI = (params: {
startTime?: string;
endTime?: string;
}) => {
return http.request<QueryListResult<QueryCodeLogInfo>>(
"get",
`/api/code/logList/all`,
{
params: filterEmptyObject(params)
}
);
};

View File

@ -32,7 +32,7 @@
</el-button> </el-button>
<el-button <el-button
type="primary" type="primary"
:icon="useRenderIcon(AddFill)" :icon="useRenderIcon(UploadIcon)"
@click="showUploadArea = !showUploadArea" @click="showUploadArea = !showUploadArea"
> >
{{ showUploadArea ? t("buttons:Hide") : t("buttons:Import") }} {{ showUploadArea ? t("buttons:Hide") : t("buttons:Import") }}
@ -45,6 +45,7 @@
ref="uploadRef" ref="uploadRef"
v-model:file-list="fileList" v-model:file-list="fileList"
drag drag
:limit="1"
action="#" action="#"
class="w-full" class="w-full"
:auto-upload="false" :auto-upload="false"
@ -98,8 +99,12 @@
</el-card> </el-card>
<PureTableBar title="查询结果" :columns="columns" @refresh="onSearch"> <PureTableBar title="查询结果" :columns="columns" @refresh="onSearch">
<template #buttons> <template #buttons>
<el-button type="primary" :icon="useRenderIcon(AddFill)"> <el-button
{{ t("buttons:Export") }} type="primary"
:icon="useRenderIcon(Export)"
@click="exportToExcel([queryResult], '查询结果')"
>
{{ t("buttons:ExportAll") }}
</el-button> </el-button>
</template> </template>
<template v-slot="{ size, dynamicColumns }"> <template v-slot="{ size, dynamicColumns }">
@ -119,10 +124,10 @@
{{ t("buttons:Deselect") }} {{ t("buttons:Deselect") }}
</el-button> </el-button>
</div> </div>
<el-popconfirm title="是否确认删除?"> <el-popconfirm title="是否确认导出?" @confirm="onbatchExport">
<template #reference> <template #reference>
<el-button type="danger" text class="mr-1"> <el-button type="primary" text class="mr-1">
{{ t("buttons:DeleteInBatches") }} {{ t("buttons:ExportInBatches") }}
</el-button> </el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
@ -210,11 +215,10 @@ import { useIndex } from "./utils/hook";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { PureTableBar } from "@/components/RePureTableBar"; import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Delete from "@iconify-icons/ep/delete";
import EditPen from "@iconify-icons/ep/edit-pen"; import EditPen from "@iconify-icons/ep/edit-pen";
import Refresh from "@iconify-icons/ep/refresh"; import Refresh from "@iconify-icons/ep/refresh";
import AddFill from "@iconify-icons/ri/add-circle-line";
import UploadIcon from "@iconify-icons/ri/upload-2-line"; import UploadIcon from "@iconify-icons/ri/upload-2-line";
import Export from "@iconify-icons/ri/download-2-line";
const { t } = useI18n(); const { t } = useI18n();
/** /**
* 表格Ref * 表格Ref
@ -244,7 +248,9 @@ const {
handleSelectionChange, handleSelectionChange,
onSelectionCancel, onSelectionCancel,
onDownloadTemplate, onDownloadTemplate,
handleDetail handleDetail,
exportToExcel,
onbatchExport
} = useIndex(tableRef); } = useIndex(tableRef);
</script> </script>

View File

@ -1,5 +1,6 @@
import { message } from "@/utils/message"; import { message } from "@/utils/message";
import { type Ref, ref, reactive } from "vue"; import { type Ref, ref, reactive } from "vue";
import * as XLSX from "xlsx";
import type { PaginationProps } from "@pureadmin/table"; import type { PaginationProps } from "@pureadmin/table";
import type { QueryCodeResult, QueryResult, QueryResultItem } from "types/code"; import type { QueryCodeResult, QueryResult, QueryResultItem } from "types/code";
import { import {
@ -13,6 +14,7 @@ import {
postCodeInfoAPI postCodeInfoAPI
} from "@/api/code"; } from "@/api/code";
import { deleteFileAPI, postUploadFileAPI } from "@/api/file"; import { deleteFileAPI, postUploadFileAPI } from "@/api/file";
import { getKeyList, cloneDeep } from "@pureadmin/utils";
export const useIndex = (tableRef: Ref) => { export const useIndex = (tableRef: Ref) => {
/** /**
@ -253,6 +255,102 @@ export const useIndex = (tableRef: Ref) => {
drawerStatus.value = true; drawerStatus.value = true;
Object.assign(rowInfo, row); Object.assign(rowInfo, row);
}; };
/**导出为excel */
const exportToExcel = (dataList: QueryCodeResult[], filename: string) => {
if (dataList.length) {
const headers = [
"序号",
"查询批次ID",
"查询文本(总)",
"查询统计",
"结果统计",
"查询状态",
"耗时(毫秒)",
"操作时间",
"待查询文本ID",
"待查询文本",
"查询结果状态"
];
for (let i = 1; i <= 5; i++) {
headers.push(
`匹配结果ID${i}`,
`匹配编码${i}`,
`匹配结果${i}`,
`匹配率(百分比)${i}`
);
}
const data = [];
let index = 1;
for (const jsonData of dataList) {
const batchId = jsonData.id;
const queryText = jsonData.query;
const queryCount = jsonData.query_count;
const resultCount = jsonData.result_count;
const status = jsonData.status === 1 ? "成功" : "失败";
const costTime = jsonData.cost_time;
const operationTime = jsonData.operation_time;
jsonData.response_result.forEach(response => {
const queryId = response.id;
const queryTextDetail = response.query_text;
const queryStatus = response.status === 1 ? "成功" : "失败";
const row = [
index++,
batchId,
queryText,
queryCount,
resultCount,
status,
costTime,
operationTime,
queryId,
queryTextDetail,
queryStatus
];
for (let i = 0; i < 5; i++) {
if (i < response.result_text.length) {
const match = response.result_text[i];
row.push(
match.id,
match.code,
match.description,
match.match_rate
);
} else {
row.push("", "", "", "");
}
}
data.push(row);
});
}
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...data]);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Query Results");
XLSX.writeFile(workbook, `${filename}.xlsx`);
message("导出成功!", { type: "success" });
}
};
/**批量导出 */
const onbatchExport = async () => {
// 获取当前选中的行
const curSelected = tableRef.value.getTableRef().getSelectionRows();
let dataJson = cloneDeep(queryResult.value); // 深拷贝,避免修改原数据
const ids = getKeyList(curSelected, "id");
let dataList = dataJson.response_result; // 拷贝的数据
let selecteList = dataList.filter((item: QueryResult) =>
ids.includes(item.id)
); // 筛选出选中的数据
// 仅赋值导出的数据,不修改原始数据
let exportData = { ...dataJson, response_result: selecteList };
exportToExcel([exportData], "查询结果");
};
return { return {
form, form,
dataList, dataList,
@ -276,6 +374,8 @@ export const useIndex = (tableRef: Ref) => {
handleSelectionChange, handleSelectionChange,
onSelectionCancel, onSelectionCancel,
onDownloadTemplate, onDownloadTemplate,
handleDetail handleDetail,
exportToExcel,
onbatchExport
}; };
}; };

View File

@ -18,8 +18,12 @@
</el-card> </el-card>
<PureTableBar title="查询结果" :columns="columns"> <PureTableBar title="查询结果" :columns="columns">
<template #buttons> <template #buttons>
<el-button type="primary" :icon="useRenderIcon(AddFill)"> <el-button
{{ t("buttons:Export") }} type="primary"
:icon="useRenderIcon(Export)"
@click="exportToExcel([queryInfo], '查询结果')"
>
{{ t("buttons:ExportAll") }}
</el-button> </el-button>
</template> </template>
<template v-slot="{ size, dynamicColumns }"> <template v-slot="{ size, dynamicColumns }">
@ -39,10 +43,10 @@
{{ t("buttons:Deselect") }} {{ t("buttons:Deselect") }}
</el-button> </el-button>
</div> </div>
<el-popconfirm title="是否确认删除?"> <el-popconfirm title="是否确认导出?" @confirm="onbatchExport">
<template #reference> <template #reference>
<el-button type="danger" text class="mr-1"> <el-button type="primary" text class="mr-1">
{{ t("buttons:DeleteInBatches") }} {{ t("buttons:ExportInBatches") }}
</el-button> </el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
@ -127,14 +131,12 @@ import { ref, reactive, onMounted, h } from "vue";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { isEmpty, isString } from "@pureadmin/utils"; import * as XLSX from "xlsx";
import { cloneDeep, getKeyList, isEmpty, isString } from "@pureadmin/utils";
import { PureTableBar } from "@/components/RePureTableBar"; import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
// import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import EditPen from "@iconify-icons/ep/edit-pen"; import EditPen from "@iconify-icons/ep/edit-pen";
import Refresh from "@iconify-icons/ep/refresh"; import Export from "@iconify-icons/ri/download-2-line";
import AddFill from "@iconify-icons/ri/add-circle-line";
// import { $t } from "@/plugins/i18n";
import type { import type {
QueryCodeLogInfo, QueryCodeLogInfo,
QueryResult, QueryResult,
@ -142,6 +144,7 @@ import type {
} from "types/code"; } from "types/code";
import { getCodeLogInfoAPI } from "@/api/code"; import { getCodeLogInfoAPI } from "@/api/code";
import { PaginationProps } from "@pureadmin/table"; import { PaginationProps } from "@pureadmin/table";
import { message } from "@/utils/message";
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -252,6 +255,115 @@ const onSelectionCancel = async () => {
// //
tableRef.value.getTableRef().clearSelection(); tableRef.value.getTableRef().clearSelection();
}; };
/**导出为excel */
const exportToExcel = (dataList: QueryCodeLogInfo[], filename: string) => {
if (dataList.length) {
const headers = [
"序号",
"查询批次ID",
"查询人ID",
"查询人账号",
"查询人昵称",
"查询人部门ID",
"查询人部门",
"查询文本(总)",
"查询统计",
"结果统计",
"查询状态",
"耗时(毫秒)",
"操作时间",
"待查询文本ID",
"待查询文本",
"查询结果状态"
];
for (let i = 1; i <= 5; i++) {
headers.push(
`匹配结果ID${i}`,
`匹配编码${i}`,
`匹配结果${i}`,
`匹配率(百分比)${i}`
);
}
const data = [];
let index = 1;
for (const jsonData of dataList) {
const batchId = jsonData.id;
const opeartion_id = jsonData.operator_id;
const opeartion_name = jsonData.operator_name;
const opeartion_nickname = jsonData.operator_nickname;
const department_id = jsonData.department_id;
const department_name = jsonData.department_name;
const queryText = jsonData.request_params;
const queryCount = jsonData.query_count;
const resultCount = jsonData.result_count;
const status = jsonData.status === 1 ? "成功" : "失败";
const costTime = jsonData.cost_time;
const operationTime = jsonData.operation_time;
jsonData.response_result = JSON.parse(
jsonData.response_result.replace(/'/g, '"').replace(/None/g, "null")
);
// @ts-ignore
jsonData.response_result.forEach(response => {
const queryId = response.id;
const queryTextDetail = response.query_text;
const queryStatus = response.status === 1 ? "成功" : "失败";
const row = [
index++,
batchId,
opeartion_id,
opeartion_name,
opeartion_nickname,
department_id,
department_name,
queryText,
queryCount,
resultCount,
status,
costTime,
operationTime,
queryId,
queryTextDetail,
queryStatus
];
for (let i = 0; i < 5; i++) {
if (i < response.result_text.length) {
const match = response.result_text[i];
row.push(match.id, match.code, match.description, match.match_rate);
} else {
row.push("", "", "", "");
}
}
data.push(row);
});
}
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...data]);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Query Results");
XLSX.writeFile(workbook, `${filename}.xlsx`);
message("导出成功!", { type: "success" });
}
};
/**批量导出 */
const onbatchExport = async () => {
//
const curSelected = tableRef.value.getTableRef().getSelectionRows();
let dataJson = cloneDeep(queryInfo.value); //
const ids = getKeyList(curSelected, "id");
let dataList = dataJson.response_result; //
let selecteList = dataList.filter((item: QueryResult) =>
ids.includes(item.id)
); //
//
let exportData = { ...dataJson, response_result: selecteList };
exportToExcel([exportData], "查询结果");
};
onMounted(async () => { onMounted(async () => {
await getQueryInfo(); await getQueryInfo();
}); });

View File

@ -35,13 +35,16 @@
<PureTableBar title="操作日志" :columns="columns" @refresh="onSearch"> <PureTableBar title="操作日志" :columns="columns" @refresh="onSearch">
<template #buttons> <template #buttons>
<!-- <el-popconfirm title="确定要删除所有日志数据吗?" @confirm="clearAll"> <el-popconfirm
title="确定要导出所有日志数据吗?"
@confirm="onExportQueryAll"
>
<template #reference> <template #reference>
<el-button type="danger" :icon="useRenderIcon(Delete)"> <el-button type="primary" :icon="useRenderIcon(Export)">
清空日志 {{ t("buttons:ExportAll") }}
</el-button> </el-button>
</template> </template>
</el-popconfirm> --> </el-popconfirm>
</template> </template>
<template v-slot="{ size, dynamicColumns }"> <template v-slot="{ size, dynamicColumns }">
<div <div
@ -60,10 +63,13 @@
{{ t("buttons:Deselect") }} {{ t("buttons:Deselect") }}
</el-button> </el-button>
</div> </div>
<el-popconfirm title="是否确认删除?"> <el-popconfirm
title="是否确认批量导出日志数据?"
@confirm="onbatchExport"
>
<template #reference> <template #reference>
<el-button type="danger" text class="mr-1"> <el-button type="primary" text class="mr-1">
{{ t("buttons:DeleteInBatches") }} {{ t("buttons:ExportInBatches") }}
</el-button> </el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
@ -110,11 +116,10 @@
defineOptions({ defineOptions({
name: "CodeQueryLog" name: "CodeQueryLog"
}); });
// import dayjs from "dayjs";
import { ref } from "vue"; import { ref } from "vue";
import View from "@iconify-icons/ep/view"; import View from "@iconify-icons/ep/view";
// import Delete from "@iconify-icons/ep/delete";
import Refresh from "@iconify-icons/ep/refresh"; import Refresh from "@iconify-icons/ep/refresh";
import Export from "@iconify-icons/ri/download-2-line";
import { PureTableBar } from "@/components/RePureTableBar"; import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { isString } from "@pureadmin/utils"; import { isString } from "@pureadmin/utils";
@ -141,7 +146,9 @@ const {
handleSelectionChange, handleSelectionChange,
handleSizeChange, handleSizeChange,
onSelectionCancel, onSelectionCancel,
getPickerShortcuts getPickerShortcuts,
onExportQueryAll,
onbatchExport
} = useQueryLog(tableRef); } = useQueryLog(tableRef);
/**处理详情 */ /**处理详情 */
const onClickDetails = (row: QueryCodeLogInfo) => { const onClickDetails = (row: QueryCodeLogInfo) => {

View File

@ -8,7 +8,10 @@ import { usePublicHooks } from "@/views/system/hooks";
import type { PaginationProps } from "@pureadmin/table"; import type { PaginationProps } from "@pureadmin/table";
import { type Ref, reactive, ref, onMounted } from "vue"; import { type Ref, reactive, ref, onMounted } from "vue";
import type { QueryCodeLogInfo } from "types/code"; import type { QueryCodeLogInfo } from "types/code";
import { getCodeLogListAPI } from "@/api/code"; import * as XLSX from "xlsx";
import { getCodeLogListAllAPI, getCodeLogListAPI } from "@/api/code";
import { message } from "@/utils/message";
import { cloneDeep, getKeyList } from "@pureadmin/utils";
export const useQueryLog = (tableRef: Ref) => { export const useQueryLog = (tableRef: Ref) => {
/**查询表单 */ /**查询表单 */
@ -294,7 +297,126 @@ export const useQueryLog = (tableRef: Ref) => {
} }
]; ];
}; };
/**导出为excel */
const exportToExcel = (dataList: QueryCodeLogInfo[], filename: string) => {
if (dataList.length) {
const headers = [
"序号",
"查询批次ID",
"查询人ID",
"查询人账号",
"查询人昵称",
"查询人部门ID",
"查询人部门",
"查询文本(总)",
"查询统计",
"结果统计",
"查询状态",
"耗时(毫秒)",
"操作时间",
"待查询文本ID",
"待查询文本",
"查询结果状态"
];
for (let i = 1; i <= 5; i++) {
headers.push(
`匹配结果ID${i}`,
`匹配编码${i}`,
`匹配结果${i}`,
`匹配率(百分比)${i}`
);
}
const data = [];
let index = 1;
for (const jsonData of dataList) {
const batchId = jsonData.id;
const opeartion_id = jsonData.operator_id;
const opeartion_name = jsonData.operator_name;
const opeartion_nickname = jsonData.operator_nickname;
const department_id = jsonData.department_id;
const department_name = jsonData.department_name;
const queryText = jsonData.request_params;
const queryCount = jsonData.query_count;
const resultCount = jsonData.result_count;
const status = jsonData.status === 1 ? "成功" : "失败";
const costTime = jsonData.cost_time;
const operationTime = jsonData.operation_time;
jsonData.response_result = JSON.parse(
jsonData.response_result.replace(/'/g, '"').replace(/None/g, "null")
);
// @ts-ignore
jsonData.response_result.forEach(response => {
const queryId = response.id;
const queryTextDetail = response.query_text;
const queryStatus = response.status === 1 ? "成功" : "失败";
const row = [
index++,
batchId,
opeartion_id,
opeartion_name,
opeartion_nickname,
department_id,
department_name,
queryText,
queryCount,
resultCount,
status,
costTime,
operationTime,
queryId,
queryTextDetail,
queryStatus
];
for (let i = 0; i < 5; i++) {
if (i < response.result_text.length) {
const match = response.result_text[i];
row.push(
match.id,
match.code,
match.description,
match.match_rate
);
} else {
row.push("", "", "", "");
}
}
data.push(row);
});
}
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...data]);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Query Results");
XLSX.writeFile(workbook, `${filename}.xlsx`);
message("导出成功!", { type: "success" });
}
};
/**导出所有查询结果 */
const onExportQueryAll = async () => {
const res = await getCodeLogListAllAPI({
startTime: form.timeRange[0] ? form.timeRange[0] : null,
endTime: form.timeRange[1] ? form.timeRange[1] : null
});
if (res.success) {
exportToExcel(res.data.result, "全部查询结果");
}
};
/**批量导出 */
const onbatchExport = async () => {
// 获取当前选中的行
const curSelected = tableRef.value.getTableRef().getSelectionRows();
const ids = getKeyList(curSelected, "id");
let data = cloneDeep(dataList.value); // 拷贝的数据
let selecteList = data.filter((item: QueryCodeLogInfo) =>
ids.includes(item.id)
); // 筛选出选中的数据
exportToExcel(selecteList, "查询结果");
};
onMounted(async () => { onMounted(async () => {
await onSearch(); await onSearch();
}); });
@ -311,6 +433,8 @@ export const useQueryLog = (tableRef: Ref) => {
handleCurrentChange, handleCurrentChange,
handleSizeChange, handleSizeChange,
handleSelectionChange, handleSelectionChange,
onSelectionCancel onSelectionCancel,
onExportQueryAll,
onbatchExport
}; };
}; };