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
eab1ac74
authored
2025-03-27 13:12:03 +0800
by
lihua
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
估值模型功能提交
1 parent
2a4a9f87
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1200 additions
and
0 deletions
src/api/modules/dataEntry.ts
src/router/modules/dataEntry.ts
src/store/modules/dataEntry.ts
src/views/data_transaction/valuationModel.vue
src/views/data_transaction/valuationModelCreate.vue
src/api/modules/dataEntry.ts
View file @
eab1ac7
...
...
@@ -48,3 +48,39 @@ export const sendEntryMsg = (params) => request({
method
:
'post'
,
params
});
/** ----------------------------------------估值模型接口--------------------------------- */
/** 获取数据产品估值模型列表 */
export
const
getValuationModelList
=
(
params
)
=>
request
({
url
:
`
${
import
.
meta
.
env
.
VITE_API_NEW_PORTAL
}
/valuation-model/page-list`
,
method
:
'post'
,
data
:
params
})
/** 保存估值模型 */
export
const
saveValuationMode
=
(
params
)
=>
request
({
url
:
`
${
import
.
meta
.
env
.
VITE_API_NEW_PORTAL
}
/valuation-model/save`
,
method
:
'post'
,
data
:
params
})
/** 更新估值模型 */
export
const
updateValuationMode
=
(
params
)
=>
request
({
url
:
`
${
import
.
meta
.
env
.
VITE_API_NEW_PORTAL
}
/valuation-model/update`
,
method
:
'put'
,
data
:
params
})
/** 删除估值模型 */
export
const
deleteValuationMode
=
(
params
)
=>
request
({
url
:
`
${
import
.
meta
.
env
.
VITE_API_NEW_PORTAL
}
/valuation-model/delete`
,
method
:
'delete'
,
data
:
params
})
/** 获取估值模型详情 */
export
const
getValuationModelDetail
=
(
params
)
=>
request
({
url
:
`
${
import
.
meta
.
env
.
VITE_API_NEW_PORTAL
}
/valuation-model/detail?guid=
${
params
.
guid
}
`
,
method
:
'get'
})
\ No newline at end of file
...
...
src/router/modules/dataEntry.ts
View file @
eab1ac7
...
...
@@ -68,6 +68,45 @@ const routes: RouteRecordRaw[] = [
},
],
},
{
path
:
'/data-entry/valuation-model'
,
component
:
Layout
,
meta
:
{
title
:
'估值模型'
,
icon
:
'sidebar-videos'
,
},
children
:
[
{
path
:
''
,
name
:
'valuationModel'
,
component
:
()
=>
import
(
'@/views/data_transaction/valuationModel.vue'
),
meta
:
{
title
:
'估值模型'
,
sidebar
:
false
,
breadcrumb
:
false
,
cache
:
true
},
},
{
path
:
'valuation-model-create'
,
name
:
'valuationModelCreate'
,
component
:
()
=>
import
(
'@/views/data_transaction/valuationModelCreate.vue'
),
meta
:
{
title
:
'新建估值模型'
,
sidebar
:
false
,
breadcrumb
:
false
,
cache
:
true
,
editPage
:
true
,
reuse
:
true
},
beforeEnter
:
(
to
,
from
)
=>
{
if
(
to
.
query
.
guid
)
{
to
.
meta
.
title
=
`编辑-
${
to
.
query
.
name
}
`
;
}
}
},
],
},
]
export
default
routes
...
...
src/store/modules/dataEntry.ts
0 → 100644
View file @
eab1ac7
const
useEntryStore
=
defineStore
(
// api标签分类guid
'isRefresh'
,
()
=>
{
const
isRefresh
=
ref
(
false
);
function
setIsRefresh
(
update
:
boolean
)
{
isRefresh
.
value
=
update
;
}
return
{
isRefresh
,
setIsRefresh
,
}
},
)
export
default
useEntryStore
\ No newline at end of file
src/views/data_transaction/valuationModel.vue
0 → 100644
View file @
eab1ac7
<
script
lang=
"ts"
setup
name=
"valuationModel"
>
import
TableTools
from
"@/components/Tools/table_tools.vue"
;
import
{
commonPageConfig
}
from
'@/components/PageNav/index'
;
import
{
getValuationModelList
,
deleteValuationMode
}
from
'@/api/modules/dataEntry'
;
import
{
TableColumnWidth
}
from
"@/utils/enum"
;
import
{
changeNum
}
from
"@/utils/common"
;
import
useEntryStore
from
"@/store/modules/dataEntry"
;
const
entryStore
=
useEntryStore
();
const
router
=
useRouter
()
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
/** 头部搜索框配置 */
const
searchItemList
=
ref
([
{
type
:
"input"
,
label
:
""
,
field
:
"damName"
,
default
:
""
,
placeholder
:
"数据产品名称"
,
clearable
:
true
,
},
{
type
:
"select"
,
label
:
""
,
field
:
"evaluateMethod"
,
default
:
""
,
placeholder
:
"评估方法"
,
options
:
[
{
label
:
"成本法"
,
value
:
"1"
},
{
label
:
"收益法"
,
value
:
"2"
},
],
clearable
:
true
,
}
]);
/** 分页及搜索传参信息配置。 */
const
page
=
ref
({
...
commonPageConfig
,
damName
:
''
,
evaluateMethod
:
''
});
const
tableSelectRowData
:
any
=
ref
([]);
const
tableInfo
=
ref
({
id
:
'valuation-model-table'
,
multiple
:
true
,
fields
:
[
{
label
:
"序号"
,
type
:
"index"
,
width
:
TableColumnWidth
.
INDEX
,
align
:
"center"
},
{
label
:
"数据产品名称"
,
field
:
"damName"
,
width
:
160
},
{
label
:
"评估方法"
,
field
:
"evaluateMethod"
,
width
:
140
,
getName
:
(
scope
)
=>
{
return
scope
.
row
.
evaluateMethod
==
'1'
?
'成本法'
:
'收益法'
;
}
},
{
label
:
"评估基准日"
,
field
:
"evaluateBaseDate"
,
width
:
TableColumnWidth
.
DATE
,
},
{
label
:
"评估价值(元)"
,
field
:
"damValuation"
,
width
:
160
,
align
:
'right'
},
{
label
:
"修改人"
,
field
:
"updateUserName"
,
width
:
TableColumnWidth
.
USERNAME
},
{
label
:
"修改时间"
,
field
:
"updateTime"
,
width
:
TableColumnWidth
.
DATETIME
},
],
data
:
[],
page
:
{
type
:
"normal"
,
rows
:
0
,
...
page
.
value
,
},
actionInfo
:
{
label
:
"操作"
,
type
:
"btn"
,
width
:
140
,
fixed
:
'right'
,
btns
:
(
scope
)
=>
{
let
btnsArr
:
any
=
[];
btnsArr
.
push
({
label
:
"编辑"
,
value
:
"edit"
,
click
:
(
scope
)
=>
{
router
.
push
({
name
:
'valuationModelCreate'
,
query
:
{
guid
:
scope
.
row
.
guid
,
name
:
scope
.
row
.
damName
}
})
}
});
btnsArr
.
push
({
label
:
"删除"
,
value
:
"delete"
,
click
:
(
scope
)
=>
{
proxy
.
$openMessageBox
(
'此操作将永久删除, 是否继续?'
,
()
=>
{
deleteValuationMode
([
scope
.
row
.
guid
]).
then
((
res
:
any
)
=>
{
if
(
res
.
code
==
proxy
.
$passCode
)
{
page
.
value
.
curr
=
1
;
getTableData
();
proxy
.
$ElMessage
({
type
:
"success"
,
message
:
"删除成功"
,
});
}
else
{
proxy
.
$ElMessage
({
type
:
'error'
,
message
:
res
.
msg
,
})
}
})
},
()
=>
{
proxy
.
$ElMessage
.
info
(
"已取消删除"
);
})
}
});
return
btnsArr
},
},
loading
:
false
})
const
toSearch
=
(
val
:
any
,
clear
:
boolean
=
false
)
=>
{
if
(
clear
)
{
searchItemList
.
value
.
map
((
item
)
=>
(
item
.
default
=
""
));
page
.
value
.
damName
=
''
;
page
.
value
.
evaluateMethod
=
""
;
}
else
{
page
.
value
.
damName
=
val
.
damName
;
page
.
value
.
evaluateMethod
=
val
.
evaluateMethod
;
}
getTableData
();
};
const
getTableData
=
()
=>
{
tableInfo
.
value
.
loading
=
true
getValuationModelList
({
pageIndex
:
page
.
value
.
curr
,
pageSize
:
page
.
value
.
limit
,
damName
:
page
.
value
.
damName
,
evaluateMethod
:
page
.
value
.
evaluateMethod
}).
then
((
res
:
any
)
=>
{
if
(
res
.
code
==
proxy
.
$passCode
)
{
const
data
=
res
.
data
||
{}
tableInfo
.
value
.
data
=
data
.
records
||
[]
tableInfo
.
value
.
page
.
limit
=
data
.
pageSize
tableInfo
.
value
.
page
.
curr
=
data
.
pageIndex
tableInfo
.
value
.
page
.
rows
=
data
.
totalRows
}
else
{
proxy
.
$ElMessage
({
type
:
'error'
,
message
:
res
.
msg
,
})
}
tableInfo
.
value
.
loading
=
false
}).
catch
(()
=>
{
tableInfo
.
value
.
loading
=
false
})
};
const
tablePageChange
=
(
info
)
=>
{
page
.
value
.
curr
=
Number
(
info
.
curr
);
page
.
value
.
limit
=
Number
(
info
.
limit
);
tableInfo
.
value
.
page
.
curr
=
page
.
value
.
curr
;
tableInfo
.
value
.
page
.
limit
=
page
.
value
.
limit
;
getTableData
();
};
const
tableSelectionChange
=
(
val
)
=>
{
tableSelectRowData
.
value
=
val
;
};
const
newCreate
=
()
=>
{
router
.
push
({
name
:
'valuationModelCreate'
});
}
const
batchDelete
=
()
=>
{
if
(
tableSelectRowData
.
value
.
length
==
0
)
{
proxy
.
$ElMessage
({
type
:
'error'
,
message
:
'请选择需要删除的数据'
,
})
return
}
proxy
.
$openMessageBox
(
'此操作将永久删除, 是否继续?'
,
()
=>
{
deleteValuationMode
(
tableSelectRowData
.
value
.
map
(
d
=>
d
.
guid
)).
then
((
res
:
any
)
=>
{
if
(
res
.
code
==
proxy
.
$passCode
)
{
page
.
value
.
curr
=
1
;
getTableData
();
proxy
.
$ElMessage
.
success
(
'删除成功'
);
}
else
{
proxy
.
$ElMessage
.
error
(
res
.
msg
);
}
})
},
()
=>
{
proxy
.
$ElMessage
.
info
(
"已取消删除"
);
})
}
onBeforeMount
(()
=>
{
// toSearch({})
})
onActivated
(()
=>
{
if
(
entryStore
.
isRefresh
)
{
getTableData
();
entryStore
.
setIsRefresh
(
false
);
}
})
</
script
>
<
template
>
<div
class=
"container_wrap"
>
<div
class=
"table_tool_wrap"
>
<!-- 头部搜索 -->
<TableTools
:searchItems=
"searchItemList"
:searchId=
"'data-source-search'"
@
search=
"toSearch"
/>
<div
class=
"tools_btns"
>
<el-button
type=
"primary"
@
click=
"newCreate"
>
新建
</el-button>
<el-button
@
click=
"batchDelete"
>
批量删除
</el-button>
</div>
</div>
<div
class=
"table_panel_wrap"
>
<Table
:tableInfo=
"tableInfo"
@
tablePageChange=
"tablePageChange"
@
tableSelectionChange=
"tableSelectionChange"
/>
</div>
</div>
</
template
>
<
style
lang=
"scss"
scoped
>
.table_tool_wrap
{
width
:
100%
;
height
:
84px
!important
;
padding
:
0
8px
;
.tools_btns
{
padding
:
0px
0
0
;
}
}
.table_panel_wrap
{
width
:
100%
;
height
:
calc
(
100%
-
84px
);
padding
:
0px
8px
0
;
}
</
style
>
\ No newline at end of file
src/views/data_transaction/valuationModelCreate.vue
0 → 100644
View file @
eab1ac7
<
script
lang=
"ts"
setup
name=
"valuationModelCreate"
>
import
{
getAssetCatalog
,
saveValuationMode
,
updateValuationMode
,
getValuationModelDetail
}
from
"@/api/modules/dataEntry"
;
import
{
useValidator
}
from
'@/hooks/useValidator'
;
import
useUserStore
from
"@/store/modules/user"
;
import
{
changeNum
,
}
from
"@/utils/common"
;
import
moment
from
"moment"
;
import
useEntryStore
from
"@/store/modules/dataEntry"
;
const
userStore
=
useUserStore
();
const
entryStore
=
useEntryStore
();
const
{
required
}
=
useValidator
();
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
const
router
=
useRouter
();
const
route
=
useRoute
();
const
fullPath
=
route
.
fullPath
;
const
fullscreenLoading
=
ref
(
false
);
/** 数据产品列表 */
const
damProductList
:
any
=
ref
([]);
const
formRef
=
ref
();
const
valuateFormItems
:
any
=
ref
([
{
label
:
"数据产品名称"
,
type
:
"select"
,
placeholder
:
"请选择,来自数据产品目录"
,
field
:
"damGuid"
,
default
:
''
,
options
:
damProductList
.
value
,
props
:
{
label
:
'damName'
,
value
:
'guid'
},
disabled
:
false
,
filterable
:
true
,
clearable
:
true
,
required
:
true
,
},
{
label
:
"基准日"
,
type
:
"date-month"
,
field
:
"evaluateBaseDate"
,
default
:
moment
(
new
Date
()).
format
(
'YYYY-MM'
),
placeholder
:
"请选择"
,
clearable
:
true
,
required
:
true
,
style
:
{
width
:
'calc(33.33% - 70px)'
,
'margin-right'
:
'8px'
},
popperClass
:
'date-month-popper'
,
disabledDate
:
(
date
)
=>
{
const
curr
=
new
Date
();
return
date
.
getFullYear
()
==
curr
.
getFullYear
()
?
date
.
getMonth
()
>
curr
.
getMonth
()
:
false
;
},
},
{
type
:
"select"
,
field
:
"evaluateMethod"
,
default
:
"1"
,
label
:
"评估方法"
,
placeholder
:
"请选择"
,
required
:
true
,
options
:
[
{
label
:
"成本法"
,
value
:
"1"
},
{
label
:
"收益法"
,
value
:
"2"
},
]
},
{
type
:
"select"
,
label
:
"使用年限(1~10)"
,
field
:
"useYears"
,
default
:
1
,
options
:
[{
value
:
1
,
label
:
'1'
},
{
value
:
2
,
label
:
'2'
},
{
value
:
3
,
label
:
'3'
},
{
value
:
4
,
label
:
'4'
},
{
value
:
5
,
label
:
'5'
},
{
value
:
6
,
label
:
'6'
},
{
value
:
7
,
label
:
'7'
},
{
value
:
8
,
label
:
'8'
},
{
value
:
9
,
label
:
'9'
},
{
value
:
10
,
label
:
'10'
}],
placeholder
:
"年限1~10"
,
clearable
:
false
,
filterable
:
true
,
required
:
true
,
visible
:
false
},
]);
const
valuateFormRules
=
ref
({
// damGuid: [required('请选择数据产品名称')],
evaluateBaseDate
:
[
required
(
'请选择基准日'
)],
evaluateMethod
:
[
required
(
'请选择评估方法'
)],
useYears
:
[{
type
:
'number'
,
min
:
1
,
max
:
10
,
message
:
"请填写年限1~10"
,
trigger
:
"change"
,
},]
});
const
handleValudateFormChange
=
(
val
,
row
,
info
)
=>
{
if
(
row
.
field
==
'evaluateMethod'
)
{
valuateFormItems
.
value
.
forEach
(
item
=>
{
item
.
default
=
info
[
item
.
field
];
if
(
item
.
field
==
'useYears'
)
{
item
.
visible
=
item
.
default
!=
'1'
;
item
.
default
=
info
.
useYears
?
info
.
useYears
:
1
;
}
})
}
}
/** 获取当月的最后一天。 */
const
getLastDayOfMonth
=
(
month
)
=>
{
const
year
=
parseInt
(
month
.
split
(
'-'
)[
0
],
10
);
const
monthIndex
=
parseInt
(
month
.
split
(
'-'
)[
1
],
10
)
-
1
;
// JavaScript 的月份是从0开始计数的
const
date
=
new
Date
(
year
,
monthIndex
+
1
,
0
);
// 使用0可以得到前一个月的最后一天
const
yearString
=
date
.
getFullYear
();
const
monthString
=
String
(
date
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
);
// JavaScript 的月份是从0开始计数的
const
dayString
=
String
(
date
.
getDate
()).
padStart
(
2
,
'0'
);
return
`
${
yearString
}
-
${
monthString
}
-
${
dayString
}
`
;
}
const
costTableField
:
any
=
ref
([
{
label
:
"环节"
,
field
:
"link"
,
width
:
160
},
{
label
:
"一级指标"
,
field
:
"primaryIndex"
,
width
:
160
},
{
label
:
"二级指标"
,
field
:
"secondIndex"
,
width
:
160
},
{
label
:
'金额(元)'
,
align
:
'right'
,
field
:
'amount'
,
type
:
'input'
,
width
:
150
,
columClass
:
'edit_cell'
},
{
label
:
"通常包含的成本输入项"
,
field
:
"costInput"
,
width
:
380
},
{
label
:
"费用科目"
,
field
:
"expenseAccount"
,
width
:
220
},
]);
const
costTableData
=
ref
([{
orderNum
:
1
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据规划'
,
secondIndex
:
'数据规划'
,
amount
:
''
,
costInput
:
'包含数据生存周期整体规划所投入的人员薪资、咨询费用及相关资源成本等'
,
expenseAccount
:
'咨询费/会议费/人工费(拆分)'
},
{
orderNum
:
2
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据采集'
,
secondIndex
:
'人工采集'
,
amount
:
''
,
costInput
:
'向数据持有人购买数据的价款、注册费、手续费、服务费等'
,
expenseAccount
:
'人工费、劳保费、劳务费、运输费'
},
{
orderNum
:
3
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据采集'
,
secondIndex
:
'自动化采集'
,
amount
:
''
,
costInput
:
'在数据采集阶段发生的人员薪酬、打印费、网络费等相关费用'
,
expenseAccount
:
'人工费、设备费、材料费'
},
{
orderNum
:
4
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据汇聚'
,
secondIndex
:
'数据传输'
,
amount
:
''
,
costInput
:
''
,
expenseAccount
:
''
},
{
orderNum
:
5
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据汇聚'
,
secondIndex
:
'网络通讯'
,
amount
:
''
,
costInput
:
'传输数据发生的管道成本'
,
expenseAccount
:
'网络费用'
},
{
orderNum
:
6
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据加工'
,
secondIndex
:
'数据脱敏'
,
amount
:
''
,
costInput
:
'对敏感数据进行变形处理所发生的人力成本、技术成本等'
,
expenseAccount
:
'人工费'
},
{
orderNum
:
7
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据加工'
,
secondIndex
:
'数据清洗'
,
amount
:
''
,
costInput
:
'去除重复数据、填补缺失值、处理异常值和转换数据格式等投入'
,
expenseAccount
:
'人工费'
},
{
orderNum
:
8
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据加工'
,
secondIndex
:
'数据标注'
,
amount
:
''
,
costInput
:
'对数据进行添加标签处理所发生的费用,人工或AI标注'
,
expenseAccount
:
'人工费、无形资产分摊'
},
{
orderNum
:
9
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据加工'
,
secondIndex
:
'数据整合'
,
amount
:
''
,
costInput
:
'数据整合成本是指合并整理来自不同数据源的数据所发生的成本'
,
expenseAccount
:
'人工费、材料费等'
},
{
orderNum
:
10
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据分析'
,
secondIndex
:
'数据分析'
,
amount
:
''
,
costInput
:
'采用适当的方法对数据进行分析整理所发生的成本费用'
,
expenseAccount
:
'人工费'
},
{
orderNum
:
11
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据分析'
,
secondIndex
:
'数据可视化'
,
amount
:
''
,
costInput
:
'通过图形化手段清晰有效地传达信息所发生的成本费用'
,
expenseAccount
:
'人工费'
},
{
orderNum
:
12
,
link
:
'顺序性环节'
,
primaryIndex
:
'数据产品开发'
,
secondIndex
:
'数据产品开发'
,
amount
:
''
,
costInput
:
'面向数据应用和服务,开发、封装数据产品所产生的费用'
,
expenseAccount
:
'人工费,股份支付,生产成本外协技术费'
},
{
orderNum
:
13
,
link
:
'全流程环节'
,
primaryIndex
:
'计算与存储'
,
secondIndex
:
'数据存储'
,
amount
:
''
,
costInput
:
'存储库的构建、优化等费用'
,
expenseAccount
:
'云存储资源使用费,数据库使用费'
},
{
orderNum
:
14
,
link
:
'全流程环节'
,
primaryIndex
:
'计算与存储'
,
secondIndex
:
'计算资源'
,
amount
:
''
,
costInput
:
'按流量计费、云服务分摊'
,
expenseAccount
:
'计算资源采购费用'
},
{
orderNum
:
15
,
link
:
'全流程环节'
,
primaryIndex
:
'数据维护'
,
secondIndex
:
'数据维护'
,
amount
:
''
,
costInput
:
'数据权属鉴证、质量评估、登记、交易成本、数据合规费用'
,
expenseAccount
:
'人工费、技术服务费'
},
{
orderNum
:
16
,
link
:
'全流程环节'
,
primaryIndex
:
'数据维护'
,
secondIndex
:
'数据维护'
,
amount
:
''
,
costInput
:
'数据加工费用,包括数据调整、补全、标注、更新和脱敏等费用'
,
expenseAccount
:
'人工费、技术服务费'
},
{
orderNum
:
17
,
link
:
'全流程环节'
,
primaryIndex
:
'数据维护'
,
secondIndex
:
'数据维护'
,
amount
:
''
,
costInput
:
'数据备份、数据迁移和应急处置等费用'
,
expenseAccount
:
'人工费、设备费、技术服务费'
},
{
orderNum
:
18
,
link
:
'全流程环节'
,
primaryIndex
:
'数据安全'
,
secondIndex
:
'信息安全'
,
amount
:
''
,
costInput
:
'软性:等保认证等'
,
expenseAccount
:
'人工费、等保服务费、质量评价服务费、鉴权咨询费'
},
{
orderNum
:
19
,
link
:
'全流程环节'
,
primaryIndex
:
'数据安全'
,
secondIndex
:
'硬件或系统安全'
,
amount
:
''
,
costInput
:
'硬件或系统:安全产品、安全管理技术或服务'
,
expenseAccount
:
'防火墙或安全软件等采购费用'
},
{
orderNum
:
20
,
link
:
'全流程环节'
,
primaryIndex
:
'间接成本'
,
secondIndex
:
'软硬件成本'
,
amount
:
''
,
costInput
:
'与数据资产相关的软硬件采购或研发以及维护费用'
,
expenseAccount
:
'材料费,产品检测费,物料消耗费,修理费'
},
{
orderNum
:
21
,
link
:
'全流程环节'
,
primaryIndex
:
'间接成本'
,
secondIndex
:
'基础设施成本'
,
amount
:
''
,
costInput
:
'包括机房、场地等建设或租赁以及维护费用'
,
expenseAccount
:
'机房建设,物业费,租金,物联网大数据中心建设费'
},
{
orderNum
:
22
,
link
:
'全流程环节'
,
primaryIndex
:
'间接成本'
,
secondIndex
:
'公共管理成本'
,
amount
:
''
,
costInput
:
'水电、职工福利、差旅费、折旧费、办公费、通讯费'
,
expenseAccount
:
'水电、职工福利、差旅费、折旧费、办公费、通讯费'
}]);
const
costTableSpanMethod
=
({
row
,
column
,
rowIndex
,
columnIndex
})
=>
{
if
(
columnIndex
==
0
)
{
//第一列环节
let
columnValue
=
costTableData
.
value
[
rowIndex
].
link
;
if
(
rowIndex
==
0
||
columnValue
!=
costTableData
.
value
[
rowIndex
-
1
].
link
)
{
let
cnt
=
costTableData
.
value
.
filter
(
d
=>
d
.
link
==
columnValue
).
length
;
return
{
rowspan
:
cnt
,
colspan
:
1
}
}
else
{
return
{
rowspan
:
0
,
colspan
:
0
}
}
}
else
if
(
columnIndex
==
1
)
{
//第二列的合并
let
columnValue
=
costTableData
.
value
[
rowIndex
].
primaryIndex
;
if
(
rowIndex
==
0
||
columnValue
!=
costTableData
.
value
[
rowIndex
-
1
].
primaryIndex
)
{
let
cnt
=
costTableData
.
value
.
filter
(
d
=>
d
.
primaryIndex
==
columnValue
).
length
;
return
{
rowspan
:
cnt
,
colspan
:
1
}
}
else
{
return
{
rowspan
:
0
,
colspan
:
0
}
}
}
else
if
(
columnIndex
==
2
)
{
//二级指标,合并数据维护。
let
columnValue
=
costTableData
.
value
[
rowIndex
].
secondIndex
;
if
(
columnValue
==
'数据维护'
)
{
if
(
columnValue
!=
costTableData
.
value
[
rowIndex
-
1
].
secondIndex
)
{
return
{
rowspan
:
3
,
colspan
:
1
}
}
else
{
return
{
rowspan
:
0
,
colspan
:
0
}
}
}
}
return
{
rowspan
:
1
,
colspan
:
1
}
}
const
costTableSummaryValue
:
any
=
ref
(
0
);
// 表格合计行
const
costTableSummaryMethod
=
({
columns
,
data
})
=>
{
let
sums
:
any
[]
=
[];
columns
.
forEach
((
column
,
index
)
=>
{
if
(
index
===
0
)
{
//需要显示'总金额'的列 坐标 :0
sums
[
index
]
=
'数据资产估值'
return
}
else
{
if
(
column
.
property
==
'amount'
)
{
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
]
=
costTableSummaryValue
.
value
=
changeNum
(
sum
,
2
,
true
)
}
else
{
sums
[
index
]
=
costTableSummaryValue
.
value
=
'N/A'
}
}
}
})
return
sums
}
/** --------------------------- 收入法 --------------------------- */
const
incomeTableField
:
any
=
ref
([
{
label
:
"指标名称"
,
field
:
"indexName"
,
width
:
160
},
{
label
:
"单位"
,
field
:
"unit"
,
width
:
100
},
{
label
:
"预测年限"
,
field
:
"years"
,
showChild
:
true
,
align
:
'center'
},
{
label
:
"说明"
,
field
:
"instructions"
,
width
:
380
},
]);
const
incomeYears
=
computed
(()
=>
{
let
formInline
=
formRef
.
value
.
formInline
;
if
(
formInline
.
evaluateMethod
==
'1'
)
{
return
[];
}
let
evaluateBaseDate
=
formInline
.
evaluateBaseDate
;
let
useYears
=
formInline
.
useYears
;
let
infos
=
evaluateBaseDate
.
split
(
'-'
);
let
year
=
parseInt
(
infos
[
0
]);
let
month
=
parseInt
(
infos
[
1
]);
if
(
month
==
12
)
{
let
a
=
[{
field
:
year
+
''
,
label
:
year
+
'年'
}];
for
(
var
i
=
1
;
i
<
useYears
+
1
;
i
++
)
{
a
.
push
({
field
:
year
+
i
+
''
,
label
:
(
year
+
i
)
+
'年'
});
}
return
a
;
}
else
if
(
month
==
1
)
{
let
a
=
[{
field
:
evaluateBaseDate
+
''
,
label
:
year
+
'年'
+
`(1)`
}];
for
(
var
i
=
1
;
i
<
useYears
+
1
;
i
++
)
{
a
.
push
({
field
:
year
+
i
+
''
,
label
:
i
==
useYears
?
((
year
+
i
)
+
'年'
+
`(1)`
)
:
((
year
+
i
)
+
'年'
)
});
}
return
a
;
}
else
{
let
a
=
[{
field
:
evaluateBaseDate
+
''
,
label
:
year
+
'年'
+
`(1~
${
month
}
)`
}];
for
(
var
i
=
1
;
i
<
useYears
+
1
;
i
++
)
{
a
.
push
({
field
:
year
+
i
+
''
,
label
:
i
==
useYears
?
((
year
+
i
)
+
'年'
+
`(
${
month
}
~12)`
)
:
((
year
+
i
)
+
'年'
)
});
}
return
a
;
}
})
const
incomeTableData
:
any
=
ref
([{
orderNum
:
1
,
indexName
:
'收入'
,
unit
:
'元'
,
instructions
:
'数据创造或者是数据所在应用场景下的收入'
},
{
orderNum
:
2
,
indexName
:
'毛利率'
,
unit
:
'%'
,
instructions
:
'数据创造或者是数据所在应用场景下的毛利率'
},
{
orderNum
:
3
,
indexName
:
'营业利润率'
,
unit
:
'%'
,
instructions
:
'数据创造或者是数据所在应用场景下的营业利润率'
},
{
orderNum
:
4
,
indexName
:
'净利润率'
,
unit
:
'%'
,
instructions
:
'数据创造或者是数据所在应用场景下的净利润率'
},
{
orderNum
:
5
,
indexName
:
'行业利润率水平'
,
unit
:
'%'
,
instructions
:
'参考同行业上市公司/企业历史年度细分业务利润率水平'
},
{
orderNum
:
6
,
indexName
:
'数据资产分成率'
,
unit
:
'%'
,
instructions
:
'即关于数据对于实现收入的贡献'
},
{
orderNum
:
7
,
indexName
:
'衰减率'
,
unit
:
'%'
,
instructions
:
'数据有效期为5年,衰减率可理解为每年20%'
},
{
orderNum
:
8
,
indexName
:
'综合分成率'
,
unit
:
'%'
,
auto
:
true
,
instructions
:
'自动计算'
},
{
orderNum
:
9
,
indexName
:
'现金流'
,
unit
:
'元'
,
auto
:
true
,
instructions
:
'自动计算'
},
{
orderNum
:
10
,
indexName
:
'折现率'
,
unit
:
'%'
,
instructions
:
'一般行业在12%-16%之间,根据数据资产可变现的情况确认'
},
{
orderNum
:
11
,
indexName
:
'折现年期'
,
unit
:
'年'
,
auto
:
true
,
instructions
:
'自动计算'
},
{
orderNum
:
12
,
indexName
:
'折现因子'
,
unit
:
''
,
auto
:
true
,
instructions
:
'自动计算'
},
{
orderNum
:
13
,
indexName
:
'折现现值'
,
unit
:
'元'
,
auto
:
true
,
instructions
:
'自动计算,收入*利润率*分成率*折现因子'
},
{
orderNum
:
14
,
indexName
:
'数据资产估值'
,
unit
:
'元'
,
auto
:
true
,
instructions
:
'自动计算'
}])
const
inputChange
=
(
val
,
scope
,
field
)
=>
{
let
row
=
scope
.
row
;
let
strArr
=
val
.
split
(
"."
);
if
(
strArr
.
length
>
1
)
{
let
right
=
strArr
[
1
];
if
(
right
===
""
||
right
.
length
<
2
)
{
row
[
field
]
=
val
=
parseFloat
(
val
||
0
).
toFixed
(
2
);
}
}
else
{
row
[
field
]
=
val
=
parseFloat
(
val
||
0
).
toFixed
(
2
);
}
}
/** 输入框输入触发事件 */
const
inputEventChange
=
(
val
,
scope
,
field
,
max
:
any
=
null
)
=>
{
let
row
=
scope
.
row
;
row
[
field
]
=
row
[
field
].
toString
().
replace
(
/
[^\d
.
]
/g
,
""
)
row
[
field
]
=
row
[
field
].
toString
().
replace
(
/
\.{2,}
/g
,
"."
)
row
[
field
]
=
row
[
field
].
toString
().
replace
(
"."
,
"$#$"
).
replace
(
/
\.
/g
,
""
).
replace
(
"$#$"
,
"."
)
row
[
field
]
=
row
[
field
].
toString
().
replace
(
/^
(\-)
*
(\d
+
)\.(\d\d\d\d\d\d)
.*$/
,
"$1$2.$3"
)
row
[
field
]
=
row
[
field
].
toString
().
replace
(
/^
\D
*
(\d{0,12}(?:\.\d{0,2})?)
.*$/g
,
"$1"
)
if
(
max
!==
null
&&
row
[
field
]
>
max
)
{
row
[
field
]
=
max
;
}
}
const
incomeCalculateData
=
computed
(()
=>
{
//响应式不生效
let
data
=
incomeTableData
.
value
;
let
resultInfo
:
any
=
{};
resultInfo
[
'综合分成率'
]
=
[];
resultInfo
[
'现金流'
]
=
[];
resultInfo
[
'折现年期'
]
=
[];
resultInfo
[
'折现因子'
]
=
[];
resultInfo
[
'折现现值'
]
=
[];
resultInfo
[
'数据资产估值'
]
=
0
;
let
transfer
=
(
v
,
need
=
true
)
=>
{
return
v
?
(
need
?
parseFloat
(
v
)
/
100
:
parseFloat
(
v
))
:
0
;
}
incomeYears
.
value
.
forEach
((
year
,
i
)
=>
{
let
C6
=
transfer
(
data
[
5
][
year
.
field
])
let
C7
=
transfer
(
data
[
6
][
year
.
field
])
let
sumC7
:
any
=
i
==
0
?
C7
:
incomeYears
.
value
.
slice
(
0
,
i
+
1
).
reduce
(
function
(
prev
,
curr
,
idx
,
arr
)
{
return
transfer
(
data
[
6
][
prev
.
field
])
+
transfer
(
data
[
6
][
curr
.
field
]);
})
resultInfo
[
'综合分成率'
].
push
(
changeNum
(
C6
*
(
1
-
sumC7
+
C7
/
2
)
*
100
,
2
,
true
));
//TODO综合分成率算法有问题
let
C1
=
transfer
(
data
[
0
][
year
.
field
],
false
)
let
C5
=
transfer
(
data
[
4
][
year
.
field
])
resultInfo
[
'现金流'
].
push
(
changeNum
(
C1
*
C5
*
resultInfo
[
'综合分成率'
][
i
]
/
100
,
2
,
true
));
if
(
i
==
0
)
{
resultInfo
[
'折现年期'
].
push
(
changeNum
(
10
/
12
/
2
,
2
,
true
));
}
else
{
resultInfo
[
'折现年期'
].
push
(
changeNum
(
parseFloat
(
resultInfo
[
'折现年期'
][
i
-
1
])
+
1
,
2
,
true
))
}
let
C10
=
transfer
(
data
[
9
][
year
.
field
]);
resultInfo
[
'折现因子'
].
push
(
changeNum
(
1
/
Math
.
pow
((
1
+
C10
),
parseFloat
(
resultInfo
[
'折现年期'
][
i
])),
2
,
true
));
resultInfo
[
'折现现值'
].
push
(
changeNum
(
parseFloat
(
resultInfo
[
'折现因子'
][
i
])
*
parseFloat
(
resultInfo
[
'现金流'
][
i
]),
2
,
true
));
})
resultInfo
[
'数据资产估值'
]
=
changeNum
(
resultInfo
[
'折现现值'
].
reduce
(
function
(
prev
,
curr
,
idx
,
arr
)
{
return
parseFloat
(
prev
)
+
parseFloat
(
curr
);
}),
2
,
true
);
return
resultInfo
;
})
const
submit
=
()
=>
{
formRef
.
value
?.
ruleFormRef
?.
validate
((
valid
,
errorItem
)
=>
{
if
(
valid
)
{
let
params
=
formRef
.
value
.
formInline
;
if
(
params
.
evaluateMethod
==
'1'
)
{
params
.
valuationCostRQVOList
=
costTableData
.
value
;
params
.
damValuation
=
costTableSummaryValue
.
value
;
}
else
{
params
.
valuationEarningsRQVOList
=
incomeTableData
.
value
;
params
.
damValuation
=
incomeCalculateData
.
value
[
'数据资产估值'
];
params
.
valuationEarningsRQVOList
.
forEach
(
d
=>
{
let
years
:
any
=
{};
incomeYears
.
value
.
forEach
(
y
=>
{
years
[
y
.
field
]
=
d
[
y
.
field
];
})
d
.
predictedYears
=
years
;
})
}
params
.
evaluateBaseDate
=
getLastDayOfMonth
(
params
.
evaluateBaseDate
);
fullscreenLoading
.
value
=
true
;
if
(
!
route
.
query
.
guid
)
{
saveValuationMode
(
params
).
then
((
res
:
any
)
=>
{
fullscreenLoading
.
value
=
false
;
if
(
res
.
code
==
proxy
.
$passCode
)
{
proxy
.
$ElMessage
.
success
(
'新建估值模型提交保存成功'
);
userStore
.
setTabbar
(
userStore
.
tabbar
.
filter
((
tab
:
any
)
=>
tab
.
fullPath
!==
fullPath
));
router
.
push
({
name
:
'valuationModel'
});
entryStore
.
setIsRefresh
(
true
);
}
else
{
proxy
.
$ElMessage
({
type
:
'error'
,
message
:
res
.
msg
,
})
}
})
}
else
{
params
.
guid
=
route
.
query
.
guid
;
updateValuationMode
(
params
).
then
((
res
:
any
)
=>
{
fullscreenLoading
.
value
=
false
;
if
(
res
.
code
==
proxy
.
$passCode
)
{
proxy
.
$ElMessage
.
success
(
'编辑估值模型提交成功'
);
userStore
.
setTabbar
(
userStore
.
tabbar
.
filter
((
tab
:
any
)
=>
tab
.
fullPath
!==
fullPath
));
router
.
push
({
name
:
'valuationModel'
});
entryStore
.
setIsRefresh
(
true
);
}
else
{
proxy
.
$ElMessage
({
type
:
'error'
,
message
:
res
.
msg
,
})
}
})
}
}
else
{
var
obj
=
Object
.
keys
(
errorItem
);
formRef
.
value
.
ruleFormRef
.
scrollToField
(
obj
[
0
])
}
})
}
const
cancel
=
()
=>
{
proxy
.
$openMessageBox
(
"当前页面尚未保存,确定放弃修改吗?"
,
()
=>
{
userStore
.
setTabbar
(
userStore
.
tabbar
.
filter
((
tab
:
any
)
=>
tab
.
fullPath
!==
fullPath
));
router
.
push
({
name
:
'valuationModel'
});
},
()
=>
{
proxy
.
$ElMessage
.
info
(
"已取消"
);
});
}
const
getDamProductListData
=
()
=>
{
getAssetCatalog
({
pageSize
:
-
1
}).
then
((
res
:
any
)
=>
{
if
(
res
.
code
==
proxy
.
$passCode
)
{
damProductList
.
value
=
res
.
data
||
[];
valuateFormItems
.
value
[
0
].
options
=
damProductList
.
value
;
}
else
{
proxy
.
$ElMessage
({
type
:
'error'
,
message
:
res
.
msg
,
})
}
})
}
onBeforeMount
(()
=>
{
getDamProductListData
();
if
(
route
.
query
.
guid
)
{
fullscreenLoading
.
value
=
true
;
getValuationModelDetail
({
guid
:
route
.
query
.
guid
}).
then
((
res
:
any
)
=>
{
fullscreenLoading
.
value
=
false
;
if
(
res
.
code
==
proxy
.
$passCode
)
{
let
detailData
=
res
.
data
||
{};
valuateFormItems
.
value
.
forEach
(
item
=>
{
item
.
default
=
detailData
[
item
.
field
];
if
(
item
.
field
==
'evaluateMethod'
)
{
valuateFormItems
.
value
.
at
(
-
1
).
visible
=
item
.
default
==
'2'
;
}
else
if
(
item
.
field
==
'evaluateBaseDate'
)
{
item
.
default
=
item
.
default
.
substring
(
0
,
7
);
}
})
if
(
detailData
.
evaluateMethod
==
'2'
)
{
incomeTableData
.
value
=
detailData
.
valuationEarningsRSVOList
||
[];
incomeTableData
.
value
.
forEach
((
d
,
index
)
=>
{
Object
.
assign
(
d
,
d
.
predictedYears
||
{});
if
(
d
.
indexName
==
'综合分成率'
||
d
.
indexName
==
'现金流'
||
d
.
indexName
==
'折现年期'
||
d
.
indexName
==
'折现因子'
||
d
.
indexName
==
'折现现值'
||
d
.
indexName
==
'数据资产估值'
)
{
d
.
auto
=
true
;
}
});
}
else
{
costTableData
.
value
=
detailData
.
valuationCostRSVOList
||
[];
costTableSummaryValue
.
value
=
detailData
.
damValuation
||
''
;
}
}
else
{
proxy
.
$ElMessage
({
type
:
'error'
,
message
:
res
.
msg
,
})
}
});
}
})
onMounted
(
async
()
=>
{
await
nextTick
();
await
nextTick
();
const
tables
:
any
=
document
.
querySelectorAll
(
"#cost-table .el-table__footer-wrapper tr>td"
);
tables
[
0
].
colSpan
=
3
;
tables
[
0
].
style
.
textAlign
=
"center"
;
tables
[
1
].
style
.
display
=
"none"
;
tables
[
2
].
style
.
display
=
"none"
;
tables
[
4
].
style
.
display
=
"none"
;
tables
[
5
].
style
.
display
=
"none"
;
})
</
script
>
<
template
>
<div
class=
"container_wrap"
v-loading=
"fullscreenLoading"
>
<div
class=
"content_main"
>
<ContentWrap
id=
"id-baseInfo"
title=
"估值类型"
instructions=
""
style=
"margin-top: 8px;"
>
<Form
ref=
"formRef"
:itemList=
"valuateFormItems"
:rules=
"valuateFormRules"
formId=
"main-model-edit"
@
select-change=
"handleValudateFormChange"
col=
"col3"
/>
</ContentWrap>
<ContentWrap
id=
"id-grade-info"
title=
"填写成本明细"
:instructions=
"formRef?.formInline?.evaluateMethod == '1' ? '填写时请按照所选数据产品的成本投入进行填写,跟数据产品产生的成本一致' : ''"
style=
"margin-top: 16px;"
>
<el-table
id=
"cost-table"
v-show=
"formRef?.formInline?.evaluateMethod == '1'"
ref=
"costTableRef"
:data=
"costTableData"
:span-method=
"costTableSpanMethod"
:summary-method=
"costTableSummaryMethod"
show-summary
border
tooltip-effect=
"light"
:tooltip-options=
"
{ placement: 'top', popperClass: 'table_cell_tooltip' }">
<el-table-column
v-for=
"(item, i) in costTableField"
: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>
</div>
<span
v-else
>
{{
item
.
getName
?
item
.
getName
(
scope
)
:
scope
.
row
[
item
.
field
]
!==
0
&&
!
scope
.
row
[
item
.
field
]
?
"--"
:
scope
.
row
[
item
.
field
]
}}
</span>
</
template
>
</el-table-column>
</el-table>
<el-table
id=
"income-table"
v-show=
"formRef?.formInline?.evaluateMethod != '1'"
ref=
"costTableRef"
:data=
"incomeTableData"
border
tooltip-effect=
"light"
:tooltip-options=
"{ placement: 'top', popperClass: 'table_cell_tooltip' }"
>
<el-table-column
type=
"index"
label=
"序号"
width=
"80"
align=
"center"
/>
<el-table-column
v-for=
"(item, i) in incomeTableField"
: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"
>
<template
v-if=
"item.showChild == true"
>
<el-table-column
v-for=
"(year, j) in incomeYears"
:label=
"year.label"
:width=
"150"
align=
"right"
:prop=
"year.field"
show-overflow-tooltip
>
<template
#
default=
"scope"
>
<div
v-if=
"scope.row.auto != true"
class=
"input_cell"
>
<el-input
v-model
.
trim=
"scope.row[year.field]"
placeholder=
"请输入"
@
change=
"(val) => inputChange(val, scope, year.field)"
@
input=
"(val) => inputEventChange(val, scope, year.field, scope.row.unit == '%' ? 100 : null)"
clearable
></el-input>
</div>
<span
v-else
>
{{
scope
.
row
.
indexName
==
'数据资产估值'
?
(
j
>
0
?
'-'
:
incomeCalculateData
[
scope
.
row
.
indexName
])
:
(
incomeCalculateData
[
scope
.
row
.
indexName
][
j
])
}}
</span>
</
template
>
</el-table-column>
</template>
<span
v-else
>
{{ scope.row[item.field] || '-' }}
</span>
</template>
</el-table-column>
</el-table>
</ContentWrap>
</div>
<div
class=
"bottom_tool_wrap"
>
<el-button
@
click=
"cancel"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"submit"
>
提交
</el-button>
</div>
</div>
</template>
<
style
lang=
"scss"
scoped
>
.container_wrap
{
padding
:
0px
;
}
.content_main
{
height
:
calc
(
100%
-
44px
);
padding
:
10px
16px
;
overflow
:
auto
;
.table-top-btns
{
margin-bottom
:
12px
;
}
}
.bottom_tool_wrap
{
height
:
44px
;
padding
:
0
16px
;
border-top
:
1px
solid
#d9d9d9
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
}
:deep
(
.el-table
)
{
td.el-table__cell
{
padding
:
2px
0
;
height
:
36px
;
.el-input
.el-input__inner
{
text-align
:
right
;
}
}
}
</
style
>
\ No newline at end of file
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