入表功调整
Showing
2 changed files
with
605 additions
and
827 deletions
| ... | @@ -8,10 +8,9 @@ export const getAssetCatalog = (params= {}) => request({ | ... | @@ -8,10 +8,9 @@ export const getAssetCatalog = (params= {}) => request({ |
| 8 | }) | 8 | }) |
| 9 | 9 | ||
| 10 | /** 获取成本项列表 */ | 10 | /** 获取成本项列表 */ |
| 11 | export const getCostList = (params) => request({ | 11 | export const getCostList = () => request({ |
| 12 | url: `${import.meta.env.VITE_API_NEW_PORTAL}/tableentry-index-classify/page-list`, | 12 | url: `${import.meta.env.VITE_API_NEW_PORTAL}/tableentry-index-classify/list`, |
| 13 | method: 'post', | 13 | method: 'post', |
| 14 | data: params | ||
| 15 | }) | 14 | }) |
| 16 | 15 | ||
| 17 | /** 获取成本项详情 */ | 16 | /** 获取成本项详情 */ | ... | ... |
| ... | @@ -6,13 +6,9 @@ | ... | @@ -6,13 +6,9 @@ |
| 6 | import { ref, inject } from "vue"; | 6 | import { ref, inject } from "vue"; |
| 7 | import { ElMessage, ElMessageBox, translate } from "element-plus"; | 7 | import { ElMessage, ElMessageBox, translate } from "element-plus"; |
| 8 | import { MoreFilled } from '@element-plus/icons-vue' | 8 | import { MoreFilled } from '@element-plus/icons-vue' |
| 9 | import StepBar from "@/components/StepBar/index.vue"; | ||
| 10 | import TableTools from "@/components/Tools/table_tools.vue"; | ||
| 11 | import Table from "@/components/Table/index.vue"; | ||
| 12 | import Form from "@/components/Form/index.vue"; | ||
| 13 | import useUserStore from "@/store/modules/user"; | 9 | import useUserStore from "@/store/modules/user"; |
| 14 | import { changeNum } from "@/utils/common"; | 10 | import { changeNum } from "@/utils/common"; |
| 15 | import { getAssetCatalog, getCostList, sendEntryMsg } from "@/api/modules/dataEntry"; | 11 | import { costDelete, getAssetCatalog, getCostList, sendEntryMsg } from "@/api/modules/dataEntry"; |
| 16 | import * as XLSXS from 'xlsx-js-style'; | 12 | import * as XLSXS from 'xlsx-js-style'; |
| 17 | import { saveAs } from 'file-saver'; | 13 | import { saveAs } from 'file-saver'; |
| 18 | 14 | ||
| ... | @@ -20,43 +16,17 @@ const { proxy } = getCurrentInstance() as any; | ... | @@ -20,43 +16,17 @@ const { proxy } = getCurrentInstance() as any; |
| 20 | const userStore = useUserStore(); | 16 | const userStore = useUserStore(); |
| 21 | const userData = JSON.parse(userStore.userData); | 17 | const userData = JSON.parse(userStore.userData); |
| 22 | 18 | ||
| 23 | const itemWidth = ref('56px'); | 19 | const reload: any = inject("reload"); |
| 24 | const itemLeft = ref('-56px'); | ||
| 25 | const reload = inject("reload"); | ||
| 26 | const loading = ref(false); | 20 | const loading = ref(false); |
| 27 | const companyName = ref(''); | 21 | const companyName = ref(''); |
| 28 | /** 默认显示步骤 */ | 22 | /** 默认显示步骤 */ |
| 29 | const step = ref(0); | 23 | const step = ref(0); |
| 30 | /** 步骤条配置信息 */ | ||
| 31 | const stepsInfo = ref({ | ||
| 32 | step: step.value, | ||
| 33 | list: [ | ||
| 34 | { title: '设置成本项', value: 1 }, | ||
| 35 | { title: '填写成本项', value: 2 }, | ||
| 36 | { title: '入表', value: 3 }, | ||
| 37 | ] | ||
| 38 | }) | ||
| 39 | 24 | ||
| 40 | const allMapList = ref([]); | 25 | const showAdd = ref(false); |
| 41 | const showLevel4 = ref(false); | ||
| 42 | const gridList = ref([ | ||
| 43 | { name1: '获取成本', code1: '0', name2: '外购成本', code2: '01', name3: '外购成本', code3: '011' }, | ||
| 44 | { name1: '获取成本', code1: '0', name2: '外购成本', code2: '01', name3: '数据加工', code3: '012' }, | ||
| 45 | { name1: '获取成本', code1: '0', name2: '数据加工', code2: '02', name3: '数据采集', code3: '021' }, | ||
| 46 | { name1: '获取成本', code1: '0', name2: '数据加工', code2: '02', name3: '数据脱敏', code3: '022' }, | ||
| 47 | { name1: '获取成本', code1: '0', name2: '数据加工', code2: '02', name3: '数据清洗', code3: '023' }, | ||
| 48 | { name1: '获取成本', code1: '0', name2: '数据加工', code2: '02', name3: '数据分析', code3: '024' }, | ||
| 49 | { name1: '存储成本', code1: '1', name2: '数据存储', code2: '11', name3: '数据存储成本', code3: '111' }, | ||
| 50 | { name1: '管理成本', code1: '2', name2: '数据维护', code2: '21', name3: '数据质检成本', code3: '211' }, | ||
| 51 | { name1: '管理成本', code1: '2', name2: '数据维护', code2: '21', name3: '数据维护', code3: '212' }, | ||
| 52 | { name1: '管理成本', code1: '2', name2: '数据维护', code2: '21', name3: '采购维护', code3: '213' }, | ||
| 53 | { name1: '管理成本', code1: '2', name2: '数据维护', code2: '21', name3: '采购租赁', code3: '214' }, | ||
| 54 | ]); | ||
| 55 | const checkedList = ref([]); | ||
| 56 | const productList = ref([]); | 26 | const productList = ref([]); |
| 57 | const costFormRef = ref(); | 27 | const costFormRef = ref(); |
| 58 | const entryFormRef = ref(); | 28 | const entryFormRef = ref(); |
| 59 | const costFormInfo = ref({}); | 29 | const costFormInfo: any = ref({}); |
| 60 | const costForm = ref({ | 30 | const costForm = ref({ |
| 61 | id: 'step-form-one', | 31 | id: 'step-form-one', |
| 62 | col: '', | 32 | col: '', |
| ... | @@ -113,7 +83,7 @@ const costForm = ref({ | ... | @@ -113,7 +83,7 @@ const costForm = ref({ |
| 113 | options: [ | 83 | options: [ |
| 114 | { label: '确认', value: 'besure', type: 'primary', style: { height: '32px' } }, | 84 | { label: '确认', value: 'besure', type: 'primary', style: { height: '32px' } }, |
| 115 | ], | 85 | ], |
| 116 | visible: false, | 86 | visible: true, |
| 117 | style: { width: 'unset', 'align-self': 'end', 'margin-right': '0px' } | 87 | style: { width: 'unset', 'align-self': 'end', 'margin-right': '0px' } |
| 118 | }, | 88 | }, |
| 119 | ], | 89 | ], |
| ... | @@ -142,7 +112,7 @@ const costForm = ref({ | ... | @@ -142,7 +112,7 @@ const costForm = ref({ |
| 142 | ] | 112 | ] |
| 143 | } | 113 | } |
| 144 | }); | 114 | }); |
| 145 | const entryForm = ref({ | 115 | const entryForm: any = ref({ |
| 146 | id: 'step-form-two', | 116 | id: 'step-form-two', |
| 147 | col: '', | 117 | col: '', |
| 148 | items: [ | 118 | items: [ |
| ... | @@ -215,15 +185,8 @@ const entryForm = ref({ | ... | @@ -215,15 +185,8 @@ const entryForm = ref({ |
| 215 | }); | 185 | }); |
| 216 | 186 | ||
| 217 | const amount = ref(0); | 187 | const amount = ref(0); |
| 218 | const sumAmount = ref([]); | 188 | const sumAmount: any = ref([]); |
| 219 | const initCheckedList = ref([]); | ||
| 220 | const checkedData = ref([]); | ||
| 221 | const costFileds = ref({}); | 189 | const costFileds = ref({}); |
| 222 | const rowCount = { | ||
| 223 | level1: { index: 0, rowspan: [] }, | ||
| 224 | level2: { index: 0, rowspan: [] }, | ||
| 225 | level3: { index: 0, rowspan: [] }, | ||
| 226 | } | ||
| 227 | const convertConfig = { | 190 | const convertConfig = { |
| 228 | intangible: { | 191 | intangible: { |
| 229 | originName: '一、账面原值', | 192 | originName: '一、账面原值', |
| ... | @@ -262,16 +225,23 @@ const convertConfig = { | ... | @@ -262,16 +225,23 @@ const convertConfig = { |
| 262 | } | 225 | } |
| 263 | } | 226 | } |
| 264 | const costTableRef = ref(null); | 227 | const costTableRef = ref(null); |
| 265 | const isInitField = ref(true); | 228 | const initField: any = ref([ |
| 266 | const initField = ref([]); //第二步初始化的表头数据 | 229 | { label: "一级指标", field: "name1", level: 1, width: 120 }, |
| 267 | const tableField = ref([ | 230 | { label: "一级分类", field: "name2", level: 2, width: 120 }, |
| 268 | { label: "一级指标", field: "name1", width: 120 }, | 231 | { label: "二级分类", field: "name3", level: 3, width: 200 }, |
| 269 | { label: "一级分类", field: "name2", width: 120 }, | 232 | { label: "三级分类", field: "name4", level: 4, width: 200, visible: false }, |
| 270 | { label: "二级分类", field: "name3", width: 120 } | 233 | { |
| 271 | ]); | 234 | label: "累计投入", field: "total", width: 120, align: 'right', visible: false, columClass: 'inverse_cell', getName: (scope) => { |
| 272 | const tableData = ref([]) | 235 | return changeNum(scope.row.total, 2, true); |
| 236 | } | ||
| 237 | }, | ||
| 238 | ]); //第二步初始化的表头数据 | ||
| 239 | const tableField: any = ref([]); | ||
| 240 | const tableData: any = ref([]) | ||
| 273 | const besure = ref(false); | 241 | const besure = ref(false); |
| 274 | const mergeRowCount = ref({}); | 242 | const mergeRowCount: any = ref({}); |
| 243 | const checkedData: any = ref([]); | ||
| 244 | |||
| 275 | const entryItem = { | 245 | const entryItem = { |
| 276 | year: '', | 246 | year: '', |
| 277 | originName: '', | 247 | originName: '', |
| ... | @@ -300,10 +270,17 @@ const entryItem = { | ... | @@ -300,10 +270,17 @@ const entryItem = { |
| 300 | }; | 270 | }; |
| 301 | 271 | ||
| 302 | const entryTableRef = ref(null); | 272 | const entryTableRef = ref(null); |
| 303 | const entryData = [] | 273 | const entryData: any = ref([]); |
| 304 | const headers = ref([]); | 274 | const bookHeaders: any = ref([ |
| 275 | { label: '项目', field: 'title', width: 140, align: 'left' } | ||
| 276 | ]); | ||
| 305 | const transposedData = ref([]); | 277 | const transposedData = ref([]); |
| 306 | 278 | ||
| 279 | const popoverVisible = ref(false); | ||
| 280 | const popoverTriggerRef = ref(null) | ||
| 281 | const currentRow: any = ref({}) | ||
| 282 | |||
| 283 | // 获取产品数据 | ||
| 307 | const getProducts = () => { | 284 | const getProducts = () => { |
| 308 | getAssetCatalog().then((res: any) => { | 285 | getAssetCatalog().then((res: any) => { |
| 309 | if (res.code == proxy.$passCode) { | 286 | if (res.code == proxy.$passCode) { |
| ... | @@ -316,148 +293,100 @@ const getProducts = () => { | ... | @@ -316,148 +293,100 @@ const getProducts = () => { |
| 316 | }) | 293 | }) |
| 317 | } | 294 | } |
| 318 | 295 | ||
| 296 | // 获取原始指标数据 | ||
| 319 | const getCostData = () => { | 297 | const getCostData = () => { |
| 320 | loading.value = true; | 298 | loading.value = true; |
| 321 | getCostList({ | 299 | getCostList().then((res: any) => { |
| 322 | pageIndex: 1, | ||
| 323 | pageSize: -1, | ||
| 324 | }).then((res: any) => { | ||
| 325 | loading.value = false; | 300 | loading.value = false; |
| 326 | const data = res.data.records || []; | 301 | tableData.value = res.data || []; |
| 327 | let levelList = { level1: [], level2: [], level3: [], level4: [] }; | 302 | getMergeRow(); |
| 328 | data.map(item => { | ||
| 329 | item.checked = false; | ||
| 330 | item.children = []; | ||
| 331 | levelList['level' + item.level].push(item); | ||
| 332 | }) | ||
| 333 | levelList.level1.map(l => allMapList.value.push(l)); | ||
| 334 | setAllMapList(levelList, allMapList.value, 2); | ||
| 335 | |||
| 336 | }).catch((res) => { | 303 | }).catch((res) => { |
| 337 | loading.value = false; | 304 | loading.value = false; |
| 338 | }); | 305 | }); |
| 339 | }; | 306 | }; |
| 340 | 307 | ||
| 341 | // 整理成本项数据 | 308 | // 单元格多选框选中监听 |
| 342 | const setAllMapList = (mapObj, arr, level) => { | 309 | const cellCheckboxChange = (val, scope) => { |
| 343 | arr.map(item => { | 310 | const { rIndex, level } = scope; |
| 344 | const code = item.code; | 311 | let rowData = tableData.value[rIndex]; |
| 345 | item.children = mapObj['level' + level].filter(a => a.parentId == code); | 312 | rowData[`checked${level}`] = val; |
| 346 | level < 3 && setAllMapList(mapObj, item.children, level + 1); | ||
| 347 | }) | ||
| 348 | // console.log(allMapList.value); | ||
| 349 | } | ||
| 350 | |||
| 351 | const setStep = async () => { | ||
| 352 | const info = costFormInfo.value; | ||
| 353 | await setFormItems(info, 'cost'); | ||
| 354 | // costForm.value.items[0].disabled = step.value > 0; | ||
| 355 | // costForm.value.items[1].visible = step.value == 1; | ||
| 356 | // costForm.value.items[2].visible = step.value == 1; | ||
| 357 | // costForm.value.items[3].visible = step.value == 1; | ||
| 358 | if (step.value == 1) { | ||
| 359 | setSumRow(); | ||
| 360 | } | ||
| 361 | stepsInfo.value.step = step.value; | ||
| 362 | nextTick(() => { | ||
| 363 | const contentDom = document.getElementsByClassName('content_main'); | ||
| 364 | if (contentDom[0]) { | ||
| 365 | contentDom[0].scrollTo({ | ||
| 366 | behavior: 'smooth', | ||
| 367 | top: 0, | ||
| 368 | }); | ||
| 369 | } | ||
| 370 | }) | ||
| 371 | } | ||
| 372 | |||
| 373 | const checkboxChange = (val, scope, level) => { | ||
| 374 | const { item, grid, child, opt } = scope; | ||
| 375 | let row = {}; | ||
| 376 | switch (level) { | ||
| 377 | case 1: | ||
| 378 | row = item; | ||
| 379 | break; | ||
| 380 | case 2: | ||
| 381 | row = grid; | ||
| 382 | break; | ||
| 383 | case 3: | ||
| 384 | row = child; | ||
| 385 | break; | ||
| 386 | case 4: | ||
| 387 | row = opt; | ||
| 388 | break; | ||
| 389 | } | ||
| 390 | let list = checkedList.value, tData = checkedData.value, tRow = { ...row, total: '0.00', memo: '', level1: item.name, level2: grid ? grid.name : '', level3: child ? child.name : '', level4: opt ? opt.name : '' }; | ||
| 391 | const eIndex = list.findIndex(item => item.guid == row.guid); | ||
| 392 | const tIndex = tData.findIndex(t => t.guid == row.guid); | ||
| 393 | |||
| 394 | if (val) { | 313 | if (val) { |
| 395 | eIndex === -1 && list.push(row); | 314 | // 选中上级 |
| 396 | if (tIndex === -1) { | 315 | for (let l = level - 1; l >= 1; l--) { |
| 397 | tRow[`level${row.level}`] = row.name; | 316 | const tIndex = l; |
| 398 | tData.push(tRow); | 317 | const rCode = rowData[`code${l}`]; |
| 399 | } | 318 | (() => { |
| 400 | if (level > 1) { | 319 | setChecked(tIndex, rCode, val); |
| 401 | item.checked = true; | 320 | })(); |
| 402 | const x = list.findIndex(l => l.guid == item.guid); | ||
| 403 | x === -1 && list.push(item); | ||
| 404 | const i = tData.findIndex(t => t.guid == item.guid); | ||
| 405 | i > -1 && tData.splice(i, 1); | ||
| 406 | if (level > 2) { | ||
| 407 | grid.checked = true; | ||
| 408 | const y = list.findIndex(l => l.guid == grid.guid); | ||
| 409 | y === -1 && list.push(grid); | ||
| 410 | const g = tData.findIndex(t => t.guid == grid.guid); | ||
| 411 | g > -1 && tData.splice(g, 1); | ||
| 412 | if (level > 3) { | ||
| 413 | child.checked = true; | ||
| 414 | const z = list.findIndex(l => l.guid == child.guid); | ||
| 415 | z === -1 && list.push(child); | ||
| 416 | const c = tData.findIndex(t => t.guid == child.guid); | ||
| 417 | c > -1 && tData.splice(c, 1); | ||
| 418 | } | ||
| 419 | } | ||
| 420 | } | 321 | } |
| 421 | } else { | 322 | } else { |
| 422 | eIndex > -1 && list.splice(eIndex, 1); | 323 | // 取消选中下级 |
| 423 | tIndex > -1 && tData.splice(tIndex, 1); | 324 | const rowList = tableData.value.filter(t => t[`code${level}`] == rowData[`code${level}`]); |
| 424 | if (level > 1) { | 325 | rowList.forEach(rData => { |
| 425 | const targetObj = level === 2 ? item : level === 3 ? grid : child; | 326 | for (let l = level; l <= 4; l++) { |
| 426 | const hasChildItem = targetObj.children.find(r => r.checked); | 327 | rData[`checked${l}`] = val; |
| 427 | const nIndex = tData.findIndex(t => t.guid == targetObj.guid); | 328 | } |
| 428 | if (!hasChildItem && nIndex === -1) { | 329 | }) |
| 429 | let nRow = { ...targetObj, total: '0.00', memo: '', level1: item.name, level2: grid ? grid.name : '', level3: child ? child.name : '', level4: opt ? opt.name : '' }; | ||
| 430 | nRow.level4 = ''; | ||
| 431 | if (level === 2) { | ||
| 432 | nRow.level2 = ''; | ||
| 433 | nRow.level3 = ''; | ||
| 434 | } else if (level === 3) { | ||
| 435 | nRow.level3 = ''; | ||
| 436 | } | ||
| 437 | tData.push(nRow); | ||
| 438 | } | ||
| 439 | } | ||
| 440 | level < 4 && setChecked(row.children); | ||
| 441 | } | 330 | } |
| 331 | rowData.edit = rowData.code4 ? rowData.checked4 : rowData.checked3; // 数据是否可编辑 | ||
| 332 | checkedData.value = tableData.value.filter(t => t.edit); | ||
| 442 | }; | 333 | }; |
| 443 | 334 | ||
| 444 | const setChecked = (arr) => { | 335 | // 设置单元格选中 |
| 445 | let list = checkedList.value, tData = checkedData.value; | 336 | const setChecked = (level, code, check) => { |
| 446 | arr.forEach(a => { | 337 | const rowList = tableData.value.filter(t => t[`code${level}`] == code); |
| 447 | a.checked = false; | 338 | rowList.forEach(rData => rData[`checked${level}`] = check) |
| 448 | const lIndex = list.findIndex(t => t.guid == a.guid); | ||
| 449 | lIndex > -1 && list.splice(lIndex, 1); | ||
| 450 | const tIndex = tData.findIndex(t => t.guid == a.guid); | ||
| 451 | tIndex > -1 && tData.splice(tIndex, 1); | ||
| 452 | if (a.children.length) { | ||
| 453 | setChecked(a.children); | ||
| 454 | } | ||
| 455 | }); | ||
| 456 | }; | 339 | }; |
| 457 | 340 | ||
| 341 | // 点击外部区域关闭处理 | ||
| 342 | const handleClickOutside = (event) => { | ||
| 343 | const popoverEl = document.querySelector('.tree-item-edit-menu') | ||
| 344 | const triggerEl: any = popoverTriggerRef.value | ||
| 345 | |||
| 346 | if (!popoverVisible.value || !popoverEl || !triggerEl) return | ||
| 347 | |||
| 348 | const clickedInPopover = popoverEl.contains(event.target) | ||
| 349 | const clickedOnTrigger = triggerEl === event.target || triggerEl.contains(event.target) | ||
| 350 | |||
| 351 | if (!clickedInPopover && !clickedOnTrigger) { | ||
| 352 | popoverVisible.value = false | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | // 切换Popover显示/隐藏 | ||
| 357 | const togglePopover = (row, event) => { | ||
| 358 | // 如果点击的是当前已激活的触发器,则关闭popover | ||
| 359 | if (popoverVisible.value && popoverTriggerRef.value === event.currentTarget) { | ||
| 360 | popoverVisible.value = false | ||
| 361 | return | ||
| 362 | } | ||
| 363 | |||
| 364 | // 设置当前行和触发器引用 | ||
| 365 | currentRow.value = row | ||
| 366 | popoverTriggerRef.value = event.currentTarget | ||
| 367 | const level = Number(row.field.split('name')[1]); | ||
| 368 | showAdd.value = level == 3 ? true : false; | ||
| 369 | |||
| 370 | // 打开popover | ||
| 371 | popoverVisible.value = true | ||
| 372 | } | ||
| 373 | |||
| 374 | // 处理菜单点击 | ||
| 375 | const handleMenuClick = (action) => { | ||
| 376 | // 关闭popover | ||
| 377 | popoverVisible.value = false; | ||
| 378 | btnClick({ value: action, row: currentRow.value }) | ||
| 379 | } | ||
| 380 | |||
| 381 | // Popover关闭后的处理 | ||
| 382 | const handlePopoverClose = () => { | ||
| 383 | currentRow.value = null | ||
| 384 | popoverTriggerRef.value = null | ||
| 385 | } | ||
| 386 | |||
| 458 | const selectChange = async (val, row, info) => { | 387 | const selectChange = async (val, row, info) => { |
| 459 | if (row.field == 'entryType') { | 388 | if (row.field == 'entryType') { |
| 460 | await setFormItems(info); | 389 | await setFormItems(info, 'entry'); |
| 461 | entryForm.value.items.at(0).default = val; | 390 | entryForm.value.items.at(0).default = val; |
| 462 | entryForm.value.items.at(1).visible = val == 'intangible' ? true : false; | 391 | entryForm.value.items.at(1).visible = val == 'intangible' ? true : false; |
| 463 | entryForm.value.items.at(2).visible = val == 'intangible' ? true : false; | 392 | entryForm.value.items.at(2).visible = val == 'intangible' ? true : false; |
| ... | @@ -497,13 +426,48 @@ const inputEventChange = (val, scope, field) => { | ... | @@ -497,13 +426,48 @@ const inputEventChange = (val, scope, field) => { |
| 497 | row[field] = row[field].toString().replace(/^\D*(\d{0,12}(?:\.\d{0,2})?).*$/g, "$1") | 426 | row[field] = row[field].toString().replace(/^\D*(\d{0,12}(?:\.\d{0,2})?).*$/g, "$1") |
| 498 | } | 427 | } |
| 499 | 428 | ||
| 429 | // 重命名 | ||
| 430 | const setName = (name, level) => { | ||
| 431 | const rIndex = currentRow.value.$index; | ||
| 432 | let rowData = tableData.value[rIndex]; | ||
| 433 | rowData[`name${level}`] = name; | ||
| 434 | } | ||
| 435 | |||
| 436 | // 新增本级 | ||
| 437 | const addSameData = (rIndex, name, level, tData) => { | ||
| 438 | let rowData = JSON.parse(JSON.stringify(tData)); | ||
| 439 | const lastCode = rowData[`code${level - 1}`]; | ||
| 440 | 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 | rowData[`name${level}`] = name; | ||
| 443 | rowData[`code${level}`] = `${lastCode}${codeVal}`; | ||
| 444 | delete rowData.name4; | ||
| 445 | delete rowData.code4; | ||
| 446 | tableData.value.splice(rIndex + 1, 0, rowData); | ||
| 447 | getMergeRow(); | ||
| 448 | } | ||
| 449 | |||
| 450 | // 新增下级 | ||
| 451 | const addLowerData = (rIndex, name, level, len) => { | ||
| 452 | let rowData = JSON.parse(JSON.stringify(tableData.value[rIndex])); | ||
| 453 | const hasLowerItem = rowData[`code${level + 1}`] ? true : false; | ||
| 454 | const lastCode = rowData[`code${level}`]; | ||
| 455 | const codeVal = (len + 1) < 10 ? '0' + (len + 1) : len + 1; | ||
| 456 | rowData[`name${level + 1}`] = name; | ||
| 457 | rowData[`code${level + 1}`] = `${lastCode}${codeVal}`; | ||
| 458 | hasLowerItem ? tableData.value.splice(rIndex + 1, 0, rowData) : tableData.value.splice(rIndex, 1, rowData); | ||
| 459 | tableField.value[3].visible = true; | ||
| 460 | getMergeRow(); | ||
| 461 | } | ||
| 462 | |||
| 463 | // 按钮点击事件 | ||
| 500 | const btnClick = async (btn, bType = null) => { | 464 | const btnClick = async (btn, bType = null) => { |
| 501 | const type = btn.value; | 465 | const type = btn.value; |
| 502 | if (type == 'add-same' || type == 'add-lower' || type == 'edit') { | 466 | if (type == 'add-same' || type == 'add-lower' || type == 'edit') { |
| 503 | const row = btn.row; | 467 | const row = btn.row; |
| 504 | const parent = btn.parent; | 468 | const { rIndex, level } = row; |
| 505 | const inputVal = type == 'edit' ? row.name : ''; | 469 | const inputVal = type == 'edit' ? row[`name${level}`] : ''; |
| 506 | let isChange = false, curGridList = type == 'add-lower' ? row.children : parent.children; | 470 | let isChange = false, rowList = tableData.value.filter(t => t[`code${level - 1}`] == row[`code${level - 1}`]); |
| 507 | ElMessageBox.prompt('', '节点名称', { | 471 | ElMessageBox.prompt('', '节点名称', { |
| 508 | confirmButtonText: '确定', | 472 | confirmButtonText: '确定', |
| 509 | cancelButtonText: '取消', | 473 | cancelButtonText: '取消', |
| ... | @@ -524,7 +488,7 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -524,7 +488,7 @@ const btnClick = async (btn, bType = null) => { |
| 524 | if (name.length > 10) { | 488 | if (name.length > 10) { |
| 525 | return '节点名称长度不能超过10个字符' | 489 | return '节点名称长度不能超过10个字符' |
| 526 | } | 490 | } |
| 527 | const isExist = curGridList.find(a => a.name == name); | 491 | const isExist = rowList.find(a => a[`name${level}`] == name); |
| 528 | if (isExist) { | 492 | if (isExist) { |
| 529 | return '节点名称已存在,请填写其他名称' | 493 | return '节点名称已存在,请填写其他名称' |
| 530 | } | 494 | } |
| ... | @@ -534,7 +498,7 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -534,7 +498,7 @@ const btnClick = async (btn, bType = null) => { |
| 534 | beforeClose: (action, instance, done) => { | 498 | beforeClose: (action, instance, done) => { |
| 535 | if (action === 'confirm') { | 499 | if (action === 'confirm') { |
| 536 | if (!instance.inputValue) { | 500 | if (!instance.inputValue) { |
| 537 | const dom = document.querySelectorAll('.prompt_msg_box .el-message-box__errormsg'); | 501 | const dom: any = document.querySelectorAll('.prompt_msg_box .el-message-box__errormsg'); |
| 538 | if (dom[0]) { | 502 | if (dom[0]) { |
| 539 | dom[0].innerHTML = '请填写节点名称'; | 503 | dom[0].innerHTML = '请填写节点名称'; |
| 540 | dom[0].style.visibility = 'visible'; | 504 | dom[0].style.visibility = 'visible'; |
| ... | @@ -552,61 +516,13 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -552,61 +516,13 @@ const btnClick = async (btn, bType = null) => { |
| 552 | const name = value.trim(); | 516 | const name = value.trim(); |
| 553 | if (type == 'edit') { | 517 | if (type == 'edit') { |
| 554 | if (value == inputVal) return | 518 | if (value == inputVal) return |
| 555 | row.name = name; | 519 | setName(name, level); |
| 556 | let list = checkedList.value, tData = checkedData.value; | ||
| 557 | tData.forEach((t) => { | ||
| 558 | if (t.guid == row.guid) { | ||
| 559 | t['level' + row.level] = name; | ||
| 560 | t.name = name; | ||
| 561 | } | ||
| 562 | if (t.parentId == row.code) { | ||
| 563 | t['level' + row.level] = name; | ||
| 564 | } | ||
| 565 | }) | ||
| 566 | list.forEach((l) => { | ||
| 567 | if (l.guid == row.guid) { | ||
| 568 | l.name = name; | ||
| 569 | } | ||
| 570 | }) | ||
| 571 | } else if (type == 'add-same') { | 520 | } else if (type == 'add-same') { |
| 572 | let code = ''; | 521 | const tData = rowList.at(-1); |
| 573 | const sameCode = curGridList.filter(c => c.parentId == row.parentId); | 522 | const tIndex = tableData.value.findIndex(t => (tData.code4 ? t.code4 === tData.code4 : t.code3 === tData.code3)); |
| 574 | sameCode.sort((a, b) => a.sortNum - b.sortNum); | 523 | addSameData(tIndex, name, level, tData); |
| 575 | const lastCode = sameCode.at(-1); | ||
| 576 | const codeVal = (sameCode.length + 1) < 10 ? '0' + (sameCode.length + 1) : sameCode.length + 1; | ||
| 577 | code = `${lastCode.parentId}${codeVal}`; | ||
| 578 | curGridList.push({ | ||
| 579 | ...JSON.parse(JSON.stringify(row)), | ||
| 580 | code: code, | ||
| 581 | name: name, | ||
| 582 | guid: `new-${code}`, | ||
| 583 | sortNum: lastCode.sortNum + 1, | ||
| 584 | children: [], | ||
| 585 | checked: false | ||
| 586 | }) | ||
| 587 | } else if (type == 'add-lower') { | 524 | } else if (type == 'add-lower') { |
| 588 | let code = '', sortNum = 1; | 525 | addLowerData(rIndex, name, level, rowList.length); |
| 589 | if (curGridList.length) { | ||
| 590 | curGridList.sort((a, b) => a.sortNum - b.sortNum); | ||
| 591 | const lastCode = curGridList.at(-1); | ||
| 592 | const codeVal = (curGridList.length + 1) < 10 ? '0' + (curGridList.length + 1) : curGridList.length + 1; | ||
| 593 | code = `${lastCode.parentId}${codeVal}`; | ||
| 594 | sortNum = lastCode.sortNum + 1; | ||
| 595 | } else { | ||
| 596 | code = `${row.code}01`; | ||
| 597 | } | ||
| 598 | curGridList.push({ | ||
| 599 | ...JSON.parse(JSON.stringify(row)), | ||
| 600 | code: code, | ||
| 601 | name: name, | ||
| 602 | sortNum: sortNum, | ||
| 603 | level: 4, | ||
| 604 | guid: `new-${code}`, | ||
| 605 | parentId: row.code, | ||
| 606 | children: [], | ||
| 607 | checked: false | ||
| 608 | }) | ||
| 609 | if (!showLevel4.value) showLevel4.value = true; | ||
| 610 | } | 526 | } |
| 611 | }).catch(() => { | 527 | }).catch(() => { |
| 612 | ElMessage({ | 528 | ElMessage({ |
| ... | @@ -616,8 +532,9 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -616,8 +532,9 @@ const btnClick = async (btn, bType = null) => { |
| 616 | }) | 532 | }) |
| 617 | } else if (type == 'remove') { | 533 | } else if (type == 'remove') { |
| 618 | const row = btn.row; | 534 | const row = btn.row; |
| 619 | const hasChild = row.children; | 535 | const { rIndex, level } = row; |
| 620 | const msg = hasChild.length ? '删除该节点会同步删除其子节点,是否确定删除?' : '确定删除该节点吗?'; | 536 | const rowList = tableData.value.filter(t => t[`code${level}`] == row[`code${level}`]); |
| 537 | const msg = level == 3 && rowList[0].code4 ? '删除该节点会同步删除其子节点,是否确定删除?' : '确定删除该节点吗?'; | ||
| 621 | ElMessageBox.confirm( | 538 | ElMessageBox.confirm( |
| 622 | msg, | 539 | msg, |
| 623 | '提示', | 540 | '提示', |
| ... | @@ -627,57 +544,21 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -627,57 +544,21 @@ const btnClick = async (btn, bType = null) => { |
| 627 | type: 'warning', | 544 | type: 'warning', |
| 628 | } | 545 | } |
| 629 | ).then(() => { | 546 | ).then(() => { |
| 630 | let curGridList = btn.parent.children; | 547 | if (level == 3) { |
| 631 | const rIndex = curGridList.findIndex(c => c.guid == row.guid); | 548 | if (rowList.length > 1) { |
| 632 | rIndex > -1 && curGridList.splice(rIndex, 1); | 549 | // 获取所有code3不等于当前code3的节点 |
| 633 | let list = checkedList.value, tData = checkedData.value; | 550 | tableData.value = tableData.value.filter(t => t.code3 !== row.code3); |
| 634 | let cRow = tData.find(c => c.guid == row.guid); | ||
| 635 | const hasChild = row.children.find(r => r.checked); | ||
| 636 | if (!cRow && hasChild) { | ||
| 637 | cRow = tData.find(c => c.guid == hasChild.guid); | ||
| 638 | } | ||
| 639 | const tIndex = tData.findIndex(c => c.guid == row.guid); | ||
| 640 | tIndex > -1 && tData.splice(tIndex, 1); | ||
| 641 | const lIndex = list.findIndex(c => c.guid == row.guid); | ||
| 642 | lIndex > -1 && list.splice(lIndex, 1); | ||
| 643 | const level = row.level; | ||
| 644 | if (level > 1 && cRow) { | ||
| 645 | const targetObj = btn.parent; | ||
| 646 | const hasChildItem = targetObj.children.find(r => r.checked); | ||
| 647 | const nIndex = tData.findIndex(t => t.guid == targetObj.guid); | ||
| 648 | if (!hasChildItem && nIndex === -1) { | ||
| 649 | let nRow = { ...cRow, ...targetObj, total: '0.00', level: targetObj.level }; | ||
| 650 | nRow[`level${targetObj.level}`] = targetObj.name; | ||
| 651 | nRow.level4 = ''; | ||
| 652 | if (level === 2) { | ||
| 653 | nRow.level2 = ''; | ||
| 654 | nRow.level3 = ''; | ||
| 655 | } else if (level === 3) { | ||
| 656 | nRow.level3 = ''; | ||
| 657 | } | ||
| 658 | tData.push(nRow); | ||
| 659 | } | ||
| 660 | } | ||
| 661 | level < 4 && setChecked(row.children); | ||
| 662 | for (let c = 0; c < curGridList.length; c++) { | ||
| 663 | const item = curGridList[c]; | ||
| 664 | if (item.sortNum > row.sortNum) { | ||
| 665 | const code = parseInt(item.code.split(item.parentId)[1], 10) - 1; | ||
| 666 | tData.forEach(t => { | ||
| 667 | if (t.guid == item.guid) { | ||
| 668 | t.code = `${t.parentId}${code < 10 ? '0' + code : code}`; | ||
| 669 | t.guid = t.guid.indexOf('new') > -1 ? `new-${t.code}` : t.guid; | ||
| 670 | t.sortNum = t.sortNum - 1; | ||
| 671 | } | ||
| 672 | }) | ||
| 673 | item.code = `${item.parentId}${code < 10 ? '0' + code : code}`; | ||
| 674 | item.guid = item.guid.indexOf('new') > -1 ? `new-${item.code}` : item.guid; | ||
| 675 | item.sortNum = item.sortNum - 1; | ||
| 676 | } else { | 551 | } else { |
| 677 | continue; | 552 | tableData.value.splice(rIndex, 1); |
| 678 | } | 553 | } |
| 554 | } else { | ||
| 555 | let rowData = tableData.value[rIndex]; | ||
| 556 | delete rowData[`name${level}`]; | ||
| 557 | delete rowData[`code${level}`]; | ||
| 558 | const level4 = tableData.value.find(t => t.code4); | ||
| 559 | !level4 && (tableField.value.at(-2).visible = false); | ||
| 679 | } | 560 | } |
| 680 | setShowLevel4(); | 561 | getMergeRow(); |
| 681 | }).catch(() => { | 562 | }).catch(() => { |
| 682 | ElMessage({ | 563 | ElMessage({ |
| 683 | type: 'info', | 564 | type: 'info', |
| ... | @@ -690,80 +571,6 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -690,80 +571,6 @@ const btnClick = async (btn, bType = null) => { |
| 690 | costFormInfo.value = { ...costFormInfo.value, ...JSON.parse(JSON.stringify(fInfo)) }; | 571 | costFormInfo.value = { ...costFormInfo.value, ...JSON.parse(JSON.stringify(fInfo)) }; |
| 691 | setStep(); | 572 | setStep(); |
| 692 | } else if (type == 'next') { | 573 | } else if (type == 'next') { |
| 693 | if (step.value == 0) { | ||
| 694 | const formEl = costFormRef.value.ruleFormRef; | ||
| 695 | const fInfo = costFormRef.value.formInline; | ||
| 696 | costFormInfo.value = { ...costFormInfo.value, ...JSON.parse(JSON.stringify(fInfo)) }; | ||
| 697 | if (!formEl) return; | ||
| 698 | const valid = await submitForm(formEl); | ||
| 699 | if (valid) { | ||
| 700 | if (checkedList.value.length == 0) { | ||
| 701 | ElMessage.warning('请勾选成本项'); | ||
| 702 | return | ||
| 703 | } | ||
| 704 | |||
| 705 | const nameArr = checkedList.value.map(c => c.name); | ||
| 706 | isInitField.value = initCheckedList.value.toString() != nameArr.toString(); | ||
| 707 | const tGuids = tableData.value.map(d => d.guid); | ||
| 708 | if (isInitField.value) { | ||
| 709 | initCheckedList.value = nameArr; | ||
| 710 | let fields = [ | ||
| 711 | { | ||
| 712 | label: "累计投入", field: "total", width: 120, align: 'right', getName: (scope) => { | ||
| 713 | return changeNum(scope.row.total, 2, true); | ||
| 714 | } | ||
| 715 | }, | ||
| 716 | ] | ||
| 717 | const hasLevel1 = checkedList.value.find(c => c.level == 1); | ||
| 718 | if (hasLevel1) { | ||
| 719 | fields.splice(-1, 0, { label: "指标", field: "level1", width: 120 }); | ||
| 720 | } | ||
| 721 | const hasLevel2 = checkedList.value.find(c => c.level == 2); | ||
| 722 | if (hasLevel2) { | ||
| 723 | fields.splice(-1, 0, { label: "一级分类", field: "level2", width: 120 }); | ||
| 724 | } | ||
| 725 | const hasLevel3 = checkedList.value.find(c => c.level == 3); | ||
| 726 | if (hasLevel3) { | ||
| 727 | fields.splice(-1, 0, { label: "二级分类", field: "level3", width: 120 }); | ||
| 728 | } | ||
| 729 | const hasLevel4 = checkedList.value.find(c => c.level == 4); | ||
| 730 | if (hasLevel4) { | ||
| 731 | fields.splice(-1, 0, { label: "三级分类", field: "level4", width: 120 }); | ||
| 732 | } | ||
| 733 | tableField.value.splice(0); | ||
| 734 | tableField.value.push(...fields); | ||
| 735 | initField.value = JSON.parse(JSON.stringify(tableField.value)); | ||
| 736 | const datas = JSON.parse(JSON.stringify(checkedData.value)); | ||
| 737 | datas.sort((a, b) => a.code.localeCompare(b.code)); | ||
| 738 | const dGuid = datas.map(d => d.guid); | ||
| 739 | let tDatas = tableData.value.filter(t => dGuid.indexOf(t.guid) > -1); | ||
| 740 | datas.forEach((td, t) => { | ||
| 741 | if (tGuids.indexOf(td.guid) == -1) { | ||
| 742 | tDatas.splice(t, 0, td) | ||
| 743 | } else { | ||
| 744 | tDatas.map(d => { | ||
| 745 | if (d.guid == td.guid) { | ||
| 746 | d.name = td.name; | ||
| 747 | d.level1 = td.level1; | ||
| 748 | d.level2 = td.level2; | ||
| 749 | d.level3 = td.level3; | ||
| 750 | d.level4 = td.level4; | ||
| 751 | } | ||
| 752 | }) | ||
| 753 | } | ||
| 754 | }) | ||
| 755 | tableData.value.splice(0); | ||
| 756 | tableData.value = tDatas; | ||
| 757 | if (tGuids.length > 0 && costFormInfo.value.baseDate && costFormInfo.value.investYear) { | ||
| 758 | setTableFields(costFormInfo.value); | ||
| 759 | besure.value = true; | ||
| 760 | } | ||
| 761 | getMergeRow(); | ||
| 762 | } | ||
| 763 | step.value++; | ||
| 764 | setStep(); | ||
| 765 | } | ||
| 766 | } else if (step.value == 1) { | ||
| 767 | const formEl1 = entryFormRef.value.ruleFormRef; | 574 | const formEl1 = entryFormRef.value.ruleFormRef; |
| 768 | const fInfo1 = entryFormRef.value.formInline; | 575 | const fInfo1 = entryFormRef.value.formInline; |
| 769 | if (!formEl1) return; | 576 | if (!formEl1) return; |
| ... | @@ -785,9 +592,14 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -785,9 +592,14 @@ const btnClick = async (btn, bType = null) => { |
| 785 | } | 592 | } |
| 786 | await setEntryData(fInfo1, fInfo2); | 593 | await setEntryData(fInfo1, fInfo2); |
| 787 | await transposeData(fInfo1.entryType); | 594 | await transposeData(fInfo1.entryType); |
| 788 | step.value++; | 595 | costForm.value.items.map((cost, c) => { |
| 789 | setStep(); | 596 | if (c == 0) { |
| 597 | cost.disabled = true | ||
| 598 | } else { | ||
| 599 | cost.visible = false | ||
| 790 | } | 600 | } |
| 601 | }) | ||
| 602 | step.value++; | ||
| 791 | } | 603 | } |
| 792 | } | 604 | } |
| 793 | } else if (type == 'refresh') { | 605 | } else if (type == 'refresh') { |
| ... | @@ -805,66 +617,13 @@ const btnClick = async (btn, bType = null) => { | ... | @@ -805,66 +617,13 @@ const btnClick = async (btn, bType = null) => { |
| 805 | } | 617 | } |
| 806 | }; | 618 | }; |
| 807 | 619 | ||
| 808 | const initTableFileds = () => { | 620 | const setStep = async () => { |
| 809 | let fields = [ | 621 | const info = costFormInfo.value; |
| 810 | { | 622 | await setFormItems(info, 'cost'); |
| 811 | label: "累计投入", field: "total", width: 120, align: 'right', getName: (scope) => { | 623 | costForm.value.items[0].disabled = step.value > 0; |
| 812 | return changeNum(scope.row.total, 2, true); | 624 | costForm.value.items[1].visible = step.value == 0; |
| 813 | } | 625 | costForm.value.items[2].visible = step.value == 0; |
| 814 | }, | 626 | costForm.value.items[3].visible = step.value == 0; |
| 815 | ] | ||
| 816 | const hasLevel1 = checkedList.value.find(c => c.level == 1); | ||
| 817 | if (hasLevel1) { | ||
| 818 | fields.splice(-1, 0, { label: "指标", field: "level1", width: 120 }); | ||
| 819 | } | ||
| 820 | const hasLevel2 = checkedList.value.find(c => c.level == 2); | ||
| 821 | if (hasLevel2) { | ||
| 822 | fields.splice(-1, 0, { label: "一级分类", field: "level2", width: 120 }); | ||
| 823 | } | ||
| 824 | const hasLevel3 = checkedList.value.find(c => c.level == 3); | ||
| 825 | if (hasLevel3) { | ||
| 826 | fields.splice(-1, 0, { label: "二级分类", field: "level3", width: 120 }); | ||
| 827 | } | ||
| 828 | const hasLevel4 = checkedList.value.find(c => c.level == 4); | ||
| 829 | if (hasLevel4) { | ||
| 830 | fields.splice(-1, 0, { label: "三级分类", field: "level4", width: 120 }); | ||
| 831 | } | ||
| 832 | tableField.value.splice(0); | ||
| 833 | tableField.value.push(...fields); | ||
| 834 | initField.value = JSON.parse(JSON.stringify(tableField.value)); | ||
| 835 | const datas = JSON.parse(JSON.stringify(checkedData.value)); | ||
| 836 | datas.sort((a, b) => a.code.localeCompare(b.code)); | ||
| 837 | const dGuid = datas.map(d => d.guid); | ||
| 838 | let tDatas = tableData.value.filter(t => dGuid.indexOf(t.guid) > -1); | ||
| 839 | datas.forEach((td, t) => { | ||
| 840 | if (tGuids.indexOf(td.guid) == -1) { | ||
| 841 | tDatas.splice(t, 0, td) | ||
| 842 | } else { | ||
| 843 | tDatas.map(d => { | ||
| 844 | if (d.guid == td.guid) { | ||
| 845 | d.name = td.name; | ||
| 846 | d.level1 = td.level1; | ||
| 847 | d.level2 = td.level2; | ||
| 848 | d.level3 = td.level3; | ||
| 849 | d.level4 = td.level4; | ||
| 850 | } | ||
| 851 | }) | ||
| 852 | } | ||
| 853 | }) | ||
| 854 | tableData.value.splice(0); | ||
| 855 | tableData.value = tDatas; | ||
| 856 | // if (tGuids.length > 0 && costFormInfo.value.baseDate && costFormInfo.value.investYear) { | ||
| 857 | // setTableFields(costFormInfo.value); | ||
| 858 | // besure.value = true; | ||
| 859 | // } | ||
| 860 | getMergeRow(); | ||
| 861 | }; | ||
| 862 | |||
| 863 | const setShowLevel4 = () => { | ||
| 864 | nextTick(() => { | ||
| 865 | const box4 = document.querySelectorAll('.grid-panel-box.box3 .grid-items'); | ||
| 866 | showLevel4.value = box4.length > 0 | ||
| 867 | }) | ||
| 868 | } | 627 | } |
| 869 | 628 | ||
| 870 | const setFormItems = (row: any = null, type) => { | 629 | const setFormItems = (row: any = null, type) => { |
| ... | @@ -906,10 +665,10 @@ const submitForm = (formEl) => { | ... | @@ -906,10 +665,10 @@ const submitForm = (formEl) => { |
| 906 | }; | 665 | }; |
| 907 | 666 | ||
| 908 | const setEntryData = (fInfo1, fInfo2) => { | 667 | const setEntryData = (fInfo1, fInfo2) => { |
| 909 | let datas = [], lastCount = -1, lastYear = {}; | 668 | let datas: any = [], lastCount = -1, lastYear: any = {}; |
| 910 | for (var f in costFileds.value) { | 669 | for (var f in costFileds.value) { |
| 911 | lastCount++; | 670 | lastCount++; |
| 912 | let row = { ...entryItem }; | 671 | let row: any = { ...entryItem }; |
| 913 | if (f != 'baseNum') { | 672 | if (f != 'baseNum') { |
| 914 | row.year = `${f}年`; | 673 | row.year = `${f}年`; |
| 915 | } else { | 674 | } else { |
| ... | @@ -930,7 +689,7 @@ const setEntryData = (fInfo1, fInfo2) => { | ... | @@ -930,7 +689,7 @@ const setEntryData = (fInfo1, fInfo2) => { |
| 930 | } else { | 689 | } else { |
| 931 | let amortize1 = 0; | 690 | let amortize1 = 0; |
| 932 | for (var d = datas.length - 1; d > (lastCount - fInfo1.shareYears); d--) { | 691 | for (var d = datas.length - 1; d > (lastCount - fInfo1.shareYears); d--) { |
| 933 | const da = datas[d]; | 692 | const da: any = datas[d]; |
| 934 | amortize1 += da.amortize2 | 693 | amortize1 += da.amortize2 |
| 935 | } | 694 | } |
| 936 | row.amortize1 = amortize1; | 695 | row.amortize1 = amortize1; |
| ... | @@ -956,7 +715,7 @@ const setTableFields = (info) => { | ... | @@ -956,7 +715,7 @@ const setTableFields = (info) => { |
| 956 | //结束年 | 715 | //结束年 |
| 957 | let nowYears = Number(info.baseDate.split('-')[0]); | 716 | let nowYears = Number(info.baseDate.split('-')[0]); |
| 958 | let Years = nowYears - smallYears | 717 | let Years = nowYears - smallYears |
| 959 | let arrYear = [], fields = [], row = { baseNum: '' }; | 718 | let arrYear: any = [], fields: any = [], row: any = { baseNum: '' }; |
| 960 | for (let i = 0; i < Years; i++) { | 719 | for (let i = 0; i < Years; i++) { |
| 961 | arrYear.push(smallYears++) | 720 | arrYear.push(smallYears++) |
| 962 | } | 721 | } |
| ... | @@ -968,13 +727,13 @@ const setTableFields = (info) => { | ... | @@ -968,13 +727,13 @@ const setTableFields = (info) => { |
| 968 | costFileds.value = row; | 727 | costFileds.value = row; |
| 969 | const date = new Date(info.baseDate); | 728 | const date = new Date(info.baseDate); |
| 970 | const currDay = date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long' }); | 729 | const currDay = date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long' }); |
| 971 | tableField.value = JSON.parse(JSON.stringify(initField.value)); | 730 | tableField.value.at(-1).visible = true; |
| 972 | tableField.value.splice(-1, 0, ...fields, { label: currDay, field: 'baseNum', type: 'input', width: 120, columClass: 'edit_cell' }); | 731 | tableField.value.splice(-1, 0, ...fields, { label: currDay, field: 'baseNum', type: 'input', width: 120, columClass: 'edit_cell' }); |
| 973 | 732 | // 设置table数据 | |
| 974 | let datas = []; | 733 | let datas: any = []; |
| 975 | tableData.value.map(t => { | 734 | tableData.value.map(t => { |
| 976 | let tRow = { ...row, ...t }; | 735 | let tRow = { ...row, ...t }; |
| 977 | const tKey = Object.keys(t); | 736 | const tKey: any = Object.keys(t); |
| 978 | tKey.forEach(k => { | 737 | tKey.forEach(k => { |
| 979 | if ((k == 'baseNum' || !isNaN(k)) && row[k] === undefined) { | 738 | if ((k == 'baseNum' || !isNaN(k)) && row[k] === undefined) { |
| 980 | delete tRow[k]; | 739 | delete tRow[k]; |
| ... | @@ -984,87 +743,107 @@ const setTableFields = (info) => { | ... | @@ -984,87 +743,107 @@ const setTableFields = (info) => { |
| 984 | }) | 743 | }) |
| 985 | tableData.value.splice(0); | 744 | tableData.value.splice(0); |
| 986 | tableData.value = datas; | 745 | tableData.value = datas; |
| 746 | getMergeRow(); | ||
| 987 | } | 747 | } |
| 988 | 748 | ||
| 989 | // 设置表格合并下标 | 749 | // 设置表格合并下标 |
| 990 | const getMergeRow = () => { | 750 | const getMergeRow = () => { |
| 991 | mergeRowCount.value = JSON.parse(JSON.stringify(rowCount)); | 751 | let list = tableData.value, info = {} |
| 992 | let list = tableData.value; | 752 | // 为每个层级初始化合并信息 |
| 993 | for (var i = 0; i < list.length; i++) { | 753 | for (let level = 1; level <= 3; level++) { |
| 994 | if (i === 0) { | 754 | const nameKey = `name${level}` |
| 995 | //第一个数据 默认合并1行,开始位置下标默认为0 | 755 | const codeKey = `code${level}` |
| 996 | for (var m in mergeRowCount.value) { | 756 | info[nameKey] = [] |
| 997 | mergeRowCount.value[m].rowspan.push(1); | 757 | |
| 998 | mergeRowCount.value[m].index = 0; | 758 | // 处理每行数据 |
| 999 | } | 759 | list.forEach((row, index) => { |
| 760 | if (index === 0) { | ||
| 761 | // 第一行默认合并1行,开始位置0 | ||
| 762 | info[nameKey][index] = 1 | ||
| 1000 | } else { | 763 | } else { |
| 1001 | // 根据拥有子级数量进行合并 | 764 | // 当前行与上一行的code和name比较 |
| 1002 | for (var m in mergeRowCount.value) { | 765 | const sameCode = row[codeKey] === list[index - 1][codeKey] |
| 1003 | let mergeRow = mergeRowCount.value[m]; | 766 | const sameName = row[nameKey] === list[index - 1][nameKey] |
| 1004 | const e = Number(m.split('level')[1]); | 767 | |
| 1005 | if (list[i][m] && list[i]['level' + (e - 1)] == list[i - 1]['level' + (e - 1)] && list[i][m] === list[i - 1][m]) { | 768 | if (sameCode && sameName) { |
| 1006 | mergeRow.rowspan[mergeRow.index] += 1; | 769 | // 找到当前分组的起始位置 |
| 1007 | mergeRow.rowspan.push(0); | 770 | let groupStart = index - 1 |
| 771 | while (groupStart > 0 && info[nameKey][groupStart] === 0) { | ||
| 772 | groupStart-- | ||
| 773 | } | ||
| 774 | // 增加合并行数 | ||
| 775 | info[nameKey][groupStart]++ | ||
| 776 | info[nameKey][index] = 0 | ||
| 1008 | } else { | 777 | } else { |
| 1009 | mergeRow.rowspan.push(1); | 778 | // 新分组,合并1行 |
| 1010 | mergeRow.index = i; | 779 | info[nameKey][index] = 1 |
| 1011 | } | ||
| 1012 | } | 780 | } |
| 1013 | } | 781 | } |
| 782 | }) | ||
| 1014 | } | 783 | } |
| 784 | |||
| 785 | mergeRowCount.value = info; | ||
| 1015 | } | 786 | } |
| 1016 | 787 | ||
| 1017 | // 表格行合并 | 788 | // 表格行合并 |
| 1018 | const tableSpanMethod = ({ row, column, rowIndex, columnIndex }) => { | 789 | const tableSpanMethod = ({ row, column, rowIndex, columnIndex }) => { |
| 1019 | if (column.property.indexOf('level') > -1 && column.property != 'level4') { | 790 | const colName = column.property |
| 1020 | const rowspan = mergeRowCount.value[column.property].rowspan; | 791 | if (mergeRowCount.value[colName]) { |
| 1021 | const _row = rowspan[rowIndex]; | 792 | const rowspan = mergeRowCount.value[colName][rowIndex] |
| 1022 | const _col = _row == 0 ? 0 : 1; | ||
| 1023 | return { | 793 | return { |
| 1024 | rowspan: _row, | 794 | rowspan: rowspan, |
| 1025 | colspan: _col | 795 | colspan: rowspan > 0 ? 1 : 0 |
| 1026 | } | 796 | } |
| 1027 | } | 797 | } |
| 798 | return { rowspan: 1, colspan: 1 } | ||
| 1028 | } | 799 | } |
| 1029 | 800 | ||
| 1030 | const isMergedCell = ({ rowIndex, columnIndex }) => { | 801 | const isMergedCell = ({ row, column, rowIndex, columnIndex }) => { |
| 1031 | const property = tableField.value[columnIndex].field; | 802 | const property = column.property; |
| 1032 | const rowspan = mergeRowCount.value[property]?.rowspan[rowIndex]; | 803 | // 只处理需要合并的列 (name1/name2/name3) |
| 1033 | return rowspan > 1 ? 'merged-cell' : ''; | 804 | if (['name1', 'name2', 'name3'].includes(property)) { |
| 805 | // 检查当前单元格是否属于合并范围 | ||
| 806 | const rowspan = mergeRowCount.value[property]?.[rowIndex]; | ||
| 807 | // 无论是合并的起始单元格(rowspan>1)还是被合并的隐藏单元格(rowspan===0) | ||
| 808 | return rowspan !== 1 ? 'merged-cell' : ''; | ||
| 809 | } | ||
| 810 | return ''; | ||
| 1034 | } | 811 | } |
| 1035 | 812 | ||
| 1036 | // 表格合计行 | 813 | // 优化后的合计计算方法 |
| 1037 | const tableSummaryMethod = ({ columns, data }) => { | 814 | const tableSummaryMethod = ({ columns, data }) => { |
| 1038 | let sums = []; | 815 | if (!besure.value) return; |
| 816 | let sums: any = [], numericColumns: any = []; // 记录需要计算的数字列 | ||
| 1039 | columns.forEach((column, index) => { | 817 | columns.forEach((column, index) => { |
| 1040 | if (index === 0) { //需要显示'总金额'的列 坐标 :0 | 818 | if (index === 0) { |
| 1041 | sums[index] = '合计' | 819 | sums[index] = '合计'; |
| 1042 | return | 820 | return; |
| 1043 | } else { | ||
| 1044 | if (column.property.indexOf('level') == -1 && column.property != 'memo') { | ||
| 1045 | const values = data.map(item => parseFloat(item[column.property] ? item[column.property].replace(/,/g, "") : 0)); | ||
| 1046 | if (!values.every(value => isNaN(value))) { | ||
| 1047 | const sum = values.reduce((prev, curr) => { | ||
| 1048 | const value = parseFloat(curr || 0) | ||
| 1049 | if (!isNaN(value)) { | ||
| 1050 | return prev + curr | ||
| 1051 | } else { | ||
| 1052 | return prev | ||
| 1053 | } | ||
| 1054 | }, 0) | ||
| 1055 | sums[index] = changeNum(sum, 2, true) | ||
| 1056 | if (column.property == 'total') { | ||
| 1057 | amount.value = sum | ||
| 1058 | } | 821 | } |
| 1059 | sumAmount.value[column.property] = sum; | 822 | // 识别需要计算的数字列 |
| 823 | if (!column.property.includes('name') && column.property !== 'memo') { | ||
| 824 | numericColumns.push({ | ||
| 825 | index, | ||
| 826 | property: column.property | ||
| 827 | }); | ||
| 1060 | } else { | 828 | } else { |
| 1061 | sums[index] = 'N/A' | 829 | sums[index] = ''; // 非数字列留空 |
| 1062 | } | ||
| 1063 | } | 830 | } |
| 1064 | } | 831 | }); |
| 1065 | }) | 832 | // 计算数字列合计 |
| 1066 | return sums | 833 | numericColumns.forEach(({ index, property }) => { |
| 1067 | } | 834 | const sum = data.reduce((total, item) => { |
| 835 | const value = parseFloat(String(item[property]).replace(/,/g, '')) || 0; | ||
| 836 | return total + value; | ||
| 837 | }, 0); | ||
| 838 | sums[index] = changeNum(sum, 2, true); | ||
| 839 | // 特殊字段处理 | ||
| 840 | if (property === 'total') { | ||
| 841 | amount.value = sum; | ||
| 842 | } | ||
| 843 | sumAmount.value[property] = sum; | ||
| 844 | }); | ||
| 845 | return sums; | ||
| 846 | }; | ||
| 1068 | 847 | ||
| 1069 | const isExist = (newArr, name) => { | 848 | const isExist = (newArr, name) => { |
| 1070 | for (let i = 0; i < newArr.length; i++) { | 849 | for (let i = 0; i < newArr.length; i++) { |
| ... | @@ -1077,19 +856,23 @@ const isExist = (newArr, name) => { | ... | @@ -1077,19 +856,23 @@ const isExist = (newArr, name) => { |
| 1077 | 856 | ||
| 1078 | // 表格数据行列转置 | 857 | // 表格数据行列转置 |
| 1079 | const transposeData = (type) => { | 858 | const transposeData = (type) => { |
| 859 | bookHeaders.value.splice(1); | ||
| 1080 | // 提取原始数据的头部作为转置后数据的列 | 860 | // 提取原始数据的头部作为转置后数据的列 |
| 1081 | headers.value = entryData.value.map((t) => { | 861 | const list = entryData.value.map((t) => { |
| 1082 | return { | 862 | return { |
| 1083 | label: t.year, | 863 | label: t.year, |
| 1084 | value: t.guid || t.year | 864 | field: t.guid || t.year, |
| 865 | width: 120, | ||
| 866 | align: 'right' | ||
| 1085 | } | 867 | } |
| 1086 | }); | 868 | }); |
| 869 | bookHeaders.value.push(...list); | ||
| 1087 | 870 | ||
| 1088 | /** | 871 | /** |
| 1089 | * 定义映射字段表(最好取全量字段) | 872 | * 定义映射字段表(最好取全量字段) |
| 1090 | * */ | 873 | * */ |
| 1091 | const mapObj = convertConfig[type] | 874 | const mapObj = convertConfig[type] |
| 1092 | const newArr = []; | 875 | const newArr: any = []; |
| 1093 | for (const t in mapObj) { | 876 | for (const t in mapObj) { |
| 1094 | for (let i = 0; i < entryData.value.length; i++) { | 877 | for (let i = 0; i < entryData.value.length; i++) { |
| 1095 | const item = entryData.value[i] | 878 | const item = entryData.value[i] |
| ... | @@ -1097,7 +880,7 @@ const transposeData = (type) => { | ... | @@ -1097,7 +880,7 @@ const transposeData = (type) => { |
| 1097 | if (result) { | 880 | if (result) { |
| 1098 | result[item.year] = item[t] | 881 | result[item.year] = item[t] |
| 1099 | } else { | 882 | } else { |
| 1100 | const obj = {} | 883 | const obj: any = {} |
| 1101 | obj.title = mapObj[t] | 884 | obj.title = mapObj[t] |
| 1102 | obj[item.year] = item[t] | 885 | obj[item.year] = item[t] |
| 1103 | newArr.push(obj) | 886 | newArr.push(obj) |
| ... | @@ -1121,248 +904,290 @@ const setLabel = (val) => { | ... | @@ -1121,248 +904,290 @@ const setLabel = (val) => { |
| 1121 | } | 904 | } |
| 1122 | } | 905 | } |
| 1123 | 906 | ||
| 1124 | const getClass = (i, checked) => { | 907 | // 下载表格 |
| 1125 | return checked ? `active${i + 1}` : ''; | 908 | const s2ab = (s) => { |
| 909 | const buf = new ArrayBuffer(s.length); | ||
| 910 | const view = new Uint8Array(buf); | ||
| 911 | for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; | ||
| 912 | return buf; | ||
| 1126 | } | 913 | } |
| 1127 | 914 | ||
| 1128 | const gridPanel = ref(null); | 915 | // 生成成本设置表 |
| 1129 | const gridItem = ref(null); | 916 | const exportDetailsToExcel = async () => { |
| 1130 | const setItemLine = () => { | 917 | // 准备工作表数据 |
| 1131 | nextTick(() => { | 918 | const wsData = [] |
| 1132 | setTimeout(() => { | 919 | |
| 1133 | if (gridItem.value) { | 920 | // 表头 |
| 1134 | const width1 = gridPanel.value[0].offsetWidth; | 921 | const headers = tableField.value.map(item => item.label) |
| 1135 | const width2 = gridItem.value[0].offsetWidth; | 922 | wsData.push(headers) |
| 1136 | // 设置::before伪元素的宽度 | 923 | |
| 1137 | itemWidth.value = `${(width1 - width2) / 2 + (showLevel4.value ? 6 : 8)}px`; | 924 | // 处理数据行 |
| 1138 | itemLeft.value = `-${(width1 - width2) / 2 + (showLevel4.value ? 6 : 8)}px`; | 925 | checkedData.value.forEach(item => { |
| 1139 | document.documentElement.style.setProperty('--item-width', itemWidth.value); | 926 | const row = tableField.value.map(f => { |
| 1140 | document.documentElement.style.setProperty('--item-left', itemLeft.value); | 927 | if (f.field.indexOf('name') == -1) { |
| 1141 | } | 928 | // 分类字段 |
| 1142 | }, 100) | 929 | return changeNum(item[f.field]) |
| 930 | } else { | ||
| 931 | // 其他字段 | ||
| 932 | return item[f.field] || '' | ||
| 933 | } | ||
| 934 | }) | ||
| 935 | wsData.push(row) | ||
| 1143 | }) | 936 | }) |
| 1144 | } | ||
| 1145 | 937 | ||
| 1146 | const spanHeight = (obj) => { | 938 | // 添加合计行 |
| 1147 | return `${obj.children.length ? obj.children.length * 48 : 48}px`; | 939 | const totalRow = ['合计', '', '', '']; |
| 1148 | } | 940 | const numField = tableField.value.filter(item => item.field.indexOf('name') == -1); |
| 941 | const numericFields = numField.map(f => f.field); | ||
| 942 | let totalValues = {} | ||
| 1149 | 943 | ||
| 1150 | const showPanel = (arr, row) => { | 944 | // 初始化合计值 |
| 1151 | arr.forEach(a => { | 945 | numericFields.forEach(field => { |
| 1152 | if (a.level < 3) { | 946 | totalValues[field] = 0 |
| 1153 | a.children.length && showPanel(a.children, row) | 947 | }) |
| 1154 | } else { | 948 | |
| 1155 | if (a.children.length) { | 949 | // 计算合计值 |
| 1156 | row.show4 = true; | 950 | checkedData.value.forEach(item => { |
| 1157 | return; | 951 | numericFields.forEach(field => { |
| 1158 | } | 952 | if (item[field]) { |
| 953 | const num = parseFloat(item[field].replace(/,/g, '')) || 0 | ||
| 954 | totalValues[field] += num | ||
| 1159 | } | 955 | } |
| 1160 | }) | 956 | }) |
| 1161 | return row.show4 || false; | 957 | }) |
| 1162 | } | ||
| 1163 | 958 | ||
| 1164 | // 设置二级分类 item的margin-bottom值 | 959 | // 将合计值添加到合计行 |
| 1165 | const setItemStyle = (row, indexObj) => { | 960 | tableField.value.forEach((field, index) => { |
| 1166 | if (indexObj) { | 961 | if (index < 4) return // 前4列已经处理 |
| 1167 | const { o } = indexObj; | 962 | if (numericFields.includes(field.field)) { |
| 1168 | setGroupStyle(); | 963 | const value = totalValues[field.field] |
| 1169 | setItemsStyle(o); | 964 | // 格式化数字,保留2位小数 |
| 1170 | return { height: 'auto' } | 965 | totalRow.push(value.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",")) |
| 1171 | } else { | 966 | } else { |
| 1172 | setHeight(); | 967 | totalRow.push('') |
| 1173 | return { 'margin-bottom': row.children.length > 1 ? ((row.children.length - 1) * 48) + 8 + 'px' : '0px' } | ||
| 1174 | } | 968 | } |
| 1175 | } | ||
| 1176 | |||
| 1177 | // 设置三级分类 group高度 | ||
| 1178 | const setGroupStyle = () => { | ||
| 1179 | nextTick(() => { | ||
| 1180 | const box3 = document.querySelectorAll('.grid-panel-box.box2 .grid-panel'); | ||
| 1181 | const box4 = document.querySelectorAll('.grid-panel-box.box3 .grid-group'); | ||
| 1182 | box4.forEach((box, b) => { | ||
| 1183 | box.style.height = box3[b].offsetHeight + 'px'; | ||
| 1184 | }) | 969 | }) |
| 970 | |||
| 971 | wsData.push(totalRow) | ||
| 972 | |||
| 973 | // 创建工作表 | ||
| 974 | const ws = XLSXS.utils.aoa_to_sheet(wsData) | ||
| 975 | |||
| 976 | // 自动调整列宽 | ||
| 977 | const colWidths = tableField.value.map((field, index) => { | ||
| 978 | const defaultWidth = field.width || 100 // 默认宽度100 | ||
| 979 | const colWidth = defaultWidth / 14 + 2; // 留一些余地 | ||
| 980 | |||
| 981 | // 取表头宽度和内容宽度的较大值 | ||
| 982 | return { wpx: colWidth * 12 } // 使用像素宽度 | ||
| 1185 | }) | 983 | }) |
| 1186 | } | ||
| 1187 | 984 | ||
| 1188 | // 设置三级分类 item高度 | 985 | ws['!cols'] = colWidths |
| 1189 | const setItemsStyle = (i) => { | 986 | |
| 1190 | nextTick(() => { | 987 | // 设置合并单元格 |
| 1191 | const box3 = document.querySelectorAll('.grid-panel-box.box2 .grid-items'); | 988 | const merges = [] |
| 1192 | const box4 = document.querySelectorAll('.grid-panel-box.box3 .group-items'); | 989 | |
| 1193 | box4.forEach((box, b) => { | 990 | // 按code1合并一级指标 |
| 1194 | const bStyle = window.getComputedStyle(box3[b]); | 991 | const level1Groups = groupBy(checkedData.value, 'code1') |
| 1195 | const h = parseFloat(bStyle.height) + parseFloat(bStyle.marginBottom); | 992 | Object.values(level1Groups).forEach(group => { |
| 1196 | box.style.height = h <= 40 ? (h + 8) + 'px' : h + 'px'; | 993 | const startRow = checkedData.value.findIndex(item => item.code1 === group[0].code1) + 1 // +1因为第一行是表头 |
| 994 | const endRow = startRow + group.length - 1 | ||
| 995 | merges.push({ s: { r: startRow, c: 0 }, e: { r: endRow, c: 0 } }) | ||
| 1197 | }) | 996 | }) |
| 997 | |||
| 998 | // 按code2合并一级分类 | ||
| 999 | const level2Groups = groupBy(checkedData.value, 'code2') | ||
| 1000 | Object.values(level2Groups).forEach(group => { | ||
| 1001 | const startRow = checkedData.value.findIndex(item => item.code2 === group[0].code2) + 1 | ||
| 1002 | const endRow = startRow + group.length - 1 | ||
| 1003 | merges.push({ s: { r: startRow, c: 1 }, e: { r: endRow, c: 1 } }) | ||
| 1198 | }) | 1004 | }) |
| 1199 | } | ||
| 1200 | 1005 | ||
| 1201 | // 设置一级分类 panel高度 | 1006 | // 按code3合并二级分类 |
| 1202 | const setHeight = () => { | 1007 | const level3Groups = groupBy(checkedData.value, 'code3') |
| 1203 | nextTick(() => { | 1008 | Object.values(level3Groups).forEach(group => { |
| 1204 | const boxArr = document.querySelectorAll('.grid-panel-box'); | 1009 | const startRow = tableData.value.findIndex(item => item.code3 === group[0].code3) + 1 |
| 1205 | if (boxArr.length) { | 1010 | const endRow = startRow + group.length - 1 |
| 1206 | const box2 = boxArr[1].querySelectorAll('.grid-panel'); | 1011 | merges.push({ s: { r: startRow, c: 2 }, e: { r: endRow, c: 2 } }) |
| 1207 | const box3 = boxArr[2].querySelectorAll('.grid-panel'); | ||
| 1208 | box2.forEach((box, b) => { | ||
| 1209 | box.style.height = box3[b].offsetHeight + 'px'; | ||
| 1210 | }) | 1012 | }) |
| 1013 | |||
| 1014 | ws['!merges'] = merges | ||
| 1015 | |||
| 1016 | // 设置单元格样式 | ||
| 1017 | const range = XLSXS.utils.decode_range(ws['!ref']) | ||
| 1018 | |||
| 1019 | for (let R = range.s.r; R <= range.e.r; ++R) { | ||
| 1020 | for (let C = range.s.c; C <= range.e.c; ++C) { | ||
| 1021 | const cellAddress = XLSXS.utils.encode_cell({ r: R, c: C }) | ||
| 1022 | |||
| 1023 | // 默认样式 | ||
| 1024 | const defaultStyle = { | ||
| 1025 | alignment: { | ||
| 1026 | vertical: 'center', | ||
| 1027 | horizontal: 'left' | ||
| 1028 | } | ||
| 1211 | } | 1029 | } |
| 1212 | }) | ||
| 1213 | } | ||
| 1214 | 1030 | ||
| 1215 | // 下载表格 | 1031 | // 表头样式 |
| 1216 | const s2ab = (s) => { | 1032 | if (R === 0) { |
| 1217 | const buf = new ArrayBuffer(s.length); | 1033 | ws[cellAddress].s = { |
| 1218 | const view = new Uint8Array(buf); | 1034 | ...defaultStyle, |
| 1219 | for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; | 1035 | } |
| 1220 | return buf; | 1036 | continue |
| 1221 | } | 1037 | } |
| 1222 | 1038 | ||
| 1223 | // 获取所有单元格对象 | 1039 | // 合计行样式 |
| 1224 | function getAllCells(pRef, type) { | 1040 | if (R === range.e.r) { |
| 1225 | const allCells = []; | 1041 | ws[cellAddress].s = { |
| 1226 | let columns = [], allColsNum = 0; | 1042 | ...defaultStyle, |
| 1227 | if (type == 'cost') { | 1043 | alignment: { |
| 1228 | allColsNum = tableField.value.length; | 1044 | vertical: 'center', |
| 1229 | tableField.value.map((tc, c) => { | 1045 | horizontal: C > 3 ? 'right' : 'left' |
| 1230 | if (tc.field.indexOf('level') == -1 || tc.field == 'memo') { | ||
| 1231 | columns.push({ ...tc, cIndex: c }) | ||
| 1232 | } | 1046 | } |
| 1233 | }); | ||
| 1234 | } else { | ||
| 1235 | headers.value.map((th, h) => { | ||
| 1236 | columns.push({ ...th, cIndex: h + 1 }) | ||
| 1237 | }); | ||
| 1238 | } | 1047 | } |
| 1239 | const colIndex = columns.map(c => c.cIndex); | 1048 | continue |
| 1240 | // 获取所有行 | 1049 | } |
| 1241 | const rows = pRef.$el.querySelectorAll('.el-table__row'); | ||
| 1242 | 1050 | ||
| 1243 | rows.forEach((rowElement, rowIndex) => { | 1051 | // 数据行样式 |
| 1244 | const cells = rowElement.querySelectorAll('.el-table__cell'); | 1052 | const fieldIndex = C |
| 1053 | const field = tableField.value[fieldIndex] | ||
| 1245 | 1054 | ||
| 1246 | cells.forEach((cellElement, cellIndex) => { | 1055 | // 数值列右对齐 |
| 1247 | const cell = { | 1056 | if (numericFields.includes(field.field)) { |
| 1248 | rowIndex: (rowIndex + 1), | 1057 | ws[cellAddress].s = { |
| 1249 | cellIndex: cellIndex, | 1058 | ...defaultStyle, |
| 1250 | value: cellElement.innerText.trim(), | 1059 | alignment: { |
| 1251 | style: window.getComputedStyle(cellElement) | 1060 | vertical: 'center', |
| 1252 | }; | 1061 | horizontal: 'right' |
| 1253 | let format = 'General'; | 1062 | } |
| 1254 | if (type == 'entry') { | 1063 | } |
| 1255 | format = colIndex.indexOf(cellIndex) > -1 ? '#,##0.00' : ''; | ||
| 1256 | } else { | ||
| 1257 | if (rowIndex == rows.length - 1) { | ||
| 1258 | format = cell.value != '合计' && cell.value ? '#,##0.00' : ''; | ||
| 1259 | } else { | 1064 | } else { |
| 1260 | format = colIndex.indexOf(cellIndex + (allColsNum - cells.length)) > -1 ? '#,##0.00' : ''; | 1065 | // 其他列左对齐 |
| 1261 | cell.cellIndex = cellIndex + (allColsNum - cells.length) | 1066 | ws[cellAddress].s = defaultStyle |
| 1067 | } | ||
| 1262 | } | 1068 | } |
| 1263 | } | 1069 | } |
| 1264 | cell.format = format; | 1070 | |
| 1265 | allCells.push(cell); | 1071 | return ws; |
| 1072 | }; | ||
| 1073 | |||
| 1074 | // 辅助函数:按属性分组 | ||
| 1075 | const groupBy = (array, key) => { | ||
| 1076 | return array.reduce((acc, obj) => { | ||
| 1077 | const groupKey = obj[key] | ||
| 1078 | if (!acc[groupKey]) { | ||
| 1079 | acc[groupKey] = [] | ||
| 1080 | } | ||
| 1081 | acc[groupKey].push(obj) | ||
| 1082 | return acc | ||
| 1083 | }, {}) | ||
| 1084 | }; | ||
| 1085 | |||
| 1086 | // 生成成本设置表 | ||
| 1087 | const exportBookToExcel = async () => { | ||
| 1088 | // 准备工作表数据 | ||
| 1089 | const wsData = [] | ||
| 1090 | |||
| 1091 | // 表头 | ||
| 1092 | const headers = bookHeaders.value.map(item => item.label) | ||
| 1093 | wsData.push(headers) | ||
| 1094 | |||
| 1095 | // 处理数据行 | ||
| 1096 | transposedData.value.forEach(item => { | ||
| 1097 | const row = bookHeaders.value.map(f => { | ||
| 1098 | if (f.field.indexOf('title') == -1) { | ||
| 1099 | // 分类字段 | ||
| 1100 | return changeNum(item[f.field]) | ||
| 1101 | } else { | ||
| 1102 | // 其他字段 | ||
| 1103 | return item[f.field] || '' | ||
| 1104 | } | ||
| 1266 | }) | 1105 | }) |
| 1106 | wsData.push(row) | ||
| 1267 | }) | 1107 | }) |
| 1268 | return allCells; | ||
| 1269 | } | ||
| 1270 | 1108 | ||
| 1271 | // 设置单元格样式 | 1109 | // 创建工作表 |
| 1272 | const applyStyles = (ws, pRef, type) => { | 1110 | const ws = XLSXS.utils.aoa_to_sheet(wsData) |
| 1273 | // 获取所有带有样式的单元格 | ||
| 1274 | const styledCells = getAllCells(pRef, type) | ||
| 1275 | 1111 | ||
| 1276 | // 设置单元格样式 | 1112 | // 自动调整列宽 |
| 1277 | styledCells.forEach((cell) => { | 1113 | const colWidths = bookHeaders.value.map((field, index) => { |
| 1278 | const cellRef = XLSXS.utils.encode_cell({ r: cell.rowIndex, c: cell.cellIndex }); | 1114 | const defaultWidth = field.width || 100 // 默认宽度100 |
| 1279 | const style = cell.style; | 1115 | const colWidth = defaultWidth / 14 + 2; // 留一些余地 |
| 1116 | |||
| 1117 | // 取表头宽度和内容宽度的较大值 | ||
| 1118 | return { wpx: colWidth * 12 } // 使用像素宽度 | ||
| 1119 | }) | ||
| 1120 | |||
| 1121 | ws['!cols'] = colWidths | ||
| 1280 | 1122 | ||
| 1281 | // 设置单元格样式 | 1123 | // 设置单元格样式 |
| 1282 | const cellStyle = { | 1124 | const range = XLSXS.utils.decode_range(ws['!ref']) |
| 1283 | alignment: { | 1125 | // 数值字段(除title外的所有字段) |
| 1284 | horizontal: cell.format ? 'right' : style.textAlign, | 1126 | const numericFields = bookHeaders.value.slice(1).map(f => f.field); |
| 1285 | vertical: 'center', // 垂直居中 | ||
| 1286 | }, | ||
| 1287 | }; | ||
| 1288 | 1127 | ||
| 1289 | ws[cellRef] = ws[cellRef] || {}; | 1128 | for (let R = range.s.r; R <= range.e.r; ++R) { |
| 1290 | ws[cellRef].s = cellStyle; | 1129 | for (let C = range.s.c; C <= range.e.c; ++C) { |
| 1291 | if (cell.format) { | 1130 | const cellAddress = XLSXS.utils.encode_cell({ r: R, c: C }) |
| 1292 | ws[cellRef].z = cell.format; | 1131 | |
| 1293 | } else { | 1132 | // 确保单元格存在(有些空值单元格可能不存在) |
| 1294 | ws[cellRef].t = 's'; | 1133 | if (!ws[cellAddress]) { |
| 1295 | ws[cellRef].v = cell.value; | 1134 | ws[cellAddress] = {}; |
| 1296 | } | 1135 | } |
| 1297 | }); | 1136 | |
| 1298 | // 合并单元格 | 1137 | // 默认样式(垂直居中) |
| 1299 | const mergedCells = document.querySelectorAll('.merged-cell'); | 1138 | const defaultStyle = { |
| 1300 | mergedCells.forEach((cell) => { | ||
| 1301 | // 设置合并单元格的样式 | ||
| 1302 | const mergedCellStyle = { | ||
| 1303 | alignment: { | 1139 | alignment: { |
| 1304 | vertical: 'center', // 垂直居中 | 1140 | vertical: 'center', |
| 1305 | }, | 1141 | horizontal: 'left' |
| 1306 | }; | 1142 | } |
| 1143 | } | ||
| 1307 | 1144 | ||
| 1308 | const topLeftCellRef = XLSXS.utils.encode_cell({ r: cell.rowIndex, c: cell.cellIndex }); | 1145 | // 表头样式(第1行) |
| 1309 | ws[topLeftCellRef] = ws[topLeftCellRef] || {}; | 1146 | if (R === 0) { |
| 1310 | ws[topLeftCellRef].s = mergedCellStyle; | 1147 | ws[cellAddress].s = { |
| 1311 | }); | 1148 | ...defaultStyle, |
| 1312 | } | 1149 | // font: { bold: true } // 表头加粗 |
| 1150 | } | ||
| 1151 | continue | ||
| 1152 | } | ||
| 1313 | 1153 | ||
| 1314 | // 创建一个隐藏的 div 用于测量文本宽度 | 1154 | // 获取当前列对应的字段 |
| 1315 | const measureDiv = document.createElement('div'); | 1155 | const field = bookHeaders.value[C]; |
| 1316 | measureDiv.style.position = 'absolute'; | ||
| 1317 | measureDiv.style.visibility = 'hidden'; | ||
| 1318 | measureDiv.style.whiteSpace = 'nowrap'; | ||
| 1319 | document.body.appendChild(measureDiv); | ||
| 1320 | |||
| 1321 | // 测量文本宽度的函数 | ||
| 1322 | function measureTextWidth(text, fontSize, fontFamily) { | ||
| 1323 | measureDiv.style.fontSize = `${fontSize}px`; | ||
| 1324 | measureDiv.style.fontFamily = fontFamily; | ||
| 1325 | measureDiv.textContent = text; | ||
| 1326 | return measureDiv.offsetWidth; | ||
| 1327 | } | ||
| 1328 | 1156 | ||
| 1329 | const adjustColumnWidth = (ws) => { | 1157 | // 判断是否为数值列(包括最后一行) |
| 1330 | const range = XLSXS.utils.decode_range(ws['!ref']); | 1158 | const isNumeric = numericFields.includes(field?.field); |
| 1331 | const defaultFontSize = 11; // 默认字体大小 | 1159 | const cellValue = ws[cellAddress].v; |
| 1332 | const defaultFontFamily = 'Arial'; // 默认字体族 | ||
| 1333 | 1160 | ||
| 1334 | for (let C = range.s.c; C <= range.e.c; ++C) { | 1161 | // 数值列特殊处理(无论是否最后一行) |
| 1335 | let maxWidth = 0; | 1162 | if (isNumeric) { |
| 1336 | for (let R = range.s.r; R <= range.e.r; ++R) { | 1163 | ws[cellAddress].s = { |
| 1337 | const cellRef = XLSXS.utils.encode_cell({ r: R, c: C }); | 1164 | alignment: { |
| 1338 | const cellValue = ws[cellRef]?.v?.toString() || ''; | 1165 | vertical: 'center', |
| 1339 | const width = measureTextWidth(cellValue, defaultFontSize, defaultFontFamily); | 1166 | horizontal: 'right' |
| 1340 | maxWidth = Math.max(maxWidth, width); | ||
| 1341 | } | 1167 | } |
| 1168 | }; | ||
| 1342 | 1169 | ||
| 1343 | // 根据测量的宽度计算列宽 | 1170 | // 确保数值被正确识别为数字类型 |
| 1344 | const colWidth = maxWidth / defaultFontSize + 2; // 留一些余地 | 1171 | if (cellValue !== undefined && cellValue !== "" && !isNaN(cellValue)) { |
| 1345 | ws['!cols'] = ws['!cols'] || []; | 1172 | ws[cellAddress].t = 'n'; // 数字类型 |
| 1346 | ws['!cols'][C] = { wpx: colWidth * defaultFontSize }; // 使用像素宽度 | 1173 | ws[cellAddress].z = '#,##0.00'; // 数字格式 |
| 1347 | } | 1174 | } |
| 1175 | } else { | ||
| 1176 | // 文本列保持默认样式 | ||
| 1177 | ws[cellAddress].s = defaultStyle; | ||
| 1178 | } | ||
| 1179 | } | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | return ws; | ||
| 1348 | }; | 1183 | }; |
| 1349 | 1184 | ||
| 1350 | const exportClick = () => { | 1185 | const exportClick = async () => { |
| 1351 | // 获取第一个表格的数据 | 1186 | // 获取第一个表格的数据 |
| 1352 | const table1 = document.getElementById('cost-table'); | 1187 | const ws1 = await exportDetailsToExcel(); |
| 1353 | const ws1 = XLSXS.utils.table_to_sheet(table1); | ||
| 1354 | 1188 | ||
| 1355 | // 获取第二个表格的数据 | 1189 | // 获取第二个表格的数据 |
| 1356 | const table2 = document.getElementById('entry-table'); | 1190 | const ws2 = await exportBookToExcel(); |
| 1357 | const ws2 = XLSXS.utils.table_to_sheet(table2); | ||
| 1358 | |||
| 1359 | // 调整列宽 | ||
| 1360 | adjustColumnWidth(ws1); | ||
| 1361 | adjustColumnWidth(ws2); | ||
| 1362 | |||
| 1363 | // 添加样式 | ||
| 1364 | applyStyles(ws1, costTableRef.value, 'cost'); | ||
| 1365 | applyStyles(ws2, entryTableRef.value, 'entry'); | ||
| 1366 | 1191 | ||
| 1367 | // 创建工作簿并添加两个工作表 | 1192 | // 创建工作簿并添加两个工作表 |
| 1368 | const wb = XLSXS.utils.book_new(); | 1193 | const wb = XLSXS.utils.book_new(); |
| ... | @@ -1409,35 +1234,30 @@ const setSumRow = () => { | ... | @@ -1409,35 +1234,30 @@ const setSumRow = () => { |
| 1409 | } | 1234 | } |
| 1410 | 1235 | ||
| 1411 | onActivated(() => { | 1236 | onActivated(() => { |
| 1237 | tableField.value = JSON.parse(JSON.stringify(initField.value)); | ||
| 1412 | getProducts(); | 1238 | getProducts(); |
| 1413 | getCostData(); | 1239 | getCostData(); |
| 1414 | }); | 1240 | }); |
| 1415 | 1241 | ||
| 1416 | 1242 | ||
| 1417 | onMounted(() => { | 1243 | onMounted(() => { |
| 1418 | setItemLine(); | 1244 | // 添加/移除全局点击监听 |
| 1419 | window.addEventListener('resize', setItemLine); | 1245 | document.addEventListener('click', handleClickOutside) |
| 1420 | }); | 1246 | }) |
| 1421 | 1247 | ||
| 1422 | onUpdated(() => { | 1248 | onBeforeUnmount(() => { |
| 1423 | setItemLine(); | 1249 | document.removeEventListener('click', handleClickOutside) |
| 1424 | }); | 1250 | }) |
| 1425 | 1251 | ||
| 1426 | onUnmounted(() => { | 1252 | onUpdated(() => { |
| 1427 | window.removeEventListener('resize', setItemLine); | 1253 | // setItemLine(); |
| 1428 | }); | 1254 | }); |
| 1429 | 1255 | ||
| 1430 | watch(showLevel4, (newVal, oldVal) => { | ||
| 1431 | setItemLine(); | ||
| 1432 | }) | ||
| 1433 | </script> | 1256 | </script> |
| 1434 | 1257 | ||
| 1435 | <template> | 1258 | <template> |
| 1436 | <div class="container_wrap"> | 1259 | <div class="container_wrap"> |
| 1437 | <div class="content_main"> | 1260 | <div class="content_main"> |
| 1438 | <!-- <div class="top_tool_wrap"> | ||
| 1439 | <StepBar :steps-info="stepsInfo" /> | ||
| 1440 | </div> --> | ||
| 1441 | <div class="operator_panel_wrap" :style="{ 'min-height': 'unset' }" v-loading="loading"> | 1261 | <div class="operator_panel_wrap" :style="{ 'min-height': 'unset' }" v-loading="loading"> |
| 1442 | <div class="v-tip" v-show="step == 0"> | 1262 | <div class="v-tip" v-show="step == 0"> |
| 1443 | <div class="tip-icon"></div> | 1263 | <div class="tip-icon"></div> |
| ... | @@ -1455,152 +1275,71 @@ watch(showLevel4, (newVal, oldVal) => { | ... | @@ -1455,152 +1275,71 @@ watch(showLevel4, (newVal, oldVal) => { |
| 1455 | <!-- <el-button type="primary" plain @click="senMessage">入表咨询</el-button> --> | 1275 | <!-- <el-button type="primary" plain @click="senMessage">入表咨询</el-button> --> |
| 1456 | </div> | 1276 | </div> |
| 1457 | </div> | 1277 | </div> |
| 1458 | <div class="grid-box-wrap" v-show="step == 3"> | ||
| 1459 | <!-- 头部标题 --> | ||
| 1460 | <div class="grid-panel-wrap header" :class="{ col4: showLevel4 }"> | ||
| 1461 | <template v-for="(list, l) in gridList" :key="'panel'+l"> | ||
| 1462 | <div class="panel-header" v-if="l < 3 || showLevel4">{{ list.name }}</div> | ||
| 1463 | </template> | ||
| 1464 | </div> | ||
| 1465 | <div class="grid-panel-wrap" :class="{ col4: showLevel4 }" v-for="(item, i) in allMapList" | ||
| 1466 | :key="'panel-' + i"> | ||
| 1467 | <!-- 一级指标 --> | ||
| 1468 | <div class="grid-panel-box"> | ||
| 1469 | <div class="grid-panel" ref="gridPanel"> | ||
| 1470 | <div class="grid-items after" ref="gridItem" :class="getClass(i, item.checked)"> | ||
| 1471 | <el-checkbox v-model="item.checked" @change="val => checkboxChange(val, { item }, 1)" /> | ||
| 1472 | <span class="item-label">{{ item.name }}</span> | ||
| 1473 | <span class="circle"></span> | ||
| 1474 | </div> | ||
| 1475 | </div> | ||
| 1476 | </div> | ||
| 1477 | <!-- 一级分类 --> | ||
| 1478 | <div class="grid-panel-box box1"> | ||
| 1479 | <template v-for="(grid, g) in item.children" :key="'grid' + i + '-' + g"> | ||
| 1480 | <div class="grid-panel" :class="{ before: g < item.children.length - 1, left8: showLevel4 }"> | ||
| 1481 | <div class="grid-items before after" :class="getClass(i, grid.checked)"> | ||
| 1482 | <el-checkbox v-model="grid.checked" @change="val => checkboxChange(val, { item, grid }, 2)" /> | ||
| 1483 | <span class="item-label">{{ grid.name }}</span> | ||
| 1484 | <span class="circle"></span> | ||
| 1485 | </div> | ||
| 1486 | </div> | ||
| 1487 | </template> | ||
| 1488 | </div> | ||
| 1489 | <!-- 二级分类 --> | ||
| 1490 | <div class="grid-panel-box box2 before" :class="{ after: showLevel4 }"> | ||
| 1491 | <template v-for="(grid, g) in item.children" :key="'grid' + i + '-' + g"> | ||
| 1492 | <div class="grid-panel height_auto" :class="{ left8: showLevel4 }" v-if="grid.children.length"> | ||
| 1493 | <div class="grid-items before" | ||
| 1494 | :class="[getClass(i, child.checked), { after: child.children.length }]" | ||
| 1495 | v-for="(child, c) in grid.children" :key="'item' + i + '-' + g + '-' + c" | ||
| 1496 | :style="setItemStyle(child, null)"> | ||
| 1497 | <el-checkbox v-model="child.checked" | ||
| 1498 | @change="val => checkboxChange(val, { item, grid, child }, 3)" /> | ||
| 1499 | <span class="item-label">{{ child.name }}</span> | ||
| 1500 | <div class="item-tool"> | ||
| 1501 | <el-popover placement="bottom-end" :width="108" trigger="click" popper-class="popover_btns"> | ||
| 1502 | <template #reference> | ||
| 1503 | <el-icon> | ||
| 1504 | <MoreFilled /> | ||
| 1505 | </el-icon> | ||
| 1506 | </template> | ||
| 1507 | <template #default> | ||
| 1508 | <div class="tool-btns"> | ||
| 1509 | <div @click="btnClick({ value: 'add-same', row: child, parent: grid })">新增本级</div> | ||
| 1510 | <div @click="btnClick({ value: 'add-lower', row: child, parent: grid })">新增下级</div> | ||
| 1511 | <div @click="btnClick({ value: 'edit', row: child, parent: grid })">重命名</div> | ||
| 1512 | <div v-if="grid.children.length > 1" | ||
| 1513 | @click="btnClick({ value: 'remove', row: child, parent: grid })">删除</div> | ||
| 1514 | </div> | ||
| 1515 | </template> | ||
| 1516 | </el-popover> | ||
| 1517 | </div> | ||
| 1518 | <span class="circle" :style="{ height: spanHeight(child) }"></span> | ||
| 1519 | </div> | ||
| 1520 | </div> | ||
| 1521 | </template> | ||
| 1522 | </div> | ||
| 1523 | <!-- 三级分类 --> | ||
| 1524 | <div class="grid-panel-box box3" v-if="showLevel4"> | ||
| 1525 | <div class="grid-panel no_padding" v-if="showPanel(item.children, item)"> | ||
| 1526 | <template v-for="(grid, g) in item.children" :key="'grid' + i + '-' + g"> | ||
| 1527 | <div class="grid-group"> | ||
| 1528 | <template v-for="(child, c) in grid.children" :key="'item' + i + '-' + g + '-' + c"> | ||
| 1529 | <div class="group-items before"> | ||
| 1530 | <div class="grid-items before" :class="getClass(i, opt.checked)" | ||
| 1531 | v-for="(opt, o) in child.children" :key="'pis' + i + '-' + g + '-' + c + '-' + o" | ||
| 1532 | :style="setItemStyle(opt, { o })"> | ||
| 1533 | <el-checkbox v-model="opt.checked" | ||
| 1534 | @change="val => checkboxChange(val, { item, grid, child, opt }, 4)" /> | ||
| 1535 | <span class="item-label">{{ opt.name }}</span> | ||
| 1536 | <div class="item-tool"> | ||
| 1537 | <el-popover placement="bottom-end" :width="108" trigger="click" | ||
| 1538 | popper-class="popover_btns"> | ||
| 1539 | <template #reference> | ||
| 1540 | <el-icon> | ||
| 1541 | <MoreFilled /> | ||
| 1542 | </el-icon> | ||
| 1543 | </template> | ||
| 1544 | <template #default> | ||
| 1545 | <div class="tool-btns"> | ||
| 1546 | <div @click="btnClick({ value: 'edit', row: opt, parent: child })">重命名</div> | ||
| 1547 | <div @click="btnClick({ value: 'remove', row: opt, parent: child })">删除</div> | ||
| 1548 | </div> | ||
| 1549 | </template> | ||
| 1550 | </el-popover> | ||
| 1551 | </div> | ||
| 1552 | </div> | ||
| 1553 | </div> | ||
| 1554 | </template> | ||
| 1555 | </div> | ||
| 1556 | </template> | ||
| 1557 | </div> | ||
| 1558 | </div> | ||
| 1559 | </div> | ||
| 1560 | </div> | ||
| 1561 | <div class="table_panel_wrap"> | 1278 | <div class="table_panel_wrap"> |
| 1562 | <div class="amount_tool"> | 1279 | <div class="amount_tool" v-if="besure"> |
| 1563 | <span class="amount_text">累计投入:</span> | 1280 | <span class="amount_text">累计投入:</span> |
| 1564 | <span class="amount_num">{{ changeNum(amount, 2, true) }}</span> | 1281 | <span class="amount_num">{{ changeNum(amount, 2, true) }}</span> |
| 1565 | <span>元</span> | 1282 | <span>元</span> |
| 1566 | </div> | 1283 | </div> |
| 1567 | <div class="table_panel"> | 1284 | <div class="table_panel"> |
| 1568 | <el-table id="cost-table" v-show="step == 0" ref="costTableRef" :data="tableData" | 1285 | <el-table id="cost-table" v-show="step == 0" ref="costTableRef" :data="tableData" |
| 1569 | :span-method="tableSpanMethod" :summary-method="tableSummaryMethod" show-summary border | 1286 | :span-method="tableSpanMethod" :show-summary="besure" :summary-method="tableSummaryMethod" |
| 1570 | :cell-class-name="isMergedCell"> | 1287 | :cell-class-name="isMergedCell" border> |
| 1571 | <el-table-column v-for="(item, i) in tableField" :label="item.label" :width="item.width" | 1288 | <template v-for="(item, i) in tableField" :key="'tField' + i"> |
| 1572 | :min-width="item.minWidth" :fixed="item.fixed" :align="item.align" :sortable="item.sortable ?? false" | 1289 | <el-table-column v-if="item.visible ?? true" :label="item.label" :width="item.width" |
| 1573 | :prop="item.field" :class-name="item.columClass" show-overflow-tooltip> | 1290 | :min-width="item.minWidth" :fixed="item.fixed" :align="item.align" |
| 1291 | :sortable="item.sortable ?? false" :prop="item.field" :class-name="item.columClass" | ||
| 1292 | show-overflow-tooltip> | ||
| 1574 | <template #default="scope"> | 1293 | <template #default="scope"> |
| 1575 | <div class="input_cell" v-if="item.type == 'input'"> | 1294 | <div class="input_cell" v-if="item.type == 'input'"> |
| 1576 | <el-input v-model.trim="scope.row[item.field]" placeholder="请输入" :maxlength="item.maxlength ?? ''" | 1295 | <el-input v-model.trim="scope.row[item.field]" placeholder="请输入" |
| 1577 | @change="(val) => inputChange(val, scope, item.field)" | 1296 | :maxlength="item.maxlength ?? ''" @change="(val) => inputChange(val, scope, item.field)" |
| 1578 | @input="(val) => inputEventChange(val, scope, item.field)" clearable></el-input> | 1297 | @input="(val) => inputEventChange(val, scope, item.field)" |
| 1298 | :disabled="scope.row.edit ? false : true" clearable></el-input> | ||
| 1579 | <span>{{ scope.row[item.field] ? changeNum(scope.row[item.field], 2, true) : | 1299 | <span>{{ scope.row[item.field] ? changeNum(scope.row[item.field], 2, true) : |
| 1580 | Number(scope.row[item.field]) == 0 ? '0.00' : '' }}</span> | 1300 | Number(scope.row[item.field]) == 0 ? '0.00' : '' }}</span> |
| 1581 | </div> | 1301 | </div> |
| 1582 | <span v-else> | 1302 | <div class="cell-tool" v-else> |
| 1583 | {{ item.getName ? item.getName(scope) : scope.row[item.field] !== 0 && !scope.row[item.field] ? | 1303 | <span class="cell_text_group"> |
| 1304 | <el-checkbox v-if="item.field != 'total' && scope.row[item.field]" | ||
| 1305 | v-model="scope.row['checked' + item.level]" | ||
| 1306 | @change="val => cellCheckboxChange(val, { ...item, ...scope.row, rIndex: scope.$index })" /> | ||
| 1307 | <span class="cell_text"> | ||
| 1308 | {{ item.getName ? item.getName(scope) : scope.row[item.field] !== 0 && | ||
| 1309 | !scope.row[item.field] | ||
| 1310 | ? | ||
| 1584 | "--" : scope.row[item.field] }} | 1311 | "--" : scope.row[item.field] }} |
| 1585 | </span> | 1312 | </span> |
| 1313 | </span> | ||
| 1314 | <el-icon v-if="item.field == 'name3' || (item.field == 'name4' && scope.row[item.field])" | ||
| 1315 | class="list-more" color="#666" | ||
| 1316 | @click="e => togglePopover({ ...item, ...scope.row, rIndex: scope.$index }, e)"> | ||
| 1317 | <MoreFilled /> | ||
| 1318 | </el-icon> | ||
| 1319 | </div> | ||
| 1586 | </template> | 1320 | </template> |
| 1587 | </el-table-column> | 1321 | </el-table-column> |
| 1322 | </template> | ||
| 1588 | </el-table> | 1323 | </el-table> |
| 1589 | <el-table id="entry-table" ref="entryTableRef" :data="transposedData" stripe border v-show="step == 1"> | 1324 | <el-table id="entry-table" ref="entryTableRef" :data="transposedData" stripe border v-show="step == 1"> |
| 1590 | <el-table-column prop="title" label="项目" :width="140"> | 1325 | <!-- <el-table-column prop="title" label="项目" :width="140"> |
| 1591 | <template v-slot="{ row }"> | 1326 | <template v-slot="{ row }"> |
| 1592 | <span>{{ setLabel(row.title) }}</span> | 1327 | <span>{{ setLabel(row.title) }}</span> |
| 1593 | </template> | 1328 | </template> |
| 1594 | </el-table-column> | 1329 | </el-table-column> --> |
| 1595 | <el-table-column v-for="(item, index) in headers" :key="index" :prop="item.value" :label="item.label" | 1330 | <el-table-column v-for="(item, index) in bookHeaders" :key="index" :prop="item.field" :label="item.label" |
| 1596 | :width="120" align="right"> | 1331 | :width="item.width" :align="item.align"> |
| 1597 | <template v-slot:header> | 1332 | <template #default="scope"> |
| 1333 | <span v-if="item.field == 'title'">{{ setLabel(scope.row[item.field]) }}</span> | ||
| 1334 | <span v-else>{{ changeNum(scope.row[item.field], 2) }}</span> | ||
| 1335 | </template> | ||
| 1336 | <!-- <template v-slot:header> | ||
| 1598 | <span v-html="item.label"></span> | 1337 | <span v-html="item.label"></span> |
| 1599 | </template> | 1338 | </template> |
| 1600 | <template v-slot="{ row }"> | 1339 | <template v-slot="{ row }"> |
| 1601 | <span v-if="typeof row[item.value] == 'number'">{{ changeNum(row[item.value], 2, true) }}</span> | 1340 | <span v-if="typeof row[item.field] == 'number'">{{ changeNum(row[item.field], 2, true) }}</span> |
| 1602 | <span v-else></span> | 1341 | <span v-else></span> |
| 1603 | </template> | 1342 | </template> --> |
| 1604 | </el-table-column> | 1343 | </el-table-column> |
| 1605 | </el-table> | 1344 | </el-table> |
| 1606 | </div> | 1345 | </div> |
| ... | @@ -1615,13 +1354,21 @@ watch(showLevel4, (newVal, oldVal) => { | ... | @@ -1615,13 +1354,21 @@ watch(showLevel4, (newVal, oldVal) => { |
| 1615 | <div class="tool_btns"> | 1354 | <div class="tool_btns"> |
| 1616 | <div class="btns"> | 1355 | <div class="btns"> |
| 1617 | <el-button @click="btnClick({ value: 'refresh' })">重置</el-button> | 1356 | <el-button @click="btnClick({ value: 'refresh' })">重置</el-button> |
| 1618 | <el-button @click="btnClick({ value: 'next' })" v-if="step == 0">入表</el-button> | 1357 | <el-button type="primary" @click="btnClick({ value: 'next' })" v-if="step == 0">入表</el-button> |
| 1619 | <!-- <el-button @click="btnClick({ value: 'prev' })" v-if="step == 1">上一步</el-button> | 1358 | <el-button type="primary" @click="btnClick({ value: 'prev' })" v-if="step == 1">上一步</el-button> |
| 1620 | <el-button type="primary" @click="btnClick({ value: 'prev' })" v-if="step == 2">上一步</el-button> | ||
| 1621 | <el-button type="primary" @click="btnClick({ value: 'next' })" v-if="step < 2">下一步</el-button> --> | ||
| 1622 | </div> | 1359 | </div> |
| 1623 | </div> | 1360 | </div> |
| 1624 | </div> | 1361 | </div> |
| 1362 | <el-popover :visible="popoverVisible" placement="bottom-start" width="110" trigger="click" | ||
| 1363 | popper-class="tree-item-edit-menu" :virtual-ref="popoverTriggerRef" virtual-triggering :hide-after="0" :offset="8" | ||
| 1364 | @after-leave="handlePopoverClose"> | ||
| 1365 | <div class="levitation-ul" @mousedown.stop> | ||
| 1366 | <span class="levitation-li" @click="handleMenuClick('add-same')" v-show="showAdd">新增本级分类</span> | ||
| 1367 | <span class="levitation-li" @click="handleMenuClick('add-lower')" v-show="showAdd">新增下级分类</span> | ||
| 1368 | <span class="levitation-li" @click="handleMenuClick('edit')">重命名</span> | ||
| 1369 | <span class="levitation-li" @click="handleMenuClick('remove')">删除</span> | ||
| 1370 | </div> | ||
| 1371 | </el-popover> | ||
| 1625 | </template> | 1372 | </template> |
| 1626 | 1373 | ||
| 1627 | <style lang="scss" scoped> | 1374 | <style lang="scss" scoped> |
| ... | @@ -1968,6 +1715,25 @@ watch(showLevel4, (newVal, oldVal) => { | ... | @@ -1968,6 +1715,25 @@ watch(showLevel4, (newVal, oldVal) => { |
| 1968 | 1715 | ||
| 1969 | :deep(.el-table) { | 1716 | :deep(.el-table) { |
| 1970 | td.el-table__cell { | 1717 | td.el-table__cell { |
| 1718 | .cell-tool { | ||
| 1719 | display: flex; | ||
| 1720 | justify-content: space-between; | ||
| 1721 | align-items: center; | ||
| 1722 | |||
| 1723 | .cell_text_group { | ||
| 1724 | display: flex; | ||
| 1725 | |||
| 1726 | .cell_text { | ||
| 1727 | margin-left: 4px; | ||
| 1728 | line-height: 32px; | ||
| 1729 | } | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | .list-more { | ||
| 1733 | cursor: pointer; | ||
| 1734 | } | ||
| 1735 | } | ||
| 1736 | |||
| 1971 | &.edit_cell { | 1737 | &.edit_cell { |
| 1972 | padding: 4px 0; | 1738 | padding: 4px 0; |
| 1973 | 1739 | ||
| ... | @@ -1985,6 +1751,13 @@ watch(showLevel4, (newVal, oldVal) => { | ... | @@ -1985,6 +1751,13 @@ watch(showLevel4, (newVal, oldVal) => { |
| 1985 | } | 1751 | } |
| 1986 | } | 1752 | } |
| 1987 | } | 1753 | } |
| 1754 | |||
| 1755 | &.inverse_cell { | ||
| 1756 | .cell_text_group { | ||
| 1757 | display: block; | ||
| 1758 | width: 100%; | ||
| 1759 | } | ||
| 1760 | } | ||
| 1988 | } | 1761 | } |
| 1989 | 1762 | ||
| 1990 | .el-table__footer-wrapper tr td { | 1763 | .el-table__footer-wrapper tr td { |
| ... | @@ -1993,4 +1766,10 @@ watch(showLevel4, (newVal, oldVal) => { | ... | @@ -1993,4 +1766,10 @@ watch(showLevel4, (newVal, oldVal) => { |
| 1993 | } | 1766 | } |
| 1994 | } | 1767 | } |
| 1995 | } | 1768 | } |
| 1769 | |||
| 1770 | :deep(.el-popper) { | ||
| 1771 | &.tree-item-edit-menu { | ||
| 1772 | transform: translateX(-10px); | ||
| 1773 | } | ||
| 1774 | } | ||
| 1996 | </style> | 1775 | </style> | ... | ... |
-
Please register or sign in to post a comment