2e7924af by lxs

入表功调整

1 parent 8e00cd08
......@@ -11,6 +11,7 @@ import { changeNum } from "@/utils/common";
import { costDelete, getAssetCatalog, getCostList, sendEntryMsg } from "@/api/modules/dataEntry";
import * as XLSXS from 'xlsx-js-style';
import { saveAs } from 'file-saver';
import { t } from "@wangeditor/editor";
const { proxy } = getCurrentInstance() as any;
const userStore = useUserStore();
......@@ -226,9 +227,9 @@ const convertConfig = {
}
const costTableRef = ref(null);
const initField: any = ref([
{ label: "一级指标", field: "name1", level: 1, width: 120 },
{ label: "一级分类", field: "name2", level: 2, width: 120 },
{ label: "二级分类", field: "name3", level: 3, width: 200 },
{ label: "一级指标", field: "name1", level: 1, width: 120, visible: true },
{ label: "一级分类", field: "name2", level: 2, width: 120, visible: true },
{ label: "二级分类", field: "name3", level: 3, width: 200, visible: true },
{ label: "三级分类", field: "name4", level: 4, width: 200, visible: false },
{
label: "累计投入", field: "total", width: 120, align: 'right', visible: false, columClass: 'inverse_cell', getName: (scope) => {
......@@ -241,6 +242,7 @@ const tableData: any = ref([])
const besure = ref(false);
const mergeRowCount: any = ref({});
const checkedData: any = ref([]);
const checkedField: any = ref([]);
const entryItem = {
year: '',
......@@ -427,8 +429,7 @@ const inputEventChange = (val, scope, field) => {
}
// 重命名
const setName = (name, level) => {
const rIndex = currentRow.value.$index;
const setName = (name, level, rIndex) => {
let rowData = tableData.value[rIndex];
rowData[`name${level}`] = name;
}
......@@ -439,8 +440,12 @@ const addSameData = (rIndex, name, level, tData) => {
const lastCode = rowData[`code${level - 1}`];
const tCode = tData[`code${level}`].split(lastCode)[1];
const codeVal = parseInt(tCode, 10) < 10 ? `0${parseInt(tCode, 10) + 1}` : parseInt(tCode, 10) + 1;
for (var r in rowData) {
if (r.indexOf('name') == -1 && r.indexOf('code') == -1) rowData[r] = '';
}
rowData[`name${level}`] = name;
rowData[`code${level}`] = `${lastCode}${codeVal}`;
rowData[`checked${level}`] = false;
delete rowData.name4;
delete rowData.code4;
tableData.value.splice(rIndex + 1, 0, rowData);
......@@ -453,8 +458,14 @@ const addLowerData = (rIndex, name, level, len) => {
const hasLowerItem = rowData[`code${level + 1}`] ? true : false;
const lastCode = rowData[`code${level}`];
const codeVal = (len + 1) < 10 ? '0' + (len + 1) : len + 1;
for (var r in rowData) {
if (r.indexOf('name') == -1 && r.indexOf('code') == -1) rowData[r] = '';
}
rowData[`name${level + 1}`] = name;
rowData[`code${level + 1}`] = `${lastCode}${codeVal}`;
rowData[`checked${level + 1}`] = false;
rowData.edit = false;
hasLowerItem ? tableData.value.splice(rIndex + 1, 0, rowData) : tableData.value.splice(rIndex, 1, rowData);
tableField.value[3].visible = true;
getMergeRow();
......@@ -467,7 +478,7 @@ const btnClick = async (btn, bType = null) => {
const row = btn.row;
const { rIndex, level } = row;
const inputVal = type == 'edit' ? row[`name${level}`] : '';
let isChange = false, rowList = tableData.value.filter(t => t[`code${level - 1}`] == row[`code${level - 1}`]);
let isChange = false, rowList = type == 'add-same' ? tableData.value.filter(t => t[`code${level - 1}`] == row[`code${level - 1}`]) : tableData.value.filter(t => t[`code${level}`] == row[`code${level}`]);
ElMessageBox.prompt('', '节点名称', {
confirmButtonText: '确定',
cancelButtonText: '取消',
......@@ -488,7 +499,7 @@ const btnClick = async (btn, bType = null) => {
if (name.length > 10) {
return '节点名称长度不能超过10个字符'
}
const isExist = rowList.find(a => a[`name${level}`] == name);
const isExist = rowList.find(a => type == 'add-same' ? a[`name${level}`] == name : a[`name${level + 1}`] == name);
if (isExist) {
return '节点名称已存在,请填写其他名称'
}
......@@ -516,7 +527,7 @@ const btnClick = async (btn, bType = null) => {
const name = value.trim();
if (type == 'edit') {
if (value == inputVal) return
setName(name, level);
setName(name, level, rIndex);
} else if (type == 'add-same') {
const tData = rowList.at(-1);
const tIndex = tableData.value.findIndex(t => (tData.code4 ? t.code4 === tData.code4 : t.code3 === tData.code3));
......@@ -552,12 +563,17 @@ const btnClick = async (btn, bType = null) => {
tableData.value.splice(rIndex, 1);
}
} else {
let rowData = tableData.value[rIndex];
delete rowData[`name${level}`];
delete rowData[`code${level}`];
const level4 = tableData.value.find(t => t.code4);
!level4 && (tableField.value.at(-2).visible = false);
const peerList = tableData.value.filter(t => t[`code${level - 1}`] == row[`code${level - 1}`]);
if (peerList.length > 1) {
tableData.value.splice(rIndex, 1);
} else {
let rowData = tableData.value[rIndex];
delete rowData[`name${level}`];
delete rowData[`code${level}`];
}
}
const level4 = tableData.value.find(t => t.code4);
!level4 && (tableField.value[3].visible = false);
getMergeRow();
}).catch(() => {
ElMessage({
......@@ -912,21 +928,50 @@ const s2ab = (s) => {
return buf;
}
// 定义边框样式 - 实线边框
const borderStyle = {
top: { style: 'thin', color: { rgb: 'D9D9D9' } },
bottom: { style: 'thin', color: { rgb: 'D9D9D9' } },
left: { style: 'thin', color: { rgb: 'D9D9D9' } },
right: { style: 'thin', color: { rgb: 'D9D9D9' } }
};
// 字体配置
const defaultFont = {
name: '宋体', // 字体名称
sz: 14 * 0.75, // 字体大小(磅)
color: { rgb: '212121' } // 黑色
};
// 设置行高(单位:磅,1px≈0.75磅)
const defaultRowHeightInPx = 36; // 默认行高36px
const headerRowHeightInPx = 32; // 表头行高32px
// 生成成本设置表
const exportDetailsToExcel = async () => {
// 准备工作表数据
const wsData = []
let wsData = [], fields: any = [];
tableField.value.map(f => {
if (f.visible || f.field.indexOf('name') == -1) {
if (f.field == 'name4') {
const exist4 = checkedData.value.find(c => c.code4)
exist4 && fields.push(f)
} else {
fields.push(f)
}
}
});
// 表头
const headers = tableField.value.map(item => item.label)
const headers = fields.map(item => item.label)
wsData.push(headers)
// 处理数据行
checkedData.value.forEach(item => {
const row = tableField.value.map(f => {
const row = fields.map(f => {
if (f.field.indexOf('name') == -1) {
// 分类字段
return changeNum(item[f.field])
return changeNum(item[f.field], 2, true)
} else {
// 其他字段
return item[f.field] || ''
......@@ -937,7 +982,7 @@ const exportDetailsToExcel = async () => {
// 添加合计行
const totalRow = ['合计', '', '', ''];
const numField = tableField.value.filter(item => item.field.indexOf('name') == -1);
const numField = fields.filter(item => item.field.indexOf('name') == -1);
const numericFields = numField.map(f => f.field);
let totalValues = {}
......@@ -957,7 +1002,7 @@ const exportDetailsToExcel = async () => {
})
// 将合计值添加到合计行
tableField.value.forEach((field, index) => {
fields.forEach((field, index) => {
if (index < 4) return // 前4列已经处理
if (numericFields.includes(field.field)) {
const value = totalValues[field.field]
......@@ -974,16 +1019,31 @@ const exportDetailsToExcel = async () => {
const ws = XLSXS.utils.aoa_to_sheet(wsData)
// 自动调整列宽
const colWidths = tableField.value.map((field, index) => {
const colWidths = fields.map((field, index) => {
const defaultWidth = field.width || 100 // 默认宽度100
const colWidth = defaultWidth / 14 + 2; // 留一些余地
const colWidth = defaultWidth * 0.75; // 留一些余地
// 取表头宽度和内容宽度的较大值
return { wpx: colWidth * 12 } // 使用像素宽度
return { wpx: colWidth } // 使用像素宽度
})
ws['!cols'] = colWidths
// 转换为磅(Excel使用磅作为单位)
const defaultRowHeight = defaultRowHeightInPx * 0.75;
const headerRowHeight = headerRowHeightInPx * 0.75;
// 初始化行高设置
ws['!rows'] = [];
// 设置表头行高
ws['!rows'][0] = { hpt: headerRowHeight, customHeight: true };
// 设置数据行高
for (let i = 1; i < wsData.length; i++) {
ws['!rows'][i] = { hpt: defaultRowHeight, customHeight: true };
}
// 设置合并单元格
const merges = []
......@@ -1025,13 +1085,16 @@ const exportDetailsToExcel = async () => {
alignment: {
vertical: 'center',
horizontal: 'left'
}
},
font: defaultFont,
border: borderStyle // 添加边框样式
}
// 表头样式
if (R === 0) {
ws[cellAddress].s = {
...defaultStyle,
fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选)
}
continue
}
......@@ -1050,7 +1113,7 @@ const exportDetailsToExcel = async () => {
// 数据行样式
const fieldIndex = C
const field = tableField.value[fieldIndex]
const field = fields[fieldIndex]
// 数值列右对齐
if (numericFields.includes(field.field)) {
......@@ -1097,7 +1160,7 @@ const exportBookToExcel = async () => {
const row = bookHeaders.value.map(f => {
if (f.field.indexOf('title') == -1) {
// 分类字段
return changeNum(item[f.field])
return changeNum(item[f.field], 2, true)
} else {
// 其他字段
return item[f.field] || ''
......@@ -1112,14 +1175,29 @@ const exportBookToExcel = async () => {
// 自动调整列宽
const colWidths = bookHeaders.value.map((field, index) => {
const defaultWidth = field.width || 100 // 默认宽度100
const colWidth = defaultWidth / 14 + 2; // 留一些余地
const colWidth = defaultWidth * 0.75; // 留一些余地
// 取表头宽度和内容宽度的较大值
return { wpx: colWidth * 12 } // 使用像素宽度
return { wpx: colWidth } // 使用像素宽度
})
ws['!cols'] = colWidths
// 转换为磅(Excel使用磅作为单位)
const defaultRowHeight = defaultRowHeightInPx * 0.75;
const headerRowHeight = headerRowHeightInPx * 0.75;
// 初始化行高设置
ws['!rows'] = [];
// 设置表头行高
ws['!rows'][0] = { hpt: headerRowHeight, customHeight: true };
// 设置数据行高
for (let i = 1; i < wsData.length; i++) {
ws['!rows'][i] = { hpt: defaultRowHeight, customHeight: true };
}
// 设置单元格样式
const range = XLSXS.utils.decode_range(ws['!ref'])
// 数值字段(除title外的所有字段)
......@@ -1139,14 +1217,16 @@ const exportBookToExcel = async () => {
alignment: {
vertical: 'center',
horizontal: 'left'
}
},
font: defaultFont,
border: borderStyle // 添加边框样式
}
// 表头样式(第1行)
if (R === 0) {
ws[cellAddress].s = {
...defaultStyle,
// font: { bold: true } // 表头加粗
fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选)
}
continue
}
......@@ -1161,10 +1241,11 @@ const exportBookToExcel = async () => {
// 数值列特殊处理(无论是否最后一行)
if (isNumeric) {
ws[cellAddress].s = {
...defaultStyle,
alignment: {
vertical: 'center',
horizontal: 'right'
}
},
};
// 确保数值被正确识别为数字类型
......@@ -1327,11 +1408,11 @@ onUpdated(() => {
<span>{{ setLabel(row.title) }}</span>
</template>
</el-table-column> -->
<el-table-column v-for="(item, index) in bookHeaders" :key="index" :prop="item.field" :label="item.label"
:width="item.width" :align="item.align">
<el-table-column v-for="(item, index) in bookHeaders" :key="index" :prop="item.field"
:label="item.label" :width="item.width" :align="item.align">
<template #default="scope">
<span v-if="item.field == 'title'">{{ setLabel(scope.row[item.field]) }}</span>
<span v-else>{{ changeNum(scope.row[item.field], 2) }}</span>
<span v-else>{{ changeNum(scope.row[item.field], 2, true) }}</span>
</template>
<!-- <template v-slot:header>
<span v-html="item.label"></span>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!