Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
csbr-daop
/
fe-data-trusted-space
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
5b046d4a
authored
2025-08-20 13:07:18 +0800
by
lxs
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
入表功调整
1 parent
c4eb6d2f
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
720 additions
and
779 deletions
src/api/modules/dataEntry.ts
src/views/data_entry/index.vue
src/api/modules/dataEntry.ts
View file @
5b046d4
...
...
@@ -8,10 +8,9 @@ export const getAssetCatalog = (params= {}) => request({
})
/** 获取成本项列表 */
export
const
getCostList
=
(
params
)
=>
request
({
url
:
`
${
import
.
meta
.
env
.
VITE_API_NEW_PORTAL
}
/tableentry-index-classify/
page-
list`
,
export
const
getCostList
=
()
=>
request
({
url
:
`
${
import
.
meta
.
env
.
VITE_API_NEW_PORTAL
}
/tableentry-index-classify/list`
,
method
:
'post'
,
data
:
params
})
/** 获取成本项详情 */
...
...
src/views/data_entry/index.vue
View file @
5b046d4
...
...
@@ -6,13 +6,9 @@
import
{
ref
,
inject
}
from
"vue"
;
import
{
ElMessage
,
ElMessageBox
,
translate
}
from
"element-plus"
;
import
{
MoreFilled
}
from
'@element-plus/icons-vue'
import
StepBar
from
"@/components/StepBar/index.vue"
;
import
TableTools
from
"@/components/Tools/table_tools.vue"
;
import
Table
from
"@/components/Table/index.vue"
;
import
Form
from
"@/components/Form/index.vue"
;
import
useUserStore
from
"@/store/modules/user"
;
import
{
changeNum
}
from
"@/utils/common"
;
import
{
getAssetCatalog
,
getCostList
,
sendEntryMsg
}
from
"@/api/modules/dataEntry"
;
import
{
costDelete
,
getAssetCatalog
,
getCostList
,
sendEntryMsg
}
from
"@/api/modules/dataEntry"
;
import
*
as
XLSXS
from
'xlsx-js-style'
;
import
{
saveAs
}
from
'file-saver'
;
...
...
@@ -20,36 +16,17 @@ const { proxy } = getCurrentInstance() as any;
const
userStore
=
useUserStore
();
const
userData
=
JSON
.
parse
(
userStore
.
userData
);
const
itemWidth
=
ref
(
'56px'
);
const
itemLeft
=
ref
(
'-56px'
);
const
reload
=
inject
(
"reload"
);
const
reload
:
any
=
inject
(
"reload"
);
const
loading
=
ref
(
false
);
const
companyName
=
ref
(
''
);
/** 默认显示步骤 */
const
step
=
ref
(
0
);
/** 步骤条配置信息 */
const
stepsInfo
=
ref
({
step
:
step
.
value
,
list
:
[
{
title
:
'设置成本项'
,
value
:
1
},
{
title
:
'填写成本项'
,
value
:
2
},
{
title
:
'入表'
,
value
:
3
},
]
})
const
allMapList
=
ref
([]);
const
showLevel4
=
ref
(
false
);
const
gridList
=
ref
([
{
name
:
'一级指标'
,
code
:
'0'
,
children
:
[]
},
{
name
:
'一级分类'
,
code
:
'1'
,
children
:
[]
},
{
name
:
'二级分类'
,
code
:
'2'
,
children
:
[]
},
{
name
:
'三级分类'
,
code
:
'3'
,
children
:
[]
},
]);
const
checkedList
=
ref
([]);
const
showAdd
=
ref
(
false
);
const
productList
=
ref
([]);
const
costFormRef
=
ref
();
const
entryFormRef
=
ref
();
const
costFormInfo
=
ref
({});
const
costFormInfo
:
any
=
ref
({});
const
costForm
=
ref
({
id
:
'step-form-one'
,
col
:
''
,
...
...
@@ -77,7 +54,7 @@ const costForm = ref({
placeholder
:
"请选择"
,
clearable
:
true
,
required
:
true
,
visible
:
fals
e
,
visible
:
tru
e
,
popperClass
:
'date-year-popper'
,
disabledDate
:
(
date
)
=>
{
const
curr
=
new
Date
();
...
...
@@ -92,7 +69,7 @@ const costForm = ref({
placeholder
:
"请选择"
,
clearable
:
true
,
required
:
true
,
visible
:
fals
e
,
visible
:
tru
e
,
style
:
{
width
:
'calc(33.33% - 70px)'
,
'margin-right'
:
'8px'
},
popperClass
:
'date-month-popper'
,
disabledDate
:
(
date
)
=>
{
...
...
@@ -106,7 +83,7 @@ const costForm = ref({
options
:
[
{
label
:
'确认'
,
value
:
'besure'
,
type
:
'primary'
,
style
:
{
height
:
'32px'
}
},
],
visible
:
fals
e
,
visible
:
tru
e
,
style
:
{
width
:
'unset'
,
'align-self'
:
'end'
,
'margin-right'
:
'0px'
}
},
],
...
...
@@ -135,7 +112,7 @@ const costForm = ref({
]
}
});
const
entryForm
=
ref
({
const
entryForm
:
any
=
ref
({
id
:
'step-form-two'
,
col
:
''
,
items
:
[
...
...
@@ -208,15 +185,8 @@ const entryForm = ref({
});
const
amount
=
ref
(
0
);
const
sumAmount
=
ref
([]);
const
initCheckedList
=
ref
([]);
const
checkedData
=
ref
([]);
const
sumAmount
:
any
=
ref
([]);
const
costFileds
=
ref
({});
const
rowCount
=
{
level1
:
{
index
:
0
,
rowspan
:
[]
},
level2
:
{
index
:
0
,
rowspan
:
[]
},
level3
:
{
index
:
0
,
rowspan
:
[]
},
}
const
convertConfig
=
{
intangible
:
{
originName
:
'一、账面原值'
,
...
...
@@ -255,12 +225,24 @@ const convertConfig = {
}
}
const
costTableRef
=
ref
(
null
);
const
isInitField
=
ref
(
true
);
const
initField
=
ref
([]);
//第二步初始化的表头数据
const
tableField
=
ref
([]);
const
tableData
=
ref
([])
const
initField
:
any
=
ref
([
{
label
:
"一级指标"
,
field
:
"name1"
,
level
:
1
,
width
:
120
,
visible
:
true
},
{
label
:
"一级分类"
,
field
:
"name2"
,
level
:
2
,
width
:
120
,
visible
:
true
},
{
label
:
"二级分类"
,
field
:
"name3"
,
level
:
3
,
width
:
200
,
visible
:
true
},
{
label
:
"三级分类"
,
field
:
"name4"
,
level
:
4
,
width
:
200
,
visible
:
false
},
{
label
:
"累计投入"
,
field
:
"total"
,
width
:
120
,
align
:
'right'
,
visible
:
false
,
columClass
:
'inverse_cell'
,
getName
:
(
scope
)
=>
{
return
changeNum
(
scope
.
row
.
total
,
2
,
true
);
}
},
]);
//第二步初始化的表头数据
const
tableField
:
any
=
ref
([]);
const
tableData
:
any
=
ref
([])
const
besure
=
ref
(
false
);
const
mergeRowCount
=
ref
({});
const
mergeRowCount
:
any
=
ref
({});
const
checkedData
:
any
=
ref
([]);
const
checkedField
:
any
=
ref
([]);
const
entryItem
=
{
year
:
''
,
originName
:
''
,
...
...
@@ -289,10 +271,17 @@ const entryItem = {
};
const
entryTableRef
=
ref
(
null
);
const
entryData
=
[]
const
headers
=
ref
([]);
const
entryData
:
any
=
ref
([]);
const
bookHeaders
:
any
=
ref
([
{
label
:
'项目'
,
field
:
'title'
,
width
:
140
,
align
:
'left'
}
]);
const
transposedData
=
ref
([]);
const
popoverVisible
=
ref
(
false
);
const
popoverTriggerRef
=
ref
(
null
)
const
currentRow
:
any
=
ref
({})
// 获取产品数据
const
getProducts
=
()
=>
{
getAssetCatalog
().
then
((
res
:
any
)
=>
{
if
(
res
.
code
==
proxy
.
$passCode
)
{
...
...
@@ -305,147 +294,106 @@ const getProducts = () => {
})
}
// 获取原始指标数据
const
getCostData
=
()
=>
{
loading
.
value
=
true
;
getCostList
({
pageIndex
:
1
,
pageSize
:
-
1
,
}).
then
((
res
:
any
)
=>
{
getCostList
().
then
((
res
:
any
)
=>
{
loading
.
value
=
false
;
const
data
=
res
.
data
.
records
||
[];
let
levelList
=
{
level1
:
[],
level2
:
[],
level3
:
[],
level4
:
[]
};
data
.
map
(
item
=>
{
item
.
checked
=
false
;
item
.
ch
ildren
=
[]
;
levelList
[
'level'
+
item
.
level
].
push
(
item
)
;
const
data
=
res
.
data
||
[];
tableData
.
value
=
data
.
map
(
item
=>
{
item
.
checked1
=
false
;
item
.
checked
2
=
false
;
item
.
ch
ecked3
=
false
;
return
item
;
})
levelList
.
level1
.
map
(
l
=>
allMapList
.
value
.
push
(
l
));
setAllMapList
(
levelList
,
allMapList
.
value
,
2
);
getMergeRow
();
}).
catch
((
res
)
=>
{
loading
.
value
=
false
;
});
};
// 整理成本项数据
const
setAllMapList
=
(
mapObj
,
arr
,
level
)
=>
{
arr
.
map
(
item
=>
{
const
code
=
item
.
code
;
item
.
children
=
mapObj
[
'level'
+
level
].
filter
(
a
=>
a
.
parentId
==
code
);
level
<
3
&&
setAllMapList
(
mapObj
,
item
.
children
,
level
+
1
);
})
// console.log(allMapList.value);
}
const
setStep
=
async
()
=>
{
const
info
=
costFormInfo
.
value
;
await
setFormItems
(
info
,
'cost'
);
costForm
.
value
.
items
[
0
].
disabled
=
step
.
value
>
0
;
costForm
.
value
.
items
[
1
].
visible
=
step
.
value
==
1
;
costForm
.
value
.
items
[
2
].
visible
=
step
.
value
==
1
;
costForm
.
value
.
items
[
3
].
visible
=
step
.
value
==
1
;
if
(
step
.
value
==
1
)
{
setSumRow
();
// 单元格多选框选中监听
const
cellCheckboxChange
=
(
val
,
scope
)
=>
{
const
{
rIndex
,
level
}
=
scope
;
let
rowData
=
tableData
.
value
[
rIndex
];
rowData
[
`checked
${
level
}
`
]
=
val
;
if
(
val
)
{
// 选中上级
for
(
let
l
=
level
-
1
;
l
>=
1
;
l
--
)
{
const
tIndex
=
l
;
const
rCode
=
rowData
[
`code
${
l
}
`
];
(()
=>
{
setChecked
(
tIndex
,
rCode
,
val
);
})();
}
stepsInfo
.
value
.
step
=
step
.
value
;
nextTick
(()
=>
{
const
contentDom
=
document
.
getElementsByClassName
(
'content_main'
);
if
(
contentDom
[
0
])
{
contentDom
[
0
].
scrollTo
({
behavior
:
'smooth'
,
top
:
0
,
});
}
else
{
// 取消选中下级
const
rowList
=
tableData
.
value
.
filter
(
t
=>
t
[
`code
${
level
}
`
]
==
rowData
[
`code
${
level
}
`
]);
rowList
.
forEach
(
rData
=>
{
for
(
let
l
=
level
;
l
<=
4
;
l
++
)
{
rData
[
`checked
${
l
}
`
]
=
val
;
}
})
}
}
rowData
.
edit
=
rowData
.
code4
?
rowData
.
checked4
:
rowData
.
checked3
;
// 数据是否可编辑
checkedData
.
value
=
tableData
.
value
.
filter
(
t
=>
t
.
edit
);
};
const
checkboxChange
=
(
val
,
scope
,
level
)
=>
{
const
{
item
,
grid
,
child
,
opt
}
=
scope
;
let
row
=
{};
switch
(
level
)
{
case
1
:
row
=
item
;
break
;
case
2
:
row
=
grid
;
break
;
case
3
:
row
=
child
;
break
;
case
4
:
row
=
opt
;
break
;
}
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
:
''
};
const
eIndex
=
list
.
findIndex
(
item
=>
item
.
guid
==
row
.
guid
);
const
tIndex
=
tData
.
findIndex
(
t
=>
t
.
guid
==
row
.
guid
);
// 设置单元格选中
const
setChecked
=
(
level
,
code
,
check
)
=>
{
const
rowList
=
tableData
.
value
.
filter
(
t
=>
t
[
`code
${
level
}
`
]
==
code
);
rowList
.
forEach
(
rData
=>
rData
[
`checked
${
level
}
`
]
=
check
)
};
if
(
val
)
{
eIndex
===
-
1
&&
list
.
push
(
row
);
if
(
tIndex
===
-
1
)
{
tRow
[
`level
${
row
.
level
}
`
]
=
row
.
name
;
tData
.
push
(
tRow
);
}
if
(
level
>
1
)
{
item
.
checked
=
true
;
const
x
=
list
.
findIndex
(
l
=>
l
.
guid
==
item
.
guid
);
x
===
-
1
&&
list
.
push
(
item
);
const
i
=
tData
.
findIndex
(
t
=>
t
.
guid
==
item
.
guid
);
i
>
-
1
&&
tData
.
splice
(
i
,
1
);
if
(
level
>
2
)
{
grid
.
checked
=
true
;
const
y
=
list
.
findIndex
(
l
=>
l
.
guid
==
grid
.
guid
);
y
===
-
1
&&
list
.
push
(
grid
);
const
g
=
tData
.
findIndex
(
t
=>
t
.
guid
==
grid
.
guid
);
g
>
-
1
&&
tData
.
splice
(
g
,
1
);
if
(
level
>
3
)
{
child
.
checked
=
true
;
const
z
=
list
.
findIndex
(
l
=>
l
.
guid
==
child
.
guid
);
z
===
-
1
&&
list
.
push
(
child
);
const
c
=
tData
.
findIndex
(
t
=>
t
.
guid
==
child
.
guid
);
c
>
-
1
&&
tData
.
splice
(
c
,
1
);
}
}
}
}
else
{
eIndex
>
-
1
&&
list
.
splice
(
eIndex
,
1
);
tIndex
>
-
1
&&
tData
.
splice
(
tIndex
,
1
);
if
(
level
>
1
)
{
const
targetObj
=
level
===
2
?
item
:
level
===
3
?
grid
:
child
;
const
hasChildItem
=
targetObj
.
children
.
find
(
r
=>
r
.
checked
);
const
nIndex
=
tData
.
findIndex
(
t
=>
t
.
guid
==
targetObj
.
guid
);
if
(
!
hasChildItem
&&
nIndex
===
-
1
)
{
let
nRow
=
{
...
targetObj
,
total
:
'0.00'
,
memo
:
''
,
level1
:
item
.
name
,
level2
:
grid
?
grid
.
name
:
''
,
level3
:
child
?
child
.
name
:
''
,
level4
:
opt
?
opt
.
name
:
''
};
nRow
.
level4
=
''
;
if
(
level
===
2
)
{
nRow
.
level2
=
''
;
nRow
.
level3
=
''
;
}
else
if
(
level
===
3
)
{
nRow
.
level3
=
''
;
}
tData
.
push
(
nRow
);
}
}
level
<
4
&&
setChecked
(
row
.
children
);
// 点击外部区域关闭处理
const
handleClickOutside
=
(
event
)
=>
{
const
popoverEl
=
document
.
querySelector
(
'.tree-item-edit-menu'
)
const
triggerEl
:
any
=
popoverTriggerRef
.
value
if
(
!
popoverVisible
.
value
||
!
popoverEl
||
!
triggerEl
)
return
const
clickedInPopover
=
popoverEl
.
contains
(
event
.
target
)
const
clickedOnTrigger
=
triggerEl
===
event
.
target
||
triggerEl
.
contains
(
event
.
target
)
if
(
!
clickedInPopover
&&
!
clickedOnTrigger
)
{
popoverVisible
.
value
=
false
}
}
;
}
const
setChecked
=
(
arr
)
=>
{
let
list
=
checkedList
.
value
,
tData
=
checkedData
.
value
;
arr
.
forEach
(
a
=>
{
a
.
checked
=
false
;
const
lIndex
=
list
.
findIndex
(
t
=>
t
.
guid
==
a
.
guid
);
lIndex
>
-
1
&&
list
.
splice
(
lIndex
,
1
);
const
tIndex
=
tData
.
findIndex
(
t
=>
t
.
guid
==
a
.
guid
);
tIndex
>
-
1
&&
tData
.
splice
(
tIndex
,
1
);
if
(
a
.
children
.
length
)
{
setChecked
(
a
.
children
);
// 切换Popover显示/隐藏
const
togglePopover
=
(
row
,
event
)
=>
{
// 如果点击的是当前已激活的触发器,则关闭popover
if
(
popoverVisible
.
value
&&
popoverTriggerRef
.
value
===
event
.
currentTarget
)
{
popoverVisible
.
value
=
false
return
}
});
};
// 设置当前行和触发器引用
currentRow
.
value
=
row
popoverTriggerRef
.
value
=
event
.
currentTarget
const
level
=
Number
(
row
.
field
.
split
(
'name'
)[
1
]);
showAdd
.
value
=
level
==
3
?
true
:
false
;
// 打开popover
popoverVisible
.
value
=
true
}
// 处理菜单点击
const
handleMenuClick
=
(
action
)
=>
{
// 关闭popover
popoverVisible
.
value
=
false
;
btnClick
({
value
:
action
,
row
:
currentRow
.
value
})
}
// Popover关闭后的处理
const
handlePopoverClose
=
()
=>
{
currentRow
.
value
=
null
popoverTriggerRef
.
value
=
null
}
const
selectChange
=
async
(
val
,
row
,
info
)
=>
{
if
(
row
.
field
==
'entryType'
)
{
await
setFormItems
(
info
);
await
setFormItems
(
info
,
'entry'
);
entryForm
.
value
.
items
.
at
(
0
).
default
=
val
;
entryForm
.
value
.
items
.
at
(
1
).
visible
=
val
==
'intangible'
?
true
:
false
;
entryForm
.
value
.
items
.
at
(
2
).
visible
=
val
==
'intangible'
?
true
:
false
;
...
...
@@ -485,13 +433,57 @@ const inputEventChange = (val, scope, field) => {
row
[
field
]
=
row
[
field
].
toString
().
replace
(
/^
\D
*
(\d{0,12}(?:\.\d{0,2})?)
.*$/g
,
"$1"
)
}
// 重命名
const
setName
=
(
name
,
level
,
rIndex
)
=>
{
let
rowData
=
tableData
.
value
[
rIndex
];
rowData
[
`name
${
level
}
`
]
=
name
;
}
// 新增本级
const
addSameData
=
(
rIndex
,
name
,
level
,
tData
)
=>
{
let
rowData
=
JSON
.
parse
(
JSON
.
stringify
(
tData
));
const
lastCode
=
rowData
[
`code
${
level
-
1
}
`
];
const
tCode
=
tData
[
`code
${
level
}
`
].
split
(
lastCode
)[
1
];
const
codeVal
=
parseInt
(
tCode
,
10
)
<
10
?
`0
${
parseInt
(
tCode
,
10
)
+
1
}
`
:
parseInt
(
tCode
,
10
)
+
1
;
for
(
var
r
in
rowData
)
{
if
(
r
.
indexOf
(
'name'
)
==
-
1
&&
r
.
indexOf
(
'code'
)
==
-
1
)
rowData
[
r
]
=
''
;
}
rowData
[
`name
${
level
}
`
]
=
name
;
rowData
[
`code
${
level
}
`
]
=
`
${
lastCode
}${
codeVal
}
`
;
rowData
[
`checked
${
level
}
`
]
=
false
;
delete
rowData
.
name4
;
delete
rowData
.
code4
;
tableData
.
value
.
splice
(
rIndex
+
1
,
0
,
rowData
);
getMergeRow
();
}
// 新增下级
const
addLowerData
=
(
rIndex
,
name
,
level
,
len
)
=>
{
let
rowData
=
JSON
.
parse
(
JSON
.
stringify
(
tableData
.
value
[
rIndex
]));
const
hasLowerItem
=
rowData
[
`code
${
level
+
1
}
`
]
?
true
:
false
;
const
lastCode
=
rowData
[
`code
${
level
}
`
];
const
codeVal
=
(
len
+
1
)
<
10
?
'0'
+
(
len
+
1
)
:
len
+
1
;
for
(
var
r
in
rowData
)
{
if
(
r
.
indexOf
(
'name'
)
==
-
1
&&
r
.
indexOf
(
'code'
)
==
-
1
)
rowData
[
r
]
=
''
;
}
rowData
[
`name
${
level
+
1
}
`
]
=
name
;
rowData
[
`code
${
level
+
1
}
`
]
=
`
${
lastCode
}${
codeVal
}
`
;
rowData
[
`checked
${
level
+
1
}
`
]
=
false
;
rowData
.
edit
=
false
;
hasLowerItem
?
tableData
.
value
.
splice
(
rIndex
+
1
,
0
,
rowData
)
:
tableData
.
value
.
splice
(
rIndex
,
1
,
rowData
);
tableField
.
value
[
3
].
visible
=
true
;
getMergeRow
();
}
// 按钮点击事件
const
btnClick
=
async
(
btn
,
bType
=
null
)
=>
{
const
type
=
btn
.
value
;
if
(
type
==
'add-same'
||
type
==
'add-lower'
||
type
==
'edit'
)
{
const
row
=
btn
.
row
;
const
parent
=
btn
.
parent
;
const
inputVal
=
type
==
'edit'
?
row
.
name
:
''
;
let
isChange
=
false
,
curGridList
=
type
==
'add-lower'
?
row
.
children
:
parent
.
children
;
const
{
rIndex
,
level
}
=
row
;
const
inputVal
=
type
==
'edit'
?
row
[
`name
${
level
}
`
]
:
''
;
let
isChange
=
false
,
rowList
=
type
==
'add-same'
?
tableData
.
value
.
filter
(
t
=>
t
[
`code
${
level
-
1
}
`
]
==
row
[
`code
${
level
-
1
}
`
])
:
tableData
.
value
.
filter
(
t
=>
t
[
`code
${
level
}
`
]
==
row
[
`code
${
level
}
`
])
;
ElMessageBox
.
prompt
(
''
,
'节点名称'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
...
...
@@ -512,7 +504,7 @@ const btnClick = async (btn, bType = null) => {
if
(
name
.
length
>
10
)
{
return
'节点名称长度不能超过10个字符'
}
const
isExist
=
curGridList
.
find
(
a
=>
a
.
name
==
name
);
const
isExist
=
rowList
.
find
(
a
=>
type
==
'add-same'
?
a
[
`name
${
level
}
`
]
==
name
:
a
[
`name
${
level
+
1
}
`
]
==
name
);
if
(
isExist
)
{
return
'节点名称已存在,请填写其他名称'
}
...
...
@@ -522,7 +514,7 @@ const btnClick = async (btn, bType = null) => {
beforeClose
:
(
action
,
instance
,
done
)
=>
{
if
(
action
===
'confirm'
)
{
if
(
!
instance
.
inputValue
)
{
const
dom
=
document
.
querySelectorAll
(
'.prompt_msg_box .el-message-box__errormsg'
);
const
dom
:
any
=
document
.
querySelectorAll
(
'.prompt_msg_box .el-message-box__errormsg'
);
if
(
dom
[
0
])
{
dom
[
0
].
innerHTML
=
'请填写节点名称'
;
dom
[
0
].
style
.
visibility
=
'visible'
;
...
...
@@ -540,61 +532,13 @@ const btnClick = async (btn, bType = null) => {
const
name
=
value
.
trim
();
if
(
type
==
'edit'
)
{
if
(
value
==
inputVal
)
return
row
.
name
=
name
;
let
list
=
checkedList
.
value
,
tData
=
checkedData
.
value
;
tData
.
forEach
((
t
)
=>
{
if
(
t
.
guid
==
row
.
guid
)
{
t
[
'level'
+
row
.
level
]
=
name
;
t
.
name
=
name
;
}
if
(
t
.
parentId
==
row
.
code
)
{
t
[
'level'
+
row
.
level
]
=
name
;
}
})
list
.
forEach
((
l
)
=>
{
if
(
l
.
guid
==
row
.
guid
)
{
l
.
name
=
name
;
}
})
setName
(
name
,
level
,
rIndex
);
}
else
if
(
type
==
'add-same'
)
{
let
code
=
''
;
const
sameCode
=
curGridList
.
filter
(
c
=>
c
.
parentId
==
row
.
parentId
);
sameCode
.
sort
((
a
,
b
)
=>
a
.
sortNum
-
b
.
sortNum
);
const
lastCode
=
sameCode
.
at
(
-
1
);
const
codeVal
=
(
sameCode
.
length
+
1
)
<
10
?
'0'
+
(
sameCode
.
length
+
1
)
:
sameCode
.
length
+
1
;
code
=
`
${
lastCode
.
parentId
}${
codeVal
}
`
;
curGridList
.
push
({
...
JSON
.
parse
(
JSON
.
stringify
(
row
)),
code
:
code
,
name
:
name
,
guid
:
`new-
${
code
}
`
,
sortNum
:
lastCode
.
sortNum
+
1
,
children
:
[],
checked
:
false
})
const
tData
=
rowList
.
at
(
-
1
);
const
tIndex
=
tableData
.
value
.
findIndex
(
t
=>
(
tData
.
code4
?
t
.
code4
===
tData
.
code4
:
t
.
code3
===
tData
.
code3
));
addSameData
(
tIndex
,
name
,
level
,
tData
);
}
else
if
(
type
==
'add-lower'
)
{
let
code
=
''
,
sortNum
=
1
;
if
(
curGridList
.
length
)
{
curGridList
.
sort
((
a
,
b
)
=>
a
.
sortNum
-
b
.
sortNum
);
const
lastCode
=
curGridList
.
at
(
-
1
);
const
codeVal
=
(
curGridList
.
length
+
1
)
<
10
?
'0'
+
(
curGridList
.
length
+
1
)
:
curGridList
.
length
+
1
;
code
=
`
${
lastCode
.
parentId
}${
codeVal
}
`
;
sortNum
=
lastCode
.
sortNum
+
1
;
}
else
{
code
=
`
${
row
.
code
}
01`
;
}
curGridList
.
push
({
...
JSON
.
parse
(
JSON
.
stringify
(
row
)),
code
:
code
,
name
:
name
,
sortNum
:
sortNum
,
level
:
4
,
guid
:
`new-
${
code
}
`
,
parentId
:
row
.
code
,
children
:
[],
checked
:
false
})
if
(
!
showLevel4
.
value
)
showLevel4
.
value
=
true
;
addLowerData
(
rIndex
,
name
,
level
,
rowList
.
length
);
}
}).
catch
(()
=>
{
ElMessage
({
...
...
@@ -604,8 +548,9 @@ const btnClick = async (btn, bType = null) => {
})
}
else
if
(
type
==
'remove'
)
{
const
row
=
btn
.
row
;
const
hasChild
=
row
.
children
;
const
msg
=
hasChild
.
length
?
'删除该节点会同步删除其子节点,是否确定删除?'
:
'确定删除该节点吗?'
;
const
{
rIndex
,
level
}
=
row
;
const
rowList
=
tableData
.
value
.
filter
(
t
=>
t
[
`code
${
level
}
`
]
==
row
[
`code
${
level
}
`
]);
const
msg
=
level
==
3
&&
rowList
[
0
].
code4
?
'删除该节点会同步删除其子节点,是否确定删除?'
:
'确定删除该节点吗?'
;
ElMessageBox
.
confirm
(
msg
,
'提示'
,
...
...
@@ -615,57 +560,26 @@ const btnClick = async (btn, bType = null) => {
type
:
'warning'
,
}
).
then
(()
=>
{
let
curGridList
=
btn
.
parent
.
children
;
const
rIndex
=
curGridList
.
findIndex
(
c
=>
c
.
guid
==
row
.
guid
);
rIndex
>
-
1
&&
curGridList
.
splice
(
rIndex
,
1
);
let
list
=
checkedList
.
value
,
tData
=
checkedData
.
value
;
let
cRow
=
tData
.
find
(
c
=>
c
.
guid
==
row
.
guid
);
const
hasChild
=
row
.
children
.
find
(
r
=>
r
.
checked
);
if
(
!
cRow
&&
hasChild
)
{
cRow
=
tData
.
find
(
c
=>
c
.
guid
==
hasChild
.
guid
);
}
const
tIndex
=
tData
.
findIndex
(
c
=>
c
.
guid
==
row
.
guid
);
tIndex
>
-
1
&&
tData
.
splice
(
tIndex
,
1
);
const
lIndex
=
list
.
findIndex
(
c
=>
c
.
guid
==
row
.
guid
);
lIndex
>
-
1
&&
list
.
splice
(
lIndex
,
1
);
const
level
=
row
.
level
;
if
(
level
>
1
&&
cRow
)
{
const
targetObj
=
btn
.
parent
;
const
hasChildItem
=
targetObj
.
children
.
find
(
r
=>
r
.
checked
);
const
nIndex
=
tData
.
findIndex
(
t
=>
t
.
guid
==
targetObj
.
guid
);
if
(
!
hasChildItem
&&
nIndex
===
-
1
)
{
let
nRow
=
{
...
cRow
,
...
targetObj
,
total
:
'0.00'
,
level
:
targetObj
.
level
};
nRow
[
`level
${
targetObj
.
level
}
`
]
=
targetObj
.
name
;
nRow
.
level4
=
''
;
if
(
level
===
2
)
{
nRow
.
level2
=
''
;
nRow
.
level3
=
''
;
}
else
if
(
level
===
3
)
{
nRow
.
level3
=
''
;
}
tData
.
push
(
nRow
);
}
}
level
<
4
&&
setChecked
(
row
.
children
);
for
(
let
c
=
0
;
c
<
curGridList
.
length
;
c
++
)
{
const
item
=
curGridList
[
c
];
if
(
item
.
sortNum
>
row
.
sortNum
)
{
const
code
=
parseInt
(
item
.
code
.
split
(
item
.
parentId
)[
1
],
10
)
-
1
;
tData
.
forEach
(
t
=>
{
if
(
t
.
guid
==
item
.
guid
)
{
t
.
code
=
`
${
t
.
parentId
}${
code
<
10
?
'0'
+
code
:
code
}
`
;
t
.
guid
=
t
.
guid
.
indexOf
(
'new'
)
>
-
1
?
`new-
${
t
.
code
}
`
:
t
.
guid
;
t
.
sortNum
=
t
.
sortNum
-
1
;
if
(
level
==
3
)
{
if
(
rowList
.
length
>
1
)
{
// 获取所有code3不等于当前code3的节点
tableData
.
value
=
tableData
.
value
.
filter
(
t
=>
t
.
code3
!==
row
.
code3
);
}
else
{
tableData
.
value
.
splice
(
rIndex
,
1
);
}
})
item
.
code
=
`
${
item
.
parentId
}${
code
<
10
?
'0'
+
code
:
code
}
`
;
item
.
guid
=
item
.
guid
.
indexOf
(
'new'
)
>
-
1
?
`new-
${
item
.
code
}
`
:
item
.
guid
;
item
.
sortNum
=
item
.
sortNum
-
1
;
}
else
{
continue
;
const
peerList
=
tableData
.
value
.
filter
(
t
=>
t
[
`code
${
level
-
1
}
`
]
==
row
[
`code
${
level
-
1
}
`
]);
if
(
peerList
.
length
>
1
)
{
tableData
.
value
.
splice
(
rIndex
,
1
);
}
else
{
let
rowData
=
tableData
.
value
[
rIndex
];
delete
rowData
[
`name
${
level
}
`
];
delete
rowData
[
`code
${
level
}
`
];
}
}
setShowLevel4
();
const
level4
=
tableData
.
value
.
find
(
t
=>
t
.
code4
);
!
level4
&&
(
tableField
.
value
[
3
].
visible
=
false
);
getMergeRow
();
}).
catch
(()
=>
{
ElMessage
({
type
:
'info'
,
...
...
@@ -678,80 +592,6 @@ const btnClick = async (btn, bType = null) => {
costFormInfo
.
value
=
{
...
costFormInfo
.
value
,
...
JSON
.
parse
(
JSON
.
stringify
(
fInfo
))
};
setStep
();
}
else
if
(
type
==
'next'
)
{
if
(
step
.
value
==
0
)
{
const
formEl
=
costFormRef
.
value
.
ruleFormRef
;
const
fInfo
=
costFormRef
.
value
.
formInline
;
costFormInfo
.
value
=
{
...
costFormInfo
.
value
,
...
JSON
.
parse
(
JSON
.
stringify
(
fInfo
))
};
if
(
!
formEl
)
return
;
const
valid
=
await
submitForm
(
formEl
);
if
(
valid
)
{
if
(
checkedList
.
value
.
length
==
0
)
{
ElMessage
.
warning
(
'请勾选成本项'
);
return
}
const
nameArr
=
checkedList
.
value
.
map
(
c
=>
c
.
name
);
isInitField
.
value
=
initCheckedList
.
value
.
toString
()
!=
nameArr
.
toString
();
const
tGuids
=
tableData
.
value
.
map
(
d
=>
d
.
guid
);
if
(
isInitField
.
value
)
{
initCheckedList
.
value
=
nameArr
;
let
fields
=
[
{
label
:
"累计投入"
,
field
:
"total"
,
width
:
120
,
align
:
'right'
,
getName
:
(
scope
)
=>
{
return
changeNum
(
scope
.
row
.
total
,
2
,
true
);
}
},
]
const
hasLevel1
=
checkedList
.
value
.
find
(
c
=>
c
.
level
==
1
);
if
(
hasLevel1
)
{
fields
.
splice
(
-
1
,
0
,
{
label
:
"指标"
,
field
:
"level1"
,
width
:
120
});
}
const
hasLevel2
=
checkedList
.
value
.
find
(
c
=>
c
.
level
==
2
);
if
(
hasLevel2
)
{
fields
.
splice
(
-
1
,
0
,
{
label
:
"一级分类"
,
field
:
"level2"
,
width
:
120
});
}
const
hasLevel3
=
checkedList
.
value
.
find
(
c
=>
c
.
level
==
3
);
if
(
hasLevel3
)
{
fields
.
splice
(
-
1
,
0
,
{
label
:
"二级分类"
,
field
:
"level3"
,
width
:
120
});
}
const
hasLevel4
=
checkedList
.
value
.
find
(
c
=>
c
.
level
==
4
);
if
(
hasLevel4
)
{
fields
.
splice
(
-
1
,
0
,
{
label
:
"三级分类"
,
field
:
"level4"
,
width
:
120
});
}
tableField
.
value
.
splice
(
0
);
tableField
.
value
.
push
(...
fields
);
initField
.
value
=
JSON
.
parse
(
JSON
.
stringify
(
tableField
.
value
));
const
datas
=
JSON
.
parse
(
JSON
.
stringify
(
checkedData
.
value
));
datas
.
sort
((
a
,
b
)
=>
a
.
code
.
localeCompare
(
b
.
code
));
const
dGuid
=
datas
.
map
(
d
=>
d
.
guid
);
let
tDatas
=
tableData
.
value
.
filter
(
t
=>
dGuid
.
indexOf
(
t
.
guid
)
>
-
1
);
datas
.
forEach
((
td
,
t
)
=>
{
if
(
tGuids
.
indexOf
(
td
.
guid
)
==
-
1
)
{
tDatas
.
splice
(
t
,
0
,
td
)
}
else
{
tDatas
.
map
(
d
=>
{
if
(
d
.
guid
==
td
.
guid
)
{
d
.
name
=
td
.
name
;
d
.
level1
=
td
.
level1
;
d
.
level2
=
td
.
level2
;
d
.
level3
=
td
.
level3
;
d
.
level4
=
td
.
level4
;
}
})
}
})
tableData
.
value
.
splice
(
0
);
tableData
.
value
=
tDatas
;
if
(
tGuids
.
length
>
0
&&
costFormInfo
.
value
.
baseDate
&&
costFormInfo
.
value
.
investYear
)
{
setTableFields
(
costFormInfo
.
value
);
besure
.
value
=
true
;
}
getMergeRow
();
}
step
.
value
++
;
setStep
();
}
}
else
if
(
step
.
value
==
1
)
{
const
formEl1
=
entryFormRef
.
value
.
ruleFormRef
;
const
fInfo1
=
entryFormRef
.
value
.
formInline
;
if
(
!
formEl1
)
return
;
...
...
@@ -773,9 +613,14 @@ const btnClick = async (btn, bType = null) => {
}
await
setEntryData
(
fInfo1
,
fInfo2
);
await
transposeData
(
fInfo1
.
entryType
);
step
.
value
++
;
setStep
();
costForm
.
value
.
items
.
map
((
cost
,
c
)
=>
{
if
(
c
==
0
)
{
cost
.
disabled
=
true
}
else
{
cost
.
visible
=
false
}
})
step
.
value
++
;
}
}
}
else
if
(
type
==
'refresh'
)
{
...
...
@@ -793,11 +638,13 @@ const btnClick = async (btn, bType = null) => {
}
};
const
setShowLevel4
=
()
=>
{
nextTick
(()
=>
{
const
box4
=
document
.
querySelectorAll
(
'.grid-panel-box.box3 .grid-items'
);
showLevel4
.
value
=
box4
.
length
>
0
})
const
setStep
=
async
()
=>
{
const
info
=
costFormInfo
.
value
;
await
setFormItems
(
info
,
'cost'
);
costForm
.
value
.
items
[
0
].
disabled
=
step
.
value
>
0
;
costForm
.
value
.
items
[
1
].
visible
=
step
.
value
==
0
;
costForm
.
value
.
items
[
2
].
visible
=
step
.
value
==
0
;
costForm
.
value
.
items
[
3
].
visible
=
step
.
value
==
0
;
}
const
setFormItems
=
(
row
:
any
=
null
,
type
)
=>
{
...
...
@@ -839,10 +686,10 @@ const submitForm = (formEl) => {
};
const
setEntryData
=
(
fInfo1
,
fInfo2
)
=>
{
let
datas
=
[],
lastCount
=
-
1
,
lastYear
=
{};
let
datas
:
any
=
[],
lastCount
=
-
1
,
lastYear
:
any
=
{};
for
(
var
f
in
costFileds
.
value
)
{
lastCount
++
;
let
row
=
{
...
entryItem
};
let
row
:
any
=
{
...
entryItem
};
if
(
f
!=
'baseNum'
)
{
row
.
year
=
`
${
f
}
年`
;
}
else
{
...
...
@@ -863,7 +710,7 @@ const setEntryData = (fInfo1, fInfo2) => {
}
else
{
let
amortize1
=
0
;
for
(
var
d
=
datas
.
length
-
1
;
d
>
(
lastCount
-
fInfo1
.
shareYears
);
d
--
)
{
const
da
=
datas
[
d
];
const
da
:
any
=
datas
[
d
];
amortize1
+=
da
.
amortize2
}
row
.
amortize1
=
amortize1
;
...
...
@@ -889,25 +736,29 @@ const setTableFields = (info) => {
//结束年
let
nowYears
=
Number
(
info
.
baseDate
.
split
(
'-'
)[
0
]);
let
Years
=
nowYears
-
smallYears
let
arrYear
=
[],
fields
=
[],
row
=
{
baseNum
:
''
};
let
arrYear
:
any
=
[],
fields
:
any
=
[],
row
:
any
=
{
baseNum
:
''
};
for
(
let
i
=
0
;
i
<
Years
;
i
++
)
{
arrYear
.
push
(
smallYears
++
)
}
arrYear
.
forEach
(
item
=>
{
const
field
=
`
${
item
}
`
;
fields
.
push
({
label
:
`
${
item
}
年`
,
field
:
field
,
type
:
'input'
,
width
:
100
,
columClass
:
'edit_cell'
},)
fields
.
push
({
label
:
`
${
item
}
年`
,
field
:
field
,
type
:
'input'
,
width
:
100
,
align
:
'right'
,
columClass
:
'edit_cell'
},)
row
[
field
]
=
''
;
})
costFileds
.
value
=
row
;
const
date
=
new
Date
(
info
.
baseDate
);
const
currDay
=
date
.
toLocaleDateString
(
'zh-CN'
,
{
year
:
'numeric'
,
month
:
'long'
});
tableField
.
value
=
JSON
.
parse
(
JSON
.
stringify
(
initField
.
value
));
tableField
.
value
.
splice
(
-
1
,
0
,
...
fields
,
{
label
:
currDay
,
field
:
'baseNum'
,
type
:
'input'
,
width
:
120
,
columClass
:
'edit_cell'
});
let
datas
=
[];
const
modifiedStr
=
currDay
.
replace
(
/
(\d
+
)
年
(\d
+
)
月/
,
(
_
,
year
,
month
)
=>
{
return
`
${
year
}
年1-
${
month
}
月`
;
});
tableField
.
value
.
at
(
-
1
).
visible
=
true
;
tableField
.
value
=
tableField
.
value
.
filter
(
item
=>
item
.
field
.
indexOf
(
'name'
)
>
-
1
||
item
.
field
==
'total'
);
tableField
.
value
.
splice
(
-
1
,
0
,
...
fields
,
{
label
:
modifiedStr
,
field
:
'baseNum'
,
type
:
'input'
,
width
:
120
,
align
:
'right'
,
columClass
:
'edit_cell'
});
// 设置table数据
let
datas
:
any
=
[];
tableData
.
value
.
map
(
t
=>
{
let
tRow
=
{
...
row
,
...
t
};
const
tKey
=
Object
.
keys
(
t
);
const
tKey
:
any
=
Object
.
keys
(
t
);
tKey
.
forEach
(
k
=>
{
if
((
k
==
'baseNum'
||
!
isNaN
(
k
))
&&
row
[
k
]
===
undefined
)
{
delete
tRow
[
k
];
...
...
@@ -917,87 +768,107 @@ const setTableFields = (info) => {
})
tableData
.
value
.
splice
(
0
);
tableData
.
value
=
datas
;
getMergeRow
();
}
// 设置表格合并下标
const
getMergeRow
=
()
=>
{
mergeRowCount
.
value
=
JSON
.
parse
(
JSON
.
stringify
(
rowCount
));
let
list
=
tableData
.
value
;
for
(
var
i
=
0
;
i
<
list
.
length
;
i
++
)
{
if
(
i
===
0
)
{
//第一个数据 默认合并1行,开始位置下标默认为0
for
(
var
m
in
mergeRowCount
.
value
)
{
mergeRowCount
.
value
[
m
].
rowspan
.
push
(
1
);
mergeRowCount
.
value
[
m
].
index
=
0
;
}
let
list
=
tableData
.
value
,
info
=
{}
// 为每个层级初始化合并信息
for
(
let
level
=
1
;
level
<=
3
;
level
++
)
{
const
nameKey
=
`name
${
level
}
`
const
codeKey
=
`code
${
level
}
`
info
[
nameKey
]
=
[]
// 处理每行数据
list
.
forEach
((
row
,
index
)
=>
{
if
(
index
===
0
)
{
// 第一行默认合并1行,开始位置0
info
[
nameKey
][
index
]
=
1
}
else
{
// 根据拥有子级数量进行合并
for
(
var
m
in
mergeRowCount
.
value
)
{
let
mergeRow
=
mergeRowCount
.
value
[
m
];
const
e
=
Number
(
m
.
split
(
'level'
)[
1
]);
if
(
list
[
i
][
m
]
&&
list
[
i
][
'level'
+
(
e
-
1
)]
==
list
[
i
-
1
][
'level'
+
(
e
-
1
)]
&&
list
[
i
][
m
]
===
list
[
i
-
1
][
m
])
{
mergeRow
.
rowspan
[
mergeRow
.
index
]
+=
1
;
mergeRow
.
rowspan
.
push
(
0
);
// 当前行与上一行的code和name比较
const
sameCode
=
row
[
codeKey
]
===
list
[
index
-
1
][
codeKey
]
const
sameName
=
row
[
nameKey
]
===
list
[
index
-
1
][
nameKey
]
if
(
sameCode
&&
sameName
)
{
// 找到当前分组的起始位置
let
groupStart
=
index
-
1
while
(
groupStart
>
0
&&
info
[
nameKey
][
groupStart
]
===
0
)
{
groupStart
--
}
// 增加合并行数
info
[
nameKey
][
groupStart
]
++
info
[
nameKey
][
index
]
=
0
}
else
{
mergeRow
.
rowspan
.
push
(
1
);
mergeRow
.
index
=
i
;
}
// 新分组,合并1行
info
[
nameKey
][
index
]
=
1
}
}
})
}
mergeRowCount
.
value
=
info
;
}
// 表格行合并
const
tableSpanMethod
=
({
row
,
column
,
rowIndex
,
columnIndex
})
=>
{
if
(
column
.
property
.
indexOf
(
'level'
)
>
-
1
&&
column
.
property
!=
'level4'
)
{
const
rowspan
=
mergeRowCount
.
value
[
column
.
property
].
rowspan
;
const
_row
=
rowspan
[
rowIndex
];
const
_col
=
_row
==
0
?
0
:
1
;
const
colName
=
column
.
property
if
(
mergeRowCount
.
value
[
colName
])
{
const
rowspan
=
mergeRowCount
.
value
[
colName
][
rowIndex
]
return
{
rowspan
:
_row
,
colspan
:
_col
rowspan
:
rowspan
,
colspan
:
rowspan
>
0
?
1
:
0
}
}
return
{
rowspan
:
1
,
colspan
:
1
}
}
const
isMergedCell
=
({
rowIndex
,
columnIndex
})
=>
{
const
property
=
tableField
.
value
[
columnIndex
].
field
;
const
rowspan
=
mergeRowCount
.
value
[
property
]?.
rowspan
[
rowIndex
];
return
rowspan
>
1
?
'merged-cell'
:
''
;
const
isMergedCell
=
({
row
,
column
,
rowIndex
,
columnIndex
})
=>
{
const
property
=
column
.
property
;
// 只处理需要合并的列 (name1/name2/name3)
if
([
'name1'
,
'name2'
,
'name3'
].
includes
(
property
))
{
// 检查当前单元格是否属于合并范围
const
rowspan
=
mergeRowCount
.
value
[
property
]?.[
rowIndex
];
// 无论是合并的起始单元格(rowspan>1)还是被合并的隐藏单元格(rowspan===0)
return
rowspan
!==
1
?
'merged-cell'
:
''
;
}
return
''
;
}
//
表格合计行
//
优化后的合计计算方法
const
tableSummaryMethod
=
({
columns
,
data
})
=>
{
let
sums
=
[];
if
(
!
besure
.
value
)
return
;
let
sums
:
any
=
[],
numericColumns
:
any
=
[];
// 记录需要计算的数字列
columns
.
forEach
((
column
,
index
)
=>
{
if
(
index
===
0
)
{
//需要显示'总金额'的列 坐标 :0
sums
[
index
]
=
'合计'
return
}
else
{
if
(
column
.
property
.
indexOf
(
'level'
)
==
-
1
&&
column
.
property
!=
'memo'
)
{
const
values
=
data
.
map
(
item
=>
parseFloat
(
item
[
column
.
property
]
?
item
[
column
.
property
].
replace
(
/,/g
,
""
)
:
0
));
if
(
!
values
.
every
(
value
=>
isNaN
(
value
)))
{
const
sum
=
values
.
reduce
((
prev
,
curr
)
=>
{
const
value
=
parseFloat
(
curr
||
0
)
if
(
!
isNaN
(
value
))
{
return
prev
+
curr
}
else
{
return
prev
}
},
0
)
sums
[
index
]
=
changeNum
(
sum
,
2
,
true
)
if
(
column
.
property
==
'total'
)
{
amount
.
value
=
sum
if
(
index
===
0
)
{
sums
[
index
]
=
'合计'
;
return
;
}
sumAmount
.
value
[
column
.
property
]
=
sum
;
// 识别需要计算的数字列
if
(
!
column
.
property
.
includes
(
'name'
)
&&
column
.
property
!==
'memo'
)
{
numericColumns
.
push
({
index
,
property
:
column
.
property
});
}
else
{
sums
[
index
]
=
'N/A'
}
}
sums
[
index
]
=
''
;
// 非数字列留空
}
})
return
sums
}
});
// 计算数字列合计
numericColumns
.
forEach
(({
index
,
property
})
=>
{
const
sum
=
data
.
reduce
((
total
,
item
)
=>
{
const
value
=
parseFloat
(
String
(
item
[
property
]).
replace
(
/,/g
,
''
))
||
0
;
return
total
+
value
;
},
0
);
sums
[
index
]
=
changeNum
(
sum
,
2
,
true
);
// 特殊字段处理
if
(
property
===
'total'
)
{
amount
.
value
=
sum
;
}
sumAmount
.
value
[
property
]
=
sum
;
});
return
sums
;
};
const
isExist
=
(
newArr
,
name
)
=>
{
for
(
let
i
=
0
;
i
<
newArr
.
length
;
i
++
)
{
...
...
@@ -1010,19 +881,23 @@ const isExist = (newArr, name) => {
// 表格数据行列转置
const
transposeData
=
(
type
)
=>
{
bookHeaders
.
value
.
splice
(
1
);
// 提取原始数据的头部作为转置后数据的列
headers
.
value
=
entryData
.
value
.
map
((
t
)
=>
{
const
list
=
entryData
.
value
.
map
((
t
)
=>
{
return
{
label
:
t
.
year
,
value
:
t
.
guid
||
t
.
year
field
:
t
.
guid
||
t
.
year
,
width
:
120
,
align
:
'right'
}
});
bookHeaders
.
value
.
push
(...
list
);
/**
* 定义映射字段表(最好取全量字段)
* */
const
mapObj
=
convertConfig
[
type
]
const
newArr
=
[];
const
newArr
:
any
=
[];
for
(
const
t
in
mapObj
)
{
for
(
let
i
=
0
;
i
<
entryData
.
value
.
length
;
i
++
)
{
const
item
=
entryData
.
value
[
i
]
...
...
@@ -1030,7 +905,7 @@ const transposeData = (type) => {
if
(
result
)
{
result
[
item
.
year
]
=
item
[
t
]
}
else
{
const
obj
=
{}
const
obj
:
any
=
{}
obj
.
title
=
mapObj
[
t
]
obj
[
item
.
year
]
=
item
[
t
]
newArr
.
push
(
obj
)
...
...
@@ -1054,248 +929,360 @@ const setLabel = (val) => {
}
}
const
getClass
=
(
i
,
checked
)
=>
{
return
checked
?
`active
${
i
+
1
}
`
:
''
;
// 下载表格
const
s2ab
=
(
s
)
=>
{
const
buf
=
new
ArrayBuffer
(
s
.
length
);
const
view
=
new
Uint8Array
(
buf
);
for
(
let
i
=
0
;
i
!==
s
.
length
;
++
i
)
view
[
i
]
=
s
.
charCodeAt
(
i
)
&
0xFF
;
return
buf
;
}
const
gridPanel
=
ref
(
null
);
const
gridItem
=
ref
(
null
);
const
setItemLine
=
()
=>
{
nextTick
(()
=>
{
setTimeout
(()
=>
{
if
(
gridItem
.
value
)
{
const
width1
=
gridPanel
.
value
[
0
].
offsetWidth
;
const
width2
=
gridItem
.
value
[
0
].
offsetWidth
;
// 设置::before伪元素的宽度
itemWidth
.
value
=
`
${(
width1
-
width2
)
/
2
+
(
showLevel4
.
value
?
6
:
8
)}
px`
;
itemLeft
.
value
=
`-
${(
width1
-
width2
)
/
2
+
(
showLevel4
.
value
?
6
:
8
)}
px`
;
document
.
documentElement
.
style
.
setProperty
(
'--item-width'
,
itemWidth
.
value
);
document
.
documentElement
.
style
.
setProperty
(
'--item-left'
,
itemLeft
.
value
);
}
},
100
)
})
}
// 定义边框样式 - 实线边框
const
borderStyle
=
{
top
:
{
style
:
'thin'
,
color
:
{
rgb
:
'888888'
}
},
bottom
:
{
style
:
'thin'
,
color
:
{
rgb
:
'888888'
}
},
left
:
{
style
:
'thin'
,
color
:
{
rgb
:
'888888'
}
},
right
:
{
style
:
'thin'
,
color
:
{
rgb
:
'888888'
}
}
};
const
spanHeight
=
(
obj
)
=>
{
return
`
${
obj
.
children
.
length
?
obj
.
children
.
length
*
48
:
48
}
px`
;
}
// 字体配置
const
defaultFont
=
{
name
:
'宋体'
,
// 字体名称
sz
:
14
*
0.75
,
// 字体大小(磅)
color
:
{
rgb
:
'212121'
}
// 黑色
};
const
showPanel
=
(
arr
,
row
)
=>
{
arr
.
forEach
(
a
=>
{
if
(
a
.
level
<
3
)
{
a
.
children
.
length
&&
showPanel
(
a
.
children
,
row
)
// 设置行高(单位:磅,1px≈0.75磅)
const
defaultRowHeightInPx
=
36
;
// 默认行高36px
const
headerRowHeightInPx
=
32
;
// 表头行高32px
// 生成成本设置表
const
exportDetailsToExcel
=
async
()
=>
{
// 准备工作表数据
let
wsData
=
[],
fields
:
any
=
[];
tableField
.
value
.
map
(
f
=>
{
if
(
f
.
visible
||
f
.
field
.
indexOf
(
'name'
)
==
-
1
)
{
if
(
f
.
field
==
'name4'
)
{
const
exist4
=
checkedData
.
value
.
find
(
c
=>
c
.
code4
)
exist4
&&
fields
.
push
(
f
)
}
else
{
if
(
a
.
children
.
length
)
{
row
.
show4
=
true
;
return
;
fields
.
push
(
f
)
}
}
})
return
row
.
show4
||
false
;
}
});
// 设置二级分类 item的margin-bottom值
const
setItemStyle
=
(
row
,
indexObj
)
=>
{
if
(
indexObj
)
{
const
{
o
}
=
indexObj
;
setGroupStyle
();
setItemsStyle
(
o
);
return
{
height
:
'auto'
}
// 表头
const
headers
=
fields
.
map
(
item
=>
item
.
label
)
wsData
.
push
(
headers
)
// 判断哪些列是数值类型
const
numField
=
fields
.
filter
(
item
=>
item
.
field
.
indexOf
(
'name'
)
==
-
1
);
const
numericFields
=
numField
.
map
(
f
=>
f
.
field
);
const
isNumericColumn
=
fields
.
map
(
field
=>
numericFields
.
includes
(
field
.
field
));
// 处理数据行
checkedData
.
value
.
forEach
(
item
=>
{
const
row
=
fields
.
map
(
f
=>
{
if
(
f
.
field
.
indexOf
(
'name'
)
==
-
1
)
{
// 分类字段
return
changeNum
(
item
[
f
.
field
],
2
,
true
)
}
else
{
setHeight
();
return
{
'margin-bottom'
:
row
.
children
.
length
>
1
?
((
row
.
children
.
length
-
1
)
*
48
)
+
8
+
'px'
:
'0px'
}
// 其他字段
return
item
[
f
.
field
]
||
''
}
}
// 设置三级分类 group高度
const
setGroupStyle
=
()
=>
{
nextTick
(()
=>
{
const
box3
=
document
.
querySelectorAll
(
'.grid-panel-box.box2 .grid-panel'
);
const
box4
=
document
.
querySelectorAll
(
'.grid-panel-box.box3 .grid-group'
);
box4
.
forEach
((
box
,
b
)
=>
{
box
.
style
.
height
=
box3
[
b
].
offsetHeight
+
'px'
;
})
wsData
.
push
(
row
)
})
}
// 设置三级分类 item高度
const
setItemsStyle
=
(
i
)
=>
{
nextTick
(()
=>
{
const
box3
=
document
.
querySelectorAll
(
'.grid-panel-box.box2 .grid-items'
);
const
box4
=
document
.
querySelectorAll
(
'.grid-panel-box.box3 .group-items'
);
box4
.
forEach
((
box
,
b
)
=>
{
const
bStyle
=
window
.
getComputedStyle
(
box3
[
b
]);
const
h
=
parseFloat
(
bStyle
.
height
)
+
parseFloat
(
bStyle
.
marginBottom
);
box
.
style
.
height
=
h
<=
40
?
(
h
+
8
)
+
'px'
:
h
+
'px'
;
// 添加合计行
const
totalRow
=
[
'合计'
,
''
,
''
,
''
];
let
totalValues
=
{}
// 初始化合计值
numericFields
.
forEach
(
field
=>
{
totalValues
[
field
]
=
0
})
// 计算合计值
checkedData
.
value
.
forEach
(
item
=>
{
numericFields
.
forEach
(
field
=>
{
if
(
item
[
field
])
{
const
num
=
parseFloat
(
item
[
field
].
replace
(
/,/g
,
''
))
||
0
totalValues
[
field
]
+=
num
}
})
})
}
// 设置一级分类 panel高度
const
setHeight
=
()
=>
{
nextTick
(()
=>
{
const
boxArr
=
document
.
querySelectorAll
(
'.grid-panel-box'
);
if
(
boxArr
.
length
)
{
const
box2
=
boxArr
[
1
].
querySelectorAll
(
'.grid-panel'
);
const
box3
=
boxArr
[
2
].
querySelectorAll
(
'.grid-panel'
);
box2
.
forEach
((
box
,
b
)
=>
{
box
.
style
.
height
=
box3
[
b
].
offsetHeight
+
'px'
;
// 将合计值添加到合计行
fields
.
forEach
((
field
,
index
)
=>
{
if
(
index
<
4
)
return
// 前4列已经处理
if
(
numericFields
.
includes
(
field
.
field
))
{
const
value
=
totalValues
[
field
.
field
]
// 格式化数字,保留2位小数
totalRow
.
push
(
value
.
toFixed
(
2
).
replace
(
/
\B(?=(\d{3})
+
(?!\d))
/g
,
","
))
}
else
{
totalRow
.
push
(
''
)
}
})
wsData
.
push
(
totalRow
)
// 创建工作表
const
ws
=
XLSXS
.
utils
.
aoa_to_sheet
(
wsData
)
// 自动调整列宽
const
colWidths
=
fields
.
map
((
field
,
index
)
=>
{
const
defaultWidth
=
field
.
width
||
100
// 默认宽度100
const
colWidth
=
100
*
0.75
;
// 留一些余地
// 取表头宽度和内容宽度的较大值
return
{
wpx
:
colWidth
}
// 使用像素宽度
})
ws
[
'!cols'
]
=
colWidths
// 转换为磅(Excel使用磅作为单位)
const
defaultRowHeight
=
defaultRowHeightInPx
*
0.75
;
const
headerRowHeight
=
headerRowHeightInPx
*
0.75
;
// 初始化行高设置
ws
[
'!rows'
]
=
[];
// 设置表头行高
ws
[
'!rows'
][
0
]
=
{
hpt
:
headerRowHeight
,
customHeight
:
true
};
// 设置数据行高
for
(
let
i
=
1
;
i
<
wsData
.
length
;
i
++
)
{
ws
[
'!rows'
][
i
]
=
{
hpt
:
defaultRowHeight
,
customHeight
:
true
};
}
// 设置合并单元格
const
merges
=
[]
// 按code1合并一级指标
const
level1Groups
=
groupBy
(
checkedData
.
value
,
'code1'
)
Object
.
values
(
level1Groups
).
forEach
(
group
=>
{
const
startRow
=
checkedData
.
value
.
findIndex
(
item
=>
item
.
code1
===
group
[
0
].
code1
)
+
1
// +1因为第一行是表头
const
endRow
=
startRow
+
group
.
length
-
1
merges
.
push
({
s
:
{
r
:
startRow
,
c
:
0
},
e
:
{
r
:
endRow
,
c
:
0
}
})
})
}
// 下载表格
const
s2ab
=
(
s
)
=>
{
const
buf
=
new
ArrayBuffer
(
s
.
length
);
const
view
=
new
Uint8Array
(
buf
);
for
(
let
i
=
0
;
i
!==
s
.
length
;
++
i
)
view
[
i
]
=
s
.
charCodeAt
(
i
)
&
0xFF
;
return
buf
;
}
// 按code2合并一级分类
const
level2Groups
=
groupBy
(
checkedData
.
value
,
'code2'
)
Object
.
values
(
level2Groups
).
forEach
(
group
=>
{
const
startRow
=
checkedData
.
value
.
findIndex
(
item
=>
item
.
code2
===
group
[
0
].
code2
)
+
1
const
endRow
=
startRow
+
group
.
length
-
1
merges
.
push
({
s
:
{
r
:
startRow
,
c
:
1
},
e
:
{
r
:
endRow
,
c
:
1
}
})
})
// 获取所有单元格对象
function
getAllCells
(
pRef
,
type
)
{
const
allCells
=
[];
let
columns
=
[],
allColsNum
=
0
;
if
(
type
==
'cost'
)
{
allColsNum
=
tableField
.
value
.
length
;
tableField
.
value
.
map
((
tc
,
c
)
=>
{
if
(
tc
.
field
.
indexOf
(
'level'
)
==
-
1
||
tc
.
field
==
'memo'
)
{
columns
.
push
({
...
tc
,
cIndex
:
c
})
// 按code3合并二级分类
const
level3Groups
=
groupBy
(
checkedData
.
value
,
'code3'
)
Object
.
values
(
level3Groups
).
forEach
(
group
=>
{
const
startRow
=
tableData
.
value
.
findIndex
(
item
=>
item
.
code3
===
group
[
0
].
code3
)
+
1
const
endRow
=
startRow
+
group
.
length
-
1
merges
.
push
({
s
:
{
r
:
startRow
,
c
:
2
},
e
:
{
r
:
endRow
,
c
:
2
}
})
})
ws
[
'!merges'
]
=
merges
// 设置单元格样式
const
range
=
XLSXS
.
utils
.
decode_range
(
ws
[
'!ref'
])
for
(
let
R
=
range
.
s
.
r
;
R
<=
range
.
e
.
r
;
++
R
)
{
for
(
let
C
=
range
.
s
.
c
;
C
<=
range
.
e
.
c
;
++
C
)
{
const
cellAddress
=
XLSXS
.
utils
.
encode_cell
({
r
:
R
,
c
:
C
})
// 默认样式
const
defaultStyle
=
{
alignment
:
{
vertical
:
'center'
,
horizontal
:
'left'
},
font
:
defaultFont
,
border
:
borderStyle
// 添加边框样式
}
});
}
else
{
headers
.
value
.
map
((
th
,
h
)
=>
{
columns
.
push
({
...
th
,
cIndex
:
h
+
1
})
});
// 表头样式
if
(
R
===
0
)
{
// 如果该列是数值列,则表头也右对齐
const
isNumeric
=
isNumericColumn
[
C
];
ws
[
cellAddress
].
s
=
{
...
defaultStyle
,
alignment
:
{
vertical
:
'center'
,
horizontal
:
isNumeric
?
'right'
:
'left'
},
fill
:
{
fgColor
:
{
rgb
:
'F2F2F2'
}
}
// 表头背景色(可选)
}
continue
}
const
colIndex
=
columns
.
map
(
c
=>
c
.
cIndex
);
// 获取所有行
const
rows
=
pRef
.
$el
.
querySelectorAll
(
'.el-table__row'
);
rows
.
forEach
((
rowElement
,
rowIndex
)
=>
{
const
cells
=
rowElement
.
querySelectorAll
(
'.el-table__cell'
);
// 合计行样式
if
(
R
===
range
.
e
.
r
)
{
ws
[
cellAddress
].
s
=
{
...
defaultStyle
,
alignment
:
{
vertical
:
'center'
,
horizontal
:
isNumericColumn
[
C
]
?
'right'
:
'left'
},
// fill: { fgColor: { rgb: 'FFF1D4' } } // 合计行背景色(可选)
}
continue
}
cells
.
forEach
((
cellElement
,
cellIndex
)
=>
{
const
cell
=
{
rowIndex
:
(
rowIndex
+
1
),
cellIndex
:
cellIndex
,
value
:
cellElement
.
innerText
.
trim
(),
style
:
window
.
getComputedStyle
(
cellElement
)
};
let
format
=
'General'
;
if
(
type
==
'entry'
)
{
format
=
colIndex
.
indexOf
(
cellIndex
)
>
-
1
?
'#,##0.00'
:
''
;
}
else
{
if
(
rowIndex
==
rows
.
length
-
1
)
{
format
=
cell
.
value
!=
'合计'
&&
cell
.
value
?
'#,##0.00'
:
''
;
// 数据行样式
const
fieldIndex
=
C
const
field
=
fields
[
fieldIndex
]
// 数值列右对齐
if
(
isNumericColumn
[
C
])
{
ws
[
cellAddress
].
s
=
{
...
defaultStyle
,
alignment
:
{
vertical
:
'center'
,
horizontal
:
'right'
}
}
}
else
{
format
=
colIndex
.
indexOf
(
cellIndex
+
(
allColsNum
-
cells
.
length
))
>
-
1
?
'#,##0.00'
:
''
;
cell
.
cellIndex
=
cellIndex
+
(
allColsNum
-
cells
.
length
)
// 其他列左对齐
ws
[
cellAddress
].
s
=
defaultStyle
}
}
}
return
ws
;
};
// 辅助函数:按属性分组
const
groupBy
=
(
array
,
key
)
=>
{
return
array
.
reduce
((
acc
,
obj
)
=>
{
const
groupKey
=
obj
[
key
]
if
(
!
acc
[
groupKey
])
{
acc
[
groupKey
]
=
[]
}
acc
[
groupKey
].
push
(
obj
)
return
acc
},
{})
};
// 生成成本设置表
const
exportBookToExcel
=
async
()
=>
{
// 准备工作表数据
const
wsData
=
[]
// 表头
const
headers
=
bookHeaders
.
value
.
map
(
item
=>
item
.
label
)
wsData
.
push
(
headers
)
// 处理数据行
transposedData
.
value
.
forEach
(
item
=>
{
const
row
=
bookHeaders
.
value
.
map
(
f
=>
{
if
(
f
.
field
.
indexOf
(
'title'
)
==
-
1
)
{
// 分类字段
return
changeNum
(
item
[
f
.
field
],
2
,
true
)
}
else
{
// 其他字段
return
item
[
f
.
field
]
||
''
}
cell
.
format
=
format
;
allCells
.
push
(
cell
);
})
wsData
.
push
(
row
)
})
return
allCells
;
}
// 设置单元格样式
const
applyStyles
=
(
ws
,
pRef
,
type
)
=>
{
// 获取所有带有样式的单元格
const
styledCells
=
getAllCells
(
pRef
,
type
)
// 创建工作表
const
ws
=
XLSXS
.
utils
.
aoa_to_sheet
(
wsData
)
// 设置单元格样式
styledCells
.
forEach
((
cell
)
=>
{
const
cellRef
=
XLSXS
.
utils
.
encode_cell
({
r
:
cell
.
rowIndex
,
c
:
cell
.
cellIndex
});
const
style
=
cell
.
style
;
// 自动调整列宽
const
colWidths
=
bookHeaders
.
value
.
map
((
field
,
index
)
=>
{
const
defaultWidth
=
field
.
width
||
100
// 默认宽度100
const
colWidth
=
defaultWidth
*
0.75
;
// 留一些余地
// 取表头宽度和内容宽度的较大值
return
{
wpx
:
colWidth
}
// 使用像素宽度
})
ws
[
'!cols'
]
=
colWidths
// 转换为磅(Excel使用磅作为单位)
const
defaultRowHeight
=
defaultRowHeightInPx
*
0.75
;
const
headerRowHeight
=
headerRowHeightInPx
*
0.75
;
// 初始化行高设置
ws
[
'!rows'
]
=
[];
// 设置表头行高
ws
[
'!rows'
][
0
]
=
{
hpt
:
headerRowHeight
,
customHeight
:
true
};
// 设置数据行高
for
(
let
i
=
1
;
i
<
wsData
.
length
;
i
++
)
{
ws
[
'!rows'
][
i
]
=
{
hpt
:
defaultRowHeight
,
customHeight
:
true
};
}
// 设置单元格样式
const
cellStyle
=
{
alignment
:
{
horizontal
:
cell
.
format
?
'right'
:
style
.
textAlign
,
vertical
:
'center'
,
// 垂直居中
},
};
const
range
=
XLSXS
.
utils
.
decode_range
(
ws
[
'!ref'
])
// 确定哪些列是数值列(field不包含'title'的列)
const
isNumericColumn
=
bookHeaders
.
value
.
map
(
f
=>
f
.
field
.
indexOf
(
'title'
)
===
-
1
);
ws
[
cellRef
]
=
ws
[
cellRef
]
||
{};
ws
[
cellRef
].
s
=
cellStyle
;
if
(
cell
.
format
)
{
ws
[
cellRef
].
z
=
cell
.
format
;
}
else
{
ws
[
cellRef
].
t
=
's'
;
ws
[
cellRef
].
v
=
cell
.
value
;
for
(
let
R
=
range
.
s
.
r
;
R
<=
range
.
e
.
r
;
++
R
)
{
for
(
let
C
=
range
.
s
.
c
;
C
<=
range
.
e
.
c
;
++
C
)
{
const
cellAddress
=
XLSXS
.
utils
.
encode_cell
({
r
:
R
,
c
:
C
})
// 确保单元格存在(有些空值单元格可能不存在)
if
(
!
ws
[
cellAddress
])
{
ws
[
cellAddress
]
=
{}
;
}
});
// 合并单元格
const
mergedCells
=
document
.
querySelectorAll
(
'.merged-cell'
);
mergedCells
.
forEach
((
cell
)
=>
{
// 设置合并单元格的样式
const
mergedCellStyle
=
{
// 默认样式(垂直居中)
const
defaultStyle
=
{
alignment
:
{
vertical
:
'center'
,
// 垂直居中
vertical
:
'center'
,
horizontal
:
'left'
},
};
font
:
defaultFont
,
border
:
borderStyle
// 添加边框样式
}
const
topLeftCellRef
=
XLSXS
.
utils
.
encode_cell
({
r
:
cell
.
rowIndex
,
c
:
cell
.
cellIndex
});
ws
[
topLeftCellRef
]
=
ws
[
topLeftCellRef
]
||
{};
ws
[
topLeftCellRef
].
s
=
mergedCellStyle
;
});
}
// 判断当前列是否为数值列
const
isNumeric
=
isNumericColumn
[
C
];
// 数值列的对齐方式
const
alignment
=
{
vertical
:
'center'
,
horizontal
:
isNumeric
?
'right'
:
'left'
};
// 表头样式(第1行)
if
(
R
===
0
)
{
ws
[
cellAddress
].
s
=
{
...
defaultStyle
,
alignment
:
alignment
,
// 使用统一对齐方式
fill
:
{
fgColor
:
{
rgb
:
'F2F2F2'
}
}
// 表头背景色(可选)
}
continue
}
// 创建一个隐藏的 div 用于测量文本宽度
const
measureDiv
=
document
.
createElement
(
'div'
);
measureDiv
.
style
.
position
=
'absolute'
;
measureDiv
.
style
.
visibility
=
'hidden'
;
measureDiv
.
style
.
whiteSpace
=
'nowrap'
;
document
.
body
.
appendChild
(
measureDiv
);
// 测量文本宽度的函数
function
measureTextWidth
(
text
,
fontSize
,
fontFamily
)
{
measureDiv
.
style
.
fontSize
=
`
${
fontSize
}
px`
;
measureDiv
.
style
.
fontFamily
=
fontFamily
;
measureDiv
.
textContent
=
text
;
return
measureDiv
.
offsetWidth
;
}
// 数据行样式
const
cellValue
=
ws
[
cellAddress
].
v
;
const
adjustColumnWidth
=
(
ws
)
=>
{
const
range
=
XLSXS
.
utils
.
decode_range
(
ws
[
'!ref'
]);
const
defaultFontSize
=
11
;
// 默认字体大小
const
defaultFontFamily
=
'Arial'
;
// 默认字体族
ws
[
cellAddress
].
s
=
{
...
defaultStyle
,
alignment
:
alignment
// 使用统一对齐方式
};
for
(
let
C
=
range
.
s
.
c
;
C
<=
range
.
e
.
c
;
++
C
)
{
let
maxWidth
=
0
;
for
(
let
R
=
range
.
s
.
r
;
R
<=
range
.
e
.
r
;
++
R
)
{
const
cellRef
=
XLSXS
.
utils
.
encode_cell
({
r
:
R
,
c
:
C
});
const
cellValue
=
ws
[
cellRef
]?.
v
?.
toString
()
||
''
;
const
width
=
measureTextWidth
(
cellValue
,
defaultFontSize
,
defaultFontFamily
);
maxWidth
=
Math
.
max
(
maxWidth
,
width
);
// 确保数值被正确识别为数字类型
if
(
isNumeric
&&
cellValue
!==
undefined
&&
cellValue
!==
""
&&
!
isNaN
(
cellValue
))
{
ws
[
cellAddress
].
t
=
'n'
;
// 数字类型
ws
[
cellAddress
].
z
=
'#,##0.00'
;
// 数字格式
}
}
// 根据测量的宽度计算列宽
const
colWidth
=
maxWidth
/
defaultFontSize
+
2
;
// 留一些余地
ws
[
'!cols'
]
=
ws
[
'!cols'
]
||
[];
ws
[
'!cols'
][
C
]
=
{
wpx
:
colWidth
*
defaultFontSize
};
// 使用像素宽度
}
return
ws
;
};
const
exportClick
=
()
=>
{
const
exportClick
=
async
()
=>
{
// 获取第一个表格的数据
const
table1
=
document
.
getElementById
(
'cost-table'
);
const
ws1
=
XLSXS
.
utils
.
table_to_sheet
(
table1
);
const
ws1
=
await
exportDetailsToExcel
();
// 获取第二个表格的数据
const
table2
=
document
.
getElementById
(
'entry-table'
);
const
ws2
=
XLSXS
.
utils
.
table_to_sheet
(
table2
);
// 调整列宽
adjustColumnWidth
(
ws1
);
adjustColumnWidth
(
ws2
);
// 添加样式
applyStyles
(
ws1
,
costTableRef
.
value
,
'cost'
);
applyStyles
(
ws2
,
entryTableRef
.
value
,
'entry'
);
const
ws2
=
await
exportBookToExcel
();
// 创建工作簿并添加两个工作表
const
wb
=
XLSXS
.
utils
.
book_new
();
...
...
@@ -1342,220 +1329,129 @@ const setSumRow = () => {
}
onActivated
(()
=>
{
tableField
.
value
=
JSON
.
parse
(
JSON
.
stringify
(
initField
.
value
));
getProducts
();
getCostData
();
});
onMounted
(()
=>
{
setItemLine
();
window
.
addEventListener
(
'resize'
,
setItemLine
);
})
;
// 添加/移除全局点击监听
document
.
addEventListener
(
'click'
,
handleClickOutside
)
})
on
Updated
(()
=>
{
setItemLine
();
})
;
on
BeforeUnmount
(()
=>
{
document
.
removeEventListener
(
'click'
,
handleClickOutside
)
})
onU
nmoun
ted
(()
=>
{
window
.
removeEventListener
(
'resize'
,
setItemLine
);
onU
pda
ted
(()
=>
{
// setItemLine(
);
});
watch
(
showLevel4
,
(
newVal
,
oldVal
)
=>
{
setItemLine
();
})
</
script
>
<
template
>
<div
class=
"container_wrap"
>
<div
class=
"content_main"
>
<div
class=
"top_tool_wrap"
>
<StepBar
:steps-info=
"stepsInfo"
/>
</div>
<div
class=
"operator_panel_wrap"
:style=
"
{ 'min-height': step == 0 ? 'calc(100% - 112px)' : 'unset' }"
v-loading="loading">
<ContentWrap
title=
"入表类型"
description=
""
:expandSwicth=
"false"
v-show=
"step == 1"
>
<Form
ref=
"entryFormRef"
:itemList=
"entryForm.items"
formId=
"dam-base-form"
:rules=
"entryForm.rules"
col=
"col3"
@
selectChange=
"selectChange"
/>
</ContentWrap>
<div
class=
"operator_panel_wrap"
:style=
"
{ 'min-height': 'unset' }" v-loading="loading">
<div
class=
"v-tip"
v-show=
"step == 0"
>
<div
class=
"tip-icon"
></div>
<div
class=
"tip-des"
>
本工具提供的入表评估结果仅为初步测算参考,基于用户输入参数生成,不代表最终入表金额。实际入表需遵循《企业数据资源相关会计处理暂行规定》及会计准则要求,经专业审计机构确认后方可生效。
</div>
</div>
<ContentWrap
:title=
"step == 0 ? '设置成本项' : step == 1 ? '填写成本明细' : '文件预览'"
description=
""
:expandSwicth=
"false"
:style=
"step == 1 ?
{ 'margin-top': '16px' } : {}">
<ContentWrap
:title=
"step == 0 ? '设置成本项' : '文件预览'"
description=
""
:expandSwicth=
"false"
:style=
"step == 1 ?
{ 'margin-top': '16px' } : {}">
<div
class=
"table_tool_wrap"
>
<Form
ref=
"costFormRef"
:itemList=
"costForm.items"
formId=
"dam-base-form"
:rules=
"costForm.rules"
col=
"col3"
@
btnClick=
"btnClick"
@
selectChange=
"selectChange"
/>
<div
class=
"tool_btn"
v-if=
"step ==
2
"
>
<div
class=
"tool_btn"
v-if=
"step ==
1
"
>
<el-button
type=
"primary"
@
click=
"exportClick"
>
下载文件
</el-button>
<!--
<el-button
type=
"primary"
plain
@
click=
"senMessage"
>
入表咨询
</el-button>
-->
</div>
</div>
<div
class=
"grid-box-wrap"
v-show=
"step == 0"
>
<!-- 头部标题 -->
<div
class=
"grid-panel-wrap header"
:class=
"
{ col4: showLevel4 }">
<template
v-for=
"(list, l) in gridList"
:key=
"'panel'+l"
>
<div
class=
"panel-header"
v-if=
"l
< 3
||
showLevel4
"
>
{{
list
.
name
}}
</div>
</
template
>
</div>
<div
class=
"grid-panel-wrap"
:class=
"{ col4: showLevel4 }"
v-for=
"(item, i) in allMapList"
:key=
"'panel-' + i"
>
<!-- 一级指标 -->
<div
class=
"grid-panel-box"
>
<div
class=
"grid-panel"
ref=
"gridPanel"
>
<div
class=
"grid-items after"
ref=
"gridItem"
:class=
"getClass(i, item.checked)"
>
<el-checkbox
v-model=
"item.checked"
@
change=
"val => checkboxChange(val, { item }, 1)"
/>
<span
class=
"item-label"
>
{{ item.name }}
</span>
<span
class=
"circle"
></span>
</div>
</div>
</div>
<!-- 一级分类 -->
<div
class=
"grid-panel-box box1"
>
<
template
v-for=
"(grid, g) in item.children"
:key=
"'grid' + i + '-' + g"
>
<div
class=
"grid-panel"
:class=
"
{ before: g
< item
.
children
.
length
-
1
,
left8:
showLevel4
}"
>
<div
class=
"grid-items before after"
:class=
"getClass(i, grid.checked)"
>
<el-checkbox
v-model=
"grid.checked"
@
change=
"val => checkboxChange(val,
{ item, grid }, 2)" />
<span
class=
"item-label"
>
{{
grid
.
name
}}
</span>
<span
class=
"circle"
></span>
</div>
</div>
</
template
>
</div>
<!-- 二级分类 -->
<div
class=
"grid-panel-box box2 before"
:class=
"{ after: showLevel4 }"
>
<
template
v-for=
"(grid, g) in item.children"
:key=
"'grid' + i + '-' + g"
>
<div
class=
"grid-panel height_auto"
:class=
"
{ left8: showLevel4 }" v-if="grid.children.length">
<div
class=
"grid-items before"
:class=
"[getClass(i, child.checked),
{ after: child.children.length }]"
v-for="(child, c) in grid.children" :key="'item' + i + '-' + g + '-' + c"
:style="setItemStyle(child, null)">
<el-checkbox
v-model=
"child.checked"
@
change=
"val => checkboxChange(val,
{ item, grid, child }, 3)" />
<span
class=
"item-label"
>
{{
child
.
name
}}
</span>
<div
class=
"item-tool"
>
<el-popover
placement=
"bottom-end"
:width=
"108"
trigger=
"click"
popper-class=
"popover_btns"
>
<template
#
reference
>
<el-icon>
<MoreFilled
/>
</el-icon>
</
template
>
<
template
#
default
>
<div
class=
"tool-btns"
>
<div
@
click=
"btnClick(
{ value: 'add-same', row: child, parent: grid })">新增本级
</div>
<div
@
click=
"btnClick(
{ value: 'add-lower', row: child, parent: grid })">新增下级
</div>
<div
@
click=
"btnClick(
{ value: 'edit', row: child, parent: grid })">重命名
</div>
<div
v-if=
"grid.children.length > 1"
@
click=
"btnClick(
{ value: 'remove', row: child, parent: grid })">删除
</div>
</div>
</
template
>
</el-popover>
</div>
<span
class=
"circle"
:style=
"{ height: spanHeight(child) }"
></span>
</div>
</div>
</template>
</div>
<!-- 三级分类 -->
<div
class=
"grid-panel-box box3"
v-if=
"showLevel4"
>
<div
class=
"grid-panel no_padding"
v-if=
"showPanel(item.children, item)"
>
<
template
v-for=
"(grid, g) in item.children"
:key=
"'grid' + i + '-' + g"
>
<div
class=
"grid-group"
>
<template
v-for=
"(child, c) in grid.children"
:key=
"'item' + i + '-' + g + '-' + c"
>
<div
class=
"group-items before"
>
<div
class=
"grid-items before"
:class=
"getClass(i, opt.checked)"
v-for=
"(opt, o) in child.children"
:key=
"'pis' + i + '-' + g + '-' + c + '-' + o"
:style=
"setItemStyle(opt,
{ o })">
<el-checkbox
v-model=
"opt.checked"
@
change=
"val => checkboxChange(val,
{ item, grid, child, opt }, 4)" />
<span
class=
"item-label"
>
{{
opt
.
name
}}
</span>
<div
class=
"item-tool"
>
<el-popover
placement=
"bottom-end"
:width=
"108"
trigger=
"click"
popper-class=
"popover_btns"
>
<template
#
reference
>
<el-icon>
<MoreFilled
/>
</el-icon>
</
template
>
<
template
#
default
>
<div
class=
"tool-btns"
>
<div
@
click=
"btnClick(
{ value: 'edit', row: opt, parent: child })">重命名
</div>
<div
@
click=
"btnClick(
{ value: 'remove', row: opt, parent: child })">删除
</div>
</div>
</
template
>
</el-popover>
</div>
</div>
</div>
</template>
</div>
</template>
</div>
</div>
</div>
</div>
<div
class=
"table_panel_wrap"
v-show=
"step > 0"
>
<div
class=
"amount_tool"
v-if=
"step == 1"
>
<div
class=
"table_panel_wrap"
>
<div
class=
"amount_tool"
v-if=
"besure"
>
<span
class=
"amount_text"
>
累计投入:
</span>
<span
class=
"amount_num"
>
{{
changeNum
(
amount
,
2
,
true
)
}}
</span>
<span>
元
</span>
</div>
<div
class=
"table_panel"
>
<el-table
id=
"cost-table"
v-show=
"step == 1"
ref=
"costTableRef"
:data=
"tableData"
:span-method=
"tableSpanMethod"
:summary-method=
"tableSummaryMethod"
show-summary
border
:cell-class-name=
"isMergedCell"
>
<el-table-column
v-for=
"(item, i) in tableField"
:label=
"item.label"
:width=
"item.width"
:min-width=
"item.minWidth"
:fixed=
"item.fixed"
:align=
"item.align"
:sortable=
"item.sortable ?? false"
:prop=
"item.field"
:class-name=
"item.columClass"
show-overflow-tooltip
>
<el-table
id=
"cost-table"
v-show=
"step == 0"
ref=
"costTableRef"
:data=
"tableData"
:span-method=
"tableSpanMethod"
:show-summary=
"besure"
:summary-method=
"tableSummaryMethod"
:cell-class-name=
"isMergedCell"
stripe
border
>
<template
v-for=
"(item, i) in tableField"
:key=
"'tField' + i"
>
<el-table-column
v-if=
"item.visible ?? true"
:label=
"item.label"
:width=
"item.width"
:min-width=
"item.minWidth"
:fixed=
"item.fixed"
:align=
"item.align"
:sortable=
"item.sortable ?? false"
:prop=
"item.field"
:class-name=
"item.columClass"
show-overflow-tooltip
>
<template
#
default=
"scope"
>
<div
class=
"input_cell"
v-if=
"item.type == 'input'"
>
<el-input
v-model
.
trim=
"scope.row[item.field]"
placeholder=
"请输入"
:maxlength=
"item.maxlength ?? ''"
@
change=
"(val) => inputChange(val, scope, item.field)"
@
input=
"(val) => inputEventChange(val, scope, item.field)"
clearable
></el-input>
<el-input
v-model
.
trim=
"scope.row[item.field]"
:placeholder=
"scope.row.edit ? '' : '--'"
:maxlength=
"item.maxlength ?? ''"
@
change=
"(val) => inputChange(val, scope, item.field)"
@
input=
"(val) => inputEventChange(val, scope, item.field)"
:disabled=
"scope.row.edit ? false : true"
clearable
></el-input>
<span>
{{
scope
.
row
[
item
.
field
]
?
changeNum
(
scope
.
row
[
item
.
field
],
2
,
true
)
:
Number
(
scope
.
row
[
item
.
field
])
==
0
?
'0.00'
:
''
}}
</span>
</div>
<span
v-else
>
{{
item
.
getName
?
item
.
getName
(
scope
)
:
scope
.
row
[
item
.
field
]
!==
0
&&
!
scope
.
row
[
item
.
field
]
?
<div
class=
"cell-tool"
v-else
>
<span
class=
"cell_text_group"
>
<el-checkbox
v-if=
"item.field != 'total' && scope.row[item.field]"
v-model=
"scope.row['checked' + item.level]"
@
change=
"val => cellCheckboxChange(val,
{ ...item, ...scope.row, rIndex: scope.$index })" />
<span
class=
"cell_text"
>
{{
item
.
getName
?
item
.
getName
(
scope
)
:
scope
.
row
[
item
.
field
]
!==
0
&&
!
scope
.
row
[
item
.
field
]
?
"--"
:
scope
.
row
[
item
.
field
]
}}
</span>
</span>
<el-icon
v-if=
"item.field == 'name3' || (item.field == 'name4' && scope.row[item.field])"
class=
"list-more"
color=
"#666"
@
click=
"e => togglePopover(
{ ...item, ...scope.row, rIndex: scope.$index }, e)">
<MoreFilled
/>
</el-icon>
</div>
</
template
>
</el-table-column>
</el-table>
<el-table
id=
"entry-table"
ref=
"entryTableRef"
:data=
"transposedData"
stripe
border
v-show=
"step == 2"
>
<el-table-column
prop=
"title"
label=
"项目"
:width=
"140"
>
<
template
v-slot=
"{ row }"
>
<span>
{{
setLabel
(
row
.
title
)
}}
</span>
</
template
>
</el-table-column>
<el-table-column
v-for=
"(item, index) in headers"
:key=
"index"
:prop=
"item.value"
:label=
"item.label"
:width=
"120"
align=
"right"
>
<
template
v-slot:header
>
<span
v-html=
"item.label"
></span>
</template>
<
template
v-slot=
"{ row }"
>
<span
v-if=
"typeof row[item.value] == 'number'"
>
{{
changeNum
(
row
[
item
.
value
],
2
,
true
)
}}
</span>
<span
v-else
></span>
</el-table>
<el-table
id=
"entry-table"
ref=
"entryTableRef"
:data=
"transposedData"
stripe
border
v-show=
"step == 1"
>
<el-table-column
v-for=
"(item, index) in bookHeaders"
:key=
"index"
:prop=
"item.field"
:label=
"item.label"
:width=
"item.width"
:align=
"item.align"
>
<
template
#
default=
"scope"
>
<span
v-if=
"item.field == 'title'"
>
{{
setLabel
(
scope
.
row
[
item
.
field
])
}}
</span>
<span
v-else
>
{{
changeNum
(
scope
.
row
[
item
.
field
],
2
,
true
)
}}
</span>
</
template
>
</el-table-column>
</el-table>
</div>
</div>
</ContentWrap>
<ContentWrap
title=
"入表类型"
description=
""
:expandSwicth=
"false"
v-show=
"step == 0"
>
<Form
ref=
"entryFormRef"
:itemList=
"entryForm.items"
formId=
"dam-base-form"
:rules=
"entryForm.rules"
col=
"col3"
@
selectChange=
"selectChange"
/>
</ContentWrap>
</div>
</div>
<div
class=
"tool_btns"
>
<div
class=
"btns"
>
<el-button
@
click=
"btnClick({ value: 'refresh' })"
>
重置
</el-button>
<el-button
@
click=
"btnClick({ value: 'prev' })"
v-if=
"step == 1"
>
上一步
</el-button>
<el-button
type=
"primary"
@
click=
"btnClick({ value: 'prev' })"
v-if=
"step ==
2
"
>
上一步
</el-button>
<el-button
type=
"primary"
@
click=
"btnClick({ value: 'next' })"
v-if=
"step < 2"
>
下一步
</el-button
>
<el-button
type=
"primary"
@
click=
"btnClick({ value: 'next' })"
v-if=
"step == 0"
>
入表
</el-button>
<el-button
type=
"primary"
@
click=
"btnClick({ value: 'prev' })"
v-if=
"step ==
1
"
>
上一步
</el-button>
</div
>
</div>
</div>
<el-popover
:visible=
"popoverVisible"
placement=
"bottom-start"
width=
"110"
trigger=
"click"
popper-class=
"tree-item-edit-menu"
:virtual-ref=
"popoverTriggerRef"
virtual-triggering
:hide-after=
"0"
:offset=
"8"
@
after-leave=
"handlePopoverClose"
>
<div
class=
"levitation-ul"
@
mousedown
.
stop
>
<span
class=
"levitation-li"
@
click=
"handleMenuClick('add-same')"
v-show=
"showAdd"
>
新增本级分类
</span>
<span
class=
"levitation-li"
@
click=
"handleMenuClick('add-lower')"
v-show=
"showAdd"
>
新增下级分类
</span>
<span
class=
"levitation-li"
@
click=
"handleMenuClick('edit')"
>
重命名
</span>
<span
class=
"levitation-li"
@
click=
"handleMenuClick('remove')"
>
删除
</span>
</div>
</el-popover>
</template>
<
style
lang=
"scss"
scoped
>
...
...
@@ -1848,7 +1744,7 @@ watch(showLevel4, (newVal, oldVal) => {
background
:
#FFFBF2
;
border
:
1px
solid
rgba
(
255
,
241
,
212
,
1
);
border-radius
:
4px
;
margin
:
5
px
0px
8px
;
margin
:
16
px
0px
8px
;
padding
:
2px
0px
;
.tip-icon
{
...
...
@@ -1902,6 +1798,30 @@ watch(showLevel4, (newVal, oldVal) => {
:deep
(
.el-table
)
{
td.el-table__cell
{
.cell-tool
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.cell_text_group
{
display
:
flex
;
.el-checkbox
{
height
:
24px
;
line-height
:
24px
;
}
.cell_text
{
margin-left
:
4px
;
line-height
:
24px
;
}
}
.list-more
{
cursor
:
pointer
;
}
}
&
.edit_cell
{
padding
:
4px
0
;
...
...
@@ -1911,6 +1831,11 @@ watch(showLevel4, (newVal, oldVal) => {
.input_cell
{
position
:
relative
;
.el-input
.el-input__inner
{
text-align
:
right
;
height
:
24px
;
}
>
span
{
position
:
absolute
;
left
:
0
;
...
...
@@ -1919,6 +1844,13 @@ watch(showLevel4, (newVal, oldVal) => {
}
}
}
&
.inverse_cell
{
.cell_text_group
{
display
:
block
;
width
:
100%
;
}
}
}
.el-table__footer-wrapper
tr
td
{
...
...
@@ -1926,5 +1858,15 @@ watch(showLevel4, (newVal, oldVal) => {
text-align
:
right
;
}
}
.el-table__footer-wrapper
tfoot
td
.el-table__cell
{
background
:
#FFF1D4
;
}
}
:deep
(
.el-popper
)
{
&.tree-item-edit-menu
{
transform
:
translateX
(
-10px
);
}
}
</
style
>
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment