This commit is contained in:
zhaohy
2024-08-29 15:41:56 +08:00
23 changed files with 922 additions and 478 deletions

View File

@@ -1,10 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="8.98974609375" height="8.14453125" viewBox="0 0 8.98974609375 8.14453125" fill="none">
<path d="M7.93101 4.53462L6.23624 4.53462L5.52032 3.46466L6.49265 1.79796L5.44381 0L3.32621 0L2.27236 1.79796L3.29704 3.54617L2.62652 4.54987L1.05875 4.54987L0 6.34726L1.05875 8.1452L3.17144 8.1452L4.06128 6.62695L4.93729 6.62695L5.81886 8.13029L7.93102 8.13029L8.98978 6.33258L7.93101 4.53462ZM3.19734 4.59392L3.8643 3.59569L5.00553 3.59569L5.73168 4.68208L4.88461 6.1274L4.09644 6.1274L3.19734 4.59392Z" fill="url(#linear_fill_60_2513)" >
</path>
<defs>
<linearGradient id="linear_fill_60_2513" x1="4.494873046875" y1="0" x2="4.494873046875" y2="8.14453125" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#4DACE6" />
<stop offset="1" stop-color="#2A93D5" />
</linearGradient>
</defs>
<svg xmlns="http://www.w3.org/2000/svg" width="12.34" height="10.758" viewBox="0 0 12.34 10.758">
<g id="组_6" data-name="组 6" transform="translate(-614 -150.796)">
<g id="组_2" data-name="组 2" transform="translate(614 150.796)">
<path id="路径_4" data-name="路径 4" d="M67.653,196.269H56.4a.537.537,0,0,1-.541-.533v-8.743a.537.537,0,0,1,.541-.533H67.653a.537.537,0,0,1,.541.533v8.743A.537.537,0,0,1,67.653,196.269Z" transform="translate(-55.854 -185.512)" fill="#ffa000"/>
<path id="路径_5" data-name="路径 5" d="M61.866,119.866H55.854v-2.911a.55.55,0,0,1,.527-.569H60.5a.535.535,0,0,1,.507.406l.863,3.074Z" transform="translate(-55.854 -116.387)" fill="#ffa000"/>
<path id="路径_6" data-name="路径 6" d="M158.881,264.762h-9.094a.521.521,0,0,1-.516-.526v-7.173a.521.521,0,0,1,.516-.526h9.094a.521.521,0,0,1,.516.526v7.173A.517.517,0,0,1,158.881,264.762Z" transform="translate(-148.006 -254.637)" fill="#fff"/>
<path id="路径_7" data-name="路径 7" d="M67.653,334.52H56.4a.535.535,0,0,1-.541-.528v-6.855a.535.535,0,0,1,.541-.528H67.653a.535.535,0,0,1,.541.528v6.855A.535.535,0,0,1,67.653,334.52Z" transform="translate(-55.854 -323.762)" fill="#ffca28"/>
<path id="路径_8" data-name="路径 8" d="M129.146,444H126.2a.291.291,0,0,1,0-.58h2.941a.291.291,0,0,1,.007.581Zm0,1.951H126.2a.281.281,0,0,1-.27-.29.277.277,0,0,1,.27-.291h2.941a.281.281,0,0,1,.27.291.276.276,0,0,1-.263.29Z" transform="translate(-124.979 -438.985)" fill="#fff8e1"/>
</g>
<g id="组_3" data-name="组 3" transform="translate(622.818 153.637)">
<path id="路径_12" data-name="路径 12" d="M667.159,350.215V355.2l1.215-1.327,1.3,1.42v-5.076" transform="translate(-667.159 -350.215)" fill="#2778ff"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 888 B

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,10 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9.1005859375" height="9.099609375" viewBox="0 0 9.1005859375 9.099609375" fill="none">
<path d="M7.01762 4.69157L2.30136 4.69157C2.04227 4.66303 1.84615 4.44409 1.84615 4.18343C1.84615 3.92276 2.04227 3.70384 2.30136 3.67525L7.01762 3.67525C7.27673 3.70384 7.47285 3.92276 7.47285 4.18343C7.47285 4.44409 7.27673 4.66303 7.01762 4.69157ZM7.01762 6.69587L2.30136 6.69587C2.04227 6.6673 1.84615 6.44837 1.84615 6.18771C1.84615 5.92704 2.04227 5.70809 2.30136 5.67952L7.01762 5.67952C7.27673 5.70809 7.47285 5.92704 7.47285 6.18771C7.47285 6.44837 7.27673 6.6673 7.01762 6.69587ZM9.09498 8.33346L9.09498 1.98149C9.09498 1.21918 8.46167 1.27564 8.46167 1.27564L4.88941 1.27564C4.77006 1.27634 4.65399 1.23653 4.56021 1.16271C4.56021 1.16271 4.40816 0.880585 4.12926 0.428757C3.87605 -0.0795288 3.54708 0.00531769 3.54708 0.00531769L0.785301 0.00531769C0 0.00531769 0 0.824379 0 0.824379L0 8.27722C0 9.2087 0.633301 9.09628 0.633301 9.09628L8.53744 9.09628C9.19643 9.09547 9.09498 8.33345 9.09498 8.33345L9.09498 8.33346Z" fill="url(#linear_fill_60_2485)" >
</path>
<defs>
<linearGradient id="linear_fill_60_2485" x1="4.55029296875" y1="0" x2="4.55029296875" y2="9.099609375" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#4DACE6" />
<stop offset="1" stop-color="#2A93D5" />
</linearGradient>
</defs>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="13" viewBox="0 0 8 13">
<path id="路径_14" data-name="路径 14" d="M320.7,183.7h-6a1,1,0,0,0-1,1v11.875a.124.124,0,0,0,.2.1l3.65-2.875a.252.252,0,0,1,.3,0l3.65,2.875a.124.124,0,0,0,.2-.1V184.7A1,1,0,0,0,320.7,183.7Zm-.656,3.334a.486.486,0,0,1-.486.486h-4a.486.486,0,1,1,0-.973h4A.486.486,0,0,1,320.044,187.034Zm0-2.039a.486.486,0,0,1-.486.486h-4a.486.486,0,1,1,0-.973h4A.488.488,0,0,1,320.044,184.995Z" transform="translate(-313.7 -183.7)" fill="#2778ff"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1,228 @@
/* eslint-disable */
/** 导出Excel需要依赖
* npm install xlsx file-saver -S
* npm install script-loader -S -D
*/
import ExcelJS from 'exceljs';
import FileSaver from 'file-saver';
// export default exportExcel;
// 导出excel文件
/**
*
* @param {*} tableColumns 表头
* @param {*} data 数据
* @param {*} fillName 文件名
* @param {*} isMerge 是否合并单元格
* @param {*} firstKey 第一个字段的key用来判断序号列是否合并
* @param {*} start 合并单元格开始列
* @param {*} end 合并单元格结束列
* @returns
*/
export function exportExcel (tableColumns,data,fillName,isMerge = false, firstKey = '',start = 0, end = 0) {
debugger
if (!data || data.length == 0) {
return;
}
if (isMerge) {
// 需要合并序号
for (let i = 0; i < data.length; i++) {
// 自定义单元格内容,这里返回序号
if (i == 0) {
data[i].index = 1;
// return 1;
} else if (data[i - 1][firstKey] == data[i][firstKey]) {
data[i].index = data[i - 1].index;
// return data.value[index].index;
} else {
data[i].index = data[i - 1].index + 1;
}
}
} else {
// 不需要合并序号
for (let i = 0; i < data.length; i++) {
data[i].index = i + 1;
}
}
// 创建工作簿
const workbook = new ExcelJS.Workbook();
// 添加工作表名为sheet1
const sheet1 = workbook.addWorksheet('sheet1');
// 导出的表头名
let tHeader = ['序号'];
// 字段名
let filterVal = ['index'];
// 表格columns
let columns = [{ header: '序号', key: 'index', width: 10 }];
for (let i = 0; i < tableColumns.length; i++) {
if (tableColumns[i].dataIndex) {
tHeader.push(tableColumns[i].title);
filterVal.push(tableColumns[i].dataIndex);
columns.push({
header: tableColumns[i].title,
key: tableColumns[i].dataIndex,
width: tableColumns[i].width ? tableColumns[i].width / 5 : 20,
});
}
}
//传入的数据
const list = data;
//格式化数据
const datas = formatJson(filterVal, list);
// 获取表头所有键
// const headers = Object.keys(data[0]);
// 获取表头
sheet1.columns = columns;
// 将数据写入工作表
datas.forEach((row) => {
// const values = Object.values(row);
sheet1.addRow(row);
});
// 判断是否合并单元格
if (isMerge) {
// 遍历列,从 start 列到 end 列
for (let col = start; col <= end; col++) {
for (let row = 3; row <= datas.length + 1; row++) {
const currentCellValue = sheet1.getCell(row, col).value;
const previousCellValue = sheet1.getCell(row - 1, col).value;
// 从第二列开始就要看前一列是否已经合并
let isMerged = true
if (col > 1) {
isMerged = ifMerged(sheet1,row - 1, col-1,row, col-1)
}
if (currentCellValue === previousCellValue && isMerged) {
// 检查是上边需要合并的单元格是否已经合并
const mergeInfo = getMergeInfo(sheet1, row - 1, col)
if ( mergeInfo.isMerged ) {
sheet1.unMergeCells( mergeInfo.startRow, col, row - 1, col);
sheet1.mergeCells(mergeInfo.startRow, col, row, col);
} else {
sheet1.mergeCells(row, col, row - 1, col);
}
}
}
}
}
// 修改所有单元格样式
// 遍历每一行
sheet1.eachRow((row, rowNumber) => {
// 遍历每个单元格
row.eachCell((cell) => {
// 设置边框样式
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' },
};
// 设置居中对齐
cell.alignment = {
vertical: 'middle',
horizontal: 'center',
};
});
});
// 获取标题行数据
const titleCell = sheet1.getRow(1);
// 设置行高为30
titleCell.height = 30;
// 设置标题行单元格样式
titleCell.eachCell((cell) => {
// 设置标题行背景颜色为黄色
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFFF' },
};
// 设置标题行字体
cell.font = {
// color: { argb: 'FF0000' }, //颜色为红色
bold: true, // 字体粗体
size: 18, // 设置字体大小为18
};
});
// 获取第二行到最后一行的内容数据
const bodyRows = sheet1.getRows(2, sheet1.rowCount);
// 处理内容行的数据
bodyRows.forEach((bodyRow) => {
// 设置行高为20
bodyRow.height = 20;
bodyRow.eachCell((cell) => {
cell.font = {
size: 16, // 设置内容行字体大小为16
};
});
});
// 导出表格文件
workbook.xlsx
.writeBuffer()
.then((buffer) => {
let file = new Blob([buffer], { type: 'application/octet-stream' });
FileSaver.saveAs(file, fillName + '.xlsx');
})
.catch((error) => console.log('Error writing excel export', error));
};
/**
* 格式化表格数据
* @filterVal 格式头
* @jsonData 用来格式化的表格数据
*/
function formatJson (filterVal, jsonData) {
return jsonData.map((v) => filterVal.map((j) => v[j]));
};
/**
* 获取给定行和列的单元格是否为合并单元格,并返回合并起始行
* @param {Worksheet} worksheet - ExcelJS 工作表对象
* @param {number} row - 单元格的行号 (从 1 开始)
* @param {number} col - 单元格的列号 (从 1 开始)
* @returns {Object} - 返回一个对象,包含 isMerged 和 startRow 属性
*/
function getMergeInfo(worksheet, row, col) {
// 遍历所有的合并范围
for (const mergeRange in worksheet._merges) {
if (worksheet._merges.hasOwnProperty(mergeRange)) {
const { top, left, bottom, right } = worksheet._merges[mergeRange];
// 检查行列是否在当前合并范围内
if (row >= top && row <= bottom && col >= left && col <= right) {
return { isMerged: true, startRow: top }; // 找到合并范围,返回合并信息
}
}
}
return { isMerged: false, startRow: null }; // 单元格不在任何合并范围内
}
// 函数:检查两个单元格是否属于同一个合并区域
function ifMerged(worksheet, row1, col1, row2, col2) {
const merges = worksheet._merges; // 获取所有的合并区域
for (let mergeAddress in merges) {
const mergeRange = merges[mergeAddress];
const { top, left, bottom, right } = mergeRange;
const isCell1InRange = (row1 >= top && row1 <= bottom && col1 >= left && col1 <= right);
const isCell2InRange = (row2 >= top && row2 <= bottom && col2 >= left && col2 <= right);
if (isCell1InRange && isCell2InRange) {
return true;
}
}
return false;
}

