UNPKG

ttk-app-core

Version:
1,128 lines (1,071 loc) 52.6 kB
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> ) }