vue3+AntvS2基本使用与导出excel
安装 antv/s2 和 antv/s2-vue
npm i @antv/s2
npm i @antv/s2-vue
react项目自行更换 antv/s2-vue
在vue3里使用
新建一个名为 PageThreeLook.vue 的文件。
由于数据有时很大,所以这边是在后端返回数据后就先计算,然后再渲染的。计算是再 getPageList()方法里进行
<!-- 预算与实际---页面 -->
<template>
<div class="home">
<el-container class="page-main">
<el-header height="auto">
<div
v-show="queryParams.toolQuery.queryParamsShow"
style="transition: all 0.3s; overflow: hidden"
>
搜索条件
</div>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin: 5px 0;
"
>
<div style="display: flex; width: 50%; align-items: center">
<span style="font-weight: 900; font-size: 12px; color: #000">{{
queryParams.PageName
}}</span>---假数据
</div>
<div style="width: 50%; display: flex; overflow-x: auto">
<el-button type="primary" size="small" @click="searchData"
>搜索</el-button
>
<el-button
style="margin-left: 10px"
type="success"
size="small"
@click="click_look"
>当前页导出excel</el-button
>
</div>
</div>
</el-header>
<el-main
:style="{
height: queryParams.toolQuery.queryParamsShow
? 'calc(100% - 200px)'
: 'calc(100% - 180px)',
}"
>
<div v-if="!SAut.show">
需要需要加定时器,没有数据就不显示,有数据了在显示
</div>
<div v-else style="width: 100%; height: 100%">
<SheetComponent
ref="tableRef"
:dataCfg="SAut.s2DataConfig"
:options="SAut.s2Options"
:adaptive="{
width: true,
height: true,
}"
loading
/>
</div>
</el-main>
</el-container>
<el-drawer
v-model="Look.show"
title="自定义列表"
direction="rtl"
size="90%"
:show-close="false"
destroy-on-close
:with-header="false"
>
<div style="width: 100%; height: 100vh; overflow: auto">
<ThreePageXiangQingLook
:ArrayList="Look.list"
@submitOK="onSubmitOK_Look"
/>
</div>
</el-drawer>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { useRouter, useRoute, onBeforeRouteLeave } from "vue-router";
import { SelectAnnualSummary } from "../../api/index";
import { ElNotification, ElDatePicker } from "element-plus";
import ThreePageXiangQingLook from "./ThreeXiangQingLook.vue";
import { Aggregation, PivotSheet, QueryDataType, VALUE_FIELD } from "@antv/s2";
import { SheetComponent } from "@antv/s2-vue";
import "@antv/s2-vue/dist/style.min.css";
const router = useRouter();
const route = useRoute();
const tableRef = ref(null);
const SAut = ref({
show: false,
s2DataConfig: null,
s2Options: null,
});
const antv_Demo = (list) => {
setTimeout(() => {
SAut.value.show = true;
const s2DataConfig = {
fields: {
rows: ["deptname", "zjzmoney", "type"],
columns: [],
values: [
"januaryMoney",
"februaryMoney",
"marchMoney",
"aprilMoney",
"mayMoney",
"juneMoney",
"julyMoney",
"augustMoney",
"septemberMoney",
"octoberMoney",
"novemberMoney",
"decemberMoney",
"noMoney",
"HeJi",
],
},
meta: [
{
field: "deptname",
name: "部门",
},
{
field: "zjzmoney",
name: "年度目标",
},
{
field: "type",
name: "类别",
},
{
field: "januaryMoney",
name: "1月",
},
{
field: "februaryMoney",
name: "2月",
},
{
field: "januaryMoney",
name: "1月",
},
{
field: "marchMoney",
name: "3月",
},
{
field: "aprilMoney",
name: "4月",
},
{
field: "mayMoney",
name: "5月",
},
{
field: "juneMoney",
name: "6月",
},
{
field: "julyMoney",
name: "7月",
},
{
field: "augustMoney",
name: "8月",
},
{
field: "septemberMoney",
name: "9月",
},
{
field: "octoberMoney",
name: "10月",
},
{
field: "novemberMoney",
name: "11月",
},
{
field: "decemberMoney",
name: "12月",
},
{
field: "noMoney",
name: "未完成年度目标额度",
},
{
field: "HeJi",
name: "全年合计",
},
],
data: list,
};
const s2Options = {
width: 600,
height: 480,
conditions: {
text: [
{
field: "januaryMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.januaryMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "februaryMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.februaryMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "marchMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.marchMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "aprilMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.aprilMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "mayMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.mayMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "juneMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.juneMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "julyMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.julyMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "augustMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.augustMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "septemberMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.septemberMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "octoberMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.octoberMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "novemberMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.novemberMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "decemberMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.decemberMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "noMoney",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.noMoney < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
{
field: "HeJi",
mapping(fieldValue, data) {
// 根据单元格数据动态标记
if (data.HeJi < 0) {
return {
fill: "#fd0101",
};
}
return {
fill: "#000",
};
},
},
],
},
};
SAut.value.s2DataConfig = s2DataConfig;
SAut.value.s2Options = s2Options;
}, 1000);
};
// 导出
const Look = ref({
show: false,
type: null,
item: null,
list: [],
});
const onSubmitOK_Look = (val) => {
//console.log("关闭当前页面", val);
Look.value.item = null;
Look.value.type = null;
Look.value.show = false;
};
const click_look = () => {
Look.value.list = queryParams.value.tableConfig.tableData.all;
setTimeout(() => {
Look.value.show = true;
}, 300);
};
const Look_Action = ref("look");
let queryParams = ref({
PageName: "预算年汇总",
action: false,
Cookie_USER: null,
loadingTxt: "",
loading: {
table: false,
},
tableConfig: {
tableData: {
all: [],
},
tableColumn: [
{
field: "deptname",
show: true,
label: "部门",
width: "150",
fixed: "left",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "zjzmoney",
show: true,
label: "年度目标",
width: "150",
fixed: "left",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "type",
show: true,
label: "类型",
fixed: "left",
width: "100",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "januaryMoney",
show: true,
label: "1月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "februaryMoney",
show: true,
label: "2月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "marchMoney",
show: true,
label: "3月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "aprilMoney",
show: true,
label: "4月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "mayMoney",
show: true,
label: "5月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "juneMoney",
show: true,
label: "6月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "julyMoney",
show: true,
label: "7月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "augustMoney",
show: true,
label: "8月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "septemberMoney",
show: true,
label: "9月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "octoberMoney",
show: true,
label: "10月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "novemberMoney",
show: true,
label: "11月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "decemberMoney",
show: true,
label: "12月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "noMoney",
show: true,
label: "未完成年度目标额度",
width: "130",
fixed: "right",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "HeJi",
show: true,
label: "全年合计",
width: "130",
fixed: "right",
sortable: false,
overflowShow: false,
disabled: true,
},
],
},
toolQuery: {
queryParams: {
sqksjs: null, //申请时间
area: null, //部门
actions: null,
customername: null, //用工单位
},
queryParamsShow: true,
},
direction: 1,
});
function calculateTotals(data) {
const totals = {};
// 遍历原始数据
data.forEach((item) => {
const { deptname, type } = item;
// 只处理非'合计'的项目
if (deptname !== "合计") {
// 初始化合计对象
if (!totals[type]) {
totals[type] = {
deptname: "合计",
type: type,
};
}
// 动态累加金额字段
Object.keys(item).forEach((key) => {
// 跳过 deptname 和 type 字段
if (key !== "deptname" && key !== "type") {
totals[type][key] = (
Number(totals[type][key] || 0) + Number(item[key])
).toFixed(2);
} else if (key == "su") {
totals[type][key] = item[key];
}
});
}
});
// 将合计对象转换为数组
const totalArray = Object.values(totals);
// 返回原始数据和合计数据的合并结果
return [...data, ...totalArray];
}
function val_Null_Undefined(val) {
if (val === null || val === undefined || val === "") {
return "空值";
} else {
return "正常值";
}
}
const FN_NoMoney = (row) => {
let zjzmoney = val_Null_Undefined(row.zjzmoney);
let HeJi = val_Null_Undefined(row.HeJi);
if (row.type == "差额" || row.type == "预算完成率") {
return "/";
}
if (zjzmoney === "空值") {
zjzmoney = 0;
} else {
zjzmoney = Number(row.zjzmoney) || 0;
}
if (HeJi === "空值") {
HeJi = 0;
} else {
HeJi = Number(row.HeJi) || 0;
}
let a = zjzmoney - HeJi;
// row.noMoney = Number(a.toFixed(2));
return Number(a.toFixed(2));
};
// 列表初始化
const getPageList = () => {
SAut.value.show = false;
let obj = {
dateTime: "2024-08",
page: 1,
limit: 100,
};
queryParams.value.loading.table = true;
queryParams.value.loadingTxt = "加载中。。。";
queryParams.value.tableConfig.tableData.all = [];
window.setTimeout(() => {
let TableList = [
{
type: "预算利润",
deptname: "第一个板块",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "第一个板块",
zjzmoney: 0.0,
januaryMoney: -10.83,
februaryMoney: -104.83,
marchMoney: -10.83,
aprilMoney: -100.83,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "预算利润",
deptname: "第二个板块",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "第二个板块",
zjzmoney: 0.0,
januaryMoney: -7099.17,
februaryMoney: -79.17,
marchMoney: -79.17,
aprilMoney: -9.17,
mayMoney: -99.17,
juneMoney: -199.17,
julyMoney: -299.73,
augustMoney: 6832.13,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "预算利润",
deptname: "第三个板块",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 831791.17,
octoberMoney: 843707.26,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "第三个板块",
zjzmoney: 0.0,
januaryMoney: 527144.27,
februaryMoney: 1834.09,
marchMoney: 17483.19,
aprilMoney: 20503.38,
mayMoney: 45261.39,
juneMoney: 7233.9,
julyMoney: 626.19,
augustMoney: 428.76,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "预算利润",
deptname: "第四个板块",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "第四个板块",
zjzmoney: 0.0,
januaryMoney: -437.04,
februaryMoney: 55.32,
marchMoney: -1101.3,
aprilMoney: 388.38,
mayMoney: 2642.51,
juneMoney: 607.41,
julyMoney: -69.02,
augustMoney: 4665.14,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "预算利润",
deptname: "第五个板块",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "第五个板块",
zjzmoney: 0.0,
januaryMoney: 2.78,
februaryMoney: 20.53,
marchMoney: 8.66,
aprilMoney: 20.67,
mayMoney: 435.14,
juneMoney: 41.44,
julyMoney: 15.71,
augustMoney: 25.1,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "预算利润",
deptname: "第六个板块",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "第六个板块",
zjzmoney: 0.0,
januaryMoney: -34.27,
februaryMoney: 3.46,
marchMoney: -2924.74,
aprilMoney: -193.37,
mayMoney: 914.59,
juneMoney: 803.58,
julyMoney: -815.51,
augustMoney: 84.1,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "预算利润",
deptname: "第七个板块",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "第七个板块",
zjzmoney: 0.0,
januaryMoney: -81.09,
februaryMoney: -12.07,
marchMoney: -2.45,
aprilMoney: -99.94,
mayMoney: 488.92,
juneMoney: 209.04,
julyMoney: 37.8,
augustMoney: 342.53,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "预算利润",
deptname: "总公司",
zjzmoney: 0.0,
januaryMoney: 0.0,
februaryMoney: 0.0,
marchMoney: 0.0,
aprilMoney: 0.0,
mayMoney: 0.0,
juneMoney: 0.0,
julyMoney: 0.0,
augustMoney: 0.0,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
{
type: "实际利润",
deptname: "总公司",
zjzmoney: 0.0,
januaryMoney: 639.83,
februaryMoney: 813.44,
marchMoney: 780.8,
aprilMoney: 97.56,
mayMoney: 2.12,
juneMoney: 1.58,
julyMoney: 81.77,
augustMoney: 89.62,
septemberMoney: 0.0,
octoberMoney: 0.0,
novemberMoney: 0.0,
decemberMoney: 0.0,
},
];
let liaaa = calculateTotals(TableList);
liaaa.forEach((item) => {
let a = [
item.januaryMoney,
item.februaryMoney,
item.marchMoney,
item.aprilMoney,
item.mayMoney,
item.juneMoney,
item.julyMoney,
item.augustMoney,
item.septemberMoney,
item.octoberMoney,
item.novemberMoney,
item.decemberMoney,
];
item.HeJi = Fn_HeJi(a);
item.noMoney = FN_NoMoney(item);
});
let oneListTwo = AREA_Fn(liaaa);
oneListTwo.forEach((item) => {
item.noMoney = FN_NoMoney(item);
});
queryParams.value.tableConfig.tableData.all = oneListTwo;
console.log("测试测试", oneListTwo);
antv_Demo(oneListTwo);
}, 300);
};
// 计算每一行 1月到12月的总和
const Fn_HeJi = (item) => {
let total = 0;
for (let i = 0; i < item.length; i++) {
total += Number(item[i]);
}
return total.toFixed(2);
};
// 根据 部门 把相同组的放到一起,并且在下边追加 余额对象
const AREA_Fn = (list) => {
let aa = transformData(list, [
"januaryMoney",
"februaryMoney",
"marchMoney",
"aprilMoney",
"mayMoney",
"juneMoney",
"julyMoney",
"augustMoney",
"septemberMoney",
"octoberMoney",
"novemberMoney",
"decemberMoney",
"HeJi",
]);
let bb = AREA_Fn2(aa);
return bb;
};
const transformData = (data, fieldsToSum) => {
const groupedData = {};
// 遍历输入数组,按 deptname 分组
data.forEach((item) => {
const { deptname, ...rest } = item; // 解构出 deptname 和剩余字段
if (!groupedData[deptname]) {
groupedData[deptname] = []; // 初始化部门数组
}
groupedData[deptname].push(rest); // 将剩余字段加入对应的部门数组
});
// 遍历每个部门,并在每个部门内添加 '差额' 对象
const result = Object.entries(groupedData).map(([dept, items]) => {
// 创建 '差额' 对象
const differenceItem = { deptname: dept, type: "差额" };
// 遍历第一个对象的键值,排除 deptname 和 type
for (const key in items[0]) {
if (key !== "deptname" && key !== "type" && key !== "zjzmoney") {
// 排除 deptname 和 type 字段
differenceItem[key] = 0; // 将值设为 0
differenceItem.zjzmoney = items[0].zjzmoney;
}
}
let ccc = [
...items.map((item) => ({ deptname: dept, ...item })),
differenceItem,
];
let dddd = calculateDifference(ccc, fieldsToSum);
// 返回当前部门的对象数组,包括原始数据和新加的差额对象
return dddd;
});
// 展平结果数组
return result.flat();
};
function calculateDifference(list, keyList) {
// 定义变量来保存实际利润和预算利润
let selfRecruitCost = {}; // 存储实际利润
let supplierCost = {}; // 存储预算利润
// 遍历 list,分别提取实际利润和预算利润
list.forEach((item) => {
if (item.type === "实际利润") {
keyList.forEach((key) => {
selfRecruitCost[key] = item[key]; // 复制实际利润字段
});
} else if (item.type === "预算利润") {
keyList.forEach((key) => {
supplierCost[key] = item[key]; // 复制预算利润字段
});
}
});
// 找到差额项
let differenceItem = list.find((item) => item.type === "差额");
// 计算差额
if (differenceItem) {
keyList.forEach((key) => {
let aa = (selfRecruitCost[key] || 0) - (supplierCost[key] || 0);
differenceItem[key] = aa.toFixed(2);
});
}
return list; // 返回更新后的 list
}
// 根据 部门 把相同组的放到一起,并且在下边追加 预算完成率对象
const AREA_Fn2 = (list) => {
let aa = transformData2(list, [
"januaryMoney",
"februaryMoney",
"marchMoney",
"aprilMoney",
"mayMoney",
"juneMoney",
"julyMoney",
"augustMoney",
"septemberMoney",
"octoberMoney",
"novemberMoney",
"decemberMoney",
"HeJi",
]);
return aa;
};
const transformData2 = (data, fieldsToSum) => {
const groupedData = {};
// 遍历输入数组,按 deptname 分组
data.forEach((item) => {
const { deptname, ...rest } = item; // 解构出 deptname 和剩余字段
if (!groupedData[deptname]) {
groupedData[deptname] = []; // 初始化部门数组
}
groupedData[deptname].push(rest); // 将剩余字段加入对应的部门数组
});
// 遍历每个部门,并在每个部门内添加 '预算完成率' 对象
const result = Object.entries(groupedData).map(([dept, items]) => {
// 创建 '预算完成率' 对象
const differenceItem = { deptname: dept, type: "预算完成率" };
// 遍历第一个对象的键值,排除 deptname 和 type
for (const key in items[0]) {
if (key !== "deptname" && key !== "type" && key !== "zjzmoney") {
// 排除 deptname 和 type 字段
differenceItem[key] = 0; // 将值设为 0
differenceItem.zjzmoney = items[0].zjzmoney;
}
}
let ccc = [
...items.map((item) => ({ deptname: dept, ...item })),
differenceItem,
];
let dddd = calculateDifference2(ccc, fieldsToSum);
// 返回当前部门的对象数组,包括原始数据和新加的预算完成率对象
return dddd;
});
// console.log(result);
// 展平结果数组
return result.flat();
};
function calculateDifference2(list, keyList) {
// 定义变量来保存实际利润和预算利润
let selfRecruitCost = {}; // 存储实际利润
let supplierCost = {}; // 存储预算利润
// 遍历 list,分别提取实际利润和预算利润
list.forEach((item) => {
if (item.type === "实际利润") {
keyList.forEach((key) => {
selfRecruitCost[key] = item[key]; // 复制实际利润字段
});
} else if (item.type === "预算利润") {
keyList.forEach((key) => {
supplierCost[key] = item[key]; // 复制预算利润字段
});
}
});
// 找到预算完成率项
let differenceItem = list.find((item) => item.type === "预算完成率");
// 计算预算完成率
if (differenceItem) {
keyList.forEach((key) => {
let a = selfRecruitCost[key] || 0;
let b = supplierCost[key] || 0;
if (a === 0 || b == 0) {
differenceItem[key] = "0%";
} else {
let cc = (a / b) * 100;
differenceItem[key] = `${cc.toFixed(0)}%`;
}
});
}
return list; // 返回更新后的 list
}
// 搜索
const searchData = () => {
getPageList();
};
onMounted(() => {
Look_Action.value = route.query.Type_Action_Look_Value;
getPageList();
});
</script>
<style>
.jsxAAA_Did {
text-align: center;
display: flex;
flex-direction: column;
}
.jsxBBB_Did {
/* width: 100%; */
background-color: #89f0d1;
box-sizing: border-box;
padding: 5px 10px;
margin-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
}
.my-header-cellTwo {
font-weight: bold !important;
background: #f2f6fc !important;
color: #303133;
}
.el-table__body tr:hover > td {
background-color: #a7a8eb !important;
}
</style>
<style lang="less" scoped>
/deep/.el-scrollbar {
.el-scrollbar__bar.is-horizontal {
height: 14px;
}
.el-scrollbar__bar.is-vertical {
width: 14px;
}
.el-scrollbar__bar.is-horizontal .el-scrollbar__thumb {
opacity: 1;
background-color: #7ef8ee;
box-shadow: 0 0 6px #00000026;
}
.el-scrollbar__bar.is-vertical .el-scrollbar__thumb {
opacity: 1;
background-color: #7ef8ee;
box-shadow: 0 0 6px #00000026;
}
}
/deep/.el-drawer__body {
padding: 0 !important;
}
.home {
.page-main {
height: 100vh;
background-color: #ffffff;
}
.page-main .el-main {
padding: 5px 10px 10px 10px;
}
.page-main .el-header {
height: auto !important;
padding: 5px 10px 0 10px;
}
.page-main .el-footer {
padding: 10px;
text-align: right;
}
.el-header .el-row {
padding-top: 5px;
}
.el-header .query-params_hide {
height: 0;
}
/*搜索条件每行对应 height 45px*/
.el-header .query-params_show {
min-height: 90px;
}
.el-header .el-dropdown__caret-button {
height: 32px;
}
.form-edit .el-dialog__header {
padding: 5px;
}
.form-edit .el-form-item__content,
.form-edit .el-date-editor.el-input,
.form-edit .el-select {
width: 200px;
}
.form-edit .el-form-item label {
font-weight: 500;
}
.form-edit .el-tabs__content {
height: calc(100% - 40px);
overflow: auto;
}
.form-edit .el-table__fixed-body-wrapper {
top: 37px !important;
}
.form-edit .el-dialog__footer {
padding-bottom: 10px;
}
.item-select .el-dialog__header {
padding: 1px 20px;
background-color: rgba(0, 0, 0, 0.1);
}
.item-select .el-dialog__body {
padding: 0;
}
.cell .el-checkbox {
margin: 0;
}
span[class="el-tooltip el-icon-setting"],
span[class="el-tooltip el-icon-setting focusing"] {
font-size: 25px;
position: absolute;
top: 0;
bottom: 0;
right: 10px;
margin: auto;
cursor: pointer;
color: #409eff;
}
.el-table__fixed,
.el-table__fixed-right {
height: auto !important;
bottom: 11px;
}
#orderTemp {
height: 100%;
width: 100%;
}
/*行颜色*/
.el-table .cutoff-row {
background: #ffd9b3;
}
.el-table .enabled-row {
background: #f6dbdb;
}
.el-date-editor.el-input,
.el-date-editor.el-input__inner {
width: 100% !important;
}
a {
color: #337ab7;
text-decoration: none;
}
a:focus,
a:hover {
color: #23527c;
text-decoration: underline;
}
.el-tabs__header {
margin: 0 0 5px !important;
}
/deep/ .el-dialog__header {
padding: 0;
}
.el-form-item--small {
margin-bottom: 5px;
}
.my-header {
display: flex;
flex-direction: row;
justify-content: space-between;
}
/deep/ .el-dialog__body {
padding: 10px 10px;
}
/deep/ .el-upload-list {
height: 200px;
overflow-y: auto;
}
/deep/ .el-dialog__body {
height: 90% !important;
}
/deep/.el-table .cell {
padding: 0 2px;
}
/deep/.el-drawer__header {
margin-bottom: 0;
// padding-top: 0;
}
/* 左右摆动 */
.shake-box {
cursor: pointer;
animation: shake 1.5s linear infinite;
}
@keyframes shake {
10% {
transform: rotate(15deg);
}
20% {
transform: rotate(-10deg);
}
30% {
transform: rotate(5deg);
}
40% {
transform: rotate(-5deg);
}
50%,
100% {
transform: rotate(0deg);
}
}
.problem {
width: 100%;
height: 100%;
// background-color: #e48e8e;
overflow-y: auto;
}
}
</style>
新建一个名为 ThreeXiangQingLook.vue 的文件当做打印页面。
暂时不知道怎么把 图表数据导出excel,所以采取了一个笨方法:图表数组数据都有了,直接把这个放到一个table表格里,然后在通过 XLSX导出为excel文件。
<!-- 预算与实际---页面 -->
<template>
<div class="home">
<el-container class="page-main">
<el-header height="auto">
<el-button
style="margin-left: 10px"
type="success"
size="small"
@click="click_look"
>当前页导出excel</el-button
>
</el-header>
<el-main
:style="{
height: queryParams.toolQuery.queryParamsShow
? 'calc(100% - 200px)'
: 'calc(100% - 180px)',
}"
>
<el-table
:data="queryParams.tableConfig.tableData.all"
:element-loading-text="queryParams.loadingTxt"
v-loading="queryParams.loading.table"
highlight-current-row
size="small"
height="100%"
ref="tableData"
id="ThreeXiangQingTabLe"
border
:header-cell-class-name="my_header_cellTwo"
:row-class-name="tableRowClassName"
:span-method="objectSpanMethod"
>
<template
v-for="(
column, index
) in queryParams.tableConfig.tableColumn.filter(
(item) => item.show
)"
>
<el-table-column
align="center"
:label="column.label"
:width="column.width"
:prop="column.field"
:fixed="column.fixed"
:sortable="column.sortable ? true : false"
>
</el-table-column>
</template>
</el-table>
</el-main>
</el-container>
</div>
</template>
<script setup>
import {
ref,
onMounted,
nextTick,
} from "vue";
import {
rowMergeHandle,
} from "../../../utile/tool";
import * as XLSX from "xlsx";
const tableData = ref(null);
let queryParams = ref({
loading: {
table: false,
},
tableConfig: {
tableData: {
all: [],
},
tableColumn: [
{
field: "deptname",
show: true,
label: "部门",
width: "150",
fixed: "left",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "zjzmoney",
show: true,
label: "年度目标",
width: "150",
fixed: "left",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "type",
show: true,
label: "类型",
fixed: "left",
width: "100",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "januaryMoney",
show: true,
label: "1月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "februaryMoney",
show: true,
label: "2月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "marchMoney",
show: true,
label: "3月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "aprilMoney",
show: true,
label: "4月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "mayMoney",
show: true,
label: "5月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "juneMoney",
show: true,
label: "6月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "julyMoney",
show: true,
label: "7月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "augustMoney",
show: true,
label: "8月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "septemberMoney",
show: true,
label: "9月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "octoberMoney",
show: true,
label: "10月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "novemberMoney",
show: true,
label: "11月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "decemberMoney",
show: true,
label: "12月",
width: "200",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "noMoney",
show: true,
label: "未完成年度目标额度",
width: "130",
fixed: "right",
sortable: false,
overflowShow: false,
disabled: true,
},
{
field: "HeJi",
show: true,
label: "全年合计",
width: "130",
fixed: "right",
sortable: false,
overflowShow: false,
disabled: true,
},
],
tableColumnLook: [],
},
pageConfig: {
//每页行数F_IsCutOff
limit: 100,
// 当前页
page: 1,
//总记录数
count: 0,
},
needMergeArr: ["deptname", "zjzmoney"],
rowMergeArrs: [],
toolQuery: {
queryParams: {
sqksjs: null, //申请时间
area: null, //部门
actions: null,
customername: null, //用工单位
bug: "全部",
type: "全部",
},
queryParamsShow: true,
},
direction: 1,
});
// 表头变色
const my_header_cellTwo = ({ column, rowIndex, columnIndex }) => {
if (column.label == "年度目标") {
return "BudgetStyle11";
} else if (
column.label == "1月" ||
column.label == "2月" ||
column.label == "3月" ||
column.label == "4月" ||
column.label == "5月" ||
column.label == "6月" ||
column.label == "7月" ||
column.label == "8月" ||
column.label == "9月" ||
column.label == "10月" ||
column.label == "11月" ||
column.label == "12月"
) {
return "BudgetStyle55";
} else {
return "BudgetStyle55";
}
};
// 指定列变色
const columnbackgroundStyle = ({ row, column, rowIndex, columnIndex }) => {
if (column.label == "年度目标") {
return { "background-color": "#92d050", color: "#000" };
}
};
const tableRowClassName = ({ row, rowIndex }) => {
return "";
};
function convertStringNumbersToNumbers(arr) {
arr.forEach((obj) => {
// 遍历对象的每个属性
for (let key in obj) {
// 确保属性是对象自身的属性
if (obj.hasOwnProperty(key)) {
// 检查属性值是否为数字字符串
if (!isNaN(obj[key]) && typeof obj[key] === "string") {
obj[key] = Number(obj[key]); // 转换为数字
}
}
}
});
return arr;
}
const props = defineProps({
ArrayList: {
type: Array,
default: [],
},
});
// 列表初始化
const getPageList = () => {
queryParams.value.loading.table = true;
queryParams.value.loadingTxt = "加载计算中。。。";
queryParams.value.tableConfig.tableData.all = [];
window.setTimeout(() => {
console.log("传来的数据", props.ArrayList);
queryParams.value.loading.table = false;
queryParams.value.loadingTxt = "";
queryParams.value.tableConfig.tableData.all = props.ArrayList;
queryParams.value.rowMergeArrs = rowMergeHandle(
queryParams.value.needMergeArr,
props.ArrayList
);
nextTick(() => {
if (tableData.value && tableData.value.doLayout) {
tableData.value.doLayout();
}
});
}, 1000);
};
// 单元格合并
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
for (let res in queryParams.value.needMergeArr) {
if (queryParams.value.needMergeArr[res] == column.property) {
return mergeAction(column.property, rowIndex, columnIndex);
}
}
};
const mergeAction = (val, rowIndex) => {
let _row = queryParams.value.rowMergeArrs[val].rowArr[rowIndex];
let _col = _row > 0 ? 1 : 0;
return [_row, _col];
};
const click_look = () => {
console.log("需要导出");
exportToExcel("#ThreeXiangQingTabLe", queryParams.value.PageName);
};
function exportToExcel(idSelector, fileName, titleNum = 1) {
const table = document.querySelector(idSelector).cloneNode(true);
const fixedRightNode = table.querySelector(".el-table__fixed-right");
if (fixedRightNode) {
table.removeChild(fixedRightNode);
}
const fixedNode = table.querySelector(".el-table__fixed");
if (fixedNode) {
table.removeChild(fixedNode);
}
const headerDom = table.querySelector(".el-table__header-wrapper");
const bodyDom = table.querySelector(".el-table__body-wrapper");
// 找到操作列并删除它
const actionColumnCells = Array.from(
headerDom.querySelectorAll(".cell")
).filter((cell) => cell.innerText === "查看");
actionColumnCells.forEach((cell) => {
const index = parseInt(cell.cellIndex, 10);
if (!isNaN(index)) {
cell.parentElement.removeChild(cell);
Array.from(
bodyDom.querySelectorAll(`.cell:nth-child(${index + 1})`)
).forEach((cell) => cell.parentElement.removeChild(cell));
}
});
const container = document.createElement("div");
container.appendChild(headerDom);
container.appendChild(bodyDom);
const ws = XLSX.utils.table_to_sheet(container, {
raw: true,
display: true,
});
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
const wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
type: "array",
});
try {
const fileData = new Blob([wbout], {
type: "application/octet-stream",
});
const a = document.createElement("a");
a.href = URL.createObjectURL(fileData);
a.download = `${fileName}.xlsx`;
a.click();
} catch (e) {}
}
const jcsg = () => {
getPageList();
};
onMounted(() => {
jcsg();
});
</script>
<style>
.jsxAAA_Did {
text-align: center;
display: flex;
flex-direction: column;
}
.jsxBBB_Did {
/* width: 100%; */
background-color: #89f0d1;
box-sizing: border-box;
padding: 5px 10px;
margin-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
}
.my-header-cellTwo {
font-weight: bold !important;
background: #f2f6fc !important;
color: #303133;
}
.el-table__body tr:hover > td {
background-color: #a7a8eb !important;
}
</style>
<style lang="less" scoped>
/deep/.el-scrollbar {
.el-scrollbar__bar.is-horizontal {
height: 14px;
}
.el-scrollbar__bar.is-vertical {
width: 14px;
}
.el-scrollbar__bar.is-horizontal .el-scrollbar__thumb {
opacity: 1;
background-color: #7ef8ee;
box-shadow: 0 0 6px #00000026;
}
.el-scrollbar__bar.is-vertical .el-scrollbar__thumb {
opacity: 1;
background-color: #7ef8ee;
box-shadow: 0 0 6px #00000026;
}
}
/deep/.el-drawer__body {
padding: 0 !important;
}
.home {
.page-main {
height: 100vh;
background-color: #ffffff;
}
.page-main .el-main {
padding: 5px 10px 10px 10px;
}
.page-main .el-header {
height: auto !important;
padding: 5px 10px 0 10px;
}
.page-main .el-footer {
padding: 10px;
text-align: right;
}
.el-header .el-row {
padding-top: 5px;
}
.el-header .query-params_hide {
height: 0;
}
/*搜索条件每行对应 height 45px*/
.el-header .query-params_show {
min-height: 90px;
}
.el-header .el-dropdown__caret-button {
height: 32px;
}
.form-edit .el-dialog__header {
padding: 5px;
}
.form-edit .el-form-item__content,
.form-edit .el-date-editor.el-input,
.form-edit .el-select {
width: 200px;
}
.form-edit .el-form-item label {
font-weight: 500;
}
.form-edit .el-tabs__content {
height: calc(100% - 40px);
overflow: auto;
}
.form-edit .el-table__fixed-body-wrapper {
top: 37px !important;
}
.form-edit .el-dialog__footer {
padding-bottom: 10px;
}
.item-select .el-dialog__header {
padding: 1px 20px;
background-color: rgba(0, 0, 0, 0.1);
}
.item-select .el-dialog__body {
padding: 0;
}
.cell .el-checkbox {
margin: 0;
}
span[class="el-tooltip el-icon-setting"],
span[class="el-tooltip el-icon-setting focusing"] {
font-size: 25px;
position: absolute;
top: 0;
bottom: 0;
right: 10px;
margin: auto;
cursor: pointer;
color: #409eff;
}
.el-table__fixed,
.el-table__fixed-right {
height: auto !important;
bottom: 11px;
}
#orderTemp {
height: 100%;
width: 100%;
}
/*行颜色*/
.el-table .cutoff-row {
background: #ffd9b3;
}
.el-table .enabled-row {
background: #f6dbdb;
}
.el-date-editor.el-input,
.el-date-editor.el-input__inner {
width: 100% !important;
}
a {
color: #337ab7;
text-decoration: none;
}
a:focus,
a:hover {
color: #23527c;
text-decoration: underline;
}
.el-tabs__header {
margin: 0 0 5px !important;
}
/deep/ .el-dialog__header {
padding: 0;
}
.el-form-item--small {
margin-bottom: 5px;
}
.my-header {
display: flex;
flex-direction: row;
justify-content: space-between;
}
/deep/ .el-dialog__body {
padding: 10px 10px;
}
/deep/ .el-upload-list {
height: 200px;
overflow-y: auto;
}
/deep/ .el-dialog__body {
height: 90% !important;
}
/deep/.el-table .cell {
padding: 0 2px;
}
/deep/.el-drawer__header {
margin-bottom: 0;
// padding-top: 0;
}
/* 左右摆动 */
.shake-box {
cursor: pointer;
animation: shake 1.5s linear infinite;
}
@keyframes shake {
10% {
transform: rotate(15deg);
}
20% {
transform: rotate(-10deg);
}
30% {
transform: rotate(5deg);
}
40% {
transform: rotate(-5deg);
}
50%,
100% {
transform: rotate(0deg);
}
}
.problem {
width: 100%;
height: 100%;
// background-color: #e48e8e;
overflow-y: auto;
}
}
</style>