20260712212917
This commit is contained in:
1 parent
4677f6c519
commit
00472688ab
361 files changed
-153949
No files matched your search
@@ -1,465 +0,0 @@
|
||||
<script setup>
|
||||
import { ElMessage } from "element-plus";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useUserStore } from "@/store/user";
|
||||
import axios from "@/utils/axios";
|
||||
import { compareAndClassifyData } from "@/utils/dataDiffUtils";
|
||||
import { getTableColumns } from "@/utils/dodata";
|
||||
import { downloadZip } from "@/utils/file";
|
||||
|
||||
const props = defineProps({
|
||||
viewName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
footerData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
searchCondition: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
orderField: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 10000,
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const confirmLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const loadingTip = ref("正在加载中 . . .");
|
||||
|
||||
const step = ref(0);
|
||||
|
||||
const tableData = ref([]);
|
||||
const oldTableData = ref([]);
|
||||
|
||||
// 计算总页数
|
||||
const totalFiles = computed(() => {
|
||||
const total = Number(props.total);
|
||||
const limit = Number(props.limit);
|
||||
|
||||
if (Number.isNaN(total) || Number.isNaN(limit) || limit === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.ceil(total / limit);
|
||||
});
|
||||
|
||||
// 计算每个文件的范围
|
||||
const files = computed(() => {
|
||||
const filesArr = [];
|
||||
for (let i = 0; i < totalFiles.value; i++) {
|
||||
const start = i * props.limit + 1;
|
||||
const end = Math.min((i + 1) * props.limit, props.total);
|
||||
filesArr.push({ start, end });
|
||||
}
|
||||
return filesArr;
|
||||
});
|
||||
async function onOpened() {
|
||||
try {
|
||||
// 获取数据
|
||||
const res = await axios.get("/loadData", {
|
||||
params: {
|
||||
viewName: "s_columnexcel",
|
||||
searchCondition: `col_TableName='${props.viewName}' AND userid = '${userStore.userInfo.userid}'`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.data.success) {
|
||||
ElMessage.warning(`加载失败:${res.data.message}`);
|
||||
console.error(`加载失败:${res.data.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.data.data.length === 0) {
|
||||
oldTableData.value = [];
|
||||
|
||||
// 当没有数据时,获取表格列数据
|
||||
const columnRes = await getTableColumns("v_cw_zdorderfee_f_business");
|
||||
if (!columnRes.success) {
|
||||
ElMessage.warning(`加载失败: ${columnRes.error}`);
|
||||
console.error(`加载失败: ${columnRes.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
columnRes.data.forEach((item) => {
|
||||
tableData.value.push({
|
||||
col_TableName: props.viewName,
|
||||
col_FieldName: item.prop,
|
||||
col_Caption: item.label,
|
||||
col_Width: item.width,
|
||||
col_Visible: "1",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = res.data.data || [];
|
||||
}
|
||||
|
||||
// 更新 tableData 中的 ShowSummary
|
||||
tableData.value.forEach((item) => {
|
||||
item.ShowSummary = props.footerData.some((footerItem) =>
|
||||
Object.prototype.hasOwnProperty.call(footerItem, item.col_FieldName),
|
||||
)
|
||||
? "1"
|
||||
: "0";
|
||||
});
|
||||
|
||||
oldTableData.value = JSON.parse(JSON.stringify(tableData.value));
|
||||
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
ElMessage.warning(`加载失败:${error.message}`);
|
||||
console.error(`请求出错:${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfirm() {
|
||||
confirmLoading.value = true;
|
||||
|
||||
const { insertdata, updatedata, deletedata, hasChanges } = compareAndClassifyData(
|
||||
tableData.value,
|
||||
oldTableData.value,
|
||||
"b_id",
|
||||
["ShowSummary"],
|
||||
);
|
||||
|
||||
if (hasChanges) {
|
||||
const userid = userStore.userInfo.userid;
|
||||
|
||||
const modifiedInsertData = insertdata
|
||||
.map((item) => ({
|
||||
...item,
|
||||
userid,
|
||||
}))
|
||||
.map((item) => {
|
||||
delete item.ShowSummary;
|
||||
return item;
|
||||
});
|
||||
|
||||
const modifiedUpdateData = updatedata
|
||||
.map((item) => ({
|
||||
...item,
|
||||
}))
|
||||
.map((item) => {
|
||||
delete item.ShowSummary;
|
||||
return item;
|
||||
});
|
||||
|
||||
const requestData = [
|
||||
{
|
||||
tableName: "s_columnexcel",
|
||||
keyField: "b_id",
|
||||
inserts: modifiedInsertData,
|
||||
updates: modifiedUpdateData,
|
||||
deletes: [],
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
const response = await axios.post("/saveobjectV2", requestData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
confirmLoading.value = false;
|
||||
step.value = 1;
|
||||
|
||||
oldTableData.value = JSON.parse(JSON.stringify(tableData.value));
|
||||
} else {
|
||||
ElMessage.error(`保存导出所有页配置失败:${response.data.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(`保存导出所有页配置失败:${error.message}`);
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
} else {
|
||||
confirmLoading.value = false;
|
||||
step.value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
function onClosed() {
|
||||
loading.value = true;
|
||||
loadingTip.value = "正在加载中 . . .";
|
||||
step.value = 0;
|
||||
tableData.value = [];
|
||||
oldTableData.value = [];
|
||||
}
|
||||
|
||||
async function handleExportExcel(start, end) {
|
||||
try {
|
||||
loading.value = true;
|
||||
loadingTip.value = "正在导出中 . . .";
|
||||
|
||||
const exportColumns = tableData.value.filter((item) => item.col_Visible === "1");
|
||||
|
||||
const response = await axios.post(
|
||||
"/excel/exportAll",
|
||||
{
|
||||
viewName: props.viewName,
|
||||
columns: exportColumns,
|
||||
searchCondition: props.searchCondition,
|
||||
orderField: props.orderField,
|
||||
minIndex: start - 1,
|
||||
maxIndex: end - 1,
|
||||
},
|
||||
{ responseType: "blob" },
|
||||
);
|
||||
|
||||
downloadFromResponse(response, "excel", "");
|
||||
|
||||
ElMessage.success("导出成功!");
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
// 处理请求失败的情况
|
||||
ElMessage.warning(`导出失败:${error.message}`);
|
||||
console.error("导出出错", error);
|
||||
}
|
||||
}
|
||||
|
||||
function downloadFromResponse(res, type, defaultFileName = "") {
|
||||
let blob;
|
||||
let disposition;
|
||||
|
||||
if (res.data && res.headers) {
|
||||
blob = new Blob([res.data], {
|
||||
type: res.headers["content-type"] || "application/octet-stream",
|
||||
});
|
||||
disposition = res.headers["content-disposition"];
|
||||
} else {
|
||||
blob = res instanceof Blob ? res : new Blob([res]);
|
||||
disposition = res.headers ? res.headers.get("Content-Disposition") : null;
|
||||
}
|
||||
|
||||
let fileName = defaultFileName || "";
|
||||
|
||||
// 判断 Content-Disposition 中的文件名
|
||||
if (disposition) {
|
||||
// 匹配 filename* 和 filename 格式
|
||||
const fileNameMatch = disposition.match(/filename\*?=\s*([^;]+)/i); // 兼容 filename 和 filename* 格式
|
||||
if (fileNameMatch && fileNameMatch[1]) {
|
||||
// 如果匹配到的文件名包含编码,解码它
|
||||
fileName = decodeURIComponent(fileNameMatch[1].replace(/^UTF-8''/, ""));
|
||||
}
|
||||
}
|
||||
|
||||
const blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
if (type === "preview") {
|
||||
// 预览:新窗口打开
|
||||
window.open(blobUrl, "_blank");
|
||||
} else {
|
||||
// 下载
|
||||
const link = document.createElement("a");
|
||||
link.href = blobUrl;
|
||||
if (fileName) link.download = fileName;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
}
|
||||
|
||||
// 释放 URL
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
}
|
||||
|
||||
async function handleDownloadZip() {
|
||||
try {
|
||||
loading.value = true;
|
||||
loadingTip.value = "正在下载中 . . .";
|
||||
const filesToDownload = [];
|
||||
|
||||
for (let i = 0; i < files.value.length; i++) {
|
||||
loadingTip.value = `正在下载第 ${i + 1} 个. . .`;
|
||||
const file = files.value[i];
|
||||
const { start, end } = file;
|
||||
|
||||
// 通过 axios 获取文件数据
|
||||
const response = await axios.post(
|
||||
"/excel/exportAll",
|
||||
{
|
||||
viewName: props.viewName,
|
||||
columns: tableData.value.filter((item) => item.col_Visible === "1"),
|
||||
searchCondition: props.searchCondition,
|
||||
orderField: props.orderField,
|
||||
minIndex: start - 1,
|
||||
maxIndex: end - 1,
|
||||
},
|
||||
{ responseType: "blob" },
|
||||
);
|
||||
|
||||
// 生成临时 URL
|
||||
const blobUrl = window.URL.createObjectURL(response.data);
|
||||
|
||||
// 收集文件的名称和临时 URL
|
||||
filesToDownload.push({
|
||||
mx_filename: `${start}-${end}.xlsx`,
|
||||
mx_mapfilename: blobUrl,
|
||||
});
|
||||
}
|
||||
|
||||
// 调用 downloadZip 方法,传递文件列表
|
||||
await downloadZip(filesToDownload, "所有页合计");
|
||||
|
||||
// 释放生成的临时 URL
|
||||
filesToDownload.forEach((file) => {
|
||||
window.URL.revokeObjectURL(file.url);
|
||||
});
|
||||
|
||||
loading.value = false;
|
||||
ElMessage.success("压缩包下载成功!");
|
||||
} catch (error) {
|
||||
ElMessage.warning(`下载失败:${error.message}`);
|
||||
console.error("下载出错", error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog title="导出所有页" width="500" v-bind="$attrs" @closed="onClosed" @opened="onOpened">
|
||||
<div v-loading="loading" class="g3-container" :element-loading-text="loadingTip">
|
||||
<vxe-table
|
||||
v-if="step === 0"
|
||||
border
|
||||
stripe
|
||||
header-align="center"
|
||||
:data="tableData"
|
||||
:sort-config="{
|
||||
// showIcon: false,
|
||||
trigger: 'cell',
|
||||
}"
|
||||
:filter-config="{
|
||||
showIcon: false,
|
||||
}"
|
||||
:column-drag-config="{
|
||||
showIcon: false,
|
||||
trigger: 'cell',
|
||||
}"
|
||||
:row-config="{
|
||||
keyField: 'col_FieldName',
|
||||
useKey: true,
|
||||
isCurrent: true,
|
||||
isHover: true,
|
||||
}"
|
||||
size="small"
|
||||
:cell-config="{
|
||||
height: 26,
|
||||
}"
|
||||
:column-config="{
|
||||
resizable: true,
|
||||
}"
|
||||
show-overflow
|
||||
show-header-overflow
|
||||
height="100%"
|
||||
>
|
||||
<vxe-column field="seq" type="seq" width="50" align="center" title=" " fixed="left" />
|
||||
<vxe-column title="列名" field="col_FieldName" sortable />
|
||||
<vxe-column title="标头" field="col_Caption" sortable />
|
||||
<vxe-column title="宽度" field="col_Width" sortable />
|
||||
<vxe-column title="导出" field="col_Visible" align="center" width="60" sortable>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.col_Visible" true-value="1" false-value="0" />
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="合计" field="" align="center" width="60" sortable>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.ShowSummary" true-value="1" false-value="0" disabled />
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
|
||||
<div v-else class="g3-list-container">
|
||||
<div class="g3-list-header">
|
||||
<div>导出 {{ props.total }} 条数据 ,共 {{ totalFiles }} 个文件</div>
|
||||
<div>
|
||||
<el-button size="small" type="primary" @click="handleDownloadZip"> 打包导出 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="g3-list">
|
||||
<div v-for="(item, index) in files" :key="index" class="g3-list-item">
|
||||
第 {{ index + 1 }} 份文件({{ item.start }}-{{ item.end }})
|
||||
<div class="export-button">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleExportExcel(item.start, item.end)"
|
||||
>
|
||||
导出
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button v-if="step === 1" @click="step = 0"> 返回 </el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="loading || tableData.length === 0 || confirmLoading"
|
||||
@click="handleConfirm"
|
||||
>
|
||||
确认
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.g3-container {
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.g3-list-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.g3-list-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 48px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.g3-list-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.g3-list-header {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.g3-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.g3-list-item {
|
||||
background-color: #fff;
|
||||
padding: 12px 0px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.export-button {
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user