Merge branch 'feature/2.9.42309.01-社保福利档案添加非系统人员列表' into release/2.9.42309.01

This commit is contained in:
黎永顺 2023-09-11 13:43:28 +08:00
commit a583087f5f
11 changed files with 583 additions and 26 deletions

View File

@ -13,6 +13,10 @@ export const getCondition = params => {
export const queryList = (params) => {
return postFetch("/api/bs/hrmsalary/archives/getTable", params);
};
//社保福利档案_非系统人员列表
export const getExtTable = (params) => {
return postFetch("/api/bs/hrmsalary/archives/getExtTable", params);
};
//社保福利档案列表
export const queryInsuranceTabTotal = (params) => {
return WeaTools.callApi("/api/bs/hrmsalary/archives/queryInsuranceTabTotal", params);

View File

@ -0,0 +1,87 @@
/*
* Author: 黎永顺
* name: 导入-步骤一
* Description:
* Date: 2023/8/11
*/
import React, { Component } from "react";
import { WeaLocaleProvider } from "ecCom";
import { Icon, message, Upload } from "antd";
const Dragger = Upload.Dragger;
const { getLabel } = WeaLocaleProvider;
class ImpStep1 extends Component {
constructor(props) {
super(props);
this.state = {
fileList: []
};
}
handleChange = (data) => {
const { fileList, file } = data;
if (file.response && typeof (file.response) != "undefined" && file.status !== "removed") message.success(getLabel(111, "上传成功"));
this.setState({ fileList: fileList.slice(-1) });
};
render() {
const { fileList } = this.state;
const dragger = {
accept: ".xlsx",
name: "file",
multiple: false,
action: "/api/doc/upload/uploadFile",
fileList,
onChange: this.handleChange
};
return (
<div className="weapp-batch-impsteps-picker-content-imp-step1">
{/* 导入选项 */}
{
this.props.importParams &&
<div className="weapp-salary-tb-border-bottom import-option">
<div>{getLabel(543201, "导入选项")}</div>
{this.props.importParams}
</div>
}
<div className="title">{getLabel(543202, "导入Excel")}</div>
<p className="draggerUploadWrapper">
<Dragger {...dragger}>
<div>
<p className="iconUpload"><Icon type="inbox"/></p>
<p className="uplaod-title">{getLabel(543203, "点击或将文件拖拽到此区域上传")}</p>
<p
className="uplaod-subTitle">{getLabel(543204, "支持单个或批量上传,严禁上传公司内部资料及其他违禁文件")}</p>
</div>
</Dragger>
</p>
<div className="bottom-border">
<div>{getLabel(27577, "操作步骤")}</div>
<p>
<span>{`1. ${getLabel(30907, "第一步")},${getLabel(543205, "请选择导出的Excel文件或")}`}</span>&nbsp;&nbsp;
<a href={this.props.link} className="weapp-salary-link"
target="_blank">{getLabel(543207, "点击这里下载模板")}</a>&nbsp;&nbsp;
{this.props.exportDataDom}
</p>
<p>{`2. ${getLabel(543211, "第二步")},${getLabel(543212, "请一定要确定Excel文档中的格式是模板中的格式")},${getLabel(543213, "没有被修改掉")}`}</p>
<p>{`3. ${getLabel(543216, "第三步")},${getLabel(543215, "选择填写好的Excel文档")},${getLabel(543214, "点击“下一步”按钮进行数据预览")}`}</p>
<p>
{`4. ${getLabel(543217, "第四步")},${getLabel(543218, "如果以上步骤和Excel文档正确的话")},${getLabel(543219, "导入成功会有提示")},${getLabel(543220, "数据会被正确导入")}${getLabel(543221, "如果有问题")},${getLabel(543222, "则会提示Excel文档的错误之处")}`}
</p>
</div>
<div className="description">
<div>{getLabel(543223, "Excel文件说明")}</div>
<p>{`1. ${getLabel(543224, "后缀名为xls或者xlsx")};`}</p>
<p>{`2. ${getLabel(543225, "数据请勿放在合并的单元格中")};`}</p>
<p><span>{`3. ${getLabel(543226, "账单月份格式必须为")}:YYYY-MM`}</span></p>
</div>
</div>
);
}
}
export default ImpStep1;

View File

@ -0,0 +1,49 @@
/*
* Author: 黎永顺
* name: 导入-步骤二
* Description:
* Date: 2023/9/5
*/
import React, { Component } from "react";
import { WeaTable } from "ecCom";
import { postFetch } from "../../../util/request";
class ImpStep2 extends Component {
constructor(props) {
super(props);
this.state = {
loading: false, columns: [], dataSource: []
};
}
componentDidMount() {
this.init();
}
init = () => {
const { previewUrl, imageId } = this.props;
const payload = { imageId };
this.setState({ loading: true });
postFetch(previewUrl, payload).then(({ status, data }) => {
this.setState({ loading: false });
if (status) {
const { headers, list } = data;
this.setState({
columns: _.map(headers, (item, index) => ({ title: item, dataIndex: index + "", width: 120 })),
dataSource: _.map(list, item => {
return _.reduce(item, (pre, cur, key) => (_.assign(pre, { [key]: cur })), {});
})
});
}
}).catch(() => this.setState({ loading: false }));
};
render() {
const { dataSource, columns, loading } = this.state;
return (
<WeaTable dataSource={dataSource} columns={columns} pagination={false} loading={loading} scroll={{ x: 800 }}/>
);
}
}
export default ImpStep2;

View File

@ -0,0 +1,51 @@
/*
* Author: 黎永顺
* name: 导入-步骤3
* Description:
* Date: 2023/8/11
*/
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTable } from "ecCom";
import successImg from "../../importModal/success.svg";
const getLabel = WeaLocaleProvider.getLabel;
class ImpStep3 extends Component {
render() {
const { importResult } = this.props;
return (
<div className="weapp-batch-impsteps-picker-content-imp-step3">
{
!_.isEmpty(importResult) ?
<div className="weapp-batch-impsteps-picker-spinText">
<p><img src={successImg} alt=""/></p>
<p>
<span>{getLabel(389249, "已导入")}</span>
<span style={{ color: "green" }}> {importResult.successCount}</span>&nbsp;&nbsp;
<span>{`${getLabel(30690, "条数据")},${getLabel(25009, "失败")}`}</span>
<span style={{ color: "red" }}> {importResult.errorCount}&nbsp;&nbsp;</span>{getLabel(30690, "")}
</p>
</div> :
<div className="weapp-batch-impsteps-picker-spinText">
<p>{getLabel(111, "导入失败")}</p>
</div>
}
{
!_.isEmpty(importResult.errorData) &&
<WeaTable
columns={[
{
title: getLabel(25700, "错误信息"),
dataIndex: "message"
}
]}
dataSource={importResult.errorData} pagination={false}
scroll={{ y: `calc(100vh - 387px)` }}
/>
}
</div>
);
}
}
export default ImpStep3;

View File

@ -0,0 +1,153 @@
/*
* Author: 黎永顺
* name: 导入弹框-步骤条
* Description:
* Date: 2023/8/11
*/
import React, { Component } from "react";
import { Button, message, Modal } from "antd";
import { WeaDialog, WeaLocaleProvider, WeaSteps } from "ecCom";
import ImpStep1 from "./components/impStep1";
import ImpStep2 from "./components/impStep2";
import ImpStep3 from "./components/impStep3";
import "./index.less";
const { getLabel } = WeaLocaleProvider;
const Step = WeaSteps.Step;
class Index extends Component {
constructor(props) {
super(props);
this.state = {
current: 0
};
}
componentWillReceiveProps(nextProps, nextContext) {
if (JSON.stringify(nextProps.importResult) !== JSON.stringify(this.props.importResult) && !_.isEmpty(nextProps.importResult)) {
this.setState({
current: this.state.current + 1
});
}
if (nextProps.visible !== this.props.visible && !nextProps.visible) this.setState({ current: 0 });
}
renderChildren = () => {
const { current } = this.state;
const { importParams, link, excludeKey, importResult, exportDataDom = null } = this.props;
let CurrentDom = null;
switch (current) {
case 0:
CurrentDom = <ImpStep1 importParams={importParams} link={link} exportDataDom={exportDataDom}
ref={dom => this.step1Ref = dom}/>;
break;
case 1:
CurrentDom = <ImpStep2 {...this.props}/>;
if (excludeKey) {
CurrentDom = <ImpStep3 importResult={importResult}/>;
}
break;
case 2:
CurrentDom = <ImpStep3 importResult={importResult}/>;
break;
default:
CurrentDom = null;
break;
}
return CurrentDom;
};
/*
* Author: 黎永顺
* Description: 上一步
* Params:
* Date: 2023/9/5
*/
handlePreviousStep = () => {
Modal.confirm({
title: getLabel(131329, "信息确认"),
content: getLabel(111, "是否放弃已上传的文件?"),
onOk: () => this.setState({ current: this.state.current - 1 }, () => this.props.onResetImportResult())
});
};
/*
* Author: 黎永顺
* Description: 下一步
* Params:
* Date: 2023/8/11
*/
handleNext = () => {
const { params, importResult } = this.props;
if (_.isEmpty(importResult)) {
const { fileList } = this.step1Ref.state;
if (!_.isEmpty(params)) {
if (!Object.values(params).every(o => !!o)) {
Modal.warning({
title: getLabel(131329, "信息确认"),
content: getLabel(518702, "必要信息不完整,红色*为必填项!")
});
return;
}
}
if (_.isEmpty(fileList)) {
message.warning(getLabel(111, "请先上传EXCEL文件"));
return;
}
const [file] = fileList;
const { response } = file;
this.props.nextCallback(response.data.fileid);
} else {
this.setState({ current: this.state.current + 1 });
}
};
render() {
const { current } = this.state;
const stepData = [
{ key: 0, label: getLabel(543202, "上传EXCEL") },
{ key: 1, label: getLabel(543200, "数据预览") },
{ key: 2, label: getLabel(502835, "导入数据") }
];
const btns = [
<Button type="ghost" onClick={this.handlePreviousStep}>{getLabel(1876, "上一步")}</Button>,
<Button type="primary" onClick={this.handleNext}
loading={this.props.nextloading}>{getLabel(1402, "下一步")}</Button>,
<Button type="primary" onClick={() => this.props.onCancel(true)}>{getLabel(555, "完成")}</Button>
];
return (
<WeaDialog
{...this.props}
scalable hasScroll className="importBox" initLoadCss
buttons={current === 0 ? _.nth(btns, 1) : (!this.props.excludeKey && current === 1) ? _.take(btns, 2) : _.takeRight(btns)}
style={{
width: 800,
height: 606.6,
minHeight: 200,
minWidth: 380,
maxHeight: "90%",
maxWidth: "90%",
overflow: "hidden",
transform: "translate(0px, 0px)"
}}
>
<div className="importCont">
<div className="weapp-batch-impsteps-picker-content-imp-steps">
<WeaSteps current={current}>
{/*this.props.key: 不需要展示的步骤*/}
{
_.map(_.filter(stepData, item => item.key !== this.props.excludeKey), it => (
<Step key={it.key} description={it.label}/>))
}
</WeaSteps>
</div>
<div className="weapp-batch-impsteps-picker">
{
this.renderChildren()
}
</div>
</div>
</WeaDialog>
);
}
}
export default Index;

View File

@ -0,0 +1,143 @@
.importBox {
.importCont {
padding: 16px 8px;
.weapp-batch-impsteps-picker-content-imp-steps {
width: 80%;
margin: 0 auto;
}
.weapp-batch-impsteps-picker {
margin: 16px auto;
.weapp-batch-impsteps-picker-content-imp-step1 {
width: 98%;
background-color: #fff;
margin: 8px auto;
border-radius: 3px;
padding: 1px 12px;
.weapp-batch-impsteps-picker-content-imp-step1 div {
color: #111;
line-height: 22px;
}
.weapp-salary-tb-border-bottom .weapp-salary-tb-filter.weapp-salary-import-param {
box-sizing: border-box;
padding: 16px;
height: auto;
flex-wrap: wrap;
width: 100%;
}
.weapp-salary-import-param {
border: 1px solid #ebedf0;
padding: 8px;
margin: 4px 0 14px;
}
.weapp-salary-tb-filter {
display: flex;
flex-wrap: wrap;
align-items: center;
height: 46px;
}
.weapp-salary-tb-border-bottom .weapp-salary-tb-filter.weapp-salary-import-param .tbf-item {
display: flex;
justify-content: flex-start !important;
}
.weapp-salary-tb-filter .tbf-item {
padding: 0 20px 0 0;
display: flex;
align-items: center;
font-size: 12px;
color: #111;
height: 40px;
}
.weapp-salary-tb-filter .tbf-item > .tbfi-label {
flex-basis: 100px;
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 10px;
color: #666;
}
.draggerUploadWrapper {
margin: 16px 0 0;
.ant-upload-drag-container {
padding: 24px 0 16px;
.iconUpload {
i {
color: #5d9cec;
font-size: 43px;
}
}
.uplaod-title {
font-size: 14px;
color: #333;
height: 24px;
line-height: 24px;
margin-top: 8px;
}
.uplaod-subTitle {
height: 22px;
font-size: 12px;
color: #666;
text-align: center;
line-height: 22px;
}
}
}
.bottom-border, .description {
margin-top: 12px;
p {
font-size: 12px;
color: #666;
line-height: 15px;
margin: 12px 0;
}
}
.bottom-border {
border-bottom: 1px solid #e5e5e5;
.weapp-salary-link {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #5d9cec;
}
}
}
}
.weapp-batch-impsteps-picker-content-imp-step3 {
.weapp-batch-impsteps-picker-spinText {
position: relative;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
text-align: center;
p {
margin: 14px 0;
}
}
}
}
}

View File

@ -26,5 +26,12 @@ export const tabCondition = [
showcount: true,
title: "停缴员工",
viewcondition: "stop"
}
},
{
color: "#000000",
groupid: "ext",
showcount: true,
title: "非系统人员",
viewcondition: "ext"
},
];

