核算导入导出

This commit is contained in:
MustangDeng 2022-04-26 16:35:07 +08:00
parent 88caca1d04
commit 5df55a6724
8 changed files with 496 additions and 23 deletions

View File

@ -353,13 +353,73 @@ export const saveAcctResult = (params) => {
}).then(res => res.json())
}
// 核算结果--导入核算结果前生成导入模板时可选的薪资项目
export const getImportField = (params) => {
return WeaTools.callApi('/api/bs/hrmsalary/salaryacct/acctresult/importField', 'GET', params);
}
// 核算结果-导入模板
export const getImportTemplate = (salaryItemIds, salaryAcctRecordId) => {
fetch('/api/bs/hrmsalary/salaryacct/acctresult/importtemplate/export?salaryItemIds=' + salaryItemIds + "&salaryAcctRecordId=" + salaryAcctRecordId).then(res => res.blob().then(blob => {
var filename=`薪资核算.xlsx`
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}))
}
// 核算结果-导入预览
export const previewAcctResult= (params) => {
return fetch('/api/bs/hrmsalary/salaryacct/acctresult/preview', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
}
// 核算结果-导入
export const importAcctResult = (params) => {
return fetch('/api/bs/hrmsalary/salaryacct/acctresult/importSalaryAcctResult', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
}
// 核算结果-导出全部
export const exportAcctResult = (salaryAcctRecordId) => {
fetch('/api/bs/hrmsalary/salaryacct/acctresult/export?salaryAcctRecordId=' + salaryAcctRecordId ).then(res => res.blob().then(blob => {
var filename=`薪资核算.xlsx`
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}))
}
// 线下对比-列表
export const comparisonResultList = (params) => {
return fetch('/api/bs/hrmsalary/salaryacct/comparisonresult/list', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
}

View File

@ -0,0 +1,145 @@
import React from 'react'
import ImportModal from '../../../../components/importModal'
import { Button } from 'antd'
import { inject, observer } from 'mobx-react';
import SelectFieldModal from './selectFieldModal';
@inject('calculateStore')
@observer
export default class AcctResultImportModal extends React.Component {
constructor(props) {
super(props)
this.state = {
modalParam: {
salaryAcctRecordId: "",
salaryItemIds: ""
},
step: 0,
selectFieldVisible: false
}
}
componentWillMount() {
const { id } = this.props;
let modalParam = { ...this.state.modalParam }
modalParam.salaryAcctRecordId = id
this.setState({
modalParam
})
}
// 获取模板
handleAccResultTemplateLink() {
const { calculateStore: { getImportTemplate }} = this.props;
getImportTemplate(this.state.modalParam.salaryItemIds, this.state.modalParam.salaryAcctRecordId)
}
// 设置步骤
setStep(step) {
this.setState({step})
}
// 完成
handleFinish() {
this.setState({step: 0})
this.props.onCancel()
const { calculateStore: { acctResultList } } = this.props;
acctResultList(this.props.id)
}
// 关闭
handleCancel() {
this.setState({
modalVisiable: false,
step: 0
})
}
// 渲染第一步表单
renderFormComponent() {
return <Button onClick={() => {
this.handleSelectedField()
}}>请选择表单字段</Button>
}
// 选择表单字段
handleSelectedField() {
this.setState({
selectFieldVisible: true
})
}
// 添加表头字段
handleAdd(fieldDate) {
let salaryItemIdsList = []
fieldDate.formulaItems.map(item => {
if(item.checked) {
salaryItemIdsList.push(item.salaryItemId)
}
})
fieldDate.inputItems.map(item => {
if(item.checked) {
salaryItemIdsList.push(item.salaryItemId)
}
})
let salaryItemIds = ""
if(salaryItemIdsList.length > 0) {
salaryItemIds = salaryItemIdsList.join(",")
}
let modalParam = { ...this.state.modalParam }
modalParam.salaryItemIds = salaryItemIds
this.setState({
modalParam
})
this.props.onAdd(fieldDate)
}
render() {
const { calculateStore } = this.props;
const { fetchPreviewAcctResult, previewAcctResultColumns, previewAcctResultDataSource, importAcctResult, fetchImportAcctResult } = calculateStore
const { step, selectFieldVisible, modalParam } = this.state;
const { visiable } = this.props;
return (
<div>
{
visiable && <ImportModal
params={modalParam}
columns={previewAcctResultColumns}
step={step}
setStep={this.setStep.bind(this)}
slideDataSource={previewAcctResultDataSource}
importResult={importAcctResult}
onFinish={() => {
this.handleFinish()
}}
previewImport={(params) => {fetchPreviewAcctResult(params)}}
importFile={(params) => {fetchImportAcctResult(params)}}
templateLink={ () => { this.handleAccResultTemplateLink()}}
renderFormComponent={() => this.renderFormComponent()}
visiable={visiable}
onCancel={() => { this.props.onCancel() }}
/>
}
{
selectFieldVisible && <SelectFieldModal
id={this.props.id}
visible={selectFieldVisible}
fieldData={this.props.fieldData}
onAdd={(fieldDate) => {
this.handleAdd(fieldDate)
}}
onCancel={() => {
this.setState({
selectFieldVisible: false
})
}}
/>
}
</div>
)
}
}

View File

@ -0,0 +1,111 @@
import React from 'react'
import { Modal, Row, Col, Button } from 'antd'
import { inject, observer } from 'mobx-react';
import { WeaCheckbox } from 'ecCom'
@inject('calculateStore')
@observer
export default class SelectFieldModal extends React.Component {
constructor(props) {
super(props)
this.state = {
fieldData: {}
}
}
componentWillMount() {
const {calculateStore: { getImportField } } = this.props;
getImportField(this.props.id).then(data => {
let fieldData = {};
let formulaItems = []
formulaItems = data.formulaItems
if(this.props.fieldData.formulaItems) {
formulaItems = this.props.fieldData.formulaItems
}
let inputItems = []
inputItems = data.inputItems
if(this.props.fieldData.inputItems) {
inputItems = this.props.fieldData.inputItems
}
fieldData.formulaItems = formulaItems;
fieldData.inputItems = inputItems;
this.setState({
fieldData
})
this.fieldData = fieldData
})
}
// 公式项改变
handleFormalChange(item, value, flag) {
item.checked = value == 1 ? true: false
if(flag) { // 公式项
this.fieldData.formulaItems.map(fieldItem => {
if(item.salaryItemId == fieldItem.salaryItemId) {
fieldItem.checked = item.checked
}
})
} else { // 输入项
this.fieldData.inputItems.map(fieldItem => {
if(item.salaryItemId == fieldItem.salaryItemId) {
fieldItem.checked = item.checked
}
})
}
}
// 添加按钮点击回调
handleAddClick() {
this.props.onAdd(this.fieldData)
this.props.onCancel()
}
render() {
const { fieldData } = this.state;
return (
<Modal visible={this.props.visible} width={800} onCancel={() =>{this.props.onCancel()}}
footer={null}
>
<div style={{height: "50px", lineHeight: "50px"}}>
<span style={{fontSize: "14px", fontWeight: "600"}}>添加表头字段</span>
<Button type="primary" style={{float: "right", marginRight: "50px"}} onClick={() => {this.handleAddClick()}}>添加</Button>
</div>
<div style={{marginTop: "20px"}}>
<div style={{height: "40px", lineHeight: "40px"}}>
<WeaCheckbox content="公式项"/>
</div>
<div style={{height: "100px", border: "1px solid #f2f2f2", margin: "10px", padding: "10px", overflowY: 'scroll'}}>
<Row>
{ fieldData.formulaItems && fieldData.formulaItems.map(item => (
<Col span={6}><WeaCheckbox value={item.checked ? 1 : 0} content={item.salaryItemName} onChange={(value) => {
this.handleFormalChange(item, value, true)
}}/></Col>
))}
</Row>
</div>
</div>
<div style={{marginTop: "20px"}}>
<div style={{height: "50px", lineHeight: "50px"}}>
<WeaCheckbox content="输入项"/>
</div>
<div style={{height: "100px", border: "1px solid #f2f2f2", margin: "10px", padding: "10px", overflowY: "scroll"}}>
<Row>
{ fieldData.inputItems && fieldData.inputItems.map(item => (
<Col span={6}><WeaCheckbox value={item.checked ? 1 : 0} content={item.salaryItemName} onChange={(value) => {
this.handleFormalChange(item, value, true)
}}/></Col>
))}
</Row>
</div>
</div>
<div style={{marginTop: "20px"}}>
<WeaCheckbox content="只显示已选中"/>
</div>
</Modal>
)
}
}

View File

@ -1,12 +1,33 @@
import React from 'react'
import { Button, Table } from "antd"
import { WeaInputSearch, WeaCheckbox } from 'ecCom'
import { WeaInputSearch, WeaCheckbox, WeaTable } from 'ecCom'
import { mergeDetailColumns, dataSource } from './columns'
import { getQueryString } from '../../util/url'
import CustomTab from '../../components/customTab'
import { inject, observer } from 'mobx-react';
@inject('calculateStore')
@observer
export default class CompareDetail extends React.Component {
render() {
constructor(props) {
super(props)
this.id = ""
this.state = {
onlyDiffEmployee: true,
onlyDiffSalaryItem: true,
}
}
componentWillMount() {
let id = getQueryString("id");
this.id = id;
const { calculateStore: {fetchComparisonResultList}} = this.props;
const { onlyDiffEmployee, onlyDiffSalaryItem} = this.state;
fetchComparisonResultList(onlyDiffEmployee, onlyDiffSalaryItem, this.id)
}
render() {
const renderRightOperation = () => {
return (
<div style={{display: "inline-block"}}>
@ -20,8 +41,18 @@ export default class CompareDetail extends React.Component {
const renderLeftOperation = () => {
return (
<div>
<WeaCheckbox content="只显示有差异的人员" />
<WeaCheckbox content="只显示有差异的薪资项目" />
<WeaCheckbox content="只显示有差异的人员" value={this.state.onlyDiffEmployee ? 1 : 0}
onChange={(value) => {
this.setState({
onlyDiffEmployee: value == 1
})
}}
/>
<WeaCheckbox content="只显示有差异的薪资项目" value={this.state.onlyDiffSalaryItem ? 1 : 0} onChange={(value) => {
this.setState({
onlyDiffSalaryItem: value == 1
})
}}/>
</div>
)
}
@ -43,7 +74,7 @@ export default class CompareDetail extends React.Component {
</div>
<div className="tableWrapper">
<Table dataSource={dataSource} columns={mergeDetailColumns}/>
<WeaTable dataSource={dataSource} columns={mergeDetailColumns}/>
</div>

View File

@ -6,7 +6,7 @@ import SalaryDetail from './salaryDetail'
import { Button, Menu, Dropdown, Modal } from 'antd'
import { WeaInputSearch } from "ecCom"
import { getQueryString } from '../../util/url'
import AcctResultImportModal from './acctResult/importModal/acctResultImportModal';
@inject('calculateStore')
@observer
@ -14,7 +14,9 @@ export default class CalculateDetail extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedKey: "0"
selectedKey: "0",
fieldData: {},
acctResultImportVisiable: false
}
this.id = ""
}
@ -23,7 +25,9 @@ export default class CalculateDetail extends React.Component {
let id = getQueryString("id");
this.id = id;
const { calculateStore: {checkTaxAgent}} = this.props;
checkTaxAgent(id)
checkTaxAgent(this.id)
let modalParam = {...this.state.modalParam , salaryAcctRecordId: id}
this.setState({modalParam})
}
// 核算点击事件
@ -41,17 +45,34 @@ export default class CalculateDetail extends React.Component {
onCancel() {}
});
}
render() {
const { selectedKey } = this.state;
const handleMenuClick = (e) => {
if(e.key == "2") {
window.open("/spa/hrmSalary/static/index.html#/main/hrmSalary/compareDetail")
}
// 更多选项点击
handleMenuClick = (e) => {
if(e.key == "1") { // 导入
this.setState({
acctResultImportVisiable: true
})
} else if(e.key == "2") {
window.open("/spa/hrmSalary/static/index.html#/main/hrmSalary/compareDetail?id=" + this.id)
} else if(e.key == "3") {
const {calculateStore: {exportAll}} = this.props;
exportAll(this.id)
}
}
// 导入表单添加表头回调
handleAcctModalAdd(fieldData) {
this.setState({
fieldData
})
}
render() {
const { selectedKey, modalParam, acctResultImportVisiable } = this.state;
const menu = (
<Menu onClick={handleMenuClick}>
<Menu onClick={this.handleMenuClick.bind(this)}>
<Menu.Item key="1">导入</Menu.Item>
<Menu.Item key="2">线下对比</Menu.Item>
<Menu.Item key="3">导出全部</Menu.Item>
@ -97,7 +118,21 @@ export default class CalculateDetail extends React.Component {
{
selectedKey == 1 && <SalaryDetail />
}
{
acctResultImportVisiable && <AcctResultImportModal
visiable={acctResultImportVisiable}
fieldData={this.state.fieldData}
onAdd={(fieldData) => {
this.handleAcctModalAdd(fieldData)
}}
onCancel={() => this.setState({
acctResultImportVisiable: false,
fieldData: {}
})}
id={this.id}
/>
}
</div>
)

View File

@ -183,7 +183,7 @@ export default class Payroll extends React.Component {
}
// 预览
handlePreview() {
handlePreview() {
window.open("/spa/hrmSalary/static/index.html#/main/hrmSalary/templatePreview")
}

View File

@ -36,6 +36,13 @@ export class calculateStore {
@observable acctResultListColumns = []; // 列
@observable acctresultDetailForm = {}; // 编辑薪资表单数据
@observable acctResultListTableStore = new TableStore()
// 导入
@observable importFieldData = {}; // 表头选择列表
@observable acctResultImportPreview = {}; // 核算结果预览
@observable previewAcctResultList = {}; //预览数据
@observable previewAcctResultColumns = []; // 预览列表
@observable previewAcctResultDataSource = []; // 预览DataSource
@observable importAcctResult = {}; // 导入结果
//*** 线下比对 ***
@observable comparisonresultListDataSource = [];// dataSource
@ -391,4 +398,88 @@ export class calculateStore {
}
// 获取导入字段设置
@action
getImportField = (salaryAcctRecordId) => {
return new Promise((resolve, reject) => {
API.getImportField({salaryAcctRecordId}).then(res => {
if(res.status) {
this.importFieldData = res.data
resolve(res.data)
} else {
message.error(res.errormsg || "获取失败")
reject()
}
})
})
}
// 下载薪资导入核算模板
@action
getImportTemplate = (salaryItemIds, salaryAcctRecordId) => {
API.getImportTemplate(salaryItemIds, salaryAcctRecordId)
}
// 核算结果-导入预览
@action
fetchPreviewAcctResult = (params) => {
API.previewAcctResult(params).then((res) => {
if(res.status) {
this.previewAcctResultList = res.data
this.previewAcctResultColumns = res.data.headers.map((item, index) => {
let column = {}
column.title = item;
column.dataIndex = "" + index;
column.key = index + ""
return column
})
this.previewAcctResultDataSource = res.data.list.map((item) => {
let data = {}
item.map((i, index) => {
data[index + ''] = i
})
return data
})
} else {
message.error(res.errormsg || "获取失败")
}
})
}
// 核算结果-导入
@action
fetchImportAcctResult = (params) => {
API.importAcctResult(params).then(res=> {
if(res.status) {
this.importAcctResult = res.data
} else {
message.error(res.errormsg || "导入失败")
}
})
}
// 核算结果-导出全部
@action
exportAll = (salaryAcctRecordId) => {
API.exportAcctResult(salaryAcctRecordId)
}
// 线下对比-列表
@action
fetchComparisonResultList = (onlyDiffEmployee, onlyDiffSalaryItem, salaryAcctRecordId) => {
let params = {
onlyDiffEmployee,
onlyDiffSalaryItem,
salaryAcctRecordId
}
API.comparisonResultList(params).then(res => {
if(res.status) {
this.comparisonResultList = res.data
} else {
message.error(res.errormsg || "获取失败")
}
})
}
}

View File

@ -133,7 +133,7 @@ export class payrollStore {
if(res.status) {
let response = res.data.salaryTemplateBaseSet
let templateBaseData = response.data
templateBaseData.salarySob = templateBaseData.salarySob !== undefined ? templateBaseData.salarySob : null;
templateBaseData.salarySob = templateBaseData.salarySob !== undefined ? templateBaseData.salarySob + "": null;
this.templateBaseData = templateBaseData // 基础信息表单数据
this.salarySobOptions = response.salarySobOptions ?