UNPKG

ttk-app-core

Version:
883 lines (802 loc) 31.5 kB
import React from 'react' import { action as MetaAction, AppLoader } from 'edf-meta-engine' import { TableOperate2, Select, Button, Modal, Icon, PrintOption, FormDecorator, Checkbox, Cascader, DatePicker, Input } from 'edf-component' import utils from 'edf-utils' import sortSearchOption from './utils/sortSearchOption' //格式化搜索条件 import moment from 'moment' import config from './config' const Option = Select.Option import { consts } from 'edf-consts' import table from '../../../component/components/table/table' import Settlement from './components/settlement' const ARRIVAL_NotApprove = 1000020001, // 单据状态: 1000020001: 未审核 ARRIVAL_Approved = 1000020002, // 单据状态: 1000020002: 已审核 ARRIVAL_Rejected = 1000020003; // 单据状态: 1000020003: 已驳回 const checkboxKey = 'id';//table的主键 class action { constructor(option) { this.metaAction = option.metaAction this.config = config.current this.webapi = this.config.webapi this.voucherAction = option.voucherAction } //初始化数据 onInit = ({ component, injections }) => { this.component = component this.injections = injections let addEventListener = this.component.props.addEventListener this.changeSipmleDate = false if (addEventListener) { addEventListener('onTabFocus', :: this.onTabFocus) } injections.reduce('init'); this.load() } //获取到页签焦点时调用 onTabFocus = async (params) => { this.sortParmas(null, null, null, 'init') } load = () => { this.sortParmas(null, null, null, 'init') } componentDidMount = () => { this.onResize() const win = window if (win.addEventListener) { win.addEventListener('resize', this.onResize, false) } else if (win.attachEvent) { win.attachEvent('onresize', this.onResize) } else { win.onresize = this.onResize } } getTableScroll = () => { try { let tableOption = this.metaAction.gf('data.tableOption').toJS() //x y let dom = document.getElementsByClassName('ttk-scm-app-expense-list-Body')[0] //table let tableDom if (!dom) { return } if (tableOption.y) { tableDom = dom.getElementsByClassName('ant-table-fixed')[1] //table body } else { tableDom = dom.getElementsByClassName('ant-table-fixed')[0] //table header } if (tableDom && dom) { let num = dom.offsetHeight - tableDom.offsetHeight //457-525 if ((num - 30) > 0 && tableOption.y) { delete tableOption.y this.injections.reduce('update', { path: 'data.tableOption', value: tableOption }) } else if (num < 0 && !tableOption.y) { //内容超出超出区域高度 const width = dom.offsetWidth const height = dom.offsetHeight this.injections.reduce('setTableOption', { ...tableOption, y: height - 41, containerWidth: width - 20 - 50 - 50 }) } } // setTimeout(()=>{ // this.onResize() // },2000) } catch (err) { console.log(err) } } onResize = (type) => { let keyRandom = Math.floor(Math.random() * 10000) this.keyRandom = keyRandom const tableOption = this.metaAction.gf('data.tableOption') setTimeout(() => { if (this.keyRandom == keyRandom) { let dom = document.getElementsByClassName('app-pu-arrival-list-Body')[0] if (!dom) { if (type) { return } setTimeout(() => { this.onResize() }, 20) } else { let tableOption = this.metaAction.gf('data.tableOption').toJS() const width = dom.offsetWidth const height = dom.offsetHeight this.injections.reduce('setTableOption', { ...tableOption, y: height - 41, containerWidth: width - 20 }) } } }, 100) } //新增费用单 addClick = () => { let list = this.metaAction.gf('data.list').toJS(), isNew = true list.map(item => { if(item.isEdit) isNew = false }) if(!isNew) { this.metaAction.toast('warning', '您有未保存的费用单') return } let searchValue = this.metaAction.gf('data.searchValue').toJS(), businessDate = utils.moment.momentToString(moment(searchValue.period).endOf('month'), 'YYYY-MM-DD') businessDate = utils.date.transformMomentDate(businessDate) list = list.concat({ isTitle: true, id: 1, seq: list.length ? list[list.length-1].seq+1 : 1, isNew: true }, { pid: 1, seq: list.length ? list[list.length-1].seq+1 : 1, isNew: true, isEdit: true, businessDate: businessDate }) this.injections.reduce('update', { path: 'data.list', value: list}) } //更多 moreActionOpeate = (e) => { this[e.key] && this[e.key]() } //科目设置 subjectManage = async () => { if (!this.config.apps['edfx-business-subject-manage']) { throw '依赖app-asset-management-list app,请使用mk clone app-asset-management-list命令添加' } this.component.props.setPortalContent && this.component.props.setPortalContent('科目设置', 'edfx-business-subject-manage', {accessType: 'cost'}) } // 凭证习惯 voucherHabit = async() => { const ret = await this.metaAction.modal('show', { title: '凭证习惯设置', width: 480, okText: '确定', bodyStyle: {padding: '10px 24px'}, children: this.metaAction.loadApp('ttk-scm-voucherHabit-card', { store: this.component.props.store, type: 'expense', }), }) if(ret) this.metaAction.toast('success', '设置成功') } //生成凭证 addVoucher = async() => { debugger } //删除凭证 delVoucher = async() => { debugger } //批量删除费用单 delBatchClick = async () => { const selectedOption = this.metaAction.gf('data.tableCheckbox.selectedOption').toJS() //选中的 if (selectedOption.length == 0) { this.metaAction.toast('error', '请选择您要删除的数据!') return } const ret = await this.metaAction.modal('confirm', { title: '删除费用单', content: '确定删除所选费用单?' }) if (!ret) { return } let data = selectedOption.map(item => { return { id: item.id, ts: item.ts } }) data = this.delRepeat(data, 'id'); const res = await this.webapi.expenseList.deleteBatch(data) if (res) { this.metaAction.toast('success', '删除成功!') } this.injections.reduce('update', { path: 'data.tableCheckbox', value: { checkboxValue: [], selectedOption: [] } }) // 重新请求列表数据 this.sortParmas() } /*********--region start--*********** */ //渲染列 renderColumns = () => { const columns = this.metaAction.gf('data.other.columnDto').toJS() //header const arr = []; columns.forEach(data => { if(data.isVisible){ arr.push({ title: data.caption, key: data.fieldName, className: `table_td_align_${this.needAlignType(data.fieldName)}`, dataIndex: data.fieldName, width: this.getColumnsWidth(data.fieldName), render: (text, record, index) => { if(record.isTitle){ if(data.fieldName == 'seq'){ return this.renderRowSpan(text, record, index) }else if(data.fieldName == 'businessTypeName'){ return this.titleTdRender(text, record, index, data.fieldName, columns) }else{ return this.renderContent(text) } }else{ if(data.fieldName == 'seq'){ return this.renderContent(text) }else{ return this.normalTdRender(text, record, index, data.fieldName) } } } }) } }) //操作栏目列 arr.push({ title: ( <Icon name="columnset" fontFamily='edficon' className='ttk-scm-app-expense-columnset' type="youcezhankailanmushezhi" onClick={() => this.showTableSetting({ value: true })} /> ), key: 'status', dataIndex: 'status', className: 'table_fixed_width', width: 87, render: (text, record, index) => { if(record.isTitle){ return this.renderContent(text) }else{ return this.operateCol(text, record, index) } } }) return arr } //宽度 getColumnsWidth = (fieldName) => { if(fieldName == 'seq'){ return '42px' }else if(fieldName == 'businessDate'){ return '128px' }else if(fieldName == 'amount'){ return '128px' }else if(fieldName == 'departmentName' || fieldName == 'projectName' || fieldName == 'businessTypeName'){ return '168px' } } //序号列 renderRowSpan = (text, record, index) => { const num = this.calcRowSpan(record.seq, 'seq', index) const obj = { children: text, props: { rowSpan: num, }, } return obj } //合并列 renderContent = (text) => { const obj = { children: null, props: {}, }; obj.props.colSpan = 0; return obj; } //头部内容 titleTdRender = (text, record, index, fieldName, columns) => { let _this = this let visibleColumns = columns.filter(item => item.isVisible==true) return { children: <div className='columns-title'> <div className='columns-title-item columns-title-price'> <span>费用金额:</span> <span className='price'>{this.renderFixedNumber(record, 'amount')}</span> </div> <div className='columns-title-item columns-title-docCode'> <span>凭证字号:</span> <a onClick={function(){ _this.docCode(text, record, index) }}>记-001</a> </div> <div className='columns-title-item columns-title-settlement'> <span>结算:</span> <span>(银行基本户)</span> <Icon type="bianji" fontFamily="edficon" onClick={function(){ _this.settlementExpense(text, record, index) }} style={{cursor:'pointer',fontSize:'23px',position:"relative", top:"5px"}}/> </div> <div className='columns-title-item columns-title-icon'> <Icon type="chakan" fontFamily="edficon" onClick={function(){ _this.saveExpense(text, record, index) }} style={{cursor:'pointer',fontSize:'23px',position:"relative", top:"6px"}}/> <Icon type="shanchu" fontFamily="edficon" onClick={function(){ _this.delExpense(text, record, index) }} style={{cursor:'pointer',fontSize:'23px',position:"relative", top:"5px"}}/> </div> </div>, props: { colSpan: visibleColumns.length, }, }; } //查看凭证 docCode = (text, record, index) => { //let list = this.metaAction.gf('data.list').toJS() } //结算 settlementExpense = async (text, record, index) => { let list = this.metaAction.gf('data.list').toJS() const ret = await this.metaAction.modal('show', { title: '现结', width: 680, bodyStyle: { padding: 6, fontSize: 12 }, wrapClassName:'settleClass', children: <Settlement></Settlement> }) } //保存费用单 saveExpense = async (text, record, index) => { let list = this.metaAction.gf('data.list').toJS(), details = [] list = list.filter(item => { if(item.pid == record.id){ let obj = { businessTypeId: item.businessTypeId, amount: Number(item.amount) ? (Number(item.amount)).toFixed(2) : undefined, } if(item.remark) obj.remark = item.remark if(item.projectId) obj.projectId = item.projectId if(item.departmentId) obj.departmentId = item.departmentId if(item.id) obj.id = item.id if(item.ts) obj.ts = item.ts details.push(obj) return item } }) let option = { businessDate: this.metaAction.momentToString(list[0].businessDate, 'YYYY-MM-DD'), details: details, isReturnValue: true } if(record.id && !record.isNew) option.id = record.id if(record.ts && !record.isNew) option.ts = record.ts const response = await this.webapi.expenseList.create(option) if (response && response.result == false) { this.metaAction.toast('error', response.error.message) }else{ this.metaAction.toast('success', '保存成功') this.sortParmas() } } //删除费用单 delExpense = async (text, record, index) => { let list = this.metaAction.gf('data.list').toJS() const ret = await this.metaAction.modal('confirm', { title: '删除费用单', content: '确定删除所选费用单?' }) } //操作栏目列 operateCol = (text, record, index) => { let _this = this return <span> <Icon type="jia" fontFamily="edficon" onClick={function(){ _this.addDatials(text, record, index) }} style={{fontSize:'23px',position:"relative", top:"2px", color: "#33C2A1"}}/> <Icon type="bianji" fontFamily="edficon" onClick={function(){ _this.editDatials(text, record, index) }} style={{fontSize:'23px',position:"relative", top:"3px"}}/> <Icon type="shanchu" fontFamily="edficon" onClick={function(){ _this.delDatials(text, record, index) }} style={{fontSize:'23px',position:"relative", top:"2px"}}/> </span> } //新增费用明细 addDatials = (text, record, index) => { let list = this.metaAction.gf('data.list').toJS(), rowIndex list.map((item, index)=>{ if(item.pid == record.pid) { item.isEdit = true rowIndex = index } }) list.splice(rowIndex+1, 0, { pid: record.pid, seq: record.seq, isEdit: true, businessDate: list[rowIndex].businessDate}) this.injections.reduce('update', { path: 'data.list', value: list}) } //编辑费用明细 editDatials = (text, record, index) => { let list = this.metaAction.gf('data.list').toJS() list.map(item=>{ if(item.pid == record.pid) item.isEdit = true }) this.injections.reduce('update', { path: 'data.list', value: list}) } //删除费用明细 delDatials = async (text, record, index) => { //编辑状态下删除不请求后台,直接删除 if(record.isEdit) { let list = this.metaAction.gf('data.list').toJS() list.splice(index, 1) this.injections.reduce('update', { path: 'data.list', value: list}) //保存状态下删除需请求后台删除 }else{ const ret = await this.metaAction.modal('confirm', { title: '删除', content: '确认删除?' }) } } //渲染内容 normalTdRender = (text, record, index, fieldName) => { if(record.isEdit){ if(fieldName == 'businessDate'){ return this.getBusinessDate(text, record, index, fieldName) }else if(fieldName == 'departmentName' || fieldName == 'projectName' || fieldName == 'businessTypeName'){ return this.getDepartmentProject(text, record, index, fieldName) }else { return this.getInput(text, record, index, fieldName) } }else{ let type if(fieldName == 'departmentName'){ type = 'department' }else if(fieldName == 'projectName'){ type = 'project' }else if(fieldName == 'businessTypeName'){ type = 'businessType' } if(fieldName == 'businessDate'){ return this.metaAction.momentToString(record[fieldName], 'YYYY-MM-DD') }else if(fieldName == 'businessTypeName' || fieldName == 'projectName' || fieldName == 'departmentName'){ let list = this.metaAction.gf('data.other.'+type).toJS() let value = list.filter(item=>item.id==record[type+'Id']) return value[0].name } return record[fieldName] } } //记账日期 getBusinessDate = (text, record, index, fieldName) => { let _this = this return <DatePicker placeholder='记账日期' disabledDate={this.getDisabledDate} value={record.businessDate} onChange={function(e){ _this.injections.reduce('accountDateChange', {e, record, index}) }}/> } getPopupContainer2 = () => { return document.querySelector('.ant-table-body table') } //部门和项目 getDepartmentProject = (text, record, index, fieldName) => { let placeholder = '', type = '' switch (fieldName) { case 'departmentName': placeholder = '部门' type = 'department' break; case 'projectName': placeholder = '项目' type = 'project' break; case 'businessTypeName': placeholder = '收支类型' type = 'businessType' break; } return <div style={{width: '95%'}}> <Select style={{width: '100%'}} placeholder={placeholder} value={record[type+'Id']} //onFocus={() => this.getList(type)} onChange={(value) => this.onFieldChange(index, value, type)} optionFilterProp="children" filterOption={this.filterOptionSummary} dropdownFooter={ <Button type='primary' style={{ width: '100%', borderRadius: '0' }} /*onClick={this.addArchives(index, type)}*/>新增 </Button> } > {this.selectOption(type)} </Select> </div> } selectOption = (path) => { let list = this.metaAction.gf(`data.list`).toJS() list = this.metaAction.gf(`data.other.${path}`).toJS() if(!list) return return list.map(item => { return <Option value={item.id}>{item.name}</Option> }) } //备注和金额 getInput = (text, record, index, fieldName) => { let _this = this return <Input value={ fieldName == 'amount' ? this.renderFixedNumber(record, fieldName) : record[fieldName]} className={fieldName == 'amount' ? 'amount' : ''} onBlur = { function(e) { _this.amountChange(index, e.target.value, fieldName)} }/> } amountChange = (index, value, type) => { let list = this.metaAction.gf('data.list').toJS() list[index][type] = value this.injections.reduce('update', { path: 'data.list', value: list}) } renderFixedNumber = (record, fieldName) => { if(!record[fieldName]) return '' return utils.number.format(record[fieldName], 2) } //对齐方式 needAlignType = (key) => { const right = ['amount',] const left = ['businessTypeName', 'remark', 'departmentName', 'projectName'] const center = ['seq', 'businessDate'] let className = right.includes(key) ? 'right' : left.includes(key) ? 'left' : 'center' return className } //合并行的 calcRowSpan = (text, columnKey, currentRowIndex) => { let tableList = this.metaAction.gf('data.list') if (!tableList) return const rowCount = tableList.size if (rowCount == 0 || rowCount == 1) return 1 if (currentRowIndex > 0 && currentRowIndex <= rowCount && text == tableList.getIn([currentRowIndex - 1, columnKey])) { return 0 } var rowSpan = 1 for (let i = currentRowIndex + 1; i < rowCount; i++) { if (text == tableList.getIn([i, columnKey])) rowSpan++ else break } return rowSpan } //获取需要排序的列 getSortColumnsItem = (type) => { const data = this.metaAction.gf('data').toJS() const columns = [{ title: { name: 'sort', component: 'TableSort', sortOrder: 'descend', handleClick: (e) => { this.sortChange("code", e) }, title: '单据编码' }, dataIndex: 'code', key: 'code', className: 'table_center', render: this.rowSpan }] return columns.find(item => { return item.dataIndex == type }) } //设置新的栏目状态 combineColumnProp = (data) => { if (!data) return [] let newDataArray = [] data.forEach((ele, index) => { newDataArray.push({ "isVisible": ele.isVisible, "id": ele.id, 'ts': ele.ts }) }) return newDataArray } //关闭栏目设置 closeTableSetting = () => { this.injections.reduce('tableSettingVisible', { value: false }) } //显示栏目设置 修改后同步到服务端用户设置 showTableSetting = async ({ value, data }) => { /** * 更新栏目设置 */ this.injections.reduce('update', { path: 'data.showTableSetting', value: false }) const preData = this.metaAction.gf('data.other.columnDto') if (value === false) { //confirm 点击确定时 调用 this.injections.reduce('update', { path: 'data.other.columnDto', value: data }) const columnSolution = await this.webapi.expenseList.findByParam({ code: 'expenseList' }) //查询服务端的栏目 if (columnSolution) { let aa = {} aa.id = columnSolution.id aa.columnDetails = this.combineColumnProp(data), aa.ts = columnSolution.ts //同步到服务端 用户设置 const columnDetail = await this.webapi.expenseList.updateWithDetail(aa) if (columnDetail) { this.injections.reduce('settingOptionsUpdate', { visible: value, data: columnDetail.columnDetails }) } else { this.metaAction.sf('data.other.columnDto', preData) } } else { this.metaAction.sf('data.other.columnDto', preData) } } else { this.injections.reduce('tableSettingVisible', { value, data: data }) } } // 处理搜索参数 sortParmas = (search, pages, order, type, noInitDate) => { if (!search) { search = this.metaAction.gf('data.searchValue').toJS() } if (!pages) { pages = this.metaAction.gf('data.pagination').toJS() } if (!order) { order = this.metaAction.gf('data.orders').toJS() } const page = sortSearchOption(pages, null, ['total', 'totalCount', 'totalPage']); if (type == 'get') { //获取所有参数 return { ...search, orders: order } } if (type == 'init') { let currentOrg = this.metaAction.context.get("currentOrg") if(currentOrg.periodDate){ search.period = currentOrg.periodDate } //初始化数据 this.initData({ ...search, page, orders: order }, search.period) } else { //查询数据 this.requestData({ ...search, page, orders: order }) } } initData = async (params, period) => { const response = await this.webapi.expenseList.init(params) response.contextDate = period this.injections.reduce('tableLoading', false) this.injections.reduce('load', { response }) this.metaAction.sf('data.tableKey', Math.random()) setTimeout(() => { this.getTableScroll() }, 100) } requestData = async (params) => { let loading = this.metaAction.gf('data.loading') if (!loading) { this.injections.reduce('tableLoading', true) } const response = await this.webapi.expenseList.init(params) this.injections.reduce('tableLoading', false) this.injections.reduce('load', { response }) setTimeout(() => { this.getTableScroll() }, 100) } //排序发生变化 sortChange = (key, value) => { return; let params = { 'userOrderField': value == false ? null : key, 'order': value == false ? null : value } const pages = this.metaAction.gf('data.pagination').toJS() this.sortParmas(null, { ...pages, 'currentPage': 1 }, params) this.injections.reduce('sortReduce', params) } //分页发生变化 pageChanged = (current, pageSize) => { let page = this.metaAction.gf('data.pagination').toJS() const len = this.metaAction.gf('data.list').toJS().length if (pageSize) { page = { ...page, 'currentPage': len == 0 ? 1 : current, 'pageSize': pageSize } } else { page = { ...page, 'currentPage': len == 0 ? 1 : current } } this.injections.reduce('update', { path: 'data.tableCheckbox', value: { checkboxValue: [], selectedOption: [] } }) this.sortParmas(null, page) } // 指定table 以什么字段作为key值 renderRowKey = (record) => { return record[checkboxKey] } tableOnchange = async (pagination, filters, sorter) => { } rowSelection = (text, row, index) => { return undefined } //选择数据改变 checkboxChange = (arr, itemArr) => { let newArr = [] arr.forEach(item => { if (item) { newArr.push(item) } }) let newItemArr = [] itemArr.map(item => { if (item) { newItemArr.push(item) } }) this.injections.reduce('update', { path: 'data.tableCheckbox', value: { checkboxValue: newArr, selectedOption: newItemArr } }) this.selectedOption = newItemArr } periodChange = (path, value) => { this.injections.reduce('update', { path, value }) } //去重 delRepeat = (data, id) => { const arr = new Map() data.map(item => { if (!arr.has(item[id])) { arr.set(item[id], item) } }) const sum = [] for (let value of arr.values()) { sum.push(value) } return sum } componentWillUnmount = () => { if (this.props && this.props.isFix === true) return const win = window if (win.removeEventListener) { win.removeEventListener('resize', this.onResize, false) } else if (win.detachEvent) { win.detachEvent('onresize', this.onResize) } else { win.onresize = undefined } } onFieldChange = (index, value, type) => { let list = this.metaAction.gf('data.list').toJS() list[index][type+'Id'] = value this.injections.reduce('update', { path: 'data.list', value: list}) } } export default function creator(option) { const metaAction = new MetaAction(option), voucherAction = FormDecorator.actionCreator({ ...option, metaAction }),//装饰器 使用metaAtjion为参数 实现扩展 o = new action({ ...option, metaAction, voucherAction }), ret = { ...metaAction, ...voucherAction, ...o } metaAction.config({ metaHandlers: ret }) return ret }