2e7924af by lxs

入表功调整

1 parent 8e00cd08
...@@ -11,6 +11,7 @@ import { changeNum } from "@/utils/common"; ...@@ -11,6 +11,7 @@ import { changeNum } from "@/utils/common";
11 import { costDelete, getAssetCatalog, getCostList, sendEntryMsg } from "@/api/modules/dataEntry"; 11 import { costDelete, getAssetCatalog, getCostList, sendEntryMsg } from "@/api/modules/dataEntry";
12 import * as XLSXS from 'xlsx-js-style'; 12 import * as XLSXS from 'xlsx-js-style';
13 import { saveAs } from 'file-saver'; 13 import { saveAs } from 'file-saver';
14 import { t } from "@wangeditor/editor";
14 15
15 const { proxy } = getCurrentInstance() as any; 16 const { proxy } = getCurrentInstance() as any;
16 const userStore = useUserStore(); 17 const userStore = useUserStore();
...@@ -226,9 +227,9 @@ const convertConfig = { ...@@ -226,9 +227,9 @@ const convertConfig = {
226 } 227 }
227 const costTableRef = ref(null); 228 const costTableRef = ref(null);
228 const initField: any = ref([ 229 const initField: any = ref([
229 { label: "一级指标", field: "name1", level: 1, width: 120 }, 230 { label: "一级指标", field: "name1", level: 1, width: 120, visible: true },
230 { label: "一级分类", field: "name2", level: 2, width: 120 }, 231 { label: "一级分类", field: "name2", level: 2, width: 120, visible: true },
231 { label: "二级分类", field: "name3", level: 3, width: 200 }, 232 { label: "二级分类", field: "name3", level: 3, width: 200, visible: true },
232 { label: "三级分类", field: "name4", level: 4, width: 200, visible: false }, 233 { label: "三级分类", field: "name4", level: 4, width: 200, visible: false },
233 { 234 {
234 label: "累计投入", field: "total", width: 120, align: 'right', visible: false, columClass: 'inverse_cell', getName: (scope) => { 235 label: "累计投入", field: "total", width: 120, align: 'right', visible: false, columClass: 'inverse_cell', getName: (scope) => {
...@@ -241,6 +242,7 @@ const tableData: any = ref([]) ...@@ -241,6 +242,7 @@ const tableData: any = ref([])
241 const besure = ref(false); 242 const besure = ref(false);
242 const mergeRowCount: any = ref({}); 243 const mergeRowCount: any = ref({});
243 const checkedData: any = ref([]); 244 const checkedData: any = ref([]);
245 const checkedField: any = ref([]);
244 246
245 const entryItem = { 247 const entryItem = {
246 year: '', 248 year: '',
...@@ -427,8 +429,7 @@ const inputEventChange = (val, scope, field) => { ...@@ -427,8 +429,7 @@ const inputEventChange = (val, scope, field) => {
427 } 429 }
428 430
429 // 重命名 431 // 重命名
430 const setName = (name, level) => { 432 const setName = (name, level, rIndex) => {
431 const rIndex = currentRow.value.$index;
432 let rowData = tableData.value[rIndex]; 433 let rowData = tableData.value[rIndex];
433 rowData[`name${level}`] = name; 434 rowData[`name${level}`] = name;
434 } 435 }
...@@ -439,8 +440,12 @@ const addSameData = (rIndex, name, level, tData) => { ...@@ -439,8 +440,12 @@ const addSameData = (rIndex, name, level, tData) => {
439 const lastCode = rowData[`code${level - 1}`]; 440 const lastCode = rowData[`code${level - 1}`];
440 const tCode = tData[`code${level}`].split(lastCode)[1]; 441 const tCode = tData[`code${level}`].split(lastCode)[1];
441 const codeVal = parseInt(tCode, 10) < 10 ? `0${parseInt(tCode, 10) + 1}` : parseInt(tCode, 10) + 1; 442 const codeVal = parseInt(tCode, 10) < 10 ? `0${parseInt(tCode, 10) + 1}` : parseInt(tCode, 10) + 1;
443 for (var r in rowData) {
444 if (r.indexOf('name') == -1 && r.indexOf('code') == -1) rowData[r] = '';
445 }
442 rowData[`name${level}`] = name; 446 rowData[`name${level}`] = name;
443 rowData[`code${level}`] = `${lastCode}${codeVal}`; 447 rowData[`code${level}`] = `${lastCode}${codeVal}`;
448 rowData[`checked${level}`] = false;
444 delete rowData.name4; 449 delete rowData.name4;
445 delete rowData.code4; 450 delete rowData.code4;
446 tableData.value.splice(rIndex + 1, 0, rowData); 451 tableData.value.splice(rIndex + 1, 0, rowData);
...@@ -453,8 +458,14 @@ const addLowerData = (rIndex, name, level, len) => { ...@@ -453,8 +458,14 @@ const addLowerData = (rIndex, name, level, len) => {
453 const hasLowerItem = rowData[`code${level + 1}`] ? true : false; 458 const hasLowerItem = rowData[`code${level + 1}`] ? true : false;
454 const lastCode = rowData[`code${level}`]; 459 const lastCode = rowData[`code${level}`];
455 const codeVal = (len + 1) < 10 ? '0' + (len + 1) : len + 1; 460 const codeVal = (len + 1) < 10 ? '0' + (len + 1) : len + 1;
461 for (var r in rowData) {
462 if (r.indexOf('name') == -1 && r.indexOf('code') == -1) rowData[r] = '';
463 }
456 rowData[`name${level + 1}`] = name; 464 rowData[`name${level + 1}`] = name;
457 rowData[`code${level + 1}`] = `${lastCode}${codeVal}`; 465 rowData[`code${level + 1}`] = `${lastCode}${codeVal}`;
466 rowData[`checked${level + 1}`] = false;
467 rowData.edit = false;
468
458 hasLowerItem ? tableData.value.splice(rIndex + 1, 0, rowData) : tableData.value.splice(rIndex, 1, rowData); 469 hasLowerItem ? tableData.value.splice(rIndex + 1, 0, rowData) : tableData.value.splice(rIndex, 1, rowData);
459 tableField.value[3].visible = true; 470 tableField.value[3].visible = true;
460 getMergeRow(); 471 getMergeRow();
...@@ -467,7 +478,7 @@ const btnClick = async (btn, bType = null) => { ...@@ -467,7 +478,7 @@ const btnClick = async (btn, bType = null) => {
467 const row = btn.row; 478 const row = btn.row;
468 const { rIndex, level } = row; 479 const { rIndex, level } = row;
469 const inputVal = type == 'edit' ? row[`name${level}`] : ''; 480 const inputVal = type == 'edit' ? row[`name${level}`] : '';
470 let isChange = false, rowList = tableData.value.filter(t => t[`code${level - 1}`] == row[`code${level - 1}`]); 481 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}`]);
471 ElMessageBox.prompt('', '节点名称', { 482 ElMessageBox.prompt('', '节点名称', {
472 confirmButtonText: '确定', 483 confirmButtonText: '确定',
473 cancelButtonText: '取消', 484 cancelButtonText: '取消',
...@@ -488,7 +499,7 @@ const btnClick = async (btn, bType = null) => { ...@@ -488,7 +499,7 @@ const btnClick = async (btn, bType = null) => {
488 if (name.length > 10) { 499 if (name.length > 10) {
489 return '节点名称长度不能超过10个字符' 500 return '节点名称长度不能超过10个字符'
490 } 501 }
491 const isExist = rowList.find(a => a[`name${level}`] == name); 502 const isExist = rowList.find(a => type == 'add-same' ? a[`name${level}`] == name : a[`name${level + 1}`] == name);
492 if (isExist) { 503 if (isExist) {
493 return '节点名称已存在,请填写其他名称' 504 return '节点名称已存在,请填写其他名称'
494 } 505 }
...@@ -516,7 +527,7 @@ const btnClick = async (btn, bType = null) => { ...@@ -516,7 +527,7 @@ const btnClick = async (btn, bType = null) => {
516 const name = value.trim(); 527 const name = value.trim();
517 if (type == 'edit') { 528 if (type == 'edit') {
518 if (value == inputVal) return 529 if (value == inputVal) return
519 setName(name, level); 530 setName(name, level, rIndex);
520 } else if (type == 'add-same') { 531 } else if (type == 'add-same') {
521 const tData = rowList.at(-1); 532 const tData = rowList.at(-1);
522 const tIndex = tableData.value.findIndex(t => (tData.code4 ? t.code4 === tData.code4 : t.code3 === tData.code3)); 533 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) => { ...@@ -552,12 +563,17 @@ const btnClick = async (btn, bType = null) => {
552 tableData.value.splice(rIndex, 1); 563 tableData.value.splice(rIndex, 1);
553 } 564 }
554 } else { 565 } else {
555 let rowData = tableData.value[rIndex]; 566 const peerList = tableData.value.filter(t => t[`code${level - 1}`] == row[`code${level - 1}`]);
556 delete rowData[`name${level}`]; 567 if (peerList.length > 1) {
557 delete rowData[`code${level}`]; 568 tableData.value.splice(rIndex, 1);
558 const level4 = tableData.value.find(t => t.code4); 569 } else {
559 !level4 && (tableField.value.at(-2).visible = false); 570 let rowData = tableData.value[rIndex];
571 delete rowData[`name${level}`];
572 delete rowData[`code${level}`];
573 }
560 } 574 }
575 const level4 = tableData.value.find(t => t.code4);
576 !level4 && (tableField.value[3].visible = false);
561 getMergeRow(); 577 getMergeRow();
562 }).catch(() => { 578 }).catch(() => {
563 ElMessage({ 579 ElMessage({
...@@ -912,21 +928,50 @@ const s2ab = (s) => { ...@@ -912,21 +928,50 @@ const s2ab = (s) => {
912 return buf; 928 return buf;
913 } 929 }
914 930
931 // 定义边框样式 - 实线边框
932 const borderStyle = {
933 top: { style: 'thin', color: { rgb: 'D9D9D9' } },
934 bottom: { style: 'thin', color: { rgb: 'D9D9D9' } },
935 left: { style: 'thin', color: { rgb: 'D9D9D9' } },
936 right: { style: 'thin', color: { rgb: 'D9D9D9' } }
937 };
938
939 // 字体配置
940 const defaultFont = {
941 name: '宋体', // 字体名称
942 sz: 14 * 0.75, // 字体大小(磅)
943 color: { rgb: '212121' } // 黑色
944 };
945
946 // 设置行高(单位:磅,1px≈0.75磅)
947 const defaultRowHeightInPx = 36; // 默认行高36px
948 const headerRowHeightInPx = 32; // 表头行高32px
949
915 // 生成成本设置表 950 // 生成成本设置表
916 const exportDetailsToExcel = async () => { 951 const exportDetailsToExcel = async () => {
917 // 准备工作表数据 952 // 准备工作表数据
918 const wsData = [] 953 let wsData = [], fields: any = [];
954 tableField.value.map(f => {
955 if (f.visible || f.field.indexOf('name') == -1) {
956 if (f.field == 'name4') {
957 const exist4 = checkedData.value.find(c => c.code4)
958 exist4 && fields.push(f)
959 } else {
960 fields.push(f)
961 }
962 }
963 });
919 964
920 // 表头 965 // 表头
921 const headers = tableField.value.map(item => item.label) 966 const headers = fields.map(item => item.label)
922 wsData.push(headers) 967 wsData.push(headers)
923 968
924 // 处理数据行 969 // 处理数据行
925 checkedData.value.forEach(item => { 970 checkedData.value.forEach(item => {
926 const row = tableField.value.map(f => { 971 const row = fields.map(f => {
927 if (f.field.indexOf('name') == -1) { 972 if (f.field.indexOf('name') == -1) {
928 // 分类字段 973 // 分类字段
929 return changeNum(item[f.field]) 974 return changeNum(item[f.field], 2, true)
930 } else { 975 } else {
931 // 其他字段 976 // 其他字段
932 return item[f.field] || '' 977 return item[f.field] || ''
...@@ -937,7 +982,7 @@ const exportDetailsToExcel = async () => { ...@@ -937,7 +982,7 @@ const exportDetailsToExcel = async () => {
937 982
938 // 添加合计行 983 // 添加合计行
939 const totalRow = ['合计', '', '', '']; 984 const totalRow = ['合计', '', '', ''];
940 const numField = tableField.value.filter(item => item.field.indexOf('name') == -1); 985 const numField = fields.filter(item => item.field.indexOf('name') == -1);
941 const numericFields = numField.map(f => f.field); 986 const numericFields = numField.map(f => f.field);
942 let totalValues = {} 987 let totalValues = {}
943 988
...@@ -957,7 +1002,7 @@ const exportDetailsToExcel = async () => { ...@@ -957,7 +1002,7 @@ const exportDetailsToExcel = async () => {
957 }) 1002 })
958 1003
959 // 将合计值添加到合计行 1004 // 将合计值添加到合计行
960 tableField.value.forEach((field, index) => { 1005 fields.forEach((field, index) => {
961 if (index < 4) return // 前4列已经处理 1006 if (index < 4) return // 前4列已经处理
962 if (numericFields.includes(field.field)) { 1007 if (numericFields.includes(field.field)) {
963 const value = totalValues[field.field] 1008 const value = totalValues[field.field]
...@@ -974,16 +1019,31 @@ const exportDetailsToExcel = async () => { ...@@ -974,16 +1019,31 @@ const exportDetailsToExcel = async () => {
974 const ws = XLSXS.utils.aoa_to_sheet(wsData) 1019 const ws = XLSXS.utils.aoa_to_sheet(wsData)
975 1020
976 // 自动调整列宽 1021 // 自动调整列宽
977 const colWidths = tableField.value.map((field, index) => { 1022 const colWidths = fields.map((field, index) => {
978 const defaultWidth = field.width || 100 // 默认宽度100 1023 const defaultWidth = field.width || 100 // 默认宽度100
979 const colWidth = defaultWidth / 14 + 2; // 留一些余地 1024 const colWidth = defaultWidth * 0.75; // 留一些余地
980 1025
981 // 取表头宽度和内容宽度的较大值 1026 // 取表头宽度和内容宽度的较大值
982 return { wpx: colWidth * 12 } // 使用像素宽度 1027 return { wpx: colWidth } // 使用像素宽度
983 }) 1028 })
984 1029
985 ws['!cols'] = colWidths 1030 ws['!cols'] = colWidths
986 1031
1032 // 转换为磅(Excel使用磅作为单位)
1033 const defaultRowHeight = defaultRowHeightInPx * 0.75;
1034 const headerRowHeight = headerRowHeightInPx * 0.75;
1035
1036 // 初始化行高设置
1037 ws['!rows'] = [];
1038
1039 // 设置表头行高
1040 ws['!rows'][0] = { hpt: headerRowHeight, customHeight: true };
1041
1042 // 设置数据行高
1043 for (let i = 1; i < wsData.length; i++) {
1044 ws['!rows'][i] = { hpt: defaultRowHeight, customHeight: true };
1045 }
1046
987 // 设置合并单元格 1047 // 设置合并单元格
988 const merges = [] 1048 const merges = []
989 1049
...@@ -1025,13 +1085,16 @@ const exportDetailsToExcel = async () => { ...@@ -1025,13 +1085,16 @@ const exportDetailsToExcel = async () => {
1025 alignment: { 1085 alignment: {
1026 vertical: 'center', 1086 vertical: 'center',
1027 horizontal: 'left' 1087 horizontal: 'left'
1028 } 1088 },
1089 font: defaultFont,
1090 border: borderStyle // 添加边框样式
1029 } 1091 }
1030 1092
1031 // 表头样式 1093 // 表头样式
1032 if (R === 0) { 1094 if (R === 0) {
1033 ws[cellAddress].s = { 1095 ws[cellAddress].s = {
1034 ...defaultStyle, 1096 ...defaultStyle,
1097 fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选)
1035 } 1098 }
1036 continue 1099 continue
1037 } 1100 }
...@@ -1050,7 +1113,7 @@ const exportDetailsToExcel = async () => { ...@@ -1050,7 +1113,7 @@ const exportDetailsToExcel = async () => {
1050 1113
1051 // 数据行样式 1114 // 数据行样式
1052 const fieldIndex = C 1115 const fieldIndex = C
1053 const field = tableField.value[fieldIndex] 1116 const field = fields[fieldIndex]
1054 1117
1055 // 数值列右对齐 1118 // 数值列右对齐
1056 if (numericFields.includes(field.field)) { 1119 if (numericFields.includes(field.field)) {
...@@ -1097,7 +1160,7 @@ const exportBookToExcel = async () => { ...@@ -1097,7 +1160,7 @@ const exportBookToExcel = async () => {
1097 const row = bookHeaders.value.map(f => { 1160 const row = bookHeaders.value.map(f => {
1098 if (f.field.indexOf('title') == -1) { 1161 if (f.field.indexOf('title') == -1) {
1099 // 分类字段 1162 // 分类字段
1100 return changeNum(item[f.field]) 1163 return changeNum(item[f.field], 2, true)
1101 } else { 1164 } else {
1102 // 其他字段 1165 // 其他字段
1103 return item[f.field] || '' 1166 return item[f.field] || ''
...@@ -1112,14 +1175,29 @@ const exportBookToExcel = async () => { ...@@ -1112,14 +1175,29 @@ const exportBookToExcel = async () => {
1112 // 自动调整列宽 1175 // 自动调整列宽
1113 const colWidths = bookHeaders.value.map((field, index) => { 1176 const colWidths = bookHeaders.value.map((field, index) => {
1114 const defaultWidth = field.width || 100 // 默认宽度100 1177 const defaultWidth = field.width || 100 // 默认宽度100
1115 const colWidth = defaultWidth / 14 + 2; // 留一些余地 1178 const colWidth = defaultWidth * 0.75; // 留一些余地
1116 1179
1117 // 取表头宽度和内容宽度的较大值 1180 // 取表头宽度和内容宽度的较大值
1118 return { wpx: colWidth * 12 } // 使用像素宽度 1181 return { wpx: colWidth } // 使用像素宽度
1119 }) 1182 })
1120 1183
1121 ws['!cols'] = colWidths 1184 ws['!cols'] = colWidths
1122 1185
1186 // 转换为磅(Excel使用磅作为单位)
1187 const defaultRowHeight = defaultRowHeightInPx * 0.75;
1188 const headerRowHeight = headerRowHeightInPx * 0.75;
1189
1190 // 初始化行高设置
1191 ws['!rows'] = [];
1192
1193 // 设置表头行高
1194 ws['!rows'][0] = { hpt: headerRowHeight, customHeight: true };
1195
1196 // 设置数据行高
1197 for (let i = 1; i < wsData.length; i++) {
1198 ws['!rows'][i] = { hpt: defaultRowHeight, customHeight: true };
1199 }
1200
1123 // 设置单元格样式 1201 // 设置单元格样式
1124 const range = XLSXS.utils.decode_range(ws['!ref']) 1202 const range = XLSXS.utils.decode_range(ws['!ref'])
1125 // 数值字段(除title外的所有字段) 1203 // 数值字段(除title外的所有字段)
...@@ -1139,14 +1217,16 @@ const exportBookToExcel = async () => { ...@@ -1139,14 +1217,16 @@ const exportBookToExcel = async () => {
1139 alignment: { 1217 alignment: {
1140 vertical: 'center', 1218 vertical: 'center',
1141 horizontal: 'left' 1219 horizontal: 'left'
1142 } 1220 },
1221 font: defaultFont,
1222 border: borderStyle // 添加边框样式
1143 } 1223 }
1144 1224
1145 // 表头样式(第1行) 1225 // 表头样式(第1行)
1146 if (R === 0) { 1226 if (R === 0) {
1147 ws[cellAddress].s = { 1227 ws[cellAddress].s = {
1148 ...defaultStyle, 1228 ...defaultStyle,
1149 // font: { bold: true } // 表头加粗 1229 fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选)
1150 } 1230 }
1151 continue 1231 continue
1152 } 1232 }
...@@ -1161,10 +1241,11 @@ const exportBookToExcel = async () => { ...@@ -1161,10 +1241,11 @@ const exportBookToExcel = async () => {
1161 // 数值列特殊处理(无论是否最后一行) 1241 // 数值列特殊处理(无论是否最后一行)
1162 if (isNumeric) { 1242 if (isNumeric) {
1163 ws[cellAddress].s = { 1243 ws[cellAddress].s = {
1244 ...defaultStyle,
1164 alignment: { 1245 alignment: {
1165 vertical: 'center', 1246 vertical: 'center',
1166 horizontal: 'right' 1247 horizontal: 'right'
1167 } 1248 },
1168 }; 1249 };
1169 1250
1170 // 确保数值被正确识别为数字类型 1251 // 确保数值被正确识别为数字类型
...@@ -1327,11 +1408,11 @@ onUpdated(() => { ...@@ -1327,11 +1408,11 @@ onUpdated(() => {
1327 <span>{{ setLabel(row.title) }}</span> 1408 <span>{{ setLabel(row.title) }}</span>
1328 </template> 1409 </template>
1329 </el-table-column> --> 1410 </el-table-column> -->
1330 <el-table-column v-for="(item, index) in bookHeaders" :key="index" :prop="item.field" :label="item.label" 1411 <el-table-column v-for="(item, index) in bookHeaders" :key="index" :prop="item.field"
1331 :width="item.width" :align="item.align"> 1412 :label="item.label" :width="item.width" :align="item.align">
1332 <template #default="scope"> 1413 <template #default="scope">
1333 <span v-if="item.field == 'title'">{{ setLabel(scope.row[item.field]) }}</span> 1414 <span v-if="item.field == 'title'">{{ setLabel(scope.row[item.field]) }}</span>
1334 <span v-else>{{ changeNum(scope.row[item.field], 2) }}</span> 1415 <span v-else>{{ changeNum(scope.row[item.field], 2, true) }}</span>
1335 </template> 1416 </template>
1336 <!-- <template v-slot:header> 1417 <!-- <template v-slot:header>
1337 <span v-html="item.label"></span> 1418 <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!