<template>
|
<FYSearchBar ref="searchRef" @search="handleSearch">
|
<template #options>
|
<!-- 区县 -->
|
<FYOptionLocation
|
:allOption="false"
|
:level="3"
|
:checkStrictly="false"
|
v-model:value="formSearch.locations"
|
></FYOptionLocation>
|
<!-- 场景类型 -->
|
<FYOptionScene
|
:allOption="false"
|
:type="2"
|
v-model:value="formSearch.scenetype"
|
></FYOptionScene>
|
<!-- 时间 -->
|
<FYOptionTime
|
:initValue="false"
|
type="month"
|
v-model:value="formSearch.time"
|
></FYOptionTime>
|
</template>
|
<template #buttons>
|
<CompReportDownloadDialog
|
name="问题与整改汇总分析与动态跟踪清单"
|
:locations="formSearch.locations"
|
:scenetype="formSearch.scenetype"
|
:time="formSearch.time"
|
@submit="handleSearch"
|
></CompReportDownloadDialog>
|
</template>
|
</FYSearchBar>
|
<el-form ref="expandRef" :inline="true">
|
<CompQuickSet @quick-set="setOptions"></CompQuickSet>
|
</el-form>
|
<el-space ref="segmentedRef">
|
<el-segmented
|
:model-value="activeSheet"
|
:options="sheetNames"
|
@change="tabChange"
|
/>
|
</el-space>
|
<el-table
|
ref="tableRef"
|
:data="activeExcelData.data"
|
v-loading="loading"
|
table-layout="auto"
|
size="small"
|
:height="tableHeight"
|
fit
|
flexible
|
stripe
|
border
|
>
|
<template v-if="activeExcelData.head">
|
<el-table-column
|
v-for="(item, index) in activeExcelData.head"
|
:key="index"
|
:prop="item.name"
|
:label="item.name"
|
>
|
<template v-if="item.children" #default="{ row }">
|
<span v-html="row[item.name]"></span>
|
<el-table-column
|
v-for="(item1, index1) in item.children"
|
:key="index1"
|
:prop="item1.name"
|
:label="item1.name"
|
>
|
<template v-if="item1.children" #default="{ row1 }">
|
<span v-html="row1[item1.name]"></span>
|
<el-table-column
|
v-for="(item2, index2) in item1.children"
|
:key="index2"
|
:prop="item2.name"
|
:label="item2.name"
|
>
|
<template v-if="item2.children" #default="{ row2 }">
|
<span v-html="row2[item2.name]"></span>
|
</template>
|
</el-table-column>
|
</template>
|
</el-table-column>
|
</template>
|
</el-table-column>
|
</template>
|
</el-table>
|
<!-- <vue-office-excel
|
:src="excel"
|
:style="'height: ' + tableHeight"
|
@rendered="renderedHandler"
|
@error="errorHandler"
|
/> -->
|
</template>
|
<script setup>
|
/**
|
* 问题动态跟踪
|
*/
|
//引入VueOfficeExcel组件
|
import VueOfficeExcel from '@vue-office/excel';
|
//引入相关样式
|
import '@vue-office/excel/lib/index.css';
|
|
import { ref, onMounted } from 'vue';
|
import dayjs from 'dayjs';
|
import * as XLSX from 'xlsx';
|
import * as ExcelJS from 'exceljs';
|
import dataproductApi from '@/api/fysp/dataproductApi';
|
import CompReportDownloadDialog from './CompReportDownloadDialog.vue';
|
|
const emit = defineEmits(['search']);
|
|
const props = defineProps({
|
// 数据产品类型,1:问题动态跟踪;2:规范性评估;3:问题整改分析
|
productType: Number,
|
// 在数据展示之前,做预处理(主要是处理合并表头)
|
beforeDataShow: {
|
type: Function,
|
default: (data) => {
|
return data;
|
}
|
},
|
// 数据表格的表头行数
|
headNum: {
|
type: Number,
|
default: 1
|
}
|
});
|
|
const formSearch = ref({
|
locations: {},
|
scenetype: {},
|
time: dayjs().add(-1, 'M').date(1).toDate()
|
});
|
const loading = ref(false);
|
const tableHeight = ref('500');
|
let workbook;
|
const sheetNames = ref();
|
const excelDatas = ref(new Map());
|
const activeSheet = ref();
|
const activeExcelData = ref({});
|
const excel = ref('');
|
|
const searchRef = ref(null);
|
const expandRef = ref(null);
|
const segmentedRef = ref(null);
|
|
function setOptions(param) {
|
formSearch.value.locations = param.locations;
|
formSearch.value.scenetype = param.scenetype;
|
formSearch.value.sourceType = param.sourceType;
|
handleSearch(false);
|
}
|
|
function tabChange(tabName) {
|
activeSheet.value = tabName;
|
getTable(activeSheet.value);
|
}
|
|
function handleSearch(forceUpdate) {
|
const locations = formSearch.value.locations;
|
const time = formSearch.value.time;
|
const scenetype = formSearch.value.scenetype;
|
const area = {
|
provincecode: locations.pCode,
|
provincename: locations.pName,
|
citycode: locations.cCode,
|
cityname: locations.cName,
|
districtcode: locations.dCode,
|
districtname: locations.dName,
|
starttime: dayjs(time).format('YYYY-MM-DD HH:mm:ss'),
|
scensetypeid: scenetype.value
|
};
|
|
excelDatas.value.clear();
|
loading.value = true;
|
dataproductApi
|
.downloadProduct(area, props.productType, forceUpdate ? forceUpdate : false)
|
.then(async (res) => {
|
// const data = new Uint8Array(res);
|
res.arrayBuffer().then((data) => {
|
workbook = XLSX.read(data, { type: 'array' });
|
sheetNames.value = workbook.SheetNames;
|
activeSheet.value = sheetNames.value[0];
|
getTable(activeSheet.value);
|
});
|
|
// const workbook = new ExcelJS.Workbook();
|
// await workbook.xlsx.load(res);
|
// workbook.eachSheet(function (worksheet, sheetId) {
|
// console.log(worksheet.name);
|
// });
|
// const sheet1 = workbook.worksheets[0]
|
// const row = sheet1.getRow(1)
|
// console.log(row);
|
|
// console.log(res);
|
// console.log(new ArrayBuffer(res));
|
// res.arrayBuffer().then(r=>{
|
// excel.value = r
|
// })
|
|
// excel.value = new ArrayBuffer(res)
|
})
|
.finally(() => (loading.value = false));
|
}
|
|
function getTable(sheetName) {
|
if (!excelDatas.value.has(sheetName)) {
|
const worksheet = workbook.Sheets[sheetName];
|
// const tableData = XLSX.utils.sheet_to_json(worksheet, { header: 3 });
|
let tableData = XLSX.utils.sheet_to_txt(worksheet);
|
// console.log(tableData);
|
|
const regx = new RegExp(/"([^"]|\n)+"/, 'g');
|
let matchTxt = tableData.match(regx);
|
|
if (matchTxt) {
|
matchTxt.forEach((txt) => {
|
let newTxt = txt.replace(new RegExp(/\n/, 'g'), '<br />');
|
newTxt = newTxt.replace(new RegExp(/"/, 'g'), '');
|
tableData = tableData.replace(txt, newTxt);
|
});
|
// console.log(tableData);
|
}
|
|
const t = strToTableObj(tableData);
|
// console.log(head);
|
// console.log(data);
|
excelDatas.value.set(sheetName, t);
|
}
|
activeExcelData.value = excelDatas.value.get(sheetName);
|
|
// activeExcelData.value = props.beforeDataShow(tableData);
|
}
|
|
// 根据表头的行数,合并表头
|
function combineTableHead(excelData) {
|
if (excelData.length < props.headNum) return;
|
|
// const newHead = {};
|
// excelData.splice(0, props.headNum).forEach((row) => {
|
// for (const key in row) {
|
// console.log(key);
|
// }
|
// });
|
}
|
|
function calcTableHeight() {
|
const h1 = searchRef.value.$el.offsetHeight;
|
const h2 = expandRef.value.$el.offsetHeight;
|
const h3 = segmentedRef.value.$el.offsetHeight;
|
|
const h = h1 + h2 + h3;
|
return `calc(100vh - ${h}px - 60px - var(--el-main-padding) * 2)`;
|
}
|
|
function renderedHandler() {
|
console.log('渲染完成');
|
}
|
function errorHandler(e) {
|
console.log('渲染失败', e);
|
}
|
|
function strToTableObj(data, headNum) {
|
const rows = data.split('\n').map((r) => r.split('\t'));
|
if (rows.length == 0) return;
|
|
let header = 1;
|
for (let i = 1; i < rows.length; i++) {
|
const row = rows[i];
|
if (row.length == 0) {
|
break;
|
}
|
if (row[0] == '') {
|
header++;
|
} else {
|
break;
|
}
|
}
|
|
if (rows.length < header) {
|
throw new Error(`文件行数小于${header}`);
|
}
|
// 表头
|
let lastHead = [];
|
// 属性名
|
const dataKeys = [];
|
let offset = 1;
|
for (let i = header - 1; i >= 0; i--) {
|
const row = rows[i];
|
if (lastHead.length == 0) {
|
row.forEach((r, y) => {
|
lastHead.push({ name: r });
|
dataKeys.push(r);
|
});
|
} else {
|
const newHead = [];
|
row.forEach((r, y) => {
|
if (dataKeys[y] == '') {
|
dataKeys[y] = r;
|
}
|
|
const last = lastHead[y];
|
if (!last) {
|
console.log(last);
|
}
|
if (last.name == '') {
|
newHead.push({ name: r });
|
offset++;
|
} else if (r != '') {
|
newHead.push({
|
name: r,
|
children: [last]
|
});
|
offset = 1;
|
} else {
|
newHead.push({ name: '' });
|
let _index = newHead.length - 1 - offset;
|
_index = _index >= 0 ? _index : 0;
|
newHead[_index].children.push(last);
|
offset++;
|
}
|
});
|
lastHead = newHead;
|
}
|
}
|
const heads = [];
|
lastHead.forEach((h) => {
|
if (h && h.name != '') {
|
heads.push(h);
|
}
|
});
|
|
const tableData = [];
|
for (let i = header; i < rows.length; i++) {
|
const row = rows[i];
|
const data = {};
|
row.forEach((r, y) => {
|
data[dataKeys[y]] = r;
|
});
|
tableData.push(data);
|
}
|
|
return { head: heads, data: tableData };
|
}
|
|
onMounted(() => {
|
tableHeight.value = calcTableHeight();
|
// handleSearch()
|
});
|
</script>
|