View File

@@ -1,220 +0,0 @@
/* eslint-disable */
import { saveAs } from 'file-saver'
import XLSX from 'xlsx'
function generateArray(table) {
var out = [];
var rows = table.querySelectorAll('tr');
var ranges = [];
for (var R = 0; R < rows.length; ++R) {
var outRow = [];
var row = rows[R];
var columns = row.querySelectorAll('td');
for (var C = 0; C < columns.length; ++C) {
var cell = columns[C];
var colspan = cell.getAttribute('colspan');
var rowspan = cell.getAttribute('rowspan');
var cellValue = cell.innerText;
if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
//Skip ranges
ranges.forEach(function (range) {
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
}
});
//Handle Row Span
if (rowspan || colspan) {
rowspan = rowspan || 1;
colspan = colspan || 1;
ranges.push({
s: {
r: R,
c: outRow.length
},
e: {
r: R + rowspan - 1,
c: outRow.length + colspan - 1
}
});
};
//Handle Value
outRow.push(cellValue !== "" ? cellValue : null);
//Handle Colspan
if (colspan)
for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
}
out.push(outRow);
}
return [out, ranges];
};
function datenum(v, date1904) {
if (date1904) v += 1462;
var epoch = Date.parse(v);
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
function sheet_from_array_of_arrays(data, opts) {
var ws = {};
var range = {
s: {
c: 10000000,
r: 10000000
},
e: {
c: 0,
r: 0
}
};
for (var R = 0; R != data.length; ++R) {
for (var C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R;
if (range.s.c > C) range.s.c = C;
if (range.e.r < R) range.e.r = R;
if (range.e.c < C) range.e.c = C;
var cell = {
v: data[R][C]
};
if (cell.v == null) continue;
var cell_ref = XLSX.utils.encode_cell({
c: C,
r: R
});
if (typeof cell.v === 'number') cell.t = 'n';
else if (typeof cell.v === 'boolean') cell.t = 'b';
else if (cell.v instanceof Date) {
cell.t = 'n';
cell.z = XLSX.SSF._table[14];
cell.v = datenum(cell.v);
} else cell.t = 's';
ws[cell_ref] = cell;
}
}
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
return ws;
}
function Workbook() {
if (!(this instanceof Workbook)) return new Workbook();
this.SheetNames = [];
this.Sheets = {};
}
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
export function export_table_to_excel(id) {
var theTable = document.getElementById(id);
var oo = generateArray(theTable);
var ranges = oo[1];
/* original data */
var data = oo[0];
var ws_name = "SheetJS";
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
/* add ranges to worksheet */
// ws['!cols'] = ['apple', 'banan'];
ws['!merges'] = ranges;
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {
bookType: 'xlsx',
bookSST: false,
type: 'binary'
});
saveAs(new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}), "test.xlsx")
}
export function export_json_to_excel({
multiHeader = [],
header,
data,
filename,
merges = [],
autoWidth = true,
bookType = 'xlsx'
} = {}) {
/* original data */
filename = filename || 'excel-list'
data = [...data]
data.unshift(header);
for (let i = multiHeader.length - 1; i > -1; i--) {
data.unshift(multiHeader[i])
}
var ws_name = "SheetJS";
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
if (merges.length > 0) {
if (!ws['!merges']) ws['!merges'] = [];
merges.forEach(item => {
ws['!merges'].push(XLSX.utils.decode_range(item))
})
}
if (autoWidth) {
/*设置worksheet每列的最大宽度*/
const colWidth = data.map(row => row.map(val => {
/*先判断是否为null/undefined*/
if (val == null) {
return {
'wch': 10
};
}
/*再判断是否为中文*/
else if (val.toString().charCodeAt(0) > 255) {
return {
'wch': val.toString().length * 2
};
} else {
return {
'wch': val.toString().length
};
}
}))
/*以第一行为初始值*/
let result = colWidth[0];
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j]['wch'] < colWidth[i][j]['wch']) {
result[j]['wch'] = colWidth[i][j]['wch'];
}
}
}
ws['!cols'] = result;
}
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {
bookType: bookType,
bookSST: false,
type: 'binary'
});
saveAs(new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}), `${filename}.${bookType}`);
}

