ttk-app-core
Version:
enterprise develop framework
883 lines (802 loc) • 31.5 kB
JavaScript
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
}