View File

@ -2,7 +2,7 @@ import React from "react";
import { inject, observer } from "mobx-react";
import { toJS } from "mobx";
import { Button, Dropdown, Menu, message, Modal, Popover } from "antd";
import { WeaHelpfulTip, WeaLocaleProvider, WeaNewScroll, WeaSlideModal, WeaTab, WeaTop } from "ecCom";
import { WeaCheckbox, WeaHelpfulTip, WeaLocaleProvider, WeaNewScroll, WeaSlideModal, WeaTab, WeaTop } from "ecCom";
import { getSearchs, renderLoading } from "../../../util";
import BaseForm from "./baseForm";
import SlideModalTitle from "../../../components/slideModalTitle";
@ -14,11 +14,16 @@ import * as API from "../../../apis/welfareArchive";
import ImportModal from "../../../components/importModal";
import TipLabel from "../../../components/TipLabel";
import UnifiedTable from "../../../components/UnifiedTable";
import { convertToUrlString } from "../../../util/url";
import { convertToUrlString, getURLParameters } from "../../../util/url";
import { salaryArchiveDelete } from "../../../apis/payrollFiles";
import ImportDialog from "../../../components/importDialog";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
const APILIST = {
runStatuses: API["queryList"],
extWelArchiveList: API["getExtTable"]
};
@inject("archivesStore", "taxAgentStore")
@observer
export default class Archives extends React.Component {
@ -46,14 +51,20 @@ export default class Archives extends React.Component {
stayAdd: 0,
paying: 0,
stayDel: 0,
stopPay: 0
stopPay: 0,
ext: 0
},
pageInfo: {
current: 1,
pageSize: 10,
total: 0
},
salaryArchiveDelete: "" //待定薪、停薪员工 是否允许删除薪资档案 0 否, 1
salaryArchiveDelete: "", //待定薪、停薪员工 是否允许删除薪资档案 0 否, 1
importDialog: {
visible: false, title: "", nextloading: false,
link: "", importResult: {}, imageId: "",
previewUrl: "/api/bs/hrmsalary/scheme/preview"
}
};
this.record = {};
}
@ -78,7 +89,7 @@ export default class Archives extends React.Component {
const formParams = form.getFormParams() || {};
const payload = { ...pageInfo };
this.setState({ loading: { ...loading, query: true } });
API.queryList({ ...formParams, ...payload, ...params }).then(({ data, status }) => {
APILIST[_.keys(params)[0]]({ ...formParams, ...payload, ...params }).then(({ data, status }) => {
this.setState({ loading: { ...loading, query: false } });
if (status) {
const { pageInfo: paganition, columns, datas: dataSource } = data;
@ -309,8 +320,19 @@ export default class Archives extends React.Component {
// 导入
handleImport = (params) => {
const { archivesStore: { importBatch } } = this.props;
const { runStatus } = this.state;
importBatch({ ...params, runStatus });
const { runStatus, importDialog } = this.state;
this.setState(({
importDialog: {
...importDialog, nextloading: true, ...params
}
}));
importBatch({ ...params, runStatus }).then(({ status, data }) => {
this.setState(({
importDialog: {
...importDialog, nextloading: false, importResult: data, ...params
}
}));
});
};
// 导入完成
@ -375,9 +397,12 @@ export default class Archives extends React.Component {
case "suspend":
this.queryList({ runStatuses: ["3"] });
break;
default:
case "stop":
this.queryList({ runStatuses: ["4", "5"] });
break;
default:
this.queryList({ extWelArchiveList: true });
break;
}
};
handleMenuBtnClick = () => {
@ -564,13 +589,15 @@ export default class Archives extends React.Component {
{/*<div>4、数据进入【待减员】规则的第四种情况下若还需要在当前个税扣缴义务人下进行缴纳的话当前该员工的【待减员】数据进行【删除待办】操作即可若不在该个税扣缴义务人下继续缴纳维护好最后缴纳月后进行【减员】操作员工进入【停缴员工】</div>*/}
</div>;
break;
default:
case "stop":
dom = <div>
<div>1不需要缴纳社保福利的员工保存在停缴员工</div>
{/*<div>2、【停缴员工】点击取消停缴数据会回退到上次的位置从【待减员】减员到停缴员工的点击停缴返回到【在缴员工】不返回到【待减员】</div>*/}
{/*<div>3、若员工的社保福利从一个个税扣缴义务人下转到另一个个税扣缴义务人下去缴纳则在转后的个税扣缴义务人的【待增员】中进行增员操作成功后员工进入待【在缴员工】而在原个税扣缴义务人下的【停缴员工】中该员工数据将会被删除是否开启分权员工的档案数据都只保存一份</div>*/}
</div>;
break;
default:
break;
}
return dom;
};
@ -584,7 +611,8 @@ export default class Archives extends React.Component {
dataSource: dataSourceActive,
pageInfo,
tabCount,
loading
loading,
importDialog
} = this.state;
const {
form, condition, showSearchAd, setShowSearchAd,
@ -719,7 +747,7 @@ export default class Archives extends React.Component {
} type="ghost">
导出全部
</Dropdown.Button>
] : [
] : selectedKey === "stop" ? [
<WeaHelpfulTip
width={300}
title={<CancelHelpfulDiv/>}
@ -733,6 +761,15 @@ export default class Archives extends React.Component {
} type="ghost">
导出全部
</Dropdown.Button>
] : [<Button type="primary"
onClick={() => this.setState(({
runStatus: "2",
importDialog: {
...importDialog,
visible: true, title: getLabel(111, "非系统人员导入"),
link: "/api/bs/hrmsalary/scheme/template/export?extWelArchiveList=true"
}
}))}>导入</Button>
];
const pagination = {
@ -775,6 +812,7 @@ export default class Archives extends React.Component {
keyParam="viewcondition" //主键
selectedKey={selectedKey}
onChange={this.handleChangeTab}
autoCalculateWidth
searchType={["base", "advanced"]} // base基础搜索框 advanced显示高级搜索按钮
showSearchAd={showSearchAd} // 是否展开高级搜索面板
setShowSearchAd={bool => setShowSearchAd(bool)} //高级搜索面板受控
@ -807,7 +845,7 @@ export default class Archives extends React.Component {
xWidth={this.getColumns().length * 120}
/>
{
!_.isEmpty(this.getColumns()) &&
!_.isEmpty(this.getColumns()) && selectedKey !== "ext" &&
<TipLabel>{this.getTipChildren()}</TipLabel>
}
</WeaNewScroll>
@ -878,6 +916,36 @@ export default class Archives extends React.Component {
this.setState({ selectedTab: "0" });
})}/>
}
<ImportDialog
{...importDialog}
onCancel={(isFresh) => this.setState({
importDialog: {
...importDialog,
visible: false, title: "", nextloading: false,
link: "", importResult: {}, imageId: ""
}
}, () => isFresh && this.query())}
onResetImportResult={() => this.setState(({
importDialog: { ...importDialog, importResult: {}, imageId: "" }
}))}
exportDataDom={
<WeaCheckbox content={getLabel(543208, "导出现有数据")}
value={getURLParameters(importDialog.link).exportData === "true" ? "1" : "0"}
helpfulTip={getLabel(111, "提示:建议先导出现有最新数据,修改后再导入")}
onChange={val => {
const formParams = form.getFormParams() || {};
const payload = { exportData: val === "1", ...formParams };
this.setState(({
importDialog: {
...importDialog,
link: `/api/bs/hrmsalary/scheme/template/export?extWelArchiveList=true&${convertToUrlString(payload)}`
}
}));
}}
/>
}
nextCallback={imageId => this.handleImport({ imageId })}
/>
{
this.state.importVisible && <ImportModal
init={() => {

View File

@ -4,10 +4,6 @@
height: 100%;
background: #f6f6f6;
.wea-new-top-req-wapper .wea-new-top-req-main {
background: #f6f6f6 !important;
}
.wea-new-top-req-wapper .wea-new-top-req {
z-index: 0 !important;
}

View File

@ -336,7 +336,7 @@ export class ArchivesStore {
API.importBatch(params).then(res => {
if (res.status) {
this.importResult = res.data;
resolve();
resolve(res);
} else {
message.error(res.errormsg || "导入失败", 1);
reject();

View File

@ -1,11 +1,10 @@
// export const getQueryString = (name) => {
// let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
// let r = window.location.hash.split("?")[1].match(reg);
// if (r != null) {
// return decodeURIComponent(r[2]);
// };
// return null;
// }
export const getURLParameters = (url) =>
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => (
(a[v.slice(0, v.indexOf("="))] = v.slice(v.indexOf("=") + 1)), a
),
{}
);
export const getQueryString = (variable) => {
let split = window.location.hash.split("?");