ttk-app-core
Version:
enterprise develop framework
1,128 lines (1,071 loc) • 52.6 kB
JavaScript
import React from 'react'
import { Map, fromJS } from 'immutable'
import { action as MetaAction, AppLoader } from 'edf-meta-engine'
import { TableOperate, Select, LoadingMask, Button, Modal, Input, Checkbox, Icon, Upload } from 'edf-component'
import extend from './extend'
import config from './config'
import { areaList } from './city'
import renderColumns from './utils/renderColumns'
import { fetch, number, history } from 'edf-utils'
class action {
constructor(option) {
this.metaAction = option.metaAction
this.extendAction = option.extendAction
this.config = config.current
this.webapi = this.config.webapi
}
onInit = async ({ component, injections }) => {
this.extendAction.gridAction.onInit({ component, injections })
this.component = component
this.injections = injections
injections.reduce('init')
let addEventListener = this.component.props.addEventListener
let response,
paramExternalDto = {}
// if (addEventListener) {
// addEventListener('onTabFocus', :: this.onTabFocus)
// }
/* ********
菜单名 财报转换申报
使用场景 导入第三方财务软件生成的财务报表,并生成税局统一格式的财务报表。生成成功后,跳转到电局填表页
拼接规则
参数说明
参数 参数名称 类型 必填 描述 范例
gdslxDm 国地税类型代码 String 必填 区分上报的是国税还是地税,国税:1,地税:2
kjzdzzDm 会计制度准则代码 String 必填 第一阶段暂支持企业会计准则、小企业会计准则两类 企业会计准则=》2000020001,小企业会计准则 =》 2000020002
zlbsxlDm 资料报送小类代码 String 必填 企业会计准则对应的小类目前只支持一般企业//企业 =》 "ZL1001001" , 小企业 =》 "ZL1001003"
bbbsqDm 报表报送期代码 String 必填 01:年报;03:季报;04:月报
sssqQ 所属时期起 String 必填 例 2018-03-01
sssqZ 所属时期止 String 必填 例 2018-03-31
nsrsbh 纳税人识别号 String 必填 北京的第2,3位是11
nsrmc 纳税人名称 String 必填
zgswskfjDm 主管税务所科分局代码 String 必填 纳税人主管税务所科分局代码
djxh 登记序号 10111101000060491228
*******/
//获取url 先注释掉,后期对接放开
//const url = history.location
//start
const url1 = history.location
let curcontext = this.metaAction.context,
vatTaxpayerNum,
accountingStandards
if( curcontext ) {
if( typeof curcontext.get("currentOrg") == 'object' ) {
vatTaxpayerNum = curcontext.get("currentOrg").vatTaxpayerNum
accountingStandards = curcontext.get("currentOrg").accountingStandards
}
}
// let urlSearch = (url1 && url1.search) ? url1.search : '?gdslxDm=1&kjzdzzDm='+(this.metaAction.context.get("currentOrg").accountingStandards)+'&zlbsxlDm='+(this.metaAction.context.get("currentOrg").accountingStandards==2000020001?'ZL1001001':'ZL1001003' )+'&bbbsqDm=03&sssqQ=2018-04-01&sssqZ=2018-04-30&nsrsbh='+(this.metaAction.context.get("currentOrg").vatTaxpayerNum)+'&nsrmc=纳税人名称&zgswskfjDm=11111&djxh='+(this.metaAction.context.get("currentOrg").vatTaxpayerNum)
let urlSearch = (location && location.hash.indexOf('?')>=0) ? location.hash : '?gdslxDm=1&kjzdzzDm='+(accountingStandards)+'&zlbsxlDm='+(accountingStandards==2000020001?'ZL1001001':'ZL1001003' )+'&bbbsqDm=03&sssqQ=2018-04-01&sssqZ=2018-04-30&nsrsbh='+(vatTaxpayerNum)+'&nsrmc=纳税人名称&zgswskfjDm=11111&djxh='+(vatTaxpayerNum)
// const urlData = this.urlParse(url)
let urlData = this.urlParse(decodeURI(urlSearch))
//三种情况
//第一种,从云财税进来,有token。不需要调接口,直接向下走
//第二种,从国税进来,没有code,调用A接口,返回新的带有code的地址,重定向
//第三种,重定向完毕,有code,调用B接口,获取token 和其他信息,向下走
paramExternalDto = urlData
if (location.origin.indexOf('erp.jchl.com') >= 0 || location.origin.indexOf('erpdemo.jchl.com') >= 0) {
if (!urlData.code) {//没有code
// let params = location.origin + '/#' + history.location.pathname + urlSearch
let params = location.href
let res = await this.webapi.tranreport.getOauthUrl(params)
if (res) {
history.redirect(res)
}
return
} else {//有code
let res = await this.webapi.tranreport.oauthAuthentication(urlData)
if (res) {
if(res.busEx && res.busEx.code=='40029') {
let url2 = location.href,
url2str1 = url2.split('&code=')[0],
url2str2 = url2.split('&code=')[1].split('&'),
url3
if(url2str2.length) {
url2str2.shift()
}
url3 = url2str1+ url2str2.join('&')
let res3 = await this.webapi.tranreport.getOauthUrl(url3)
if (res3) {
history.redirect(res3)
}
return
}
this.metaAction.sf('data.orgDto', fromJS(res.orgDto))
this.metaAction.sf('data.paramExternalDto', fromJS(res.paramExternalDto))
this.metaAction.sf('data.tokenData', fromJS(res.token))
paramExternalDto = res.paramExternalDto
}
this.metaAction.sf('data.other.allVisible', true)
}
} else {
if( !urlData.nsrsbh || urlData.nsrsbh == "undefined" ) {
this.metaAction.toast('warning','纳税人识别号为空')
return
}
if (!urlData.djxh) {
this.metaAction.sf('data.other.allVisible', true)
} else {
let res = await this.webapi.tranreport.getOrgAndToken(urlData)
if (res) {
this.metaAction.sf('data.orgDto', fromJS(res.orgDto))
this.metaAction.sf('data.paramExternalDto', fromJS(res.paramExternalDto))
this.metaAction.sf('data.tokenData', fromJS(res.token))
paramExternalDto = res.paramExternalDto
}
LoadingMask.hide()
this.metaAction.sf('data.other.allVisible', true)
}
}
this.load(paramExternalDto)
}
load = async (urlData, response) => {
this.injections.reduce('load', urlData)
let showRptStates = this.setShowRptStates(urlData.nsrsbh, urlData.bbbsqDm)
if (showRptStates) {
this.metaAction.sf('data.other.balancesheetStatus', showRptStates.balancesheetStatus)
this.metaAction.sf('data.other.profitstatementStatus', showRptStates.profitstatementStatus)
this.metaAction.sf('data.other.cashflowstatementStatus', showRptStates.cashflowstatementStatus)
}
let res = await this.webapi.tranreport.getReportJson(urlData)
if(res) {
if( !(res.body && (!res.body.zcfzbBody && !res.body.lrbBody && !res.body.xjllbBody )) ) {
//报表转换--选择转换利润表,成功导入后前端的tab应该切换到利润表页签上。
let currentRptName = this.metaAction.gf('data.other.rpttype')
//初始化报表内容
this.injections.reduce('initTranPeport', res)
//初始化第一个报表
const rptTitle = this.metaAction.gf('data.rptTitle')
this.metaAction.sf('data.other.editStatus', false)
this.injections.reduce('setSourceRpt', res, currentRptName, rptTitle && rptTitle.toJS()[currentRptName])
this.metaAction.sf('data.balancesheetData', undefined)
this.metaAction.sf('data.cashflowstatementData', undefined)
this.metaAction.sf('data.profitstatementData', undefined)
this.metaAction.sf('data.btnState.updateState', false)//如果下一步调用接口成功,将updateState 改为false。文件名清空。返回上一步重新选择文件
this.metaAction.sf('data.btnState.nextState', false)//
}
}
setTimeout(() => {
this.onResize()
}, 20)
}
/**
* 组件从界面上移除触发
*/
componentWillUnmount = () => {
if (window.removeEventListener) {
window.removeEventListener('resize', this.onResize, false)
} else if (window.detachEvent) {
window.detachEvent('onresize', this.onResize)
} else {
window.onresize = undefined
}
}
/**
* 在初始化render之后只执行一次
*/
componentDidMount = () => {
if (window.addEventListener) {
window.addEventListener('resize', this.onResize, false)
} else if (window.attachEvent) {
window.attachEvent('onresize', this.onResize)
} else {
window.onresize = this.onResize
}
}
/**
* 计算table滚动条
*/
onResize = (e) => {
let keyRandomTab = Math.floor(Math.random() * 10000)
this.keyRandomTab = keyRandomTab
setTimeout(() => {
if (keyRandomTab == this.keyRandomTab) {
this.getTableScroll('ttk-access-app-tranreport-step2content-content', 'ant-table-thead', 0, 'ant-table-body', 'data.tableOption', e)
}
}, 200)
}
/**
* 计算table滚动条
*/
getTableScroll = (contaienr, head, num, target, path, e) => {
try {
const tableCon = document.getElementsByClassName(contaienr)[0]
if (!tableCon) {
if (e) {
return
}
setTimeout(() => {
this.getTableScroll(contaienr, head, num, target, path)
}, 500)
return
}
const header = tableCon.getElementsByClassName(head)[0]
const body = tableCon.getElementsByClassName(target)[0].getElementsByTagName('table')[0]
const pre = this.metaAction.gf(path).toJS()
const y = tableCon.offsetHeight - header.offsetHeight - num
const bodyHeight = body.offsetHeight
if (bodyHeight > y && y != pre.y) {
this.metaAction.sf(path, fromJS({ ...pre, y }))
} else if (bodyHeight < y && pre.y != null) {
this.metaAction.sf(path, fromJS({ ...pre, y: null }))
} else {
return false
}
} catch (err) {
console.log(err)
}
}
/**
* 解析url
*/
urlParse = (url) => {
let arr = [], obj = {};
if (url.indexOf('?') != -1) {
const parseStr = url.split("?")[1];
if (parseStr.indexOf("&") != -1) {
arr = parseStr.split("&");
for (let i = 0; i < arr.length; i++) {
obj[arr[i].split("=")[0]] = arr[i].split("=")[1];
}
} else {
obj[parseStr.split("=")[0]] = parseStr.split("=")[1];
}
}
return obj;
}
/**
* 转为局端格式
*/
selectLocalRptClick = async () => {
if (!this.metaAction.gf('data.btnState.updateState')) { //updateState 为false 代表没上传文件,不可以下一步
return this.metaAction.toast('warning', '请至少选择一个财务报表')
}
LoadingMask.show()
let res = await this.webapi.tranreport.importDataSource(this.getParams('importDataSource'))
LoadingMask.hide()
if (res) {
//报表转换--选择转换利润表,成功导入后前端的tab应该切换到利润表页签上。
let isMutilSelct = 0, currentRptName,
balancesheetData = this.metaAction.gf('data.balancesheetData'),
cashflowstatementData = this.metaAction.gf('data.cashflowstatementData'),
profitstatementData = this.metaAction.gf('data.profitstatementData')
if (balancesheetData) {
isMutilSelct++
currentRptName = 'balanceSheetRpt'
_hmt && _hmt.push(['_trackEvent', '财务', '报表转换', '选择文件是“资产负债表”转为局端格式'])
}
if (profitstatementData) {
isMutilSelct++
currentRptName = 'profitStatementRpt'
_hmt && _hmt.push(['_trackEvent', '财务', '报表转换', '选择文件是“利润表”转为局端格式'])
}
if (cashflowstatementData) {
isMutilSelct++
currentRptName = 'cashflowStatementRpt'
_hmt && _hmt.push(['_trackEvent', '财务', '报表转换', '选择文件是“现金流量表”转为局端格式'])
}
if (isMutilSelct > 1) {
if (balancesheetData) {
currentRptName = 'balanceSheetRpt'
} else {
currentRptName = 'profitStatementRpt'
}
//默认设置
this.metaAction.sf('data.other.rpttype', currentRptName)
}
//单选处理
this.metaAction.sf('data.other.rpttype', currentRptName)
//初始化报表内容
this.injections.reduce('initTranPeport', res)
//初始化第一个报表
const rptTitle = this.metaAction.gf('data.rptTitle')
this.metaAction.sf('data.other.editStatus', false)
this.injections.reduce('setSourceRpt', res, currentRptName, rptTitle && rptTitle.toJS()[currentRptName])
this.metaAction.sf('data.btnState.updateState', false)//如果下一步调用接口成功,将updateState 改为false。文件名清空。返回上一步重新选择文件
this.metaAction.sf('data.btnState.nextState', false)//
this.metaAction.sf('data.balancesheetData', undefined)
this.metaAction.sf('data.cashflowstatementData', undefined)
this.metaAction.sf('data.profitstatementData', undefined)
this.metaAction.sf('data.step.step2Visible', true)
this.metaAction.sf('data.step.step1Visible', false)
if (res.needMatching) {
this.nextResponseWarning( this.getMessages( this.metaAction.gf('data.btnState.nextState') ) )
} else {
this.metaAction.toast('success', '转为局端格式成功')
}
this.metaAction.sf('data.btnState.nextState', false)//
}
}
//点击转换的报表
nextClick = () => {
this.metaAction.sf('data.step.step2Visible', true)
this.metaAction.sf('data.step.step1Visible', false)
}
//获取参数
getParams = (type) => {
let params = {},
urlData = this.metaAction.gf('data.urlData')
if (type == 'init') {
params = {
name: urlData.get('nsrmc'),
accountingStandards: urlData.get('kjzdzzDm'),//kjzdzzDm
enabledYear: '2017',
enabledMonth: '03',
vatTaxpayer: urlData.get('zlbsxlDm'),//zlbsxlDm
vatTaxpayerNum: urlData.get('nsrsbh'),//nsrsbh
registeredProvincial: urlData.get('nsrsbh').substr(1, 2) + '0000',//nsrsbh
registeredCity: urlData.get('nsrsbh').substr(1, 4) + '00',
registeredCounty: urlData.get('nsrsbh').substr(1, 4) + '00'//现在地区代码是在纳税人识别号中截取的。由于纳税人识别号中好像没有精确到县,所以先默认后面是00。1—2位为省、市代码,3—6位为地区代码,7—8位为经济性质代码
}
return params
} else if (type == 'importDataSource') {
params.analysisInputParams = []
params.calcBalanceSheet = !!this.metaAction.gf('data.balancesheetData')
params.calcProfitStatement = !!this.metaAction.gf('data.profitstatementData')
params.calcCashFlowStatement = !!this.metaAction.gf('data.cashflowstatementData')
this.metaAction.gf('data.balancesheetData')
//获取从上游url传递过来的值
if (urlData) {
params.externalParam = this.metaAction.gf('data.urlData').toJS()
}
params.analysisInputParams = this.setRptList(params.analysisInputParams, 'balancesheet')
params.analysisInputParams = this.setRptList(params.analysisInputParams, 'profitstatement')
params.analysisInputParams = this.setRptList(params.analysisInputParams, 'cashflowstatement')
return params
}
}
//参数中添加报表信息
setRptList = (params, name) => {
if (this.metaAction.gf(`data.${name}Data`)) {
params.push({
fieldId: this.metaAction.gf(`data.${name}Data.id`),
fieldName: name,
flag: (name == 'balancesheet' ? 1 : (name == 'profitstatement' ? 2 : 3)),
"nsrsbh": "123456789012345"
})
}
return params
}
//步骤一 start
//通过纳税人识别号判断是显示状态
setShowRptStates = (id, bbbsqDm) => {
if (!id) return
let fourBitsId = id.substr(1, 4),//四位地址Id
twoBitsId = id.substr(1, 2),//两位地址Id
currentType
if( twoBitsId == '11') {//如果地区的前两位是11就认为是北京
if(bbbsqDm != '01') {
return {
balancesheetStatus: true,
profitstatementStatus: true,
cashflowstatementStatus: false
}
} else {
return {
balancesheetStatus: true,
profitstatementStatus: true,
cashflowstatementStatus: true
}
}
}
areaList.map(item => {
if (item.cityFourNum == fourBitsId) {
currentType = item.type
}
})
if (currentType == 1 && bbbsqDm != '01') {//北京 ,非年报
return {
balancesheetStatus: true,
profitstatementStatus: true,
cashflowstatementStatus: false
}
} else {
return {
balancesheetStatus: true,
profitstatementStatus: true,
cashflowstatementStatus: true
}
}
}
// 渲染选择文件
renderUpload = (key) => {
const file = this.metaAction.gf('data.uploadFile')
const props = {
action: 'v1/reportconverter/upload?flag='+(key == 'balancesheet' ? 1 : (key == 'profitstatement' ? 2 : 3)),
headers: {
token: fetch.getAccessToken()
},
showUploadList: false,
accept: '.xls, .xlsx'
}
let originalName
if (key == 'balancesheet') {
originalName = this.metaAction.gf('data.balancesheetData') ? this.metaAction.gf('data.balancesheetData.originalName') : ''
} else if (key == 'profitstatement') {
originalName = this.metaAction.gf('data.profitstatementData') ? this.metaAction.gf('data.profitstatementData.originalName') : ''
} else if (key == 'cashflowstatement') {
originalName = this.metaAction.gf('data.cashflowstatementData') ? this.metaAction.gf('data.cashflowstatementData.originalName') : ''
}
return (
<div style={{ display: 'flex' }}>
<div style={{ color: originalName ? '#535252' : '#c3c3c3', display: 'inline-block', marginLeft: '8px', whiteSpace: 'nowrap', border: '1px solid #d9d9d9', width: '330px', height: '38px', 'background': '#fff' }} title={originalName}
className='update-balancesheet-item-content-input'>
<span className="update-balancesheet-item-content-input-text">{originalName ? originalName : '请上传采集好的数据文件'}</span>
{originalName ? <Icon type='cuowutishi' fontFamily='edficon' className='update-shanchu-icon' onClick={this.delUpdate(key)} /> : ''}
</div>
<Upload onChange={this.handleOnChange(key)} {...props} beforeUpload={this.beforeLoad}
style={{ display: 'inline-block', width: '100px', height: '38px', marginLeft: '10px', 'lineHeight': '38px' }}>
<Button style={{ height: '38px', 'borderRadius': '0px', 'lineHeight': '38px', 'textAlign': 'center', display: 'inline-block', width: '100%', 'cursor': 'pointer' }}>{originalName ? `重选文件` : `选择文件`}</Button>
</Upload>
</div>
)
}
//删除上传文件
delUpdate = (key) => {
return async () => {
let res = this.webapi.tranreport.deleteDataSource([{
fieldId: this.metaAction.gf(`data.${key}Data.id`),
fieldName: key
}])
if (res) {
if (key == "balancesheet") {
this.metaAction.sf('data.balancesheetData', undefined)
} else if (key == "profitstatement") {
this.metaAction.sf('data.profitstatementData', undefined)
} else if (key == "cashflowstatement") {
this.metaAction.sf('data.cashflowstatementData', undefined)
}
if (!this.metaAction.gf('data.balancesheetData') &&
!this.metaAction.gf('data.profitstatementData') &&
!this.metaAction.gf('data.cashflowstatementData')) {
this.metaAction.sf('data.btnState.updateState', false)
}
this.metaAction.toast('success', '文件删除成功')
}
}
}
// 上传文件
handleOnChange = (key) => {
return (info) => {
if (!info.file.status) {
this.metaAction.toast('error', '仅支持上传Excel格式的文件')
return
}
LoadingMask.show()
if (info.file.status == 'done') {
LoadingMask.hide()
if (info.file.response.result && info.file.response.value) {
this.metaAction.toast('success', '文件上传成功')
this.injections.reduce('uploadFile', info.file.response.value, key)
} else {
this.uploadResponseWarning([info.file.response.error.message])
}
} else if (info.file.status === 'error') {
LoadingMask.hide()
this.metaAction.toast('warning', '文件上传失败')
}
}
}
//获取 上传界面的提示文本
getUpdatePrompt = () => {
let zlbsxlDm = this.metaAction.gf('data.urlData.zlbsxlDm')
return <div>
<p>注:目前只支持适用于一般企业的会计准则和小企业会计准则。</p>
{
zlbsxlDm == 'ZL1001001' ?
<p>请上传从财务软件导出的Excel格式的财务报表,可只上传一个报表。请确保本期金额是本年累计金额,上期金额是去年同期累计金额。</p> :
(zlbsxlDm == 'ZL1001003' ?
<p>请上传从财务软件导出的Excel格式的财务报表,可只上传一个报表。请确保上年金额是去年全年累计金额。</p> :
<p>请上传从财务软件导出的Excel格式的财务报表,可只上传一个报表。并确保报表数据与申报所属期一致。</p>
)
}
</div>
}
//步骤一 end
//提示内容start
getDisplayErrorMSg = (errorMsg, headerRow, footerRow) => {
//footerRow
return <div style={{ display: 'inline-table' }}>
{headerRow ? <div style={{ 'fontSize': '14px', color: '#2F2F2F', marginBottom: '13px', 'lineHeight': '18px' }}>{headerRow}<br /></div> : ''}
{errorMsg.map((item, index) => {
return <div style={{ 'fontSize': '12px', color: '#484848' }}>{item}<br /></div>
})}
{footerRow ? <div style={{ 'fontSize': '12px', color: '#484848', marginTop: '13px' }}>
立即<a style={{ display: 'inline-block', 'paddingLeft': '2px' }} className='care-adjustproject-link' href="javascript:;" onClick={this.handleAdjustClick} >调整项目</a>
</div> : ''}
</div>
}
handleAdjustClick = () => {//点击 调整项目 按钮
let btnDom = document.querySelector('.ant-confirm-btns .ant-btn-primary')
if (btnDom) {
btnDom.click()
}
let that = this
window.setTimeout(function(){
that.projectAdjustClick(true)
},100)
}
getMessages = (type) => { //提示文本
let arr = []
if (type) {//初次导入,如果存在未完全匹配(即名称完全相同)的行与列的时候
arr.push('原表与局端报表有不一致的项目,请调整项目对应关系。调整后,以后征期可直接导入啦')
} else {//后续导入报表,如果出现新的未匹配项目
arr.push('报表格式发生了变化,变化的部分与局端报表项目不匹配,请调整项目对应关系。')
}
return arr
}
handleWarningClick = async () => {//调用提示框的方法
let rpt = await this.nextResponseWarning(this.getMessages(1))
if (rpt) {
}
}
//返回提示框
responseWarning = async (messages, headerRow, footerRow) => {
let rpt = await this.metaAction.modal('warning', {
content: this.getDisplayErrorMSg(messages, headerRow, footerRow),
okText: '确定',
className: 'tranreport-prompt-modal'
})
if (rpt) {
}
}
//点击转为局端格式提示框
nextResponseWarning = async (messages) => {
let rpt = await this.responseWarning(messages, undefined, true)
return rpt
}
//上传文件提示框
uploadResponseWarning = async (messages) => {
let rpt = await this.responseWarning(messages, '导入问题:')
return rpt
}
//生成提示框
generateResponseWarning = async (messages) => {
let rpt = await this.responseWarning(messages, '生成问题:')
return rpt
}
//提示内容end
/**
* 表格样式
*/
assetOrProjectStyle = (record) => {
// return record.summary == '本月合计' || record.summary == '本年累计' ? 'total_data_weight' : ''
// return ''
}
/**
* 渲染cell金额框
*/
renderCellTextBox = (columnName, coltitle, v, rowIndex) => {
let list = this.metaAction.gf('data.source.dataList'),
currformula = list.get(rowIndex).get('sum' + this.indexTitleCase(columnName)),
text = list && (list.get(rowIndex).get(columnName) != "0.00") ? list.get(rowIndex).get(columnName) : '',
editable = list.get(rowIndex).get(columnName) == '' ? false : (list.get(rowIndex).get('isSumRow') && currformula) ? false : true,
precision = 2,
customAttribute = this.metaAction.gf('data.other.customAttribute'), //为了只有操作另一个input时才去render input
maxValue = 99999999999999.99,
minValue = -99999999999999.99
return (
<EditableCell
editable={editable}
value={() => number.toFixedLocal(text, precision)}
onBlur={(value) => this.handleBlur(rowIndex, columnName, value, coltitle, maxValue)}
onEnter={(e) => this.handleEnter(e, rowIndex, columnName, coltitle, maxValue)}
// onkeydown={(e) => this.handleKeyDown(e, rowIndex, columnName)}
toFixedLocal={() => number.toFixedLocal(text, precision)}
precision={precision}
customAttribute={customAttribute}
/>
)
}
/**
* input金额框失去焦点时处理的事件
*/
handleBlur = (rowIndex, columnName, value, coltitle, maxValue) => {
let list = this.metaAction.gf('data.source.dataList'),
oldValue = list.get(rowIndex).get(columnName),
newValue = number.transferData(value, 2),
colMaxValue = '99,999,999,999,999.99'
if (newValue && newValue.indexOf && newValue.indexOf(',') > -1) {
//对于修改格式化好的数字 避免isNaN为true
newValue = newValue.replace(/,/g, '')
}
if (newValue > maxValue ) {
if(oldValue==' ') {
newValue = '0.00'
} else {
newValue = ' '
}
list = list.update(rowIndex, item => {
item = item.set(columnName, newValue)
return item
})
this.metaAction.sf('data.source.dataList', list)
this.metaAction.toast('warning', `${coltitle}不能大于${colMaxValue},请调整`)
return
}
if (newValue < -maxValue) {
if(oldValue==' ') {
newValue = '0.00'
} else {
newValue = ' '
}
list = list.update(rowIndex, item => {
item = item.set(columnName, newValue)
return item
})
this.metaAction.sf('data.source.dataList', list)
this.metaAction.toast('warning', `${coltitle}不能小于-${colMaxValue},请调整`)
return
}
if (isNaN(newValue)) {
this.metaAction.toast('warning', '请输入数字')
return
}
if (oldValue != newValue) {
//编辑状态
this.metaAction.sf('data.other.editStatus', true)
}
//先把当前值保存进去
list = list.update(rowIndex, item => item.set(columnName, number.format(newValue, 2)))
this.metaAction.sf('data.source.dataList', list)
const customAttribute = Math.random()
this.metaAction.sf('data.other.customAttribute', customAttribute)
//递归计算合计行的值
this.calculateTotalData(rowIndex, columnName)
//修改合计值时向上保存,即 他和与他有关的合计(他是子项,不是合计项)值改变
// list = list.update(rowIndex, item => item.set(columnName, number.format(newValue, 2)))
// this.metaAction.sf('data.source.dataList', list)
}
/**
* 按enter键切换金额控件
*/
handleEnter = (e, rowIndex, columnName, coltitle, maxValue) => {
if (e.keyCode == 13 || e.key == 'Enter' || e.keyCode == 108) {
const inputs = document.getElementsByClassName('ant-input mk-input-number ttk-access-app-tranreport-step2content-tableCellInput')
const index = $(inputs).index(e.target)
let newValue = e.target.value,
colMaxValue = '99,999,999,999,999.99'
if (newValue && newValue > maxValue) {
this.metaAction.toast('warning', `${coltitle}不能大于${colMaxValue},请调整`)
return
}
if (newValue && newValue < -maxValue) {
this.metaAction.toast('warning', `${coltitle}不能小于-${colMaxValue},请调整`)
return
}
if (newValue && newValue.indexOf(',') > -1) {
newValue = newValue.replace(/,/g, '')
}
if (isNaN(newValue)) {
this.metaAction.toast('warning', '请输入数字')
return
}
inputs[index + 1].focus()
}
}
/**
* 计算合计行的值
*/
calculateTotalData = (rowIndex, columnName) => {
let totalValue,
currformula,
list = this.metaAction.gf('data.source.dataList'),
currentValue = list.get(rowIndex).get(columnName),
totalGridRow = []
/* 表达式计算说明*
* //isSumCol:true,sumCol0:'1+2-3+4+6',sumCol3:'1+2-3+4+6',sumCol1:'1+2-3+4+6',sumCol1:'1+2-3+4+6'
*1、判断当前列是否存在需要合计的行 isSumCol:true 表示需要合计
*2、根据columnName 解析当前行对应的表达式 例如:columnName='col1',当前行对应的表达式(col1:'1+2-3+4+5') col1:表示列名,后面的值表示:合计行通过以上行的索引值计算
*3、计算结果更新到合计行,如果当前修改的是合计行,则忽略当前行的计算
*/
//获取当前列所有需要合计的行
for (let _rowIndex = 0; _rowIndex < list.size; _rowIndex++) {
let rowData = list.get(_rowIndex)
if (rowData.get('isSumRow')) {
currformula = rowData.get('sum' + this.indexTitleCase(columnName))
//把合计行的值添加到对应的字典中
if (currformula && (currformula.indexOf('+') > 0 || currformula.indexOf('-') > 0)) {
let data = { key: _rowIndex + 1, value: currformula.split(':') && currformula.split(':')[1] }
totalGridRow.push(data)
}
}
}
/**
* 测试数据开始
*/
for (let tmplog of totalGridRow) {
console.log(`合计行${tmplog.key}=${tmplog.value}`)
}
/**
* 测试数据结束
*/
if (totalGridRow) {
let tmpIndex = rowIndex + 1
this.findNextTotalValue(tmpIndex, totalGridRow, columnName)
}
// totalValue = this.splitFormula(list, columnName, currformula.split(':') && currformula.split(':')[1])
// //更新合计值
// list = list.update(_rowIndex, item => item.set(columnName, totalValue))
}
//递归查找下一个合计行值
findNextTotalValue = (rowIndex, totalGridRow, columnName) => {
let totalValue, formulas = []
for (let i = 0; i < totalGridRow.length; i++) {
let strs = totalGridRow[i].value.replace(/\+/g, ',').replace(/\-/g, ',')
let minusstrs = strs.split(',')
//处理减法
for (let j = 0; j < minusstrs.length; j++) {
if (minusstrs[j] == rowIndex) {
formulas.push(totalGridRow[i])
}
}
}
let list = this.metaAction.gf('data.source.dataList')
if (formulas && formulas.length < 1) {
return
}
for (let i = 0; i < formulas.length; i++) {
totalValue = this.splitFormula(list, columnName, formulas[i].value)
//更新合计值
list = list.update(formulas[i].key - 1, item => item.set(columnName, totalValue))
this.metaAction.sf('data.source.dataList', list)
this.findNextTotalValue(formulas[i].key, totalGridRow, columnName)
}
}
//转换列头第一个字母为大写
indexTitleCase = (str) => {
return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}
/**
* 拆分表达式,做加减运算
*/
splitFormula = (list, columnName, formula) => {
// 行索引col1:2+3+4+5+6+7+8+9+10+11+12
let result = 0,
newTextArr = [],
tmpTextArr,
plusStrs = formula.split('+')
for (let i = 0; i < plusStrs.length; i++) {
//处理加法
if (plusStrs[i].indexOf('-') < 0) {
let plus = number.transferData(list.get(plusStrs[i] - 1).get(columnName))
if (i == 0) {
newTextArr.push(plus)
} else {
if (plus < 0) {
newTextArr.push('-')
newTextArr.push(Math.abs(plus))
} else {
newTextArr.push('+')
newTextArr.push(plus)
}
}
} else {
let minusStrs = plusStrs[i].split('-')
//处理减法
for (let j = 0; j < minusStrs.length; j++) {
let minus = number.transferData(list.get(minusStrs[j] - 1).get(columnName))
if (j == 0) {
if (minus < 0) {
newTextArr.push('-')
newTextArr.push(Math.abs(minus))
} else {
newTextArr.push('+')
newTextArr.push(minus)
}
} else {
if (minus < 0) {
newTextArr.push('+')
newTextArr.push(Math.abs(minus))
} else {
newTextArr.push('-')
newTextArr.push(minus)
}
}
}
}
}
tmpTextArr = newTextArr.join('')
try {
result = eval(tmpTextArr)
} catch (exception) {
console.log(exception)
}
return number.format(result, 2)
}
/**
* 报表类型切换
*/
rptTypeChange = (path, value) => {
const rptTitle = this.metaAction.gf('data.rptTitle').toJS(),
params = this.preSaveData()
if (params) {
this.injections.reduce('initTranPeport', params)
this.injections.reduce('setSourceRpt', params, value, rptTitle[value])
}
this.metaAction.sf(path, value)
//计算滚动条
setTimeout(() => {
this.onResize()
}, 20)
}
/**
* 重传Excel
*/
reSelectRptClick = async () => {
const editStatus = this.metaAction.gf('data.other.editStatus')
if (editStatus) {
//保存报表
const params = await this.preSaveData(),
urlData = this.metaAction.gf('data.urlData') && this.metaAction.gf('data.urlData').toJS()
urlData['accountingStandardsId']=this.metaAction.gf('data.paramExternalDto') && this.metaAction.gf('data.paramExternalDto').toJS().accountingStandardsId
params.paramDto = urlData
let res = await this.webapi.tranreport.saveReport(params)
if (res) {
this.metaAction.sf('data.other.editStatus', false)
}
}
const rptTitle = this.metaAction.gf('data.rptTitle').toJS(),
rpttype=this.metaAction.gf('data.other.rpttype')
//添加埋点
_hmt && _hmt.push(['_trackEvent', '财务', '报表转换', `选择文件是${rptTitle[rpttype]}重传Excel`])
//重新选择报表
this.metaAction.sf('data.step.step1Visible', true)
this.metaAction.sf('data.step.step2Visible', false)
}
/**
* 调整项目
*/
projectAdjustClick = async (fromPromp) => {
//调用调整项目前判断是否需要保存,需要的就先保存
let editStatus = this.metaAction.gf('data.other.editStatus'),
params,
urlData
//状态变化,保存报表数据
if (editStatus) {
params = await this.preSaveData()
urlData = this.metaAction.gf('data.urlData') && this.metaAction.gf('data.urlData').toJS()
urlData['accountingStandardsId']= this.metaAction.gf('data.paramExternalDto').toJS().accountingStandardsId
params.paramDto = urlData
let res = await this.webapi.tranreport.saveReport(params)
if (res) {
this.metaAction.sf('data.other.editStatus', false)
}
}
//调整项目
let reportCode = this.metaAction.gf('data.other.rpttype')
const res = await this.metaAction.modal('show', {
title: '调整项目',
// width: 789,
width: 949,
bodyStyle: { height: 365 },
okText: "重新转换",
wrapClassName:'tranreport-projectadjust-modal',
children: this.metaAction.loadApp('ttk-access-app-tranreport-projectadjust', {//app-transform-rpt//app-cashflowstatement-distribution
store: this.component.props.store,
initData: {
tabStatus: {
balancesheetStatus: this.metaAction.gf('data.other.balancesheetStatus'),
profitstatementStatus: this.metaAction.gf('data.other.profitstatementStatus'),
cashflowstatementStatus: this.metaAction.gf('data.other.cashflowstatementStatus')
},
params: {
"nsrsbh": this.metaAction.gf('data.urlData.nsrsbh'),// --纳税人识别号
"startPeriod": this.metaAction.gf('data.urlData.sssqQ'),// --申报起始日期
"endPeriod": this.metaAction.gf('data.urlData.sssqZ'),// --申报终止日期
"accountingStandardsId": this.metaAction.gf('data.urlData.accountingStandardsId'), //
"zgswskfjDm": this.metaAction.gf('data.urlData.zgswskfjDm'), //
"nsrmc": this.metaAction.gf('data.urlData.nsrmc'), //
},
"fromPromp": (typeof fromPromp!='object'),
'reportCode': reportCode.toLocaleLowerCase().substr(0, reportCode.length - 3)
}
}),
})
if (res) {
this.injections.reduce('initTranPeport', res)
const rptTitle = this.metaAction.gf('data.rptTitle').toJS()
this.injections.reduce('setSourceRpt', res, reportCode, rptTitle[reportCode])
this.metaAction.toast('success', '重新转换成功。')
//添加埋点
_hmt && _hmt.push(['_trackEvent', '财务', '报表转换', `选择文件是${rptTitle[reportCode]}调整项目`])
}
}
/**
* 生成
*/
generateClick = async () => {
//生成
let params = await this.preSaveData(),
editStatus = this.metaAction.gf('data.other.editStatus'),
checkReport,
urlData = this.metaAction.gf('data.urlData') && this.metaAction.gf('data.urlData').toJS()
urlData['accountingStandardsId']= this.metaAction.gf('data.paramExternalDto').toJS().accountingStandardsId
//状态变化,保存报表数据
if (editStatus) {
params.paramDto = urlData
let res = await this.webapi.tranreport.saveReport(params)
if (res) {
this.metaAction.sf('data.other.editStatus', false)
}
}
const checkParams = { startPeriod: urlData.sssqQ, endPeriod: urlData.sssqZ, accountingStandardsId: urlData.accountingStandardsId, ...urlData }
//校验报表
if (checkParams) {
let check = await this.webapi.tranreport.checkReport(checkParams)
if (check && !check.checkPass) {
let res1 = await this.metaAction.modal('warning', {
content: this.getDisplayGenerateErrorMSg(check),
wrapClassName:'tranreport-generate-modal-bg',
className: 'tranreport-generate-modal',
okText: '返回修改'
})
return
} else if (check && ((check.msgList && check.msgList.length) || (check.xjllbList && check.xjllbList.length) || (check.lrbList && check.lrbList.length) || (check.zcfzbList && check.zcfzbList.length)) ) {
let confirmUpReport2 = await this.metaAction.modal('confirm', {
content: this.getDisplayGenerateErrorMSg(check),
wrapClassName:'tranreport-generate-modal-bg',
className: 'tranreport-generate-modal tranreport-generate-modal-confirm',
cancelText: '返回修改',
okText: '继续生成'
})
const rptTitle2 = this.metaAction.gf('data.rptTitle').toJS(),
rpttype2 = this.metaAction.gf('data.other.rpttype')
//添加埋点
_hmt && _hmt.push(['_trackEvent', '财务', '报表转换', `选择文件是${rptTitle2[rpttype2]}进行生成`])
//跳转url
if (confirmUpReport2) {
const rediretUrl2 = await this.webapi.tranreport.getTaxReportUrl(urlData)
if (rediretUrl2) {
history.redirect(rediretUrl2)
}
}
return
}
}
let confirmUpReport = await this.metaAction.modal('confirm', {
content: this.getDisplayErrorMSg(['确定生成税务格式的财务报表,并进入到申报页面?']),
className: 'tranreport-prompt-modal'
})
const rptTitle = this.metaAction.gf('data.rptTitle').toJS(),
rpttype = this.metaAction.gf('data.other.rpttype')
//添加埋点
_hmt && _hmt.push(['_trackEvent', '财务', '报表转换', `选择文件是${rptTitle[rpttype]}进行生成`])
//跳转url
if (confirmUpReport) {
const rediretUrl = await this.webapi.tranreport.getTaxReportUrl(urlData)
if (rediretUrl) {
history.redirect(rediretUrl)
}
}
}
/**
* 准备保存数据
*/
preSaveData = () => {
let targetData,
target = this.metaAction.gf('data.targetList'),
source = this.metaAction.gf('data.source.dataList'),
oldTypeValue = this.metaAction.gf('data.other.rpttype')
if (target && source) {
targetData = target.toJS()
const sourceData = this.getSaveList( source.toJS() )
if (oldTypeValue == 'balanceSheetRpt') {
targetData.body.zcfzbBody = sourceData
} else if (oldTypeValue == 'profitStatementRpt') {
targetData.body.lrbBody = sourceData
} else if (oldTypeValue == 'cashflowStatementRpt') {
targetData.body.xjllbBody = sourceData
}
}
return targetData ? targetData : target && target.toJS()
}
getSaveList(list) {
list = list.map( item => {
for(let name in item) {
if(item[name] == ' ') {
item[name] = '0.00'
}
}
return item
})
return list
}
/**
* 表格列处理
*/
tableColumns = () => {
//会计总则
let accountingStandards = this.metaAction.gf('data.accountingStandards'),
rpttype = this.metaAction.gf('data.other.rpttype'),
headerList = this.metaAction.gf('data.source.headerList')
let res = renderColumns(headerList && headerList.toJS(), rpttype, accountingStandards, this.renderCellTextBox, this.assetOrProjectStyle)
return res
}
getDisplayGenerateErrorMSg = (check) => {
return <div style={{ display: 'block' }}>
<div className='tranreport-generate-modal-header'>校验问题</div>
{ (check.zcfzbList && check.zcfzbList.length) ? <div className='tranreport-generate-modal-content'>
<div className='tranreport-generate-modal-content-title'>
资产负债表
</div>
{this.getItems(check.zcfzbList)}
</div> : ''}
{ (check.lrbList && check.lrbList.length) ? <div className='tranreport-generate-modal-content'>
<div className='tranreport-generate-modal-content-title'>
利润表
</div>
{this.getItems(check.lrbList)}
</div> : ''}
{ (check.xjllbList && check.xjllbList.length) ? <div className='tranreport-generate-modal-content'>
<div className='tranreport-generate-modal-content-title'>
现金流量表
</div>
{this.getItems(check.xjllbList)}
</div> : ''}
{ (check.msgList && check.msgList.length) ? <div className='tranreport-generate-modal-content'>
<div className='tranreport-generate-modal-content-title'>
表间勾稽关系
</div>
{this.getItems(check.msgList)}
</div> : ''}
</div>
}
getItems(list) {
let arr = []
list.map( (item,index) => {
arr.push(
<div className='tranreport-generate-modal-content-item'>{(index+1) +'.'+ item}</div>
)
})
return arr
}
}
export default function creator(option) {
const metaAction = new MetaAction(option),
extendAction = extend.actionCreator({ ...option, metaAction }),
o = new action({ ...option, metaAction, extendAction }),
ret = { ...metaAction, ...extendAction.gridAction, ...o }
metaAction.config({ metaHandlers: ret })
return ret
}
const EditableCell = ({ editable, value, onBlur, onEnter, onkeydown, toFixedLocal, precision, customAttribute }) => {
return (
<div style={{ textAlign: 'right' }}>
{editable
? <Input.Number
// key={Math.random()}
style={{ margin: '-5px 0' }}
customAttribute={customAttribute}
className='ttk-access-app-tranreport-step2content-tablecellinput'
onPressEnter={(e) => onEnter(e)}
// onKeyDown={(e) =>{onkeydown(e)} }
value={value ? toFixedLocal(value, precision) : ''}
onBlur={(value) => onBlur(value)}
regex='^(-?[0-9]+)(?:\.[0-9]{1,2})?$' />
: <div className='ttk-access-app-tranreport-step2content-tablecellinput tablecellinputtotal' title={value}>{value ? toFixedLocal(value, precision) : ''}</div>
}
</div>
)
}