8499ffed by lihua

估值模型功能提交

1 parent 014754db
......@@ -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
......
......@@ -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
......
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
<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
<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
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!