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