View File

@@ -20,10 +20,11 @@
</a-form-item>
<a-form-item>
<a-cascader
v-model:value="queryParams.transactionType"
v-model:value="transactionType"
multiple
style="width: 200px"
:options="options"
@change="changeSelect"
placeholder="请选择交易类型"
suffix-icon="Shopping Around">
<template #tagRender="data">
@@ -49,7 +50,7 @@
</div>
<div style="display: flex; margin-top: 20px; height: calc(84% - 20px)">
<div class="detailTable">
<ns-view-list-table v-bind="tableConfig" :model="data" ref="mainRef" :scroll="{ x: 2000 }">
<ns-view-list-table v-bind="tableConfig" :model="data" ref="mainRef" :scroll="{ x: 1280 }">
<template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'accountType'">
<span v-if="record.accountType">{{ record.accountType.label }}</span>
@@ -195,6 +196,7 @@
};
const total = ref<number>();
const year = ref(new Date().getFullYear().toString());
const transactionType = ref();
const queryParams = ref({
pageNum: 1,
pageSize: 10,
@@ -202,9 +204,16 @@
accountType: props.parentId,
year: year.value,
});
const transactionTypeValue = ref();
const changeSelect = (value, selectedOptions) => {
transactionTypeValue.value = selectedOptions.flatMap((group) =>
group.flatMap((node) => [node.value, ...(node.children?.map((child) => child.value) || [])]),
);
};
const searchTableList = () => {
year.value = queryParams.value.year;
transactionType.value = queryParams.value.transactionType;
transactionTypeList.value = transactionTypeValue.value;
queryParams.value.transactionTypeList = transactionTypeValue.value;
accountType.value = queryParams.value.accountType;
getTotalTable(queryParams.value.accountType);
mainRef.value?.nsTableRef.reload();
@@ -283,6 +292,9 @@
accountType.value = props.parentId;
year.value = new Date().getFullYear();
transactionType.value = '';
transactionTypeList.value = [];
queryParams.value.transactionTypeList = transactionTypeList.value;
getTotalTable();
mainRef.value?.nsTableRef.reload();
// getDetailList();
};
@@ -364,7 +376,7 @@
};
const mainRef = ref();
const transactionType = ref();
const transactionTypeList = ref([]);
const accountType = ref();
accountType.value = props.parentId;
const tableConfig = ref({
@@ -373,6 +385,7 @@
params: {
orgId,
accountType,
transactionTypeList,
year,
},
headerActions: [
@@ -467,40 +480,49 @@
{
title: '资产类别',
dataIndex: 'accountType',
width: 100,
},
{
title: '交易方式',
dataIndex: 'transactionTypeName',
width: 100,
},
{
title: '交易日期',
dataIndex: 'transactionDate',
width: 100,
sorter: (a, b) => a.transactionDate - b.transactionDate,
},
{
title: '本期收入(tCO2)',
dataIndex: 'income',
width: 150,
sorter: (a, b) => a.income - b.income,
},
{
title: '本期支出(tCO2)',
dataIndex: 'expenditure',
width: 150,
sorter: (a, b) => a.expenditure - b.expenditure,
},
{
title: '发生金额(¥)',
width: 150,
dataIndex: 'amountIncurredValue',
},
{
title: '交易对象',
width: 100,
dataIndex: 'tradingPartner',
},
{
title: '更新人',
width: 100,
dataIndex: 'updateUser',
},
{
title: '更新时间',
width: 150,
dataIndex: 'updateTime',
},
],

View File

@@ -2,7 +2,9 @@
<div class="mainContant" v-if="homePage">
<a-card class="card" v-if="nationwide" style="margin-right: 1%; margin-bottom: 1%">
<div class="top" style="background: rgba(252, 139, 78, 0.05)">
<div class="moneyImg"><img width="68" height="68" src="../../../../src/icon/carbonAssetsMoney-1.svg" /></div>
<div class="moneyImg"
><img width="68" height="68" src="../../../../src/icon/carbonAssetsMoney-1.svg"
/></div>
<div class="moneyTitle">全国碳账户估值CNY</div>
<div class="moneyTotal" style="color: rgba(229, 102, 22, 1)">{{
nationwide.valuation
@@ -369,6 +371,7 @@
background: linear-gradient(180deg, rgba(244, 252, 250, 1) 0%, rgba(255, 255, 255, 1) 100%);
border: 1px solid rgba(42, 197, 155, 0.3);
padding: 10px;
border-radius: 8px;
.money {
opacity: 1;
font-size: 28px;

View File

@@ -85,7 +85,7 @@
<div class="ns-form-title" style="display: flex">
<div class="title">凭证上传</div>
</div>
<a-upload
<!-- <a-upload
:file-list="fileList"
name="file"
accept=".pdf"
@@ -109,33 +109,26 @@
<span>1.仅支持pdf格式文件或文件夹</span>
<span>2.文件名命名规则为能源种类_年份</span>
<span>3.每次上传自动覆盖</span>
</div>
</div> -->
<a-upload-dragger
v-model:fileList="fileList"
accept=".pdf"
name="file"
@remove="handleFileRemove"
:before-upload="beforeUpload"
@change="handleChange">
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-hint">1.仅支持pdf格式文件或文件夹</p>
<p class="ant-upload-hint">2.文件名命名规则为能源种类_年份</p>
<p class="ant-upload-hint">3.每次上传自动覆盖</p>
</a-upload-dragger>
<template #footer>
<a-button style="margin-right: 8px" @click="onClose">取消</a-button>
<a-button type="primary" @click="onSubmit">确定</a-button>
</template>
</a-drawer>
<!-- 上传凭证弹窗 -->
<!-- <a-modal :visible="openUpload" title="凭证上传" @ok="handleOk" @cancel="closeOpenUpload">
<a-upload-dragger
v-model:fileList="fileList"
name="file"
:multiple="true"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
@change="handleChange"
@drop="handleDrop"
>
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-hint" style="display: flex;flex-direction: column;">
<p>1.仅支持pdf格式文件或文件夹</p>
<p>2.文件命名规则为能源种类_年份</p>
<p>3.每次上传自动覆盖</p>
</p>
</a-upload-dragger>
</a-modal> -->
<!-- 凭证下载 -->
<a-drawer
:visible="downLoadVisible"
@@ -172,10 +165,10 @@
</template>
</template>
</a-table>
<template #footer>
<!-- <template #footer>
<a-button style="margin-right: 8px" @click="onCloseDownLoad">取消</a-button>
<a-button type="primary" @click="onSubmitDownLoad">确定</a-button>
</template>
</template> -->
</a-drawer>
</div>
</template>
@@ -183,7 +176,7 @@
import { ref, toRaw, defineExpose, createVNode } from 'vue';
import type { Rule } from 'ant-design-vue/es/form';
import { Pagination, message, Modal, Upload } from 'ant-design-vue';
import { UploadOutlined } from '@ant-design/icons-vue';
import { UploadOutlined, InboxOutlined } from '@ant-design/icons-vue';
import type { TreeSelectProps, UploadChangeParam, UploadProps } from 'ant-design-vue';
import { NsMessage } from '/nerv-lib/component';
import dayjs, { Dayjs } from 'dayjs';
@@ -1174,6 +1167,10 @@
:deep(.ant-table-container) {
padding: unset;
}
:deep(.ant-upload.ant-upload-drag) {
height: 18vh;
margin-top: 10px;
}
</style>
<style scoped>
th.column-money,

View File

@@ -119,10 +119,11 @@
<!-- 选择因子 -->
<a-modal
v-model:visible="openVisible"
v-if="openVisible"
width="60%"
title="选择因子"
@ok="onSubmit"
@cancel="onClose">
@ok="btnClick"
@cancel="onCloseClick">
<ns-view-list-table v-bind="config" ref="setFactorRef" style="height: 500px" />
</a-modal>
</div>
@@ -140,6 +141,7 @@
} from '/@/api/carbonEmissionFactorLibrary';
import { or } from '@vueuse/core';
import { setFactorConfig } from '../config';
import { NsMessage } from '/nerv-lib/saas';
defineOptions({
energyType: 'quickCalculation', // 与页面路由name一致缓存才可生效
components: {
@@ -340,8 +342,8 @@
formState.value.factorId = record.factorId;
text.value = '编辑';
visible.value = true;
emissionSources.value = record.emissionSources;
queryData.value.emissionSources = emissionSources.value;
emissionSources.value = record.factorId; //todo
queryData.value.factorId = emissionSources.value; //todo
getNewTable();
},
},
@@ -484,10 +486,26 @@
});
};
const openVisible = ref(false);
const setFactorRef = ref();
const config = setFactorConfig(orgId.value);
const selectFactor = () => {
openVisible.value = true;
};
const btnClick = () => {
let selectRowKeys = setFactorRef.value?.nsTableRef.tableState.selectedRowKeys;
if (selectRowKeys.length === 0) {
NsMessage.warn('请选择因子');
return;
} else {
newTableData.value = setFactorRef.value?.nsTableRef.tableState.selectedRows;
selectedRowKeys.value = setFactorRef.value?.nsTableRef.tableState.selectedRowKeys;
formState.value.factorId = selectedRowKeys.value[0];
openVisible.value = false;
}
};
const onCloseClick = () => {
openVisible.value = false;
};
// 关闭新增抽屉
const onClose = () => {
visible.value = false;

View File

@@ -1,3 +1,5 @@
import { quickCalculation, carbonEmissionFactorLibrary } from '/@/api/carbonEmissionFactorLibrary';
import { ref } from 'vue';
// 凭证弹窗表头
export const voucherColumns = [
{
@@ -9,8 +11,8 @@ export const voucherColumns = [
},
{
title: '日期',
dataIndex: 'updateTime',
key: 'updateTime',
dataIndex: 'bizName',
key: 'bizName',
ellipsis: true,
},
{
@@ -42,3 +44,107 @@ export const drawerColumns = [
dataIndex: 'dataSources',
},
];
export const setFactorConfig = (orgId) => {
return ref({
api: carbonEmissionFactorLibrary.getTableList,
params: { orgId, pageNum: 1, pageSize: 9999, emissionList: [0] },
treeConfig: {
header: {
icon: 'deviceType',
title: '排放分类',
},
params: { orgId},
dynamicParams: { emissionList: 'id[]' },
defaultExpandAll: true,
// checkable:true,
api: carbonEmissionFactorLibrary.getCarbonFactorTree,
fieldNames: { title: 'emissionName', key: 'id' },
formConfig: {
schemas: [
{
field: 'deviceType',
label: '设备名称',
component: 'NsInput',
autoSubmit: true,
componentProps: {
placeholder: '请输入关键字',
},
},
],
},
},
rowSelection: { type: 'radio' },
columns: [
{
title: '序号',
textNumber: 2,
dataIndex: 'address',
customRender: (text: any) => {
return text.index + 1;
},
},
{
title: '名称',
dataIndex: 'emissionSources',
textNumber: 3,
},
{
title: '排放因子',
dataIndex: 'emissionFactors',
textNumber: 4,
textEllipsis: true,
},
{
title: '排放因子单位',
dataIndex: 'emissionFactorUnits',
width: 100,
textEllipsis: true,
},
{
title: '排放环节',
dataIndex: 'emissionProcess',
textWidth: 88,
textEllipsis: true,
},
{
title: '数据来源',
dataIndex: 'dataSources',
textNumber: 5,
textEllipsis: true,
},
],
formConfig: {
schemas: [
{
field: 'emissionSources',
label: '排放源',
component: 'NsInput',
componentProps: {
placeholder: '请输入排放源',
maxLength: 20,
},
},
{
field: 'emissionProcess',
label: '排放环节',
component: 'NsSelectApi',
componentProps: {
placeholder: '请选择排放环节',
api: carbonEmissionFactorLibrary.gasAndDatabase,
resultField: 'data',
params: {
orgId: orgId.value,
type: 'emissionProcess',
},
immediate: true,
labelField: 'label',
valueField: 'value',
},
},
],
params: {},
},
// pagination: { pageSizeOptions: false },
rowKey: 'id',
});
};

View File

@@ -106,8 +106,13 @@
<span>{{ data.emissionSource }}</span>
</div>
<div class="actionMore">
<EditOutlined @click="editUnit(data)" />
<MinusCircleOutlined style="margin-left: 6px" @click="delUnit(data)" />
<EditOutlined
@click="editUnit(data)"
v-if="data.emissionSource !== '全部'" />
<MinusCircleOutlined
v-if="data.emissionSource !== '全部'"
style="margin-left: 6px"
@click="delUnit(data)" />
<PlusCircleOutlined
v-if="data.emissionSource === '全部'"
style="margin-left: 6px"
@@ -131,7 +136,7 @@
:pagination="false"
bordered
size="middle"
:scroll="{ y: 380 }">
:scroll="{ x: 660, y: 380 }">
<template #title>
<a-button type="primary" @click="downLoadVoucher">凭证</a-button>
</template>
@@ -373,20 +378,21 @@
@keydown="handleKeyDown" />
</a-form-item>
</a-col>
<a-col :span="24">
<!-- <a-col :span="24">
<a-form-item ref="name" label="关键字" name="key">
<a-input-search
v-model:value="editFormState.key"
@search="searchKey"
placeholder="请输入关键字" />
</a-form-item>
</a-col>
</a-col> -->
</a-row>
</a-form>
</a-spin>
<div class="ns-form-title-edit" style="display: flex">
<!-- <div class="ns-form-title-edit" style="display: flex">
<div class="titleEdit">因子列表</div>
</div>
</div> -->
<a-button type="primary" style="margin-bottom: 10px" @click="selectFactor">选择因子</a-button>
<a-table
:columns="drawerColumns"
:data-source="newTableData"
@@ -430,14 +436,23 @@
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-hint">1.仅支持pdf格式文件或文件夹</p>
<p class="ant-upload-hint">2.文件名命名规则为能源种类_年份</p>
<p class="ant-upload-hint">3.每次上传自动覆盖</p>
<p class="ant-upload-hint">2.每次上传自动覆盖</p>
</a-upload-dragger>
<template #footer>
<a-button style="margin-right: 8px" @click="onCloseEditData">取消</a-button>
<a-button type="primary" @click="submitEditData">确定</a-button>
</template>
</a-drawer>
<!-- 选择因子 -->
<a-modal
v-model:visible="openVisible"
v-if="openVisible"
width="60%"
title="选择因子"
@ok="btnClick"
@cancel="onCloseClick">
<ns-view-list-table v-bind="config" ref="setFactorRef" style="height: 500px" />
</a-modal>
</div>
</template>
@@ -464,6 +479,8 @@
import { group } from '/@/api/deviceManage';
import { debug, log } from 'node:console';
import { dict } from '/@/api';
import { NsMessage } from '/nerv-lib/saas';
import { setFactorConfig } from '../config';
defineOptions({
energyType: 'fillInPage', // 与页面路由name一致缓存才可生效
components: {
@@ -673,12 +690,14 @@
}
};
// 获取表头单位
const carbonEmission = ref();
const getTableHeardUnit = (id) => {
fetch(carbonInventoryCheck.findUnitById, { id: id }).then((res) => {
if (res.data) {
columns.value[1].title = '消耗量【' + res.data.unit + '】';
columns.value[2].title = '碳排因子【' + res.data.carbonEmission + '】';
columns.value[3].title = '排放量【' + res.data.carbonUnits + '】';
carbonEmission.value = res.data.carbonEmission;
}
});
};
@@ -879,6 +898,7 @@
{
title: '日期',
dataIndex: 'acquisitionDate',
width: 80,
key: 'acquisitionDate',
},
{
@@ -887,11 +907,13 @@
{
title: '数据来源',
dataIndex: 'dataSources',
width: 100,
key: 'dataSources',
},
{
title: '数值',
dataIndex: 'consumption',
width: 100,
key: 'consumption',
},
],
@@ -902,11 +924,13 @@
{
title: '数据来源',
dataIndex: 'carbonSource',
width: 100,
key: 'carbonSource',
},
{
title: '数值',
dataIndex: 'emissionFactors',
width: 100,
key: 'emissionFactors',
},
],
@@ -914,6 +938,7 @@
{
title: '排放量',
dataIndex: 'emissions',
width: 100,
key: 'emissions',
fixed: 'right',
},
@@ -1069,12 +1094,23 @@
// 获取能耗类型
const options = await dict({ params: { dicKey: 'ENERGY_TYPE' } });
energyTypeOptions.value = options.data.data;
editFormState.value.key = record.factorName;
editFormState.value.key = record.factorId;
searchKey();
editFormState.value.id = record.id;
editFormState.value.dataSources = record.dataSources;
if (record.dataSources !== undefined) {
if (record.dataSources.value === 3) {
canEdit.value = true;
automatic.value = true;
} else {
canEdit.value = false;
automatic.value = false;
}
}
editFormState.value.consumption = record.consumption;
editFormState.value.collectionNode = record.carbonSource;
editFormState.value.energyConsumptionType = record.energyConsumptionType;
changeEnergyType(record.energyConsumptionType);
editFormState.value.collectionNode = record.collectionNode;
editFormState.value.factorId = record.factorId;
editFormState.value.emissionFactors = record.emissionFactors;
selectedRowKeysEdit.value = [record.factorId];
@@ -1097,9 +1133,9 @@
};
const searchKey = () => {
if (editFormState.value.key) {
queryData.value.emissionSources = editFormState.value.key;
queryData.value.factorId = editFormState.value.key;
} else {
queryData.value.emissionSources = '';
queryData.value.factorId = 0;
}
getNewTable();
};
@@ -1137,6 +1173,7 @@
};
const spinning = ref(false);
const selectNode = (value) => {
editFormState.value.collectionNode = value;
spinning.value = true;
const getConsumeData = ref({
acquisitionDate: acquisitionDate.value,
@@ -1198,9 +1235,9 @@
if (editFormState.value.dataSources.value) {
editFormState.value.dataSources = editFormState.value.dataSources.value;
}
if (editFormState.value.collectionNode) {
editFormState.value.collectionNode = editFormState.value.collectionNode.value;
}
// if (editFormState.value.collectionNode) {
// editFormState.value.collectionNode = editFormState.value.collectionNode.value;
// }
fetch(carbonInventoryCheck.updateTable, editFormState.value).then((res) => {
if (fileList.value.length !== 0) {
const formData = ref(new FormData());
@@ -1235,6 +1272,32 @@
console.log('error', error);
});
};
const openVisible = ref(false);
const setFactorRef = ref();
const config = setFactorConfig(orgId.value);
const selectFactor = () => {
openVisible.value = true;
};
const btnClick = () => {
let selectRowKeys = setFactorRef.value?.nsTableRef.tableState.selectedRowKeys;
if (selectRowKeys.length === 0) {
NsMessage.warn('请选择因子');
return;
} else {
if (newTableData.value.emissionFactorUnits === carbonEmission.value) {
newTableData.value = setFactorRef.value?.nsTableRef.tableState.selectedRows;
selectedRowKeysEdit.value = setFactorRef.value?.nsTableRef.tableState.selectedRowKeys;
editFormState.value.emissionFactors = newTableData.value[0].emissionFactors;
editFormState.value.factorId = selectedRowKeysEdit.value[0];
openVisible.value = false;
} else {
NsMessage.warn('因子值单位不统一,请重新选择!');
}
}
};
const onCloseClick = () => {
openVisible.value = false;
};
const onCloseEditData = () => {
editData.value = false;
delIds.value = [];
@@ -1249,7 +1312,7 @@
const onChange = (pageNumber: number, size: number) => {
queryData.value.pageNum = pageNumber;
queryData.value.pageSize = size;
getNewTable();
// getNewTable();
};
// 点击切换排放统计/碳排流向
const fillInPage = ref(true);
@@ -1730,9 +1793,11 @@
.mainLeft {
width: 19%;
margin-right: 1%;
border-right: 1px solid #f2f2f2;
position: relative;
height: 96%;
height: 100%;
border: 1px solid #f2f2f2;
border-radius: 8px;
padding: 4px;
.treeRow {
display: flex;
justify-content: space-between;
@@ -1757,6 +1822,7 @@
}
.mainRight {
width: 80%;
border-left: 1px solid #f2f2f2;
}
}

View File

@@ -79,7 +79,7 @@
</template>
<script lang="ts" setup>
import { ref, toRaw } from 'vue';
import { ref, toRaw, watch, nextTick } from 'vue';
import { http } from '/nerv-lib/util/http';
import { carbonInventoryCheck } from '/@/api/carbonEmissionFactorLibrary';
import fillIn from './fillInPage/index.vue';
@@ -118,7 +118,10 @@
const openChange = (status) => {
if (status === false) {
if (formState.value.reportYear) {
defaultPickerValue.value = [dayjs('2022'), dayjs('2022')];
defaultPickerValue.value = [
dayjs(formState.value.reportYear),
dayjs(formState.value.reportYear),
];
}
}
};

View File

@@ -100,7 +100,6 @@
<a-table-summary-row>
<a-table-summary-cell></a-table-summary-cell>
<a-table-summary-cell :colSpan="2">合计</a-table-summary-cell>
<a-table-summary-cell></a-table-summary-cell>
<a-table-summary-cell>
<a-typography-text>{{ totalLastYearActualUsage + unit }}</a-typography-text>
</a-table-summary-cell>
@@ -153,24 +152,35 @@
</a-form>
</a-modal>
<!-- 基准值设置 -->
<a-modal :visible="visible" @ok="onSubmit" @cancel="onClose">
<a-modal
:visible="visible"
@ok="onSubmit"
@cancel="onClose"
:style="{ top: '20px', left: '-100px' }"
:bodyStyle="{ maxHeight: '800px', overflowY: 'auto' }">
<a-spin :spinning="loading">
<a-tooltip placement="top">
<template #title>
<span>月基准值设置使用基准年相应月份的数据作为当前年相应月份的基准值</span>
</template>
<QuestionCircleOutlined style="position: absolute; right: 60px; top: 22px; z-index: 7" />
</a-tooltip>
<div style="display: flex; margin-top: 20px; justify-content: space-between">
<a-tabs v-model:activeKey="activeKey" @change="handleTabChange">
<a-tab-pane key="1" tab="年基准值设置">
<div
style="
display: flex;
margin-bottom: 10px;
justify-content: space-between;
margin-top: 10px;
">
<span> 节点{{ props.nodeName }} </span>
<a-date-picker
v-if="activeKey === '1'"
v-model:value="selectYear"
picker="year"
valueFormat="YYYY"
@change="changeYearData" />
</div>
<a-tabs v-model:activeKey="activeKey" @change="handleTabChange">
<a-tab-pane key="1" tab="年基准值设置">
<a-table
:columns="yearColumns"
:data-source="yearTableData"
@@ -183,9 +193,29 @@
}"
:pagination="false">
</a-table>
<a-pagination
v-model:current="queryData.pageNum"
simple
:total="total"
@change="onChange"
style="display: flex; justify-content: end; margin-top: 10px" />
</a-tab-pane>
<a-tab-pane key="2" tab="月基准值设置" force-render>
<a-table :columns="monthColumns" :data-source="dataSource" bordered :pagination="false">
<div
style="
display: flex;
margin-bottom: 10px;
justify-content: space-between;
margin-top: 10px;
">
<span> 节点{{ props.nodeName }} </span>
</div>
<a-table
:columns="monthColumns"
:data-source="dataSource"
size="small"
bordered
:pagination="false">
<template #bodyCell="{ column, text, record }">
<template v-if="['referenceValue'].includes(column.dataIndex)">
<div>
@@ -235,6 +265,7 @@
</a-table>
</a-tab-pane>
</a-tabs>
</a-spin>
</a-modal>
</div>
</template>
@@ -255,7 +286,13 @@
import * as echarts from 'echarts';
import { any, string } from 'vue-types';
import type { Dayjs } from 'dayjs';
import { Pagination } from 'ant-design-vue';
defineOptions({
components: {
'a-pagination': Pagination,
},
});
// 父组件id
const props = defineProps({
parentId: {
@@ -383,8 +420,10 @@
formState.value.ids = [record.id];
if (record.lastYear === '是') {
formState.value.isLastYear = 1;
disabled.value = false;
} else {
formState.value.isLastYear = 0;
disabled.value = true;
}
formState.value.conversionRate = record.conversionRate;
formState.value.lastYearList = [record.lastYearActualUsage];
@@ -454,7 +493,14 @@
orgId: orgId.value,
type: props.type,
itemizeId: props.parentId,
pageSize: 10,
pageNum: 1,
});
const total = ref();
const onChange = (page, pageSize) => {
queryData.value.pageNum = page;
setBasicData();
};
const changeYearData = () => {
queryData.value.referenceYear = selectYear.value;
setBasicData();
@@ -462,7 +508,8 @@
const yearTableData = ref([]);
const setBasicData = () => {
fetch(carbonPlanning.benchmarkSetting, queryData.value).then((res) => {
yearTableData.value = res.data;
yearTableData.value = res.data.records;
total.value = res.data.total;
});
visible.value = true;
};
@@ -507,6 +554,7 @@
{
title: '日期',
dataIndex: 'yearMonth',
width: '20%',
},
{
title: '用电量',
@@ -543,7 +591,9 @@
const cancel = (yearMonth: string) => {
delete editableData[yearMonth];
};
const loading = ref(false);
const onSubmit = () => {
loading.value = true;
const benchmark = monthData.value;
fetch(carbonPlanning.benchmarkSubmit, {
benchmark: benchmark,
@@ -555,6 +605,7 @@
visible.value = false;
activeKey.value = '1';
selectedRowKeysSet.value = [];
loading.value = false;
getTableData();
});
};
@@ -623,8 +674,8 @@
props.year + '年预算',
'基准值',
],
top: '0',
right: '0',
top: '1%',
right: '1%',
textStyle: {
color: '#666',
fontSize: 12,
@@ -781,7 +832,6 @@
<style lang="less" scoped>
.detailContant {
height: 100%;
margin: 12px;
}
.ns-form-title {
font-weight: bold;
@@ -791,7 +841,7 @@
align-items: center;
width: 100%;
height: 5vh;
padding: 12px 12px 0 12px;
.title {
text-align: left;
height: 32px;
@@ -826,11 +876,15 @@
width: 100%;
height: calc(95% - 5vh);
overflow: auto;
padding: 12px;
.chartsPart {
width: 100%;
height: 63%;
display: flex;
justify-content: space-between;
border-radius: 12px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 2px 20px rgb(69 123 234 / 20%);
.chart {
width: 100%;
height: 65%;
@@ -938,6 +992,9 @@
right: 10px;
top: 5px;
}
:deep(.ant-card-bordered) {
border: unset;
}
</style>
<style scoped>
.editable-row-operations a {

View File

@@ -126,6 +126,9 @@
energyType: {
type: String,
},
energyTypeName: {
type: String,
},
});
const orgId = ref('');
const result = JSON.parse(sessionStorage.getItem('ORGID')!);
@@ -216,7 +219,9 @@
const option = {
backgroundColor: 'transparent',
title: {
text: '历年用电量分析',
text: selectedTime.value
? '历年' + props.energyTypeName + '分析'
: '每月' + props.energyTypeName + '分析',
x: '0',
textStyle: {
color: 'rgba(51, 51, 51, 1)',

View File

@@ -4,19 +4,39 @@
<all ref="allRef" />
</a-tab-pane>
<a-tab-pane key="2" tab="用电量">
<category ref="electricRef" :tabId="tabId" :energyType="energyType" />
<category
ref="electricRef"
:tabId="tabId"
:energyType="energyType"
:energyTypeName="energyTypeName" />
</a-tab-pane>
<a-tab-pane key="3" tab="用水量">
<category ref="useWaterRef" :tabId="tabId" :energyType="energyType" />
<category
ref="useWaterRef"
:tabId="tabId"
:energyType="energyType"
:energyTypeName="energyTypeName" />
</a-tab-pane>
<a-tab-pane key="4" tab="用气量">
<category ref="provideWaterRef" :tabId="tabId" :energyType="energyType" />
<category
ref="provideWaterRef"
:tabId="tabId"
:energyType="energyType"
:energyTypeName="energyTypeName" />
</a-tab-pane>
<a-tab-pane key="5" tab="供热量">
<category ref="carbonEmissionsRef" :tabId="tabId" :energyType="energyType" />
<category
ref="carbonEmissionsRef"
:tabId="tabId"
:energyType="energyType"
:energyTypeName="energyTypeName" />
</a-tab-pane>
<a-tab-pane key="6" tab="碳排量">
<category ref="provideHotRef" :tabId="tabId" :energyType="energyType" />
<category
ref="provideHotRef"
:tabId="tabId"
:energyType="energyType"
:energyTypeName="energyTypeName" />
</a-tab-pane>
</a-tabs>
</template>
@@ -41,6 +61,7 @@
// 切换tab页的回调
const tabId = ref(1);
const energyType = ref();
const energyTypeName = ref();
const handleTabChange = (key) => {
console.log('Tab changed:', key);
// 在这里可以执行需要在页面切换时执行的逻辑
@@ -53,6 +74,7 @@
} else if (key === '2') {
tabId.value = 4;
energyType.value = 'ELECTRICITY_USAGE';
energyTypeName.value = '用电量';
nextTick(() => {
if (electricRef.value) {
electricRef.value.electricTotal = true;
@@ -62,6 +84,7 @@
} else if (key === '3') {
tabId.value = 5;
energyType.value = 'WATER_USAGE';
energyTypeName.value = '用水量';
nextTick(() => {
if (useWaterRef.value) {
useWaterRef.value.electricTotal = true;
@@ -71,6 +94,7 @@
} else if (key === '4') {
tabId.value = 6;
energyType.value = 'GAS_USAGE';
energyTypeName.value = '用气量';
nextTick(() => {
if (provideWaterRef.value) {
provideWaterRef.value.electricTotal = true;
@@ -80,6 +104,7 @@
} else if (key === '5') {
tabId.value = 7;
energyType.value = 'CARBON_EMISSIONS';
energyTypeName.value = '供热量';
nextTick(() => {
if (carbonEmissionsRef.value) {
carbonEmissionsRef.value.electricTotal = true;
@@ -89,6 +114,7 @@
} else if (key === '6') {
tabId.value = 8;
energyType.value = 'HEAT_SUPPLY';
energyTypeName.value = '碳排量';
nextTick(() => {
if (provideHotRef.value) {
provideHotRef.value.electricTotal = true;

View File

@@ -52,6 +52,10 @@
if (graphRef.value) {
graphRef.value.downloadChart();
}
} else {
if (tableRef.value) {
tableRef.value.export1();
}
}
};

View File

@@ -16,6 +16,7 @@
</template>
<script lang="ts">
import { exportExcel } from '/@/util/ExcelUtil.js';
import { defineComponent, watch, ref, onMounted } from 'vue';
import type { TableColumnType } from 'ant-design-vue';
import { Pagination } from 'ant-design-vue';
@@ -245,6 +246,9 @@
columns.value = columnA;
total.value = dataList.value.length;
onChange(1, 10);
}; // 导出excel文件
const export1 = () => {
exportExcel(columns.value, dataList.value, '历史数据导出', true, 'deviceName', 1, 4);
};
onMounted(() => {
init();
@@ -257,6 +261,7 @@
total,
onChange,
x,
export1,
};
},
});

View File

@@ -15,7 +15,7 @@
:tree-data="treeData1"
@change="changeDeviceType" />
<a-spin :spinning="treeLoading">
<!-- <a-spin :spinning="treeLoading"> -->
<a-tree
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
@@ -25,7 +25,7 @@
:height="560"
style="width: 100%; overflow-y: auto; margin-bottom: 10px; margin-top: 10px"
:tree-data="treeData2" />
</a-spin>
<!-- </a-spin> -->
<!-- <div class="fixed-bottom"> -->
<div>

View File

@@ -18,6 +18,8 @@
</template>
<script lang="ts">
import ExcelJS from 'exceljs';
import FileSaver from 'file-saver';
import { defineComponent, ref, inject, watch, onMounted } from 'vue';
export default defineComponent({
@@ -130,6 +132,153 @@
},
{ deep: true },
);
// 导出excel文件
// 因为有多级表头,特殊处理,没有用公共方法
const export1 = () => {
if (!data.value || data.value.length == 0) {
return;
}
// 不需要合并序号
for (let i = 0; i < data.value.length; i++) {
data.value[i].index = i + 1;
}
// 创建工作簿
const workbook = new ExcelJS.Workbook();
// 添加工作表名为sheet1
const sheet1 = workbook.addWorksheet('sheet1');
// 字段名
let filterVal = [
'name',
'value',
'yoyDiff',
'yoyRate',
'momDiff',
'momRate',
'zongxiangDiff',
'zongxiangRate',
];
// 表格columns
// 添加多行表头
sheet1.addRows([
['设备/节点', '统计值', '同比', '', '环比', '', '纵向对比', ''],
['', '', '△差值', '增长率', '△差值', '增长率', '△差值', '增长率'],
]);
// 合并单元格来实现多行表头
sheet1.mergeCells('A1:A2'); // 合并 '设备/节点' 单元格
sheet1.mergeCells('B1:B2'); // 合并 '统计值' 单元格
sheet1.mergeCells('C1:D1'); // 合并 '同比' 单元格
sheet1.mergeCells('E1:F1'); // 合并 '环比' 单元格
sheet1.mergeCells('G1:H1'); // 合并 '纵向对比' 单元格
//传入的数据
const list = data.value;
//格式化数据
const datas = formatJson(filterVal, list);
// 将数据写入工作表
datas.forEach((row: any) => {
// const values = Object.values(row);
sheet1.addRow(row);
});
let column = sheet1.columns;
for (let i = 0; i < column.length; i++) {
column[i].width = 20;
}
// 修改所有单元格样式
// 遍历每一行
sheet1.eachRow((row) => {
// 遍历每个单元格
row.eachCell((cell) => {
// 设置边框样式
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' },
};
// 设置居中对齐
cell.alignment = {
vertical: 'middle',
horizontal: 'center',
};
});
});
// 获取标题行数据
const titleCell1 = sheet1.getRow(1);
// 设置行高为30
titleCell1.height = 30;
// 设置标题行单元格样式
titleCell1.eachCell((cell) => {
// 设置标题行背景颜色为黄色
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFFF' },
};
// 设置标题行字体
cell.font = {
// color: { argb: 'FF0000' }, //颜色为红色
bold: true, // 字体粗体
size: 18, // 设置字体大小为18
};
});
const titleCell2 = sheet1.getRow(2);
// 设置行高为30
titleCell2.height = 30;
// 设置标题行单元格样式
titleCell2.eachCell((cell) => {
// 设置标题行背景颜色为黄色
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFFF' },
};
// 设置标题行字体
cell.font = {
// color: { argb: 'FF0000' }, //颜色为红色
bold: true, // 字体粗体
size: 18, // 设置字体大小为18
};
});
// 获取第二行到最后一行的内容数据
const bodyRows = sheet1.getRows(3, sheet1.rowCount);
if (bodyRows) {
// 处理内容行的数据
bodyRows.forEach((bodyRow) => {
// 设置行高为20
bodyRow.height = 20;
bodyRow.eachCell((cell) => {
cell.font = {
size: 16, // 设置内容行字体大小为16
};
});
});
}
// 导出表格文件
workbook.xlsx
.writeBuffer()
.then((buffer) => {
let file = new Blob([buffer], { type: 'application/octet-stream' });
FileSaver.saveAs(file, '分析数据导出.xlsx');
})
.catch((error) => console.log('Error writing excel export', error));
};
/**
* 格式化表格数据
* @filterVal 格式头
* @jsonData 用来格式化的表格数据
*/
function formatJson(filterVal: any, jsonData: any) {
return jsonData.map((v: any) => filterVal.map((j: any) => v[j]));
}
onMounted(() => {
// 深度拷贝
data.value = JSON.parse(JSON.stringify(pageData.analysisTableList));
@@ -165,6 +314,7 @@
rowSelection,
selectedKey,
setStandard,
export1,
};
},
});

View File

@@ -16,6 +16,7 @@
</template>
<script lang="ts">
import { exportExcel } from '/@/util/ExcelUtil.js';
import { defineComponent, watch, inject, ref, onMounted } from 'vue';
import type { TableColumnType } from 'ant-design-vue';
import { Pagination } from 'ant-design-vue';
@@ -152,6 +153,9 @@
columns.value = columnA;
total.value = dataList.value.length;
onChange(1, 10);
}; // 导出excel文件
const export1 = () => {
exportExcel(columns.value, dataList.value, '图表数据导出');
};
onMounted(() => {
init();
@@ -167,6 +171,7 @@
columns,
total,
onChange,
export1,
};
},
});

View File

@@ -28,7 +28,7 @@
</template> -->
</a-tabs>
<div class="button">
<ns-icon name="xiazai" size="18" style="margin-right: 10px" @click="downloadChart" />
<ns-icon name="xiazai" size="18" style="margin-right: 10px" @click="download" />
<ns-icon :name="iconName" size="18" style="margin-right: 10px" @click="change" />
</div>
</div>
@@ -74,15 +74,27 @@
name: 'EnvironmentMonitorIndex', // 与页面路由name一致缓存才可生效
});
const downloadChart = () => {
if (activeKey.value == '1' && isGraph) {
const download = () => {
if (activeKey.value == '1') {
if (isGraph.value) {
if (graphRef.value) {
graphRef.value.downloadChart();
}
} else {
if (tableRef.value) {
tableRef.value.export1();
}
}
} else {
if (isGraph.value) {
if (analysisGraphRef.value) {
analysisGraphRef.value.downloadChart();
}
} else {
if (analysisTableRef.value) {
analysisTableRef.value.export1();
}
}
}
};
const changeActive = () => {

View File

@@ -35,14 +35,14 @@
v-if="mode == '0'"
@change="changeMode" />
<a-input v-model:value="pointName" placeholder="请输入节点名称" v-else @change="changeMode" />
<a-spin :spinning="treeLoading">
<!-- <a-spin :spinning="treeLoading"> -->
<a-tree
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
v-model:checkedKeys="checkedKeys"
:show-line="{ showLeafIcon: false }"
checkable
:height="600"
:height="500"
style="width: 100%; overflow-y: auto; margin-bottom: 10px; margin-top: 10px"
:tree-data="treeData2">
<!-- <template #title="{ title }">
@@ -59,7 +59,7 @@
<span v-else>{{ title }}</span>
</template> -->
</a-tree>
</a-spin>
<!-- </a-spin> -->
<!-- <div class="fixed-bottom"> -->
<div>

View File

@@ -38,7 +38,10 @@
查询
</a-button>
</div>
<a-button type="primary" style="position: absolute; right: 40px; top: -45px">
<a-button
type="primary"
style="position: absolute; right: 40px; top: -45px"
@click="export1()">
导出
</a-button>
</div>
@@ -66,6 +69,7 @@
<!-- </a-spin> -->
</template>
<script lang="ts" setup>
import { exportExcel } from '/@/util/ExcelUtil.js';
import { ref, onMounted } from 'vue';
// import { http } from '/nerv-lib/util/http';
import { Pagination, SelectProps, TreeSelectProps, TableColumnType } from 'ant-design-vue';
@@ -200,6 +204,10 @@
loading.value = false;
});
};
// 导出excel文件
const export1 = () => {
exportExcel(tableColumns.value, data.value, '平均数据导出');
};
onMounted(async () => {
// 获取频率
let frequency = await getEnum({ params: { enumType: 'TimeFlagEnum' } });

View File

@@ -62,7 +62,7 @@
<a-button
type="primary"
style="position: absolute; right: 40px; top: -45px"
@click="exportExcel()">
@click="export1()">
导出
</a-button>
</div>
@@ -87,8 +87,7 @@
</div>
</template>
<script lang="ts" setup>
import XLSX from 'xlsx';
// import Export2Excel from '/@/util/Export2Excel.js';
import { exportExcel } from '/@/util/ExcelUtil.js';
import { ref, onMounted, defineOptions } from 'vue';
// import { http } from '/nerv-lib/util/http';
@@ -289,6 +288,10 @@
// 获取表格数据
const getTableList = () => {
loading.value = true;
tableColumns.value = [];
data.value = [];
total.value = 0;
pageData.value = [];
let environmentType = '';
for (let i = 0; i < typeList.value.length; i++) {
if (typeList.value[i].value == typeValue.value) {
@@ -352,60 +355,9 @@
}
});
};
// 导出excel
/**导出按钮点击事件函数
* @前期准备 npm install -S xlsx file-saver 及 Export2Excel.js
*/
const exportExcel = () => {
import('/@/util/Export2Excel.js').then((excel) => {
// 导出的表头名
let tHeader = [];
let filterVal = [];
for (let i = 0; i < tableColumns.value.length; i++) {
if (tableColumns.value[i].dataIndex) {
tHeader.push(tableColumns.value[i].title);
filterVal.push(tableColumns.value[i].dataIndex);
}
}
// const tHeader = [
// 'ID',
// '名称',
// '视频ID',
// '视频标题',
// '发布',
// '视频类型',
// '播放量',
// '上传时间',
// ];
// // 导出的表头字段名
// const filterVal = [
// 'id',
// 'name',
// 'videoId',
// 'videoTitle',
// 'release',
// 'videoType',
// 'playVolume',
// 'updateTime',
// ];
//传入的数据
const list = data.value;
const datas = formatJson(filterVal, list);
excel.export_json_to_excel({
header: tHeader, // 表格头部
data: datas, // 表格数据
filename: '表格导出测试', // excel文件名
});
});
};
/**
* 格式化表格数据
* @filterVal 格式头
* @jsonData 用来格式化的表格数据
*/
const formatJson = (filterVal: any, jsonData: any) => {
return jsonData.map((v: any) => filterVal.map((j: any) => v[j]));
// 导出excel文件
const export1 = () => {
exportExcel(tableColumns.value, data.value, '历史数据导出', true, 'location', 1, 3);
};
onMounted(async () => {
// 获取频率