入表功能调整
Showing
1 changed file
with
49 additions
and
50 deletions
| ... | @@ -299,7 +299,13 @@ const getCostData = () => { | ... | @@ -299,7 +299,13 @@ const getCostData = () => { |
| 299 | loading.value = true; | 299 | loading.value = true; |
| 300 | getCostList().then((res: any) => { | 300 | getCostList().then((res: any) => { |
| 301 | loading.value = false; | 301 | loading.value = false; |
| 302 | tableData.value = res.data || []; | 302 | const data = res.data || []; |
| 303 | tableData.value = data.map(item => { | ||
| 304 | item.checked1 = false; | ||
| 305 | item.checked2 = false; | ||
| 306 | item.checked3 = false; | ||
| 307 | return item; | ||
| 308 | }) | ||
| 303 | getMergeRow(); | 309 | getMergeRow(); |
| 304 | }).catch((res) => { | 310 | }).catch((res) => { |
| 305 | loading.value = false; | 311 | loading.value = false; |
| ... | @@ -736,7 +742,7 @@ const setTableFields = (info) => { | ... | @@ -736,7 +742,7 @@ const setTableFields = (info) => { |
| 736 | } | 742 | } |
| 737 | arrYear.forEach(item => { | 743 | arrYear.forEach(item => { |
| 738 | const field = `${item}`; | 744 | const field = `${item}`; |
| 739 | fields.push({ label: `${item}年`, field: field, type: 'input', width: 100, columClass: 'edit_cell' },) | 745 | fields.push({ label: `${item}年`, field: field, type: 'input', width: 100, align: 'right', columClass: 'edit_cell' },) |
| 740 | row[field] = ''; | 746 | row[field] = ''; |
| 741 | }) | 747 | }) |
| 742 | costFileds.value = row; | 748 | costFileds.value = row; |
| ... | @@ -744,7 +750,7 @@ const setTableFields = (info) => { | ... | @@ -744,7 +750,7 @@ const setTableFields = (info) => { |
| 744 | const currDay = date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long' }); | 750 | const currDay = date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long' }); |
| 745 | tableField.value.at(-1).visible = true; | 751 | tableField.value.at(-1).visible = true; |
| 746 | tableField.value = tableField.value.filter(item => item.field.indexOf('name') > -1 || item.field == 'total'); | 752 | tableField.value = tableField.value.filter(item => item.field.indexOf('name') > -1 || item.field == 'total'); |
| 747 | tableField.value.splice(-1, 0, ...fields, { label: currDay, field: 'baseNum', type: 'input', width: 120, columClass: 'edit_cell' }); | 753 | tableField.value.splice(-1, 0, ...fields, { label: currDay, field: 'baseNum', type: 'input', width: 120, align: 'right', columClass: 'edit_cell' }); |
| 748 | // 设置table数据 | 754 | // 设置table数据 |
| 749 | let datas: any = []; | 755 | let datas: any = []; |
| 750 | tableData.value.map(t => { | 756 | tableData.value.map(t => { |
| ... | @@ -930,10 +936,10 @@ const s2ab = (s) => { | ... | @@ -930,10 +936,10 @@ const s2ab = (s) => { |
| 930 | 936 | ||
| 931 | // 定义边框样式 - 实线边框 | 937 | // 定义边框样式 - 实线边框 |
| 932 | const borderStyle = { | 938 | const borderStyle = { |
| 933 | top: { style: 'thin', color: { rgb: 'D9D9D9' } }, | 939 | top: { style: 'thin', color: { rgb: '888888' } }, |
| 934 | bottom: { style: 'thin', color: { rgb: 'D9D9D9' } }, | 940 | bottom: { style: 'thin', color: { rgb: '888888' } }, |
| 935 | left: { style: 'thin', color: { rgb: 'D9D9D9' } }, | 941 | left: { style: 'thin', color: { rgb: '888888' } }, |
| 936 | right: { style: 'thin', color: { rgb: 'D9D9D9' } } | 942 | right: { style: 'thin', color: { rgb: '888888' } } |
| 937 | }; | 943 | }; |
| 938 | 944 | ||
| 939 | // 字体配置 | 945 | // 字体配置 |
| ... | @@ -966,6 +972,11 @@ const exportDetailsToExcel = async () => { | ... | @@ -966,6 +972,11 @@ const exportDetailsToExcel = async () => { |
| 966 | const headers = fields.map(item => item.label) | 972 | const headers = fields.map(item => item.label) |
| 967 | wsData.push(headers) | 973 | wsData.push(headers) |
| 968 | 974 | ||
| 975 | // 判断哪些列是数值类型 | ||
| 976 | const numField = fields.filter(item => item.field.indexOf('name') == -1); | ||
| 977 | const numericFields = numField.map(f => f.field); | ||
| 978 | const isNumericColumn = fields.map(field => numericFields.includes(field.field)); | ||
| 979 | |||
| 969 | // 处理数据行 | 980 | // 处理数据行 |
| 970 | checkedData.value.forEach(item => { | 981 | checkedData.value.forEach(item => { |
| 971 | const row = fields.map(f => { | 982 | const row = fields.map(f => { |
| ... | @@ -982,8 +993,6 @@ const exportDetailsToExcel = async () => { | ... | @@ -982,8 +993,6 @@ const exportDetailsToExcel = async () => { |
| 982 | 993 | ||
| 983 | // 添加合计行 | 994 | // 添加合计行 |
| 984 | const totalRow = ['合计', '', '', '']; | 995 | const totalRow = ['合计', '', '', '']; |
| 985 | const numField = fields.filter(item => item.field.indexOf('name') == -1); | ||
| 986 | const numericFields = numField.map(f => f.field); | ||
| 987 | let totalValues = {} | 996 | let totalValues = {} |
| 988 | 997 | ||
| 989 | // 初始化合计值 | 998 | // 初始化合计值 |
| ... | @@ -1021,7 +1030,7 @@ const exportDetailsToExcel = async () => { | ... | @@ -1021,7 +1030,7 @@ const exportDetailsToExcel = async () => { |
| 1021 | // 自动调整列宽 | 1030 | // 自动调整列宽 |
| 1022 | const colWidths = fields.map((field, index) => { | 1031 | const colWidths = fields.map((field, index) => { |
| 1023 | const defaultWidth = field.width || 100 // 默认宽度100 | 1032 | const defaultWidth = field.width || 100 // 默认宽度100 |
| 1024 | const colWidth = defaultWidth * 0.75; // 留一些余地 | 1033 | const colWidth = 100 * 0.75; // 留一些余地 |
| 1025 | 1034 | ||
| 1026 | // 取表头宽度和内容宽度的较大值 | 1035 | // 取表头宽度和内容宽度的较大值 |
| 1027 | return { wpx: colWidth } // 使用像素宽度 | 1036 | return { wpx: colWidth } // 使用像素宽度 |
| ... | @@ -1092,8 +1101,14 @@ const exportDetailsToExcel = async () => { | ... | @@ -1092,8 +1101,14 @@ const exportDetailsToExcel = async () => { |
| 1092 | 1101 | ||
| 1093 | // 表头样式 | 1102 | // 表头样式 |
| 1094 | if (R === 0) { | 1103 | if (R === 0) { |
| 1104 | // 如果该列是数值列,则表头也右对齐 | ||
| 1105 | const isNumeric = isNumericColumn[C]; | ||
| 1095 | ws[cellAddress].s = { | 1106 | ws[cellAddress].s = { |
| 1096 | ...defaultStyle, | 1107 | ...defaultStyle, |
| 1108 | alignment: { | ||
| 1109 | vertical: 'center', | ||
| 1110 | horizontal: isNumeric ? 'right' : 'left' | ||
| 1111 | }, | ||
| 1097 | fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选) | 1112 | fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选) |
| 1098 | } | 1113 | } |
| 1099 | continue | 1114 | continue |
| ... | @@ -1105,8 +1120,9 @@ const exportDetailsToExcel = async () => { | ... | @@ -1105,8 +1120,9 @@ const exportDetailsToExcel = async () => { |
| 1105 | ...defaultStyle, | 1120 | ...defaultStyle, |
| 1106 | alignment: { | 1121 | alignment: { |
| 1107 | vertical: 'center', | 1122 | vertical: 'center', |
| 1108 | horizontal: C > 3 ? 'right' : 'left' | 1123 | horizontal: isNumericColumn[C] ? 'right' : 'left' |
| 1109 | } | 1124 | }, |
| 1125 | // fill: { fgColor: { rgb: 'FFF1D4' } } // 合计行背景色(可选) | ||
| 1110 | } | 1126 | } |
| 1111 | continue | 1127 | continue |
| 1112 | } | 1128 | } |
| ... | @@ -1116,7 +1132,7 @@ const exportDetailsToExcel = async () => { | ... | @@ -1116,7 +1132,7 @@ const exportDetailsToExcel = async () => { |
| 1116 | const field = fields[fieldIndex] | 1132 | const field = fields[fieldIndex] |
| 1117 | 1133 | ||
| 1118 | // 数值列右对齐 | 1134 | // 数值列右对齐 |
| 1119 | if (numericFields.includes(field.field)) { | 1135 | if (isNumericColumn[C]) { |
| 1120 | ws[cellAddress].s = { | 1136 | ws[cellAddress].s = { |
| 1121 | ...defaultStyle, | 1137 | ...defaultStyle, |
| 1122 | alignment: { | 1138 | alignment: { |
| ... | @@ -1200,8 +1216,8 @@ const exportBookToExcel = async () => { | ... | @@ -1200,8 +1216,8 @@ const exportBookToExcel = async () => { |
| 1200 | 1216 | ||
| 1201 | // 设置单元格样式 | 1217 | // 设置单元格样式 |
| 1202 | const range = XLSXS.utils.decode_range(ws['!ref']) | 1218 | const range = XLSXS.utils.decode_range(ws['!ref']) |
| 1203 | // 数值字段(除title外的所有字段) | 1219 | // 确定哪些列是数值列(field不包含'title'的列) |
| 1204 | const numericFields = bookHeaders.value.slice(1).map(f => f.field); | 1220 | const isNumericColumn = bookHeaders.value.map(f => f.field.indexOf('title') === -1); |
| 1205 | 1221 | ||
| 1206 | for (let R = range.s.r; R <= range.e.r; ++R) { | 1222 | for (let R = range.s.r; R <= range.e.r; ++R) { |
| 1207 | for (let C = range.s.c; C <= range.e.c; ++C) { | 1223 | for (let C = range.s.c; C <= range.e.c; ++C) { |
| ... | @@ -1222,40 +1238,35 @@ const exportBookToExcel = async () => { | ... | @@ -1222,40 +1238,35 @@ const exportBookToExcel = async () => { |
| 1222 | border: borderStyle // 添加边框样式 | 1238 | border: borderStyle // 添加边框样式 |
| 1223 | } | 1239 | } |
| 1224 | 1240 | ||
| 1241 | // 判断当前列是否为数值列 | ||
| 1242 | const isNumeric = isNumericColumn[C]; | ||
| 1243 | // 数值列的对齐方式 | ||
| 1244 | const alignment = { | ||
| 1245 | vertical: 'center', | ||
| 1246 | horizontal: isNumeric ? 'right' : 'left' | ||
| 1247 | }; | ||
| 1225 | // 表头样式(第1行) | 1248 | // 表头样式(第1行) |
| 1226 | if (R === 0) { | 1249 | if (R === 0) { |
| 1227 | ws[cellAddress].s = { | 1250 | ws[cellAddress].s = { |
| 1228 | ...defaultStyle, | 1251 | ...defaultStyle, |
| 1252 | alignment: alignment, // 使用统一对齐方式 | ||
| 1229 | fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选) | 1253 | fill: { fgColor: { rgb: 'F2F2F2' } } // 表头背景色(可选) |
| 1230 | } | 1254 | } |
| 1231 | continue | 1255 | continue |
| 1232 | } | 1256 | } |
| 1233 | 1257 | ||
| 1234 | // 获取当前列对应的字段 | 1258 | // 数据行样式 |
| 1235 | const field = bookHeaders.value[C]; | ||
| 1236 | |||
| 1237 | // 判断是否为数值列(包括最后一行) | ||
| 1238 | const isNumeric = numericFields.includes(field?.field); | ||
| 1239 | const cellValue = ws[cellAddress].v; | 1259 | const cellValue = ws[cellAddress].v; |
| 1240 | 1260 | ||
| 1241 | // 数值列特殊处理(无论是否最后一行) | 1261 | ws[cellAddress].s = { |
| 1242 | if (isNumeric) { | 1262 | ...defaultStyle, |
| 1243 | ws[cellAddress].s = { | 1263 | alignment: alignment // 使用统一对齐方式 |
| 1244 | ...defaultStyle, | 1264 | }; |
| 1245 | alignment: { | ||
| 1246 | vertical: 'center', | ||
| 1247 | horizontal: 'right' | ||
| 1248 | }, | ||
| 1249 | }; | ||
| 1250 | 1265 | ||
| 1251 | // 确保数值被正确识别为数字类型 | 1266 | // 确保数值被正确识别为数字类型 |
| 1252 | if (cellValue !== undefined && cellValue !== "" && !isNaN(cellValue)) { | 1267 | if (isNumeric && cellValue !== undefined && cellValue !== "" && !isNaN(cellValue)) { |
| 1253 | ws[cellAddress].t = 'n'; // 数字类型 | 1268 | ws[cellAddress].t = 'n'; // 数字类型 |
| 1254 | ws[cellAddress].z = '#,##0.00'; // 数字格式 | 1269 | ws[cellAddress].z = '#,##0.00'; // 数字格式 |
| 1255 | } | ||
| 1256 | } else { | ||
| 1257 | // 文本列保持默认样式 | ||
| 1258 | ws[cellAddress].s = defaultStyle; | ||
| 1259 | } | 1270 | } |
| 1260 | } | 1271 | } |
| 1261 | } | 1272 | } |
| ... | @@ -1373,7 +1384,7 @@ onUpdated(() => { | ... | @@ -1373,7 +1384,7 @@ onUpdated(() => { |
| 1373 | show-overflow-tooltip> | 1384 | show-overflow-tooltip> |
| 1374 | <template #default="scope"> | 1385 | <template #default="scope"> |
| 1375 | <div class="input_cell" v-if="item.type == 'input'"> | 1386 | <div class="input_cell" v-if="item.type == 'input'"> |
| 1376 | <el-input v-model.trim="scope.row[item.field]" placeholder="--" size="small" | 1387 | <el-input v-model.trim="scope.row[item.field]" :placeholder="scope.row.edit?'':'--'" |
| 1377 | :maxlength="item.maxlength ?? ''" @change="(val) => inputChange(val, scope, item.field)" | 1388 | :maxlength="item.maxlength ?? ''" @change="(val) => inputChange(val, scope, item.field)" |
| 1378 | @input="(val) => inputEventChange(val, scope, item.field)" | 1389 | @input="(val) => inputEventChange(val, scope, item.field)" |
| 1379 | :disabled="scope.row.edit ? false : true" clearable></el-input> | 1390 | :disabled="scope.row.edit ? false : true" clearable></el-input> |
| ... | @@ -1403,24 +1414,12 @@ onUpdated(() => { | ... | @@ -1403,24 +1414,12 @@ onUpdated(() => { |
| 1403 | </template> | 1414 | </template> |
| 1404 | </el-table> | 1415 | </el-table> |
| 1405 | <el-table id="entry-table" ref="entryTableRef" :data="transposedData" stripe border v-show="step == 1"> | 1416 | <el-table id="entry-table" ref="entryTableRef" :data="transposedData" stripe border v-show="step == 1"> |
| 1406 | <!-- <el-table-column prop="title" label="项目" :width="140"> | ||
| 1407 | <template v-slot="{ row }"> | ||
| 1408 | <span>{{ setLabel(row.title) }}</span> | ||
| 1409 | </template> | ||
| 1410 | </el-table-column> --> | ||
| 1411 | <el-table-column v-for="(item, index) in bookHeaders" :key="index" :prop="item.field" | 1417 | <el-table-column v-for="(item, index) in bookHeaders" :key="index" :prop="item.field" |
| 1412 | :label="item.label" :width="item.width" :align="item.align"> | 1418 | :label="item.label" :width="item.width" :align="item.align"> |
| 1413 | <template #default="scope"> | 1419 | <template #default="scope"> |
| 1414 | <span v-if="item.field == 'title'">{{ setLabel(scope.row[item.field]) }}</span> | 1420 | <span v-if="item.field == 'title'">{{ setLabel(scope.row[item.field]) }}</span> |
| 1415 | <span v-else>{{ changeNum(scope.row[item.field], 2, true) }}</span> | 1421 | <span v-else>{{ changeNum(scope.row[item.field], 2, true) }}</span> |
| 1416 | </template> | 1422 | </template> |
| 1417 | <!-- <template v-slot:header> | ||
| 1418 | <span v-html="item.label"></span> | ||
| 1419 | </template> | ||
| 1420 | <template v-slot="{ row }"> | ||
| 1421 | <span v-if="typeof row[item.field] == 'number'">{{ changeNum(row[item.field], 2, true) }}</span> | ||
| 1422 | <span v-else></span> | ||
| 1423 | </template> --> | ||
| 1424 | </el-table-column> | 1423 | </el-table-column> |
| 1425 | </el-table> | 1424 | </el-table> |
| 1426 | </div> | 1425 | </div> | ... | ... |
-
Please register or sign in to post a comment