515 lines
19 KiB
JavaScript
515 lines
19 KiB
JavaScript
/*
|
|
* Author: 黎永顺
|
|
* name: 统计数据范围及规则设置
|
|
* Description:
|
|
* Date: 2023/4/21
|
|
*/
|
|
import React, { Component } from "react";
|
|
import {
|
|
WeaButtonIcon,
|
|
WeaDatePicker,
|
|
WeaError,
|
|
WeaFormItem,
|
|
WeaHelpfulTip,
|
|
WeaLocaleProvider,
|
|
WeaSearchGroup,
|
|
WeaSelect,
|
|
WeaSlideModal,
|
|
WeaTable,
|
|
WeaTools
|
|
} from "ecCom";
|
|
import CustomStatisticsItemsModal from "./customStatisticsItemsModal";
|
|
import moment from "moment";
|
|
import { Button, message, Modal } from "antd";
|
|
import { getSearchs } from "../../../util";
|
|
import {
|
|
deleteRangeSetting,
|
|
reportStatisticsGetSearchCondition,
|
|
reportStatisticsItemDelete,
|
|
reportStatisticsSaveSearchCondition,
|
|
statisticsItemList
|
|
} from "../../../apis/statistics";
|
|
import { commonEnumList } from "../../../apis/ruleconfig";
|
|
import { postFetch } from "../../../util/request";
|
|
import { condition } from "./condition";
|
|
import cs from "classnames";
|
|
import "../index.less";
|
|
|
|
const getKey = WeaTools.getKey;
|
|
const { getLabel } = WeaLocaleProvider;
|
|
|
|
class StatisticalMicroSettingsSlide extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
loading: false,
|
|
selectedRowKeys: [],
|
|
conditions: [],
|
|
dataSource: [],
|
|
unitTypeList: [],
|
|
salaryMonth: [],
|
|
timeType: 10,
|
|
statisticalItemPayload: {
|
|
visible: false, id: "", dimension: "",
|
|
statisticsItemId: "", isShare: false
|
|
}
|
|
};
|
|
}
|
|
|
|
componentWillReceiveProps(nextProps, nextContext) {
|
|
if (nextProps.visible !== this.props.visible && nextProps.visible) this.getTaxAgentSelectList(nextProps);
|
|
if (nextProps.id !== this.props.id && !_.isEmpty(nextProps.id)) {
|
|
this.statisticsItemList(nextProps.id).then(r => {
|
|
});
|
|
}
|
|
if (nextProps.visible !== this.props.visible && !nextProps.visible) {
|
|
nextProps.form.resetForm();
|
|
this.setState({ selectedRowKeys: [] });
|
|
}
|
|
}
|
|
|
|
getTaxAgentSelectList = async (props) => {
|
|
const [salarySobList, empStatusList] = await Promise.all([
|
|
postFetch("/api/bs/hrmsalary/salarysob/listAuth", { filterType: "QUERY_DATA", isShare: props.isShare }),
|
|
commonEnumList({ enumClass: "com.engine.salary.enums.salarysob.SalaryEmployeeStatusEnum" })
|
|
]);
|
|
postFetch("/api/bs/hrmsalary/taxAgent/listAuth", { filterType: "QUERY_DATA", isShare: props.isShare })
|
|
.then(({ status, data }) => {
|
|
if (status) {
|
|
const conditions = _.map(condition, item => {
|
|
return {
|
|
...item,
|
|
items: _.map(item.items, child => {
|
|
if (getKey(child) === "taxAgent") {
|
|
return {
|
|
...child, viewAttr: props.isShare ? 1 : child.viewAttr,
|
|
options: _.map(data, o => ({ key: String(o.id), showname: o.name }))
|
|
};
|
|
} else if (getKey(child) === "salarySob") {
|
|
return {
|
|
...child, viewAttr: props.isShare ? 1 : child.viewAttr,
|
|
options: _.map(salarySobList.data, o => ({ key: String(o.id), showname: o.name }))
|
|
};
|
|
} else if (getKey(child) === "status") {
|
|
return {
|
|
...child, viewAttr: props.isShare ? 1 : child.viewAttr,
|
|
options: _.map(empStatusList.data, o => ({ key: o.value.toString(), showname: o.defaultLabel }))
|
|
};
|
|
}
|
|
return { ...child, viewAttr: props.isShare ? 1 : child.viewAttr };
|
|
})
|
|
};
|
|
});
|
|
this.setState({ conditions }, () => {
|
|
props.form.initFormFields(this.state.conditions);
|
|
props.id && this.reportStatisticsGetSearchCondition(props.id);
|
|
});
|
|
|
|
}
|
|
});
|
|
};
|
|
reportStatisticsGetSearchCondition = (id) => {
|
|
const { conditions } = this.state;
|
|
const { form } = this.props;
|
|
reportStatisticsGetSearchCondition({ id }).then(({ status, data }) => {
|
|
if (status && !_.isEmpty(data)) {
|
|
const { salaryEndMonth, salaryStartMonth, timeType, ...formData } = data.data;
|
|
this.setState({
|
|
timeType,
|
|
salaryMonth: [salaryStartMonth || moment().startOf("year").format("YYYY-MM"), salaryEndMonth || moment().format("YYYY-MM")]
|
|
});
|
|
const fields = _.map(conditions[0].items, it => it.domkey[0]);
|
|
fields.map(item => {
|
|
const value = item.indexOf("hiredate") !== -1 ? {
|
|
value: formData["hiredate"] || []
|
|
} : {
|
|
value: !_.isNil(formData[item]) ? _.map(formData[item], val => val.id).join(",") : "",
|
|
valueSpan: !_.isNil(formData[item]) ? _.map(formData[item], val => val.name).join(",") : "",
|
|
valueObj: !_.isNil(formData[item]) ? formData[item] : []
|
|
};
|
|
const key = item.indexOf("hiredate") !== -1 ? "hiredate1__hiredate2" : item;
|
|
form.updateFields({
|
|
[key]: value
|
|
});
|
|
});
|
|
}
|
|
});
|
|
};
|
|
reportStatisticsSaveSearchCondition = () => {
|
|
const { salaryMonth, timeType, dataSource } = this.state;
|
|
const { form, id, dimension, onClose } = this.props;
|
|
const [salaryStartMonth, salaryEndMonth] = salaryMonth;
|
|
const { department, employee, position, subCompany, taxAgent, salarySob, status, ...extra } = form.getFormDatas();
|
|
const { value, valueSpan } = taxAgent;
|
|
const { value: statusVal, valueSpan: statusValSpan } = status;
|
|
const { value: sobValue, valueSpan: sobValueSpan } = salarySob;
|
|
if (!salaryEndMonth || !salaryStartMonth) {
|
|
this.refs.weaError.showError();
|
|
return;
|
|
}
|
|
const payload = {
|
|
dimension, id, timeType,
|
|
hiredate: extra["hiredate1__hiredate2"].value || [],
|
|
department: _.map(department.valueObj, it => ({ id: it.id, name: it.name })),
|
|
employee: _.map(employee.valueObj, it => ({ id: it.id, name: it.name })),
|
|
position: _.map(position.valueObj, it => ({ id: it.id, name: it.name })),
|
|
subCompany: _.map(subCompany.valueObj, it => ({ id: it.id, name: it.name })),
|
|
taxAgent: value ? _.map(value.split(","), (it, idx) => ({ id: it, name: valueSpan.split(",")[idx] })) : [],
|
|
status: statusVal ? _.map(statusVal.split(","), (it, idx) => ({
|
|
id: it,
|
|
name: statusValSpan.split(",")[idx]
|
|
})) : [],
|
|
salarySob: sobValue ? _.map(sobValue.split(","), (it, idx) => ({
|
|
id: it,
|
|
name: sobValueSpan.split(",")[idx]
|
|
})) : [],
|
|
items: dataSource,
|
|
salaryEndMonth: salaryEndMonth + "-01",
|
|
salaryStartMonth: salaryStartMonth + "-01"
|
|
};
|
|
this.setState({ loading: true });
|
|
reportStatisticsSaveSearchCondition(payload).then(({ status, errormsg }) => {
|
|
this.setState({ loading: false });
|
|
if (status) {
|
|
onClose(true);
|
|
message.success(getLabel(111, "保存成功"));
|
|
} else {
|
|
message.error(errormsg);
|
|
}
|
|
}).catch(() => this.setState({ loading: false }));
|
|
};
|
|
reportStatisticsItemDelete = () => {
|
|
Modal.confirm({
|
|
title: getLabel(111, "信息确认"),
|
|
content: getLabel(111, "确认要删除吗?"),
|
|
onOk: () => {
|
|
const { selectedRowKeys } = this.state;
|
|
reportStatisticsItemDelete(selectedRowKeys).then(({ status, errormsg }) => {
|
|
if (status) {
|
|
message.success(getLabel(111, "删除成功"));
|
|
this.setState({
|
|
selectedRowKeys: []
|
|
}, () => {
|
|
this.statisticsItemList(this.props.id).then(r => {
|
|
deleteRangeSetting({ reportId: this.props.id });
|
|
});
|
|
});
|
|
} else {
|
|
message.error(errormsg || getLabel(111, "删除失败"));
|
|
}
|
|
});
|
|
}
|
|
});
|
|
};
|
|
statisticsItemList = async (statisticsReportId = "") => {
|
|
const { data: unitTypeList } = await this.commonEnumList();
|
|
statisticsItemList({ statisticsReportId }).then(({ status, data }) => {
|
|
if (status) {
|
|
this.setState({
|
|
dataSource: data,
|
|
unitTypeList: _.map(unitTypeList, it => ({ key: it.value.toString(), showname: it.defaultLabel }))
|
|
});
|
|
}
|
|
});
|
|
};
|
|
commonEnumList = () => {
|
|
const payload = {
|
|
enumClass: "com.engine.salary.report.enums.UnitTypeEnum"
|
|
};
|
|
return commonEnumList(payload);
|
|
};
|
|
renderGroupTitle = () => {
|
|
return <div className="groupTitleWrapper">
|
|
<span>{getLabel(111, "统计数据范围")}</span>
|
|
<span>{getLabel(111, "统计满足以下所有条件的人员薪资核算数据,不选则默认为选择全部")}</span>
|
|
</div>;
|
|
};
|
|
renderProjectTitle = () => {
|
|
const { selectedRowKeys } = this.state;
|
|
const { id, dimension, isShare } = this.props;
|
|
return <div className="groupPorjectTitleWrapper">
|
|
<div>
|
|
<span>{getLabel(111, "统计项目")}</span>
|
|
<WeaHelpfulTip width={200} placement="topLeft"
|
|
title={getLabel(111, "统计列表的统计项排序与本列表统计项的顺序一致")}
|
|
/>
|
|
</div>
|
|
<div>
|
|
{
|
|
!isShare &&
|
|
<WeaButtonIcon
|
|
buttonType="del" type="primary" disabled={_.isEmpty(selectedRowKeys)}
|
|
onClick={this.reportStatisticsItemDelete}
|
|
/>
|
|
}
|
|
{
|
|
!isShare &&
|
|
<WeaButtonIcon
|
|
buttonType="add" type="primary"
|
|
onClick={() => this.setState({
|
|
statisticalItemPayload: {
|
|
visible: true, id, dimension,
|
|
statisticsItemId: "", isShare
|
|
}
|
|
})}
|
|
/>
|
|
}
|
|
</div>
|
|
</div>;
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
salaryMonth, conditions, selectedRowKeys, loading,
|
|
statisticalItemPayload, dataSource, unitTypeList, timeType
|
|
} = this.state;
|
|
const { id, dimension, isShare } = this.props;
|
|
const columns = [
|
|
{
|
|
title: "统计项名称",
|
|
dataIndex: "itemName",
|
|
render: (txt, record) => {
|
|
return (
|
|
<a href="javascript: void(0);" onClick={() => {
|
|
this.setState({
|
|
statisticalItemPayload: { visible: true, id, dimension, statisticsItemId: record.id, isShare }
|
|
});
|
|
}}>{txt}</a>
|
|
);
|
|
}
|
|
},
|
|
{
|
|
title: "统计单位",
|
|
dataIndex: "unitType",
|
|
render: (txt, record) => {
|
|
return <WeaSelect
|
|
value={!_.isNil(txt) ? txt.toString() : ""} options={unitTypeList} style={{ width: 150 }} disabled={isShare}
|
|
onChange={unitType => this.customStatisticsItemsRef.reportStatisticsItemSave({ id: record.id, unitType })}
|
|
/>;
|
|
}
|
|
}
|
|
];
|
|
const rowSelection = {
|
|
selectedRowKeys,
|
|
onChange: (selectedRowKeys) => {
|
|
this.setState({ selectedRowKeys });
|
|
},
|
|
getCheckboxProps: record => ({
|
|
disabled: isShare
|
|
})
|
|
};
|
|
return (
|
|
<WeaSlideModal
|
|
className="microSlideWrapper"
|
|
{...this.props}
|
|
onClose={() => this.props.onClose()}
|
|
top={0}
|
|
measureT="%"
|
|
width={800}
|
|
measureX="px"
|
|
height={100}
|
|
measureY="%"
|
|
direction={"right"}
|
|
title={<TitleDialog loading={loading} isShare={isShare} onSave={this.reportStatisticsSaveSearchCondition}/>}
|
|
content={
|
|
<React.Fragment>
|
|
<WeaSearchGroup title={getLabel(111, "统计时间范围")} col={2} showGroup needTigger>
|
|
<WeaFormItem label={getLabel(111, "薪资所属月")} labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}>
|
|
<WeaError tipPosition="bottom" ref="weaError" error={getLabel(111, "此项必填")}>
|
|
<StatisticalScopePicker viewAttr={3} dateRange={salaryMonth} disabled={isShare} timeType={timeType}
|
|
onChange={(v, timeType) => this.setState({ salaryMonth: v, timeType })}/>
|
|
</WeaError>
|
|
</WeaFormItem>
|
|
</WeaSearchGroup>
|
|
{
|
|
getSearchs(this.props.form, conditions, 2, false, () => {
|
|
}, this.renderGroupTitle())
|
|
}
|
|
<WeaSearchGroup title={this.renderProjectTitle()} showGroup needTigger>
|
|
<WeaTable
|
|
rowKey="id"
|
|
columns={columns}
|
|
dataSource={dataSource}
|
|
draggable={true}
|
|
onDrop={datas => this.setState({
|
|
dataSource: _.map(datas, (it, idx) => ({ ...it, indexValue: idx.toString() }))
|
|
})}
|
|
pagination={false}
|
|
rowSelection={rowSelection}
|
|
/>
|
|
<CustomStatisticsItemsModal
|
|
ref={dom => this.customStatisticsItemsRef = dom}
|
|
{...statisticalItemPayload}
|
|
onCancel={(isRefresh) => this.setState({
|
|
statisticalItemPayload: {
|
|
visible: false, id: "", dimension: "",
|
|
statisticsItemId: "", isShare: false
|
|
}
|
|
}, () => isRefresh && this.statisticsItemList(this.props.id))}
|
|
/>
|
|
</WeaSearchGroup>
|
|
</React.Fragment>
|
|
}
|
|
/>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default StatisticalMicroSettingsSlide;
|
|
const TitleDialog = (props) => {
|
|
return <div className="titleDialog">
|
|
<div className="titleCol">
|
|
<div className="titleLeftBox">
|
|
<div className="titleIcon"><i className="icon-coms-fa"/></div>
|
|
<div className="title">{getLabel(111, "统计数据范围及规则设置")}</div>
|
|
</div>
|
|
</div>
|
|
<div className="titleCol titleRightBox">
|
|
{
|
|
!props.isShare &&
|
|
<Button type="primary" loading={props.loading} onClick={props.onSave}>{getLabel(111, "保存")}</Button>
|
|
}
|
|
</div>
|
|
</div>;
|
|
};
|
|
const StatisticalScopePicker = (props) => {
|
|
const scopeBtns = [
|
|
{ key: 1, label: getLabel(111, "上月") },
|
|
{ key: 2, label: getLabel(111, "本月") },
|
|
{ key: 3, label: getLabel(111, "一季度") },
|
|
{ key: 4, label: getLabel(111, "二季度") },
|
|
{ key: 5, label: getLabel(111, "三季度") },
|
|
{ key: 6, label: getLabel(111, "四季度") },
|
|
{ key: 7, label: getLabel(111, "上半年") },
|
|
{ key: 8, label: getLabel(111, "下半年") },
|
|
{ key: 9, label: getLabel(111, "本年") }
|
|
];
|
|
const { timeType, dateRange, onChange, viewAttr, disabled = false } = props;
|
|
const [startDate, endDate] = dateRange || [];
|
|
return <div className="date-set-area">
|
|
<div className="date-item">
|
|
{
|
|
_.map(scopeBtns.slice(0, 2), o => (
|
|
<Button type={timeType === o.key ? "primary" : "ghost"} disabled={disabled}
|
|
onClick={() => onChange(getSalaryMonthValue(o.key), o.key)}>{o.label}</Button>))
|
|
}
|
|
</div>
|
|
<div className="date-item">
|
|
{
|
|
_.map(scopeBtns.slice(2, 6), o => (
|
|
<Button type={timeType === o.key ? "primary" : "ghost"} disabled={disabled}
|
|
onClick={() => onChange(getSalaryMonthValue(o.key), o.key)}>{o.label}</Button>))
|
|
}
|
|
</div>
|
|
<div className="date-item">
|
|
{
|
|
_.map(scopeBtns.slice(6), o => (
|
|
<Button type={timeType === o.key ? "primary" : "ghost"} disabled={disabled}
|
|
onClick={() => onChange(getSalaryMonthValue(o.key), o.key)}>{o.label}</Button>))
|
|
}
|
|
</div>
|
|
<div className="data-picker">
|
|
<span className="title" onClick={(val) => onChange([], 10)}>{getLabel(111, "指定月份")}</span>
|
|
<div
|
|
className={cs("rangePickerBox", { "hide-data-picker": timeType !== 10, "show-data-picker": timeType === 10 })}>
|
|
<WeaDatePicker
|
|
value={startDate} disabled={disabled}
|
|
disabledDate={(current) => {
|
|
if (!current || !endDate) return false;
|
|
const tooEarly = moment(current.getTime()).isBefore(moment(endDate).subtract(12, "month"));
|
|
const tooLate = moment(current.getTime()).isAfter(moment(endDate));
|
|
return !!tooEarly || !!tooLate;
|
|
}}
|
|
format="YYYY-MM"
|
|
onChange={(val) => onChange([val, endDate], timeType)}
|
|
viewAttr={viewAttr}
|
|
/>
|
|
<span className="to" style={{ margin: "0 10px" }}>至</span>
|
|
<WeaDatePicker
|
|
value={endDate} disabled={disabled}
|
|
disabledDate={(current) => {
|
|
if (!current || !startDate) return false;
|
|
const tooEarly = moment(current.getTime()).isAfter(moment(startDate).add(12, "month"));
|
|
const tooLate = moment(current.getTime()).isBefore(moment(startDate));
|
|
return !!tooEarly || !!tooLate;
|
|
}}
|
|
format="YYYY-MM"
|
|
viewAttr={viewAttr}
|
|
onChange={(val) => onChange([startDate, val], timeType)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>;
|
|
};
|
|
export const MonthRangePicker = (props) => {
|
|
const { dateRange, onChange, viewAttr, disabled = false } = props;
|
|
const [startDate, endDate] = dateRange || [];
|
|
return <div className="rangePickerBox">
|
|
<WeaDatePicker
|
|
value={startDate} disabled={disabled}
|
|
disabledDate={(current) => {
|
|
// 20251212前版本(问题时不能选到当月)
|
|
// return current && endDate && current.getTime() > new Date(endDate).getTime();
|
|
return current && endDate && moment(`${new Date(current.getTime()).getFullYear()}-${new Date(current.getTime()).getMonth() + 1}`).isAfter(moment(endDate));
|
|
}}
|
|
format="YYYY-MM"
|
|
onChange={(val) => onChange([val, endDate])}
|
|
viewAttr={viewAttr}
|
|
/>
|
|
<span className="to" style={{ margin: "0 10px" }}>至</span>
|
|
<WeaDatePicker
|
|
value={endDate} disabled={disabled}
|
|
disabledDate={(current) => {
|
|
return current && startDate && current.getTime() < new Date(startDate).getTime();
|
|
}}
|
|
format="YYYY-MM"
|
|
viewAttr={viewAttr}
|
|
onChange={(val) => onChange([startDate, val])}
|
|
/>
|
|
</div>;
|
|
};
|
|
// 获取所属月份值
|
|
export const getSalaryMonthValue = (dateType) => {
|
|
let start = "", end = "";
|
|
switch (dateType) {
|
|
case 1:
|
|
start = moment().add(-1, "month").startOf("month").format("YYYY-MM");
|
|
end = moment().add(-1, "month").endOf("month").format("YYYY-MM");
|
|
break;
|
|
case 2:
|
|
start = moment().startOf("month").format("YYYY-MM");
|
|
end = moment().endOf("month").format("YYYY-MM");
|
|
break;
|
|
case 3:
|
|
start = moment().year() + "-01";
|
|
end = moment().year() + "-03";
|
|
break;
|
|
case 4:
|
|
start = moment().year() + "-04";
|
|
end = moment().year() + "-06";
|
|
break;
|
|
case 5:
|
|
start = moment().year() + "-07";
|
|
end = moment().year() + "-09";
|
|
break;
|
|
case 6:
|
|
start = moment().year() + "-10";
|
|
end = moment().year() + "-12";
|
|
break;
|
|
case 7:
|
|
start = moment().startOf("year").format("YYYY-MM");
|
|
end = moment().endOf("year").subtract(6, "month").format("YYYY-MM");
|
|
break;
|
|
case 8:
|
|
start = moment().startOf("year").add(6, "month").format("YYYY-MM");
|
|
end = moment().endOf("year").format("YYYY-MM");
|
|
break;
|
|
case 9:
|
|
start = moment().startOf("year").format("YYYY-MM");
|
|
end = moment().endOf("year").format("YYYY-MM");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return [start, end];
|
|
}; |