feature/2.9.42309.01-薪资核算详情页面列表改造(页面编辑)
This commit is contained in:
parent
f5d42d8f75
commit
8a90d58196
|
|
@ -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>
|
||||
<a href={this.props.link} className="weapp-salary-link"
|
||||
target="_blank">{getLabel(543207, "点击这里下载模板")}</a>
|
||||
{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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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>
|
||||
<span>{`${getLabel(30690, "条数据")},${getLabel(25009, "失败")}`}</span>
|
||||
<span style={{ color: "red" }}> {importResult.errorCount} </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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import TaxAgent from "./pages/taxAgent";
|
|||
import CalculateDetail from "./pages/calculateDetail";
|
||||
import PlaceOnFileDetail from "./pages/calculateDetail/placeOnFileDetail";
|
||||
import CompareDetail from "./pages/calculateDetail/compareDetail";
|
||||
import DoCalcDetail from "./pages/calculate/doCalc";
|
||||
import GenerateDeclarationDetail from "./pages/declare/generateDeclarationDetail";
|
||||
import TemplatePreview from "./pages/payroll/templatePreview";
|
||||
import MobilePayroll from "./pages/mobilePayroll";
|
||||
|
|
@ -73,6 +74,7 @@ const DataAcquisition = (props) => props.children;
|
|||
// ledger 薪资账套
|
||||
// calculate 薪资核算
|
||||
// calculateDetail 核算详情
|
||||
// DoCalcDetail 新核算详情页面
|
||||
// placeOnFileDetail 核算归档详情
|
||||
// compareDetail 线下线上对比
|
||||
// payroll 工资单发放
|
||||
|
|
@ -130,6 +132,7 @@ const Routes = (
|
|||
<Route key="ledger" path="ledger" component={Ledger}/>
|
||||
<Route key="calculate" path="calculate" component={Calculate}/>
|
||||
<Route key="calculateDetail" path="calculateDetail" component={CalculateDetail}/>
|
||||
<Route key="doCalc" path="calculate/:salaryAcctRecordId" component={DoCalcDetail}/>
|
||||
<Route key="placeOnFileDetail" path="placeOnFileDetail" component={PlaceOnFileDetail}/>
|
||||
<Route key="compareDetail" path="compareDetail" component={CompareDetail}/>
|
||||
<Route key="payroll" path="payroll" component={Payroll}/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
import React, { Component } from "react";
|
||||
import { WeaInputSearch, WeaLocaleProvider } from "ecCom";
|
||||
import { Button } from "antd";
|
||||
import "./index.less";
|
||||
|
||||
const getLabel = WeaLocaleProvider.getLabel;
|
||||
|
||||
class Index extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="advance-search">
|
||||
<WeaInputSearch/>
|
||||
<Button type="ghost" className="wea-advanced-search text-elli">{getLabel(111, "高级搜索")}</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Index;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
.advance-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
top: -2.5px;
|
||||
|
||||
.wea-advanced-search {
|
||||
top: 2px;
|
||||
left: -1px;
|
||||
height: 28px;
|
||||
line-height: 1;
|
||||
border-radius: 0;
|
||||
position: relative;
|
||||
color: #474747;
|
||||
padding: 4px 15px;
|
||||
}
|
||||
|
||||
.wea-advanced-search:hover {
|
||||
border: 1px solid #dadada;
|
||||
color: #474747;
|
||||
}
|
||||
|
||||
.text-elli {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Author: 黎永顺
|
||||
* name: 人员信息确认-基础信息
|
||||
* Description:
|
||||
* Date: 2023/9/13
|
||||
*/
|
||||
import React, { Component } from "react";
|
||||
import { WeaHelpfulTip, WeaLocaleProvider, WeaSearchGroup } from "ecCom";
|
||||
import SalaryMonthTip from "../salaryMonthTip";
|
||||
import { getSalarySobCycle, salaryacctGetForm } from "../../../../../apis/calculate";
|
||||
import { Col, Row } from "antd";
|
||||
import "./index.less";
|
||||
|
||||
const getLabel = WeaLocaleProvider.getLabel;
|
||||
|
||||
class BaseInfo extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
salaryInfo: {}, salarySobCycle: {}
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const promise = this.init();
|
||||
}
|
||||
|
||||
init = async () => {
|
||||
const { routeParams: { salaryAcctRecordId } } = this.props;
|
||||
const [salaryInfo, salarySobCycle] = await Promise.all([salaryacctGetForm({ id: salaryAcctRecordId }), getSalarySobCycle({ salaryAcctRecordId })]);
|
||||
if (salaryInfo.status && salarySobCycle.status) {
|
||||
this.setState({
|
||||
salaryInfo: salaryInfo.data, salarySobCycle: salarySobCycle.data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { salaryInfo, salarySobCycle } = this.state;
|
||||
const { formDTO } = salaryInfo || {};
|
||||
return (
|
||||
<WeaSearchGroup title={getLabel(82743, "基础信息")} needTigger showGroup className="docalc-baseinfo-layout">
|
||||
<Row type="flex" className="docalc-baseinfo">
|
||||
<Col span={12}>
|
||||
<Row>
|
||||
<Col span={6}>
|
||||
<span className="label">{getLabel(542604, "薪资所属月")}</span>
|
||||
<WeaHelpfulTip
|
||||
width={200} placement="topLeft"
|
||||
title={<SalaryMonthTip {...salarySobCycle}/>}
|
||||
style={{ marginLeft: 10 }}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={18}><span className="value">{formDTO && formDTO.salaryMonth}</span></Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Row>
|
||||
<Col span={6}><span className="label">{getLabel(519146, "核算账套")}</span></Col>
|
||||
<Col span={18}><span className="value">{formDTO && formDTO.salarySobName}</span></Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Row>
|
||||
<Col span={3}><span className="label">{getLabel(536726, "备注")}</span></Col>
|
||||
<Col span={21}><span className="value">{formDTO && formDTO.description}</span></Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</WeaSearchGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseInfo;
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
export const personConfirmSearchConditions = [
|
||||
{
|
||||
items: [
|
||||
{
|
||||
colSpan: 2,
|
||||
conditionType: "INPUT",
|
||||
domkey: ["employeeName"],
|
||||
fieldcol: 12,
|
||||
label: "姓名",
|
||||
lanId: 25034,
|
||||
labelcol: 6,
|
||||
value: "",
|
||||
viewAttr: 2
|
||||
},
|
||||
{
|
||||
colSpan: 2,
|
||||
conditionType: "INPUT",
|
||||
domkey: ["workcode"],
|
||||
fieldcol: 12,
|
||||
label: "工号",
|
||||
lanId: 1933,
|
||||
labelcol: 6,
|
||||
value: "",
|
||||
viewAttr: 2
|
||||
},
|
||||
{
|
||||
browserConditionParam: {
|
||||
completeParams: {},
|
||||
conditionDataParams: {},
|
||||
dataParams: {},
|
||||
destDataParams: {},
|
||||
hasAddBtn: false,
|
||||
hasAdvanceSerach: false,
|
||||
idSeparator: ",",
|
||||
isAutoComplete: 1,
|
||||
isDetail: 0,
|
||||
isMultCheckbox: false,
|
||||
isSingle: false,
|
||||
icon: "icon-coms-hrm",
|
||||
linkUrl: "",
|
||||
pageSize: 10,
|
||||
quickSearchName: "",
|
||||
replaceDatas: [],
|
||||
title: "",
|
||||
type: "57",
|
||||
viewAttr: 2
|
||||
},
|
||||
colSpan: 2,
|
||||
conditionType: "BROWSER",
|
||||
domkey: ["departmentIds"],
|
||||
fieldcol: 12,
|
||||
label: "部门",
|
||||
lanId: 27511,
|
||||
labelcol: 6,
|
||||
viewAttr: 2
|
||||
},
|
||||
{
|
||||
browserConditionParam: {
|
||||
completeParams: {},
|
||||
conditionDataParams: {},
|
||||
dataParams: {},
|
||||
destDataParams: {},
|
||||
hasAddBtn: false,
|
||||
hasAdvanceSerach: false,
|
||||
idSeparator: ",",
|
||||
isAutoComplete: 1,
|
||||
isDetail: 0,
|
||||
isMultCheckbox: false,
|
||||
isSingle: false,
|
||||
icon: "icon-coms-hrm",
|
||||
linkUrl: "",
|
||||
pageSize: 10,
|
||||
quickSearchName: "",
|
||||
replaceDatas: [],
|
||||
title: "",
|
||||
type: "24",
|
||||
viewAttr: 2
|
||||
},
|
||||
colSpan: 2,
|
||||
conditionType: "BROWSER",
|
||||
domkey: ["positionIds"],
|
||||
fieldcol: 12,
|
||||
label: "岗位",
|
||||
lanId: 6086,
|
||||
labelcol: 6,
|
||||
viewAttr: 2
|
||||
},
|
||||
{
|
||||
colSpan: 2,
|
||||
conditionType: "SELECT",
|
||||
domkey: ["statuses"],
|
||||
fieldcol: 12,
|
||||
multiple: true,
|
||||
label: "状态",
|
||||
lanId: 535101,
|
||||
labelcol: 6,
|
||||
options: [],
|
||||
viewAttr: 2
|
||||
}
|
||||
],
|
||||
defaultshow: true,
|
||||
title: "常用条件"
|
||||
}
|
||||
];
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Author: 黎永顺
|
||||
* name: 人员确认
|
||||
* Description:
|
||||
* Date: 2023/9/13
|
||||
*/
|
||||
import React, { Component } from "react";
|
||||
import { WeaButtonIcon, WeaHelpfulTip, WeaLocaleProvider, WeaTab, WeaTools } from "ecCom";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { Button } from "antd";
|
||||
import BaseInfo from "./baseInfo";
|
||||
import { acctemployeeList } from "../../../../../apis/calculate";
|
||||
import { personConfirmSearchConditions } from "./condition";
|
||||
import { getSearchs } from "../../../../../util";
|
||||
|
||||
const getKey = WeaTools.getKey;
|
||||
const getLabel = WeaLocaleProvider.getLabel;
|
||||
|
||||
@inject("calculateStore")
|
||||
@observer
|
||||
class Index extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectedKey: "range", showSearchAd: false,
|
||||
searchConditions: [], loading: false,
|
||||
pageInfo: { current: 1, pageSize: 10, total: 0 },
|
||||
selectedRowKeys: []
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if ($) {
|
||||
const domTabInnerList = $(".salary-calculate-do-calc-content .ant-tabs-tab-inner");
|
||||
domTabInnerList[0].setAttribute("title", "");
|
||||
domTabInnerList[1].setAttribute("title", "");
|
||||
domTabInnerList[2].setAttribute("title", "");
|
||||
}
|
||||
this.setState({
|
||||
searchConditions: _.map(personConfirmSearchConditions, item => {
|
||||
return {
|
||||
...item,
|
||||
items: _.map(item.items, o => {
|
||||
if (getKey(o) === "statuses") {
|
||||
return {
|
||||
...o,
|
||||
options: [
|
||||
{ key: "0", showname: getLabel(18883, "试用") }, { key: "1", showname: getLabel(15711, "正式") },
|
||||
{ key: "2", showname: getLabel(480, "临时") }, { key: "3", showname: getLabel(15844, "试用延期") },
|
||||
{ key: "4", showname: getLabel(542707, "解雇") }, { key: "5", showname: getLabel(6091, "离职") },
|
||||
{ key: "6", showname: getLabel(6092, "退休") }
|
||||
]
|
||||
};
|
||||
}
|
||||
return { ...o };
|
||||
}),
|
||||
title: getLabel(32905, "常用条件")
|
||||
};
|
||||
})
|
||||
}, () => {
|
||||
const { calculateStore: { PCSearchForm } } = this.props;
|
||||
PCSearchForm.initFormFields(this.state.searchConditions);
|
||||
this.acctemployeeList();
|
||||
});
|
||||
}
|
||||
|
||||
renderTabBtns = () => {
|
||||
const { selectedKey } = this.state;
|
||||
let tabBtns = [];
|
||||
switch (selectedKey) {
|
||||
case "range":
|
||||
tabBtns = [
|
||||
<WeaButtonIcon buttonType="del" type="primary" title={getLabel(111, "批量删除")}/>,
|
||||
<WeaButtonIcon buttonType="add" type="primary" title={getLabel(1421, "新增")}/>,
|
||||
<Button type="primary">{getLabel(17416, "导出")}</Button>
|
||||
];
|
||||
break;
|
||||
case "add":
|
||||
case "sub":
|
||||
tabBtns = [
|
||||
<Button type="primary">{getLabel(17416, "导出")}</Button>
|
||||
];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return tabBtns;
|
||||
};
|
||||
acctemployeeList = () => {
|
||||
const { pageInfo } = this.state;
|
||||
const { calculateStore: { PCSearchForm }, routeParams: { salaryAcctRecordId } } = this.props;
|
||||
const { departmentIds, positionIds, statuses, ...extra } = PCSearchForm.getFormParams();
|
||||
const payload = {
|
||||
salaryAcctRecordId, ...pageInfo, ...extra,
|
||||
departmentIds: !_.isEmpty(departmentIds) ? departmentIds.split(",") : [],
|
||||
positionIds: !_.isEmpty(positionIds) ? positionIds.split(",") : [],
|
||||
statuses: !_.isEmpty(statuses) ? statuses.split(",") : []
|
||||
};
|
||||
acctemployeeList(payload).then(({ status, data }) => {
|
||||
if (status) {
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { calculateStore: { PCSearchForm } } = this.props;
|
||||
const { selectedKey, showSearchAd, searchConditions, pageInfo, loading, selectedRowKeys } = this.state;
|
||||
const tabDatas = [
|
||||
{
|
||||
title: <React.Fragment>
|
||||
<span>{getLabel(542307, "核算人员范围")}</span>
|
||||
<WeaHelpfulTip
|
||||
width={200} placement="topLeft"
|
||||
title={getLabel(543551, "核算完若薪资档案中个税扣缴义务人发生调整,需先刷新【核算人员范围】再到【薪资核算】中重新核算")}
|
||||
style={{ marginLeft: 8 }}
|
||||
/>
|
||||
</React.Fragment>, viewcondition: "range"
|
||||
},
|
||||
{
|
||||
title: <React.Fragment>
|
||||
<span>{getLabel(542308, "环比上月减少人员")}</span>
|
||||
<WeaHelpfulTip
|
||||
width={200} placement="topLeft"
|
||||
title={getLabel(543552, "提示:环比上期当前选择的账套归档的各个税扣缴义务人下减少的人员")}
|
||||
style={{ marginLeft: 8 }}
|
||||
/>
|
||||
</React.Fragment>, viewcondition: "sub"
|
||||
},
|
||||
{
|
||||
title: <React.Fragment>
|
||||
<span>{getLabel(542308, "环比上月增加人员")}</span>
|
||||
<WeaHelpfulTip
|
||||
width={200} placement="topLeft"
|
||||
title={getLabel(543553, "提示:环比上期当前选择的账套归档的各个税扣缴义务人下增加的人员")}
|
||||
style={{ marginLeft: 8 }}
|
||||
/>
|
||||
</React.Fragment>, viewcondition: "add"
|
||||
}
|
||||
];
|
||||
const pagination = {
|
||||
...pageInfo,
|
||||
showTotal: total => `${getLabel(18609, "共")} ${total} ${getLabel(18256, "条")}`,
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ["10", "20", "50", "100"],
|
||||
onShowSizeChange: (current, pageSize) => {
|
||||
this.setState({ pageInfo: { ...pageInfo, current, pageSize } }, () => this.queryList());
|
||||
},
|
||||
onChange: current => {
|
||||
this.setState({ pageInfo: { ...pageInfo, current } }, () => this.queryList());
|
||||
}
|
||||
};
|
||||
const rowSelection = {
|
||||
selectedRowKeys,
|
||||
onChange: selectedRowKeys => this.setState({ selectedRowKeys })
|
||||
};
|
||||
return (
|
||||
<div className="person-confirm-layout">
|
||||
<BaseInfo {...this.props}/>
|
||||
<WeaTab
|
||||
datas={tabDatas} keyParam="viewcondition" selectedKey={selectedKey}
|
||||
onChange={v => this.setState({ selectedKey: v })} advanceHeight={220}
|
||||
buttons={this.renderTabBtns()} searchType={["base", "advanced"]}
|
||||
showSearchAd={showSearchAd} setShowSearchAd={bool => this.setState({ showSearchAd: bool })}
|
||||
searchsAd={getSearchs(PCSearchForm, searchConditions, 2, false)}
|
||||
onSearchChange={(v) => PCSearchForm.updateFields({ employeeName: v })}
|
||||
searchsBaseValue={PCSearchForm.getFormParams().employeeName}
|
||||
onSearch={this.acctemployeeList} onAdSearch={this.acctemployeeList}
|
||||
onAdReset={() => PCSearchForm.resetForm()}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Index;
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
.person-confirm-layout {
|
||||
.wea-tab .wea-tab-right, .wea-input-focus {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.docalc-baseinfo-layout {
|
||||
padding: 0;
|
||||
|
||||
.wea-title {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.wea-content.pt15 {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.docalc-baseinfo {
|
||||
background: #fff;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-right: none;
|
||||
|
||||
.ant-col-24 {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
& > div {
|
||||
border-right: 1px solid #e5e5e5;
|
||||
line-height: 30px;
|
||||
padding: 5px 16px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Author: 黎永顺
|
||||
* name: 薪资所属月提示语
|
||||
* Description:
|
||||
* Date: 2023/9/13
|
||||
*/
|
||||
import React, { Component } from "react";
|
||||
import { WeaLocaleProvider } from "ecCom";
|
||||
import "./index.less";
|
||||
|
||||
const getLabel = WeaLocaleProvider.getLabel;
|
||||
|
||||
class Index extends Component {
|
||||
render() {
|
||||
const { attendCycle, salaryCycle, salaryMonth, socialSecurityCycle } = this.props;
|
||||
const { fromDate: attendFromDate, endDate: attendEndDate } = attendCycle,
|
||||
{ fromDate: salaryFromDate, endDate: salaryEndDate } = salaryCycle;
|
||||
return (
|
||||
<div className="salary-month-tip">
|
||||
<div className="line">
|
||||
<div className="lable">{getLabel(543375, "薪资周期")}</div>
|
||||
<div className="value">{`${salaryFromDate}${getLabel(15322, "至")}${salaryEndDate}`}</div>
|
||||
</div>
|
||||
<div className="line">
|
||||
<div className="lable">{getLabel(542240, "税款所属期")}</div>
|
||||
<div className="value">{salaryMonth}</div>
|
||||
</div>
|
||||
<div className="line">
|
||||
<div className="lable">{getLabel(543475, "考勤取值周期")}</div>
|
||||
<div className="value">{`${attendFromDate}${getLabel(15322, "至")}${attendEndDate}`}</div>
|
||||
</div>
|
||||
<div className="line">
|
||||
<div className="lable">{getLabel(543466, "福利台账月份")}</div>
|
||||
<div
|
||||
className="value">{`${getLabel(19422, "引用")}${socialSecurityCycle}${getLabel(543476, "的福利台账数据")}`}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Index;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
.salary-month-tip {
|
||||
.line {
|
||||
.label {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #111;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Author: 黎永顺
|
||||
* name: 薪资核算详情
|
||||
* Description:
|
||||
* Date: 2023/9/13
|
||||
*/
|
||||
import React, { Component } from "react";
|
||||
import { WeaLocaleProvider, WeaReqTop } from "ecCom";
|
||||
import { Button, Dropdown, Menu } from "antd";
|
||||
import Layout from "./layout";
|
||||
import AdvanceInputBtn from "./components/advanceInputBtn";
|
||||
import SalaryCalcPersonConfirm from "./components/salaryCalcPersonConfirm";
|
||||
import "./index.less";
|
||||
|
||||
const getLabel = WeaLocaleProvider.getLabel;
|
||||
|
||||
class Index extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectedKey: "person"
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
console.log(this.props);
|
||||
}
|
||||
|
||||
handleButtonClick = () => {
|
||||
console.log("核算所有人");
|
||||
};
|
||||
handleMenuClick = ({ key }) => {
|
||||
console.log(key);
|
||||
};
|
||||
handleMoreMenuClick = ({ key }) => {
|
||||
console.log(key);
|
||||
};
|
||||
renderReqBtns = () => {
|
||||
const { selectedKey } = this.state;
|
||||
let reqBtns = [];
|
||||
switch (selectedKey) {
|
||||
case "calc":
|
||||
const menu = (
|
||||
<Menu onClick={this.handleMenuClick}>
|
||||
<Menu.Item key="calc_selected">{getLabel(543546, "核算所选人员")}</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
const moreMenu = (
|
||||
<Menu onClick={this.handleMoreMenuClick}>
|
||||
<Menu.Item key="import">{getLabel(32935, "导入")}</Menu.Item>
|
||||
<Menu.Item key="exportAll">{getLabel(81272, "导出全部")}</Menu.Item>
|
||||
<Menu.Item key="export_custom">{getLabel(544270, "自定义导出")}</Menu.Item>
|
||||
<Menu.Item key="offlineCompare">{getLabel(543249, "线下对比")}</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
reqBtns = [
|
||||
<Dropdown.Button onClick={this.handleButtonClick} overlay={menu} type="primary">
|
||||
{getLabel(543545, "核算所有人")}
|
||||
</Dropdown.Button>,
|
||||
<Dropdown overlay={moreMenu}><Button type="ghost">{getLabel(17499, "更多")}</Button></Dropdown>,
|
||||
<AdvanceInputBtn/>
|
||||
];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return reqBtns;
|
||||
};
|
||||
renderContent = () => {
|
||||
const { selectedKey } = this.state;
|
||||
let dom = null;
|
||||
switch (selectedKey) {
|
||||
case "person":
|
||||
dom = <SalaryCalcPersonConfirm {...this.props}/>;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return dom;
|
||||
};
|
||||
|
||||
render() {
|
||||
const tabs = [
|
||||
{ key: "person", title: getLabel(543547, "人员确认") },
|
||||
{ key: "calc", title: getLabel(538011, "薪资核算") }
|
||||
];
|
||||
const { selectedKey } = this.state;
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<div className="salary-calculate-do-calc">
|
||||
<WeaReqTop
|
||||
title={getLabel(538011, "薪资核算")} tabDatas={tabs} selectedKey={selectedKey}
|
||||
buttonSpace={10} icon={<i className="icon-coms-fa"/>} iconBgcolor="#F14A2D"
|
||||
onChange={key => this.setState({ selectedKey: key })}
|
||||
buttons={this.renderReqBtns()}
|
||||
>
|
||||
<div className="salary-calculate-do-calc-content">{this.renderContent()}</div>
|
||||
</WeaReqTop>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Index;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
.salary-calculate-do-calc {
|
||||
min-width: 1000px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #f6f6f6;
|
||||
|
||||
.wea-new-top-req-wapper .wea-new-top-req-title > div:last-child {
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.salary-calculate-do-calc-content {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import React, { Component } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import Authority from "../../mySalary/authority";
|
||||
import { salaryacctAcctresultCheckAuth } from "../../../apis/calculate";
|
||||
|
||||
@inject("taxAgentStore")
|
||||
@observer
|
||||
class Layout extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
store: { loading: false, hasRight: false }
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.salaryacctAcctresultCheckAuth();
|
||||
}
|
||||
|
||||
salaryacctAcctresultCheckAuth = () => {
|
||||
const { taxAgentStore: { getPermission } } = this.props;
|
||||
this.setState({ store: { ...this.state.store, loading: true } });
|
||||
getPermission().then(({ data }) => {
|
||||
const { isOpenDevolution } = data;
|
||||
if (isOpenDevolution) {
|
||||
const { routeParams: { salaryAcctRecordId } } = this.props;
|
||||
salaryacctAcctresultCheckAuth({ salaryAcctRecordId }).then(({ status, data }) => {
|
||||
this.setState({ store: { ...this.state.store, loading: false, hasRight: status && data } });
|
||||
});
|
||||
} else {
|
||||
this.setState({ store: { ...this.state.store, loading: false, hasRight: true } });
|
||||
}
|
||||
}).catch(() => this.setState({ store: { ...this.state.store, loading: false } }));
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Authority ecId={`${this && this.props && this.props.ecId || ""}_Authority@lulowc`}
|
||||
store={{ ...this.state.store }}>
|
||||
{this.props.children}
|
||||
</Authority>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Layout;
|
||||
|
|
@ -8,6 +8,9 @@ import { toDecimal_n } from "../util";
|
|||
const { TableStore } = WeaTableNew;
|
||||
|
||||
export class calculateStore {
|
||||
@observable PCSearchForm = new WeaForm(); //人员确认-form
|
||||
|
||||
|
||||
@observable tableStore = new TableStore(); // new table
|
||||
@observable form = new WeaForm(); // nrew 一个form
|
||||
@observable condition = []; // 存储后台得到的form数据
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { WeaForm, WeaTableNew } from "comsMobx";
|
|||
|
||||
import * as API from "../apis/taxAgent"; // 引入API接口文件
|
||||
import { decentralizationConditions, editConditions } from "../pages/taxAgent/editConditions";
|
||||
import { taxAgentRangeExtDelete } from "../apis/taxAgent";
|
||||
|
||||
const { TableStore } = WeaTableNew;
|
||||
|
||||
|
|
@ -149,12 +148,12 @@ export class TaxAgentStore {
|
|||
//薪酬统计报表权限
|
||||
this.setStatisticsReportBtn(!isOpenDevolution ? true : !!(isAdminEnable || isChief));
|
||||
//薪资核算详情页面查看权限
|
||||
this.setPayrollPermission(isAdminEnable && isOpenDevolution || !isOpenDevolution);
|
||||
this.setPayrollPermission((isOpenDevolution && isAdminEnable) || !isOpenDevolution);
|
||||
resolve({ status, data });
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}).catch(() => reject());
|
||||
});
|
||||
};
|
||||
// 人员范围列表
|
||||
|
|
|
|||
Loading…
Reference in New Issue