Merge branch 'release/2.8.3.2307.01' into feature/V2-非系统人员管理开发

# Conflicts:
#	pc4mobx/hrmSalary/index.js
#	pc4mobx/hrmSalary/pages/payrollFiles/index.js
#	pc4mobx/hrmSalary/pages/taxAgent/personalScope.js
#	pc4mobx/hrmSalary/pages/taxAgent/slideTaxagentUser.js
#	pc4mobx/hrmSalary/util/index.js
This commit is contained in:
黎永顺 2023-07-11 17:36:38 +08:00
commit ce50c9cf91
146 changed files with 10056 additions and 2121 deletions

View File

@ -564,3 +564,7 @@ export const cacheImportField = (params) => {
body: JSON.stringify(params)
}).then(res => res.json());
};
//薪资核算-页面查看权限
export const salaryacctAcctresultCheckAuth = params => {
return WeaTools.callApi("/api/bs/hrmsalary/salaryacct/acctresult/checkAuth", "GET", params);
};

View File

@ -1,4 +1,5 @@
import { WeaTools } from 'ecCom';
import { postFetch } from '../util/request';
//个税申报表-个税申报表列表
export const getDeclareList = params => {
@ -7,7 +8,7 @@ export const getDeclareList = params => {
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
},
body: JSON.stringify(params)
}).then(res => res.json())
}
@ -24,7 +25,7 @@ export const saveDeclare = params => {
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
},
body: JSON.stringify(params)
}).then(res => res.json())
}
@ -41,7 +42,7 @@ export const getDetailList = params => {
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
},
body: JSON.stringify(params)
}).then(res => res.json())
}
@ -52,13 +53,16 @@ export const exportSalaryArchive = (id = "") => {
fetch('/api/bs/hrmsalary/taxdeclaration/export?taxDeclarationId=' + id).then(res => res.blob().then(blob => {
var filename=`个税申报表.xlsx`
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}))
}
//个税申报表-撤回申报
export const withDrawTaxDeclaration = (params) => {
return postFetch('/api/bs/hrmsalary/taxdeclaration/withDrawTaxDeclaration', params);
}

View File

@ -107,6 +107,10 @@ export const saveSysItem = params => {
export const getItemTypeOption = params => {
return WeaTools.callApi('/api/bs/hrmsalary/salaryitem/listSalaryItemTypeOption', 'GET', params);
}
//获取公式描述
export const getFormulaDes = params => {
return WeaTools.callApi('/api/bs/hrmsalary/formula/des', 'GET', params);
}
// *** 公式 start ***
// 获取公式变量类型

View File

@ -1,29 +1,36 @@
import { WeaTools } from 'ecCom';
import { WeaTools } from "ecCom";
// 工资单列表
export const mySalaryBillList = params => {
return fetch('/api/bs/hrmsalary/salaryBill/mySalaryBillList', {
method: 'POST',
mode: 'cors',
return fetch("/api/bs/hrmsalary/salaryBill/mySalaryBillList", {
method: "POST",
mode: "cors",
headers: {
'Content-Type': 'application/json'
},
"Content-Type": "application/json"
},
body: JSON.stringify(params)
}).then(res => res.json())
}).then(res => res.json());
};
// 社保福利列表
export const welfareList = params => {
return WeaTools.callApi('/api/bs/hrmsalary/report/welfare/list', 'GET', params);
return WeaTools.callApi("/api/bs/hrmsalary/report/welfare/list", "GET", params);
};
// 调薪记录列表
export const recordList = params => {
return WeaTools.callApi('/api/bs/hrmsalary/report/record/list', 'GET', params);
return WeaTools.callApi("/api/bs/hrmsalary/report/record/list", "GET", params);
};
// 工资查看详情
export const mySalaryBill = params => {
return WeaTools.callApi('/api/bs/hrmsalary/salaryBill/mySalaryBill', 'GET', params);
};
return WeaTools.callApi("/api/bs/hrmsalary/salaryBill/mySalaryBill", "GET", params);
};
export const isNeedSecondPwdVerify = params => {
return WeaTools.callApi("/api/encrypt/secondauthsetting/isNeedSecondAuth", "POST", params);
};
export const doSecondAuth = params => {
return WeaTools.callApi("/api/encrypt/secondauthsetting/doSecondAuth", "POST", params);
};

View File

@ -12,6 +12,10 @@ export const getPayrollList = params => {
body: JSON.stringify(params)
}).then(res => res.json());
};
// 工资单发放进度条
export const getPayrollIssuanceProgressBar = (id) => {
return WeaTools.callApi("/api/bs/hrmsalary/progress/getRate?cacheKey=SALARY_GRANT_PROGRESS_" + id, "get", {});
};
//工资单-获取table提示信息
export const getPayrollInfo = params => {
@ -363,3 +367,24 @@ export const getAvailableSalaryItemSet = (params) => {
export const salaryBillSendSum = (params) => {
return postFetch("/api/bs/hrmsalary/salaryBill/send/sum", params);
};
//工资单发放-发送短信验证码
export const sendMobileCode = (params) => {
return postFetch("/api/bs/hrmsalary/salaryBill/sendMobileCode", params);
};
//工资单-验证方式
export const payrollCheckType = params => {
return WeaTools.callApi("/api/bs/hrmsalary/salaryBill/payrollCheckType", "GET", params);
};
// 工资单基础设置-获取设置列表
export const getSalaryBillBaseSetForm = (id) => {
return WeaTools.callApi("/api/bs/hrmsalary/salaryBill/baseSet/getForm", "get", {});
};
//工资单基础设置-保存工资单基础设置(设置水印)
export const salaryBillBaseSetSave = (params) => {
return postFetch("/api/bs/hrmsalary/salaryBill/baseSet/save", params);
};
//工资单基础设置-保存工资单基础设置(水印预览)
export const salaryBillBaseSetPreviewWaterMark = (params) => {
return postFetch("/api/bs/hrmsalary/salaryBill/baseSet/previewWaterMark", params);
};

View File

@ -65,3 +65,11 @@ export const deletePendingTodo = (params) => {
export const deleteSuspendTodo = (params) => {
return postFetch('/api/bs/hrmsalary/salaryArchive/deleteSuspendTodo', params);
}
// 待定薪、停薪员工 是否允许删除薪资档案
export const salaryArchiveDelete = (params) => {
return WeaTools.callApi('/api/bs/hrmsalary/sys/conf/code?code=salaryArchiveDelete', 'GET', params);
}
// 删除薪资档案
export const deleteSalaryArchive = (params) => {
return postFetch('/api/bs/hrmsalary/salaryArchive/deleteSalaryArchive', params);
}

View File

@ -1,45 +1,65 @@
import { WeaTools } from 'ecCom';
import { postFetch } from '../util/request';
import { WeaTools } from "ecCom";
import { postFetch } from "../util/request";
//通用字典表 {enumClass:""}
export const commonEnumList = (params) => {
return WeaTools.callApi('/api/bs/hrmsalary/common/enum/list', 'GET', params);
}
return WeaTools.callApi("/api/bs/hrmsalary/common/enum/list", "GET", params);
};
export const sysOrderRule = params => {
return WeaTools.callApi('/api/bs/hrmsalary/sys/orderRule', 'GET', params);
}
return WeaTools.callApi("/api/bs/hrmsalary/sys/orderRule", "GET", params);
};
//保存排序规则
export const updateOrderRule = (params) => {
return postFetch('/api/bs/hrmsalary/sys/updateOrderRule', params);
}
return postFetch("/api/bs/hrmsalary/sys/updateOrderRule", params);
};
//导入规则详情信息
export const sysConfCodeRule = params => {
return WeaTools.callApi('/api/bs/hrmsalary/sys/conf/code', 'GET', params);
}
return WeaTools.callApi("/api/bs/hrmsalary/sys/conf/code", "GET", params);
};
//保存导入规则
export const saveMatchEmployeeModeRule = (params) => {
return postFetch('/api/bs/hrmsalary/sys/saveMatchEmployeeModeRule', params);
}
return postFetch("/api/bs/hrmsalary/sys/saveMatchEmployeeModeRule", params);
};
//应用配置查询
export const queryAppsetting = (params) => {
return WeaTools.callApi('/api/bs/hrmsalary/sys/app/setting', 'GET', params);
}
return WeaTools.callApi("/api/bs/hrmsalary/sys/app/setting", "GET", params);
};
//加密配置保存
export const saveEncryptSetting = (params) => {
return postFetch('/api/bs/hrmsalary/sys/app/setting/saveEncryptSetting', params);
}
return postFetch("/api/bs/hrmsalary/sys/app/setting/saveEncryptSetting", params);
};
//加密配置保存
export const appSettingSave = (params) => {
return postFetch('/api/bs/hrmsalary/sys/app/setting/save', params);
}
return postFetch("/api/bs/hrmsalary/sys/app/setting/save", params);
};
//获取加密进度条
export const getEncryptProgress = params => {
return WeaTools.callApi('/api/bs/hrmsalary/sys/app/getEncryptProgress', 'GET', params);
}
return WeaTools.callApi("/api/bs/hrmsalary/sys/app/getEncryptProgress", "GET", params);
};
//保存报税规则
export const operateTaxDeclarationFunction = (params) => {
return postFetch('/api/bs/hrmsalary/sys/operateTaxDeclarationFunction', params);
}
return postFetch("/api/bs/hrmsalary/sys/operateTaxDeclarationFunction", params);
};
//保存档案删除规则
export const saveArchiveDelete = (params) => {
return postFetch("/api/bs/hrmsalary/sys/saveArchiveDelete", params);
};
//保存个税申报撤回规则
export const saveWithDrawTaxDeclaration = (params) => {
return postFetch("/api/bs/hrmsalary/sys/saveWithDrawTaxDeclaration", params);
};
//保存匹配规则
export const saveSalaryAcctEmployeeRule = (params) => {
return postFetch("/api/bs/hrmsalary/sys/saveSalaryAcctEmployeeRule", params);
};
//保存薪酬统计报表
export const reportStatisticsReportSave = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/report/save", params);
};
//薪酬统计维度下拉列表
export const reportGetForm = params => {
return WeaTools.callApi("/api/bs/hrmsalary/report/statistics/report/getForm", "GET", params);
};

View File

@ -0,0 +1,80 @@
import { WeaTools } from "ecCom";
import { postFetch } from "../util/request";
//薪酬统计维度下拉列表
export const dimensionGetForm = (params) => {
return WeaTools.callApi("/api/bs/hrmsalary/report/statistics/dimension/getForm", "GET", params);
};
//获取自定义统计项目表单
export const statisticsItemGetform = (params) => {
return WeaTools.callApi("/api/bs/hrmsalary/report/statistics/item/getForm", "GET", params);
};
//自定义统计项目列表
export const statisticsItemList = (params) => {
return WeaTools.callApi("/api/bs/hrmsalary/report/statistics/item/list", "GET", params);
};
// 保存薪酬统计维度
export const dimensionSave = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/dimension/save", params);
};
// 薪酬统计维度列表
export const dimensionList = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/dimension/list", params);
};
// 删除薪酬统计维度
export const dimensionDelete = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/dimension/delete", params);
};
//保存薪酬统计报表
export const reportStatisticsReportList = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/report/list", params);
};
//删除薪酬统计报表
export const reportStatisticsReportDelete = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/report/delete", params);
};
//获取薪酬统计报表数据
export const reportStatisticsReportGetData = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/report/getData", params);
};
//保存自定义统计项目
export const reportStatisticsItemSave = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/item/save", params);
};
//保存数据范围及负责设置
export const reportStatisticsSaveSearchCondition = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/report/saveSearchCondition", params);
};
//删除自定义统计项目
export const reportStatisticsItemDelete = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/item/delete", params);
};
//获取薪酬统计报表查询条件
export const reportStatisticsGetSearchCondition = (params) => {
return WeaTools.callApi("/api/bs/hrmsalary/report/statistics/report/getSearchCondition", "GET", params);
};
//分析图数据展示范围设置查询
export const queryRangeSetting = (params) => {
return WeaTools.callApi("/api/bs/hrmsalary/report/statistics/echarts/queryRangeSetting", "GET", params);
};
//分析图数据展示范围设置删除
export const deleteRangeSetting = (params) => {
return WeaTools.callApi("/api/bs/hrmsalary/report/statistics/echarts/deleteRangeSetting", "GET", params);
};
//分析图数据展示范围设置保存
export const saveRangeSetting = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/echarts/saveRangeSetting", params);
};
//员工列表
export const statisticsEmployeeList = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/employee/list", params);
};
//员工详情列表
export const statisticsEmployeeDetailList = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/employee/detailList", params);
};
//数据透视-列表查询
export const getDataPerspective = (params) => {
return postFetch("/api/bs/hrmsalary/report/statistics/report/getDataPerspective", params);
};

View File

@ -1,146 +1,150 @@
import { WeaTools } from 'ecCom';
import { WeaTools } from "ecCom";
import { postFetch } from "../util/request";
export const tips = params => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/tips', 'get', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/tips", "get", params);
};
export const getCondition = params => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/getSearchCondition', 'get', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/getSearchCondition", "get", params);
};
//社保福利档案列表
export const queryList = (params) => {
return postFetch('/api/bs/hrmsalary/archives/getTable', params);
return postFetch("/api/bs/hrmsalary/archives/getTable", params);
};
//社保福利档案列表
export const queryInsuranceTabTotal = (params) => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/queryInsuranceTabTotal', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/queryInsuranceTabTotal", params);
};
//删除待办-待增员
export const updateRunStatus = (params) => {
return postFetch('/api/bs/hrmsalary/archives/updateRunStatus', params);
return postFetch("/api/bs/hrmsalary/archives/updateRunStatus", params);
};
//删除待办-待减员
export const cancelStayDel = (params) => {
return postFetch('/api/bs/hrmsalary/archives/cancelStayDel', params);
return postFetch("/api/bs/hrmsalary/archives/cancelStayDel", params);
};
//全量增员
export const allStayAddToPay = (params) => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/allStayAddToPay', 'GET', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/allStayAddToPay", "GET", params);
};
//全量减员
export const allStayDelToStop = (params) => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/allStayDelToStop', 'GET', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/allStayDelToStop", "GET", params);
};
//增员
export const stayAddToPay = (params) => {
return postFetch('/api/bs/hrmsalary/archives/stayAddToPay', params);
return postFetch("/api/bs/hrmsalary/archives/stayAddToPay", params);
};
//减员
export const stayDelToStop = (params) => {
return postFetch('/api/bs/hrmsalary/archives/stayDelToStop', params);
return postFetch("/api/bs/hrmsalary/archives/stayDelToStop", params);
};
//删除社保档案
export const deleteArchive = (params) => {
return postFetch("/api/bs/hrmsalary/archives/deleteArchive", params);
};
//取消停缴
export const cancelStopPayment = (params) => {
return postFetch('/api/bs/hrmsalary/archives/cancelStopPayment', params);
return postFetch("/api/bs/hrmsalary/archives/cancelStopPayment", params);
};
export const getTable = params => {
return fetch('/api/bs/hrmsalary/archives/getTable', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
return fetch("/api/bs/hrmsalary/archives/getTable", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(params)
}).then(res => res.json());
};
export const getBaseForm = params => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/getBaseForm', 'get', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/getBaseForm", "get", params);
};
export const getPaymentForm = params => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/getPaymentForm', 'get', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/getPaymentForm", "get", params);
};
// 保存
export const save = params => {
return fetch('/api/bs/hrmsalary/archives/save', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
return fetch("/api/bs/hrmsalary/archives/save", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(params)
}).then(res => res.json());
};
// 导出档案
export const exportDocument = params => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/export', 'get', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/export", "get", params);
};
// 导入档案 - 获取组件的一些前置参数
export const getImportDocumentParams = params => {
return WeaTools.callApi('/api/bs/hrmsalary/archives/getImportParams', 'get', params);
return WeaTools.callApi("/api/bs/hrmsalary/archives/getImportParams", "get", params);
};
// 导入档案- 导出现有数据
export const exportCurData = params => {
fetch('/api/bs/hrmsalary/scheme/template/export',{
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).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);
}))
fetch("/api/bs/hrmsalary/scheme/template/export", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(params)
}).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 previewCurData = (params) => {
return fetch('/api/bs/hrmsalary/scheme/preview', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
}
return fetch("/api/bs/hrmsalary/scheme/preview", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(params)
}).then(res => res.json());
};
// 档案导入
export const importBatch = (params) => {
return fetch('/api/bs/hrmsalary/scheme/importBatch', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
}
return fetch("/api/bs/hrmsalary/scheme/importBatch", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(params)
}).then(res => res.json());
};
// 导出档案
export const exportArchives = (ids) => {
fetch('/api/bs/hrmsalary/scheme/export?ids=' + ids).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);
}))
}
fetch("/api/bs/hrmsalary/scheme/export?ids=" + ids).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);
}));
};

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="151px" height="150px" viewBox="0 0 151 150" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icon-empty-file</title>
<defs>
<polygon id="path-1" points="0 -0.0002 149.9997 -0.0002 149.9997 31.9998 0 31.9998"></polygon>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="知识文档" transform="translate(-112.000000, -299.000000)">
<g id="Group-40" transform="translate(113.000000, 321.000000)">
<g id="Group-3" transform="translate(0.000000, 89.259000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Clip-2"></g>
<path d="M149.9997,15.9998 C149.9997,24.8368 116.4217,31.9998 74.9997,31.9998 C33.5787,31.9998 -0.0003,24.8368 -0.0003,15.9998 C-0.0003,7.1638 33.5787,-0.0002 74.9997,-0.0002 C116.4217,-0.0002 149.9997,7.1638 149.9997,15.9998" id="Fill-1" fill="#E6EFF0" mask="url(#mask-2)"></path>
</g>
<line x1="116.8337" y1="5.1465" x2="127.1277" y2="5.1465" id="Stroke-4" stroke="#D3D7DC"></line>
<line x1="121.9801" y1="0" x2="121.9801" y2="10.294" id="Stroke-6" stroke="#D3D7DC"></line>
<line x1="127.1276" y1="39.0801" x2="133.1026" y2="39.0801" id="Stroke-8" stroke="#D3D7DC"></line>
<line x1="130.1149" y1="36.0928" x2="130.1149" y2="42.0678" id="Stroke-10" stroke="#D3D7DC"></line>
<line x1="17.9655" y1="38.4541" x2="25.1085" y2="38.4541" id="Stroke-12" stroke="#D3D7DC"></line>
<line x1="21.5368" y1="34.8828" x2="21.5368" y2="42.0248" id="Stroke-14" stroke="#D3D7DC"></line>
<polygon id="Fill-16" fill="#FFFFFF" points="113.029 23.0694 99.885 10.2944 99.091 11.2664 98.32 17.1834 97.716 21.4544 100.529 24.2664 106.842 25.3914 110.675 25.0164 112.842 24.2874"></polygon>
<polygon id="Stroke-18" stroke="#CFD0D6" stroke-linecap="round" stroke-linejoin="round" points="113.029 23.0694 99.885 10.2944 99.091 11.2664 98.32 17.1834 97.716 21.4544 100.529 24.2664 106.842 25.3914 110.675 25.0164 112.842 24.2874"></polygon>
<path d="M96.6842,106.4366 L42.9702,106.4366 C39.6702,106.4366 36.9702,103.7376 36.9702,100.4366 L36.9702,26.3016 C36.9702,23.0006 39.6702,20.3016 42.9702,20.3016 L96.6842,20.3016 C99.9842,20.3016 102.6842,23.0006 102.6842,26.3016 L102.6842,100.4366 C102.6842,103.7376 99.9842,106.4366 96.6842,106.4366" id="Fill-20" fill="#FFFFFF"></path>
<path d="M96.6842,106.4366 L42.9702,106.4366 C39.6702,106.4366 36.9702,103.7376 36.9702,100.4366 L36.9702,26.3016 C36.9702,23.0006 39.6702,20.3016 42.9702,20.3016 L96.6842,20.3016 C99.9842,20.3016 102.6842,23.0006 102.6842,26.3016 L102.6842,100.4366 C102.6842,103.7376 99.9842,106.4366 96.6842,106.4366 Z" id="Stroke-22" stroke="#CFD0D6"></path>
<path d="M105.3727,23.5244 C102.1367,23.5244 99.4877,20.8764 99.4877,17.6394 L99.4877,10.2944 L53.2007,10.2944 C49.9637,10.2944 47.3157,12.9424 47.3157,16.1784 L47.3157,90.5454 C47.3157,93.7814 49.9637,96.4294 53.2007,96.4294 L107.1437,96.4294 C110.3817,96.4294 113.0287,93.7814 113.0287,90.5454 L113.0287,23.5244 L105.3727,23.5244 Z" id="Fill-24" fill="#FFFFFF"></path>
<path d="M105.3727,23.5244 C102.1367,23.5244 99.4877,20.8764 99.4877,17.6394 L99.4877,10.2944 L53.2007,10.2944 C49.9637,10.2944 47.3157,12.9424 47.3157,16.1784 L47.3157,90.5454 C47.3157,93.7814 49.9637,96.4294 53.2007,96.4294 L107.1437,96.4294 C110.3817,96.4294 113.0287,93.7814 113.0287,90.5454 L113.0287,23.5244 L105.3727,23.5244 Z" id="Stroke-26" stroke="#CFD0D6"></path>
<path d="M99.987,36.3116 L60.319,36.3116 C58.944,36.3116 57.819,35.1866 57.819,33.8116 C57.819,32.4366 58.944,31.3116 60.319,31.3116 L99.987,31.3116 C101.362,31.3116 102.487,32.4366 102.487,33.8116 C102.487,35.1866 101.362,36.3116 99.987,36.3116" id="Fill-28" fill="#E9E9E9"></path>
<path d="M99.987,48.2158 L60.319,48.2158 C58.944,48.2158 57.819,47.0908 57.819,45.7158 C57.819,44.3408 58.944,43.2158 60.319,43.2158 L99.987,43.2158 C101.362,43.2158 102.487,44.3408 102.487,45.7158 C102.487,47.0908 101.362,48.2158 99.987,48.2158" id="Fill-30" fill="#E9E9E9"></path>
<path d="M99.987,60.1192 L60.319,60.1192 C58.944,60.1192 57.819,58.9942 57.819,57.6192 C57.819,56.2442 58.944,55.1192 60.319,55.1192 L99.987,55.1192 C101.362,55.1192 102.487,56.2442 102.487,57.6192 C102.487,58.9942 101.362,60.1192 99.987,60.1192" id="Fill-32" fill="#E9E9E9"></path>
<path d="M84.529,72.0235 L60.319,72.0235 C58.944,72.0235 57.819,70.8985 57.819,69.5235 C57.819,68.1485 58.944,67.0235 60.319,67.0235 L84.529,67.0235 C85.904,67.0235 87.029,68.1485 87.029,69.5235 C87.029,70.8985 85.904,72.0235 84.529,72.0235" id="Fill-34" fill="#E9E9E9"></path>
<path d="M49.4841,92.169 L49.4651,12.311 C48.4411,13.349 47.8191,14.441 47.8191,16.439 L47.8191,90.587 C47.8191,92.703 49.0641,94.436 50.7221,95.325 C50.0211,94.344 49.4841,93.459 49.4841,92.169" id="Fill-36" fill="#EBF6FF"></path>
<path d="M39.1335,102.1446 L39.1965,22.3046 C38.1725,23.3426 37.4685,24.4166 37.4685,26.4146 L37.4685,100.5626 C37.4685,102.6786 38.7435,104.4116 40.4025,105.3006 C39.7005,104.3196 39.1335,103.4346 39.1335,102.1446" id="Fill-38" fill="#EBF6FF"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -13,7 +13,7 @@ class Index extends Component {
return { ...item, fixed: "left", width: 176 };
}
if (item.dataIndex === "operate") {
return { ...item, fixed: "right", width: "120px" };
return { ...item, fixed: "right", width: item.width || "120px" };
}
return { ...item, width: "33%" };
});

View File

@ -8,17 +8,17 @@
}
.linkWapper {
a {
color: #4d7ad8;
margin-right: 8px;
}
//a {
// color: #4d7ad8;
// margin-right: 8px;
//}
i {
cursor: pointer;
}
a:hover {
text-decoration: none;
}
//a:hover {
// text-decoration: none;
//}
}
}

View File

@ -0,0 +1,94 @@
/*
* Author: 黎永顺
* name: 验证码弹框
* Description:
* Date: 2023/6/16
*/
import React, { Component } from "react";
import { WeaDialog, WeaError, WeaFormItem, WeaInput, WeaLocaleProvider, WeaSearchGroup } from "ecCom";
import { sendMobileCode } from "../../apis/payroll";
import { Button } from "antd";
import "./index.less";
const { getLabel } = WeaLocaleProvider;
class Index extends Component {
constructor(props) {
super(props);
this.state = {
captcha: "",
time: 60
};
this.timeRef = null;
}
componentWillUnmount() {
clearInterval(this.timeRef);
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.visible !== this.props.visible && !nextProps.visible) {
clearInterval(this.timeRef);
this.setState({ captcha: "", time: 60 });
}
}
handleSendCaptcha = () => {
sendMobileCode({ id: this.props.id }).then(({ status, data }) => {
if (status) {
console.log(data);
this.timeRef = setInterval(() => {
const { time } = this.state;
this.setState({ time: time - 1 }, () => {
if (this.state.time === -1) {
clearInterval(this.timeRef);
this.setState({ time: 60 });
}
});
}, 1000);
}
});
};
handleConfirm = () => {
if (!this.state.captcha) {
this.refs.weaError.showError();
// return
}
this.props.onCancel();
this.props.onConfirm();
};
render() {
const { captcha, time } = this.state;
return (
<WeaDialog
initLoadCss {...this.props} style={{ width: 550 }}
className="captchaWrapper" title={getLabel(111, "验证码验证")}
buttons={[
<Button type="primary" onClick={this.handleConfirm}>{getLabel(826, "确定")}</Button>
]}
>
<WeaSearchGroup needTigger={false} title="" showGroup>
<WeaFormItem
label={getLabel(111, "验证码")}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
>
<WeaError tipPosition="bottom" ref="weaError" error={getLabel(826, "验证码未填写")}>
<div className="captchaInputBox">
<WeaInput value={captcha} onChange={captcha => this.setState({ captcha })}/>
<Button type="primary" onClick={this.handleSendCaptcha} disabled={time !== 60}>
{
time === 60 ? getLabel(111, "发送验证码") : `${time}S`
}
</Button>
</div>
</WeaError>
</WeaFormItem>
</WeaSearchGroup>
</WeaDialog>
);
}
}
export default Index;

View File

@ -0,0 +1,29 @@
.captchaWrapper {
.wea-dialog-body {
padding: 30px 20px;
.wea-form-item-wrapper {
.wea-error {
width: 100%;
.captchaInputBox {
display: flex;
align-items: center;
.wea-input-normal {
flex: 1;
}
button {
padding: 8px 10px;
border-radius: 0;
min-width: 80px;
text-align: center;
height: 30px;
line-height: 15px;
}
}
}
}
}
}

View File

@ -0,0 +1,255 @@
/*
* Author: 黎永顺
* name: 公式列表
* Description:
* Date: 2023/4/25
*/
import React, { Component } from "react";
import { WeaInputSearch, WeaLocaleProvider } from "ecCom";
import { Tree } from "antd";
import { formualSearchField, formualSearchGroup, getFormulaDes } from "../../../apis/item";
import "../index.less";
const TreeNode = Tree.TreeNode;
const getLabel = WeaLocaleProvider.getLabel;
class CodeAction extends Component {
constructor(props) {
super(props);
this.state = {
disabled: false,
variableText: "",
funcText: "",
variItemText: "",
variableList: [], //变量列表
variableExpandedKeys: [], //变量展开的节点
funcList: [], //函数列表
funcExpandedKeys: [], //函数展开的节点
funcHoverItem: {} //选中的函数节点
};
}
componentDidMount() {
const { groupParams = {} } = this.props;
this.getFormulaDes();
this.formualSearchGroup(groupParams);
}
componentWillReceiveProps(nextProps, nextContext) {
const { isCustomFunction, isCustomFunctionClick, onChangeCustomFunction } = nextProps;
if (isCustomFunction === "1" && !isCustomFunctionClick) {
this.setState({ disabled: true });
} else {
this.setState({ disabled: false }, () => {
isCustomFunction === "1" && onChangeCustomFunction("0");
});
}
}
getFormulaDes = () => {
getFormulaDes().then(({ data }) => {
if (!_.isEmpty(data)) this.setState({ funcList: data });
});
};
formualSearchGroup = (payload) => {
formualSearchGroup(payload).then(({ status, data }) => {
if (status) this.setState({
variableList: _.map(data, item => ({
...item,
children: [{ name: "", fieldId: "searchInput" }]
}))
});
});
};
formualSearchField = (sourceId) => {
const { groupParams } = this.props;
const { variableList } = this.state;
formualSearchField({ sourceId, extendParam: { ...groupParams } }).then(({ status, data }) => {
if (status) {
this.setState({
variableList: _.map(variableList, it => ({
...it,
children: sourceId === it.key ? [...it.children, ...data] : [...it.children]
}))
});
}
});
};
handleExpandVari = (variableExpandedKeys, { expanded, node }) => {
const { props: { eventKey } } = node;
const { variableList } = this.state;
this.setState({ variableExpandedKeys });
if (expanded) {
this.formualSearchField(eventKey);
} else {
this.setState({
variableList: _.map(variableList, it => ({
...it,
children: eventKey === it.key ? [{ name: "", fieldId: "searchInput" }] : [...it.children]
}))
});
}
};
handleVariNode = (selectedKeys) => {
const { onVariSelect } = this.props;
const { variableList } = this.state;
const parentNode = _.map(variableList, it => it.key);
if (selectedKeys.join() && selectedKeys.join().indexOf("searchInput") === -1 &&
!parentNode.includes(selectedKeys.join())) {
const selectParentNodeKey = selectedKeys.join().split("_")[0];
const convertStr = _.reduce(variableList, (pre, cur) => {
if (cur.key === selectParentNodeKey) {
return pre + cur.value + "." + _.find(cur.children, child => child.fieldId === selectedKeys.join()).name;
}
return pre;
}, "");
onVariSelect(convertStr);
}
};
render() {
const {
variableList, variableExpandedKeys, variableText, variItemText,
funcList, funcText, funcExpandedKeys, funcHoverItem, disabled
} = this.state;
const { groupParams = {} } = this.props;
const { referenceType } = groupParams;
const variableDatalist = _.filter(variableList, it => it.value.indexOf(variableText) !== -1);
const funcDatalist = _.map(funcList, it => ({
...it,
children: _.filter(it.children, child => _.lowerCase(child.name).indexOf(_.lowerCase(funcText)) !== -1)
}));
return (
<div className="excel-codeAction">
<div className="excel-codeAction-item">
<div className="excel-codeAction-header">
<div className="excel-codeAction-header-title">{getLabel(111, "变量")}</div>
</div>
<div className="excel-codeAction-content">
<WeaInputSearch value={variableText} placeholder={getLabel(111, "请输入变量名称")}
className="variableOuterInput"
onChange={variableText => this.setState({ variableText })}/>
<Tree className="variableTree" showLine expandedKeys={variableExpandedKeys}
onExpand={this.handleExpandVari} onSelect={this.handleVariNode}
>
{
_.map(variableDatalist, item => {
const { key, value, children = [] } = item;
const itemChildren = _.filter(children.slice(1), it => it.name.indexOf(variItemText) !== -1);
return <TreeNode title={value} key={key}>
{
_.map([...children.slice(0, 1), ...itemChildren], (child, childIndex) => {
const { name, fieldId } = child;
return (
fieldId === "searchInput" ?
<TreeNode
title={
<WeaInputSearch
value={variItemText}
placeholder={getLabel(111, "请输入变量名称")}
onChange={variItemText => this.setState({ variItemText })}
/>
}
key={fieldId + "_" + childIndex}/> :
<TreeNode title={name} key={fieldId}/>
);
})
}
</TreeNode>;
})
}
</Tree>
</div>
</div>
{
referenceType !== "sql" &&
<React.Fragment>
<div className="excel-codeAction-item">
<div className="excel-codeAction-header">
<div className="excel-codeAction-header-title">{getLabel(111, "函数")}</div>
</div>
<div className="excel-codeAction-content">
<WeaInputSearch value={funcText} placeholder={getLabel(111, "请输入函数名称")}
className="variableOuterInput"
onChange={funcText => this.setState({ funcText })}/>
<Tree className="variableTree" showLine expandedKeys={funcExpandedKeys}
onExpand={funcExpandedKeys => this.setState({ funcExpandedKeys })}
>
{
_.map(funcDatalist, item => {
const { name, dataType, children = [] } = item;
return <TreeNode title={name} disabled={disabled} key={dataType}>
{
_.map(children, (child, childIndex) => {
const { name: childName, chineseName } = child;
return (
<TreeNode
disabled={disabled}
title={
<div className="funcListTitle"
onClick={() => this.props.onFuncSelect(childName)}
onMouseEnter={() => this.setState({ funcHoverItem: child })}>
<span className="functionName" title={childName}>{childName}</span>
<span className="functionDesc" title={chineseName}>{chineseName}</span>
</div>
}
key={childIndex}
/>
);
})
}
</TreeNode>;
})
}
</Tree>
</div>
</div>
<div className="excel-codeAction-item">
<div className="excel-codeAction-header">
<div className="excel-codeAction-header-title">
{!_.isEmpty(funcHoverItem) ? funcHoverItem.name : getLabel(111, "提示")}
</div>
</div>
<div className="excel-codeAction-content"><TipList tips={funcHoverItem}/></div>
</div>
</React.Fragment>
}
</div>
);
}
}
export default CodeAction;
const TipList = (props) => {
const { tips } = props;
const { paramDescs = [], formatString, description, example, result } = tips;
return _.isEmpty(tips) ? <div className="code-action-list">
<div className="code-action-tips">
{/*<div>{getLabel(111, "{C:选项} 用来选择特定选项字段下的备选项")}</div>*/}
{/*<div>{getLabel(111, "{U:姓名} 用来选择工作区成员")}</div>*/}
{/*<div>{getLabel(111, "{D:数据} 用来选择一个部门")}</div>*/}
</div>
</div> : <div className="code-action-list">
<div className="code-action-tips">
<div className="code-action-tips-title">{getLabel(111, "语法")}</div>
<div className="code-action-tips-info">
<div>{formatString}</div>
<div>{description}</div>
</div>
<div className="code-action-tips-title">{getLabel(111, "参数")}</div>
{
_.map(paramDescs, it => {
return <div className="code-action-tips-info">
<span>.</span>
<span>{it}</span>
</div>;
})
}
<div className="code-action-tips-title">{getLabel(111, "示例")}</div>
<span className="code-action-tips-info">{example}</span>
<div className="code-action-tips-title">{getLabel(111, "结果")}</div>
<span className="code-action-tips-info">{result}</span>
</div>
</div>;
};

View File

@ -0,0 +1,16 @@
export const keyboardBaseBtns=[
{ key:"+", label: "+" },
{ key:"-", label: "-" },
{ key:">", label: ">" },
{ key:">=", label: ">=" },
{ key:"=", label: "=" },
{ key:"*", label: "*" },
{ key:"/", label: "/" },
{ key:"<", label: "<" },
{ key:"<=", label: "<=" },
{ key:"!=", label: "!=" },
{ key:"()", label: "(" },
{ key:")", label: ")" },
{ key:"%", label: "%" },
{ key:" ", label: "space" },
]

View File

@ -0,0 +1,112 @@
// extendCodeMirror.js
/* eslint-disable */
import * as CodeMirror from "codemirror";
CodeMirror.extendMode("css", {
commentStart: "/*",
commentEnd: "*/",
newlineAfterToken: function (type, content) {
return /^[;{}]$/.test(content);
}
});
CodeMirror.extendMode("javascript", {
commentStart: "",
commentEnd: "",
// FIXME semicolons inside of for
newlineAfterToken: function (type, content, textAfter, state) {
if (this.jsonMode) {
return /^[\[,{]$/.test(content) || /^}/.test(textAfter) || /^]/.test(textAfter);
} else {
if (content == ";" && state.lexical && state.lexical.type == ")") return false;
return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
}
}
});
CodeMirror.extendMode("xml", {
commentStart: "<!--",
commentEnd: "-->",
newlineAfterToken: function (type, content, textAfter) {
return type == "tag" && />$/.test(content) || /^</.test(textAfter);
}
});
// Comment/uncomment the specified range
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
cm.operation(function () {
if (isComment) { // Comment range
cm.replaceRange(curMode.commentEnd, to);
cm.replaceRange(curMode.commentStart, from);
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
} else { // Uncomment range
var selText = cm.getRange(from, to);
var startIndex = selText.indexOf(curMode.commentStart);
var endIndex = selText.lastIndexOf(curMode.commentEnd);
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
// Take string till comment start
selText = selText.substr(0, startIndex)
// From comment start till comment end
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
// From comment end till string end
+ selText.substr(endIndex + curMode.commentEnd.length);
}
cm.replaceRange(selText, from, to);
}
});
});
// Applies automatic mode-aware indentation to the specified range
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
var cmInstance = this;
this.operation(function () {
for (var i = from.line; i <= to.line; i++) {
cmInstance.indentLine(i, "smart");
}
});
});
// Applies automatic formatting to the specified range
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
var cm = this;
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
var tabSize = cm.getOption("tabSize");
var out = "", lines = 0, atSol = from.ch == 0;
function newline() {
out += "\n";
atSol = true;
++lines;
}
for (var i = 0; i < text.length; ++i) {
var stream = new CodeMirror.StringStream(text[i], tabSize);
while (!stream.eol()) {
var inner = CodeMirror.innerMode(outer, state);
var style = outer.token(stream, state), cur = stream.current();
stream.start = stream.pos;
if (!atSol || /\S/.test(cur)) {
out += cur;
atSol = false;
}
if (!atSol && inner.mode.newlineAfterToken &&
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i + 1] || "", inner.state))
newline();
}
if (!stream.pos && outer.blankLine) outer.blankLine(state);
if (!atSol) newline();
}
cm.operation(function () {
cm.replaceRange(out, from, to);
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
cm.indentLine(cur, "smart");
cm.setSelection(from, cm.getCursor(false));
});
});
// export default CodeMirror;
module.exports = { CodeMirror };

View File

@ -0,0 +1,175 @@
import React, { Component } from "react";
import { Button } from "antd";
import { WeaLocaleProvider } from "ecCom";
import { Controlled as CodeMirror } from "react-codemirror2";
import { keyboardBaseBtns } from "./constants";
import CodeAction from "./components/codeAction";
import cs from "classnames";
import "./index.less";
import "codemirror/lib/codemirror.css";
import "codemirror/lib/codemirror.js";
import "codemirror/mode/javascript/javascript.js";
require("./extendCodeMirror");
const getLabel = WeaLocaleProvider.getLabel;
class ExcelEditor extends Component {
constructor(props) {
super(props);
this.state = {
value: "",
isFormter: false,
isCustomFunctionClick: false
};
this.editorRef = null;
this.timer = null;
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.value !== this.props.value && nextProps.value) this.setState({ value: nextProps.value });
}
componentWillUnmount() {
if (this.timer) clearInterval(this.timer);
this.setState({ isCustomFunctionClick: false });
}
autoFormatSelection = () => {
const { isFormter } = this.state;
if (isFormter) {
const script_length = this.editorRef.getValue().length;
const startPos = { line: 0, ch: 0, sticky: null };
const endPos = this.editorRef.doc.posFromIndex(script_length);
this.editorRef.setSelection(startPos, endPos);
this.editorRef.autoFormatRange(startPos, endPos);
this.editorRef.commentRange(true, startPos, endPos);
} else {
this.editorRef.undo();
// this.editorRef.undo();
}
};
insertText = text => {
const cursor = this.editorRef.getCursor();
this.editorRef.replaceRange(text, cursor);
this.editorRef.refresh();
this.editorRef.focus();
};
replaceToWidget = (editor) => {
editor.getAllMarks().forEach(m => m.clear());
};
handleVariSelect = str => this.insertText(`{${str}}`);
handleFuncSelect = str => {
const cursor = this.editorRef.getCursor();
this.editorRef.replaceRange(`${str}()`, cursor);
this.timer = setTimeout(() => {
const { line, ch } = this.editorRef.getCursor();
this.editorRef.setCursor({ line, ch: ch - 1 });
this.editorRef.refresh();
this.editorRef.focus();
}, 100);
};
handleEditorRedo = () => {
const { ch, line } = this.editorRef.getCursor();
const delStr = this.editorRef.getRange({ line, ch: ch - 1 }, { line, ch });
const codeValue = this.editorRef.getValue();
if (delStr === "}") {
if (codeValue.slice(0, ch).lastIndexOf("{") === -1) {
this.editorRef.replaceRange("", { line, ch: ch - 1 }, { line, ch });
} else {
this.editorRef.replaceRange("", { line, ch: codeValue.slice(0, ch).lastIndexOf("{") }, { line, ch });
}
} else {
this.editorRef.replaceRange("", { line, ch: ch - 1 }, { line, ch });
}
this.editorRef.refresh();
this.editorRef.focus();
};
handleBackSpaceRedo = () => {
const { ch, line } = this.editorRef.getCursor();
const delStr = this.editorRef.getRange({ line, ch: ch - 1 }, { line, ch });
const codeValue = this.editorRef.getValue();
if (delStr === "}") {
if (codeValue.slice(0, ch).lastIndexOf("{") === -1) {
this.editorRef.replaceRange("", { line, ch: ch - 1 }, { line, ch });
} else {
this.editorRef.replaceRange("", { line, ch: codeValue.slice(0, ch).lastIndexOf("{") + 1 }, { line, ch });
}
}
this.editorRef.refresh();
this.editorRef.focus();
};
render() {
const { isFormter, isCustomFunctionClick } = this.state;
const { groupParams = {}, isCustomFunction, value, onChangeCustomFunction } = this.props;
const { referenceType } = groupParams;
return (
<React.Fragment>
<div className="excel-codeWrap">
<div className="excel-codeBox">
<CodeMirror
editorDidMount={editor => this.editorRef = editor}
value={this.state.value}
onBeforeChange={(editor, data, value) => {
this.setState({ value }, () => this.props.onChange(this.state.value));
}}
onChange={(editor, data, value) => {
this.replaceToWidget(editor, data, value);
}}
options={{
lineNumbers: false,
mode: "javascript",
autofocus: false,
styleActiveLine: true,
lineWrapping: true,
matchBrackets: true,
lint: false,
indentUnit: 2,
cursorHeight: 0.85,
placeholder: "",
showCursorWhenSelecting: true
}}
onKeyDown={(_, { keyCode }) => keyCode === 8 && this.handleBackSpaceRedo()}
/>
</div>
{
referenceType !== "sql" &&
<div className="excel-codeBox-keyboard">
<div className="excel-codeBox-keyboard-operate">
<div className="excel-codeBox-keyboard-operate-content">
{
_.map(keyboardBaseBtns, item => {
const { key, label } = item;
return <Button
key={key} title={label} size="small"
className={cs(key === " " ? "excel-codeBox-keyboard-space" : "excel-codeBox-keyboard-base")}
onClick={() => this.insertText(key)}
>{label}</Button>;
})
}
</div>
<div className="excel-codeBox-keyboard-operate-clear">
<Button title="←" size="small" className="excel-codeBox-keyboard-del"
onClick={this.handleEditorRedo}></Button>
<Button title="C" size="small" className="excel-codeBox-keyboard-clear"
onClick={() => this.setState({ value: "", isCustomFunctionClick: true })}>C</Button>
</div>
</div>
<Button type="ghost"
onClick={() => this.setState({ isFormter: !isFormter }, () => this.autoFormatSelection())}>
{!isFormter ? getLabel(111, "格式美化") : getLabel(111, "格式还原")}
</Button>
</div>
}
</div>
{/*公式参数列表*/}
<CodeAction groupParams={groupParams} isCustomFunction={isCustomFunction} onVariSelect={this.handleVariSelect}
onFuncSelect={this.handleFuncSelect} codeVal={value} isCustomFunctionClick={isCustomFunctionClick}
onChangeCustomFunction={onChangeCustomFunction}
/>
</React.Fragment>
);
}
}
export default ExcelEditor;

View File

@ -0,0 +1,199 @@
.excel-codeWrap {
width: 100%;
display: flex;
justify-content: space-around;
padding: 0 0 8px;
.excel-codeBox {
flex: 1;
overflow: auto;
background: #fff;
box-sizing: content-box;
border: 1px solid #e5e5e5;
span {
font-family: Liberation Mono, LiberationMonoRegular, Courier New, monospace;
}
.CodeMirror-code {
font-size: 16px;
}
.CodeMirror-scroll {
overflow-x: visible !important;
padding: 4px;
}
.CodeMirror-sizer {
margin-left: 0 !important;
}
.CodeMirror-gutters {
border-right: none;
background-color: #f7f7f7;
opacity: 0;
display: none;
}
}
.excel-codeBox-keyboard {
width: 272px;
min-height: 232px;
padding: 20px;
background: #fff;
border: 1px solid #e5e5e5;
border-left: none;
.excel-codeBox-keyboard-operate {
display: flex;
.excel-codeBox-keyboard-operate-content {
display: flex;
flex-wrap: wrap;
flex: 1;
.excel-codeBox-keyboard-base {
width: 30px;
height: 30px;
text-align: center;
margin: 0 10px 10px 0;
}
.excel-codeBox-keyboard-space {
width: 70px;
height: 30px;
}
}
.excel-codeBox-keyboard-operate-clear {
width: 30px;
.excel-codeBox-keyboard-del {
width: 30px;
height: 70px;
}
.excel-codeBox-keyboard-clear {
width: 30px;
height: 30px;
margin-top: 10px;
}
}
}
}
}
.excel-codeAction {
width: 100%;
display: flex;
justify-content: space-between;
.excel-codeAction-item:last-child {
margin-right: 0;
.excel-codeAction-header-title {
color: rgb(217, 82, 189);
}
}
.excel-codeAction-item {
width: 33%;
min-height: 317px;
flex: 1;
background: #fff;
border: 1px solid #e5e5e5;
margin-right: 16px;
display: flex;
flex-direction: column;
.excel-codeAction-header {
display: flex;
padding: 10px 16px;
border-bottom: 1px solid #e5e5e5;
.excel-codeAction-header-title {
flex: 1;
font-weight: 600;
}
}
.excel-codeAction-content {
flex: 1;
overflow: hidden auto;
padding: 0 16px;
max-height: 280px;
position: relative;
.variableOuterInput {
width: 100%;
margin-top: 10px;
position: sticky;
top: 10px;
background-color: #fff;
z-index: 1;
}
.variableTree {
li a:hover, li a.ant-tree-node-selected {
background: transparent;
}
li:first-child {
a {
padding: 2px 5px;
}
}
li a {
width: calc(100% - 16px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.ant-tree-title {
display: inline-block;
width: 100%;
.funcListTitle {
width: 100%;
display: flex;
justify-content: space-between;
& > span {
display: inline-block;
flex: 1 1;
overflow: hidden;
text-overflow: ellipsis;
word-break: keep-all;
white-space: nowrap;
}
.functionName {
max-width: 100px;
}
.functionDesc {
max-width: 100px;
text-align: right;
color: #999;
}
}
}
}
}
.code-action-list {
padding: 10px 0;
.code-action-tips-title{
height: 22px;
line-height: 22px;
}
.code-action-tips-info{
color: #999
}
}
}
}
}

View File

@ -0,0 +1,84 @@
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTools, WeaUpload } from "ecCom";
import { Icon, Modal } from "antd";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
const { viewer } = WeaTools;
class ImageUploadList extends Component {
constructor(props) {
super(props);
this.state = {
imageUrl: ""
};
}
componentDidMount() {
const { wmImg } = this.props;
if (!_.isEmpty(wmImg)) {
this.setState({
imageUrl: wmImg[0].imgSrc
});
}
}
handleChange = (ids, list) => {
this.setState({
imageUrl: list[0].imgSrc
}, () => this.props.onChange([{ imgSrc: this.state.imageUrl }]));
};
handleDelete = () => {
Modal.confirm({
title: getLabel(111, "信息确认"),
content: getLabel(111, "确认要删除吗?"),
onOk: () => {
this.setState({
imageUrl: ""
}, () => this.props.onChange(null));
}
});
};
render() {
const { imageUrl } = this.state;
const uploadProps = {
uploadUrl: "/api/doc/upload/uploadFile",
listType: "img",
limitType: "jpg,jpeg,png,gif",
category: "string",
maxFilesNumber: 1,
onChange: this.handleChange
};
const imgPreviewProps = {
src: imageUrl,
width: 100,
height: 100
};
return (
<div className="uploadWrapper">
{
imageUrl &&
<div className="previewWrapper">
<img data-imgsrc={imgPreviewProps.src} {...imgPreviewProps} onClick={viewer} alt=""/>
<div className="operateWrapper">
<i className="icon-coms-Delete operateIcon" onClick={this.handleDelete}/>
</div>
</div>
}
{
!imageUrl &&
<WeaUpload {...uploadProps}>
<div className="upload-select-picture-card">
<Icon type="plus"/>
<div className="uploadText">{getLabel(111, "上传图片")}</div>
</div>
</WeaUpload>
}
</div>
);
}
}
export default ImageUploadList;

View File

@ -0,0 +1,68 @@
.textSetting {
.uploadWrapper {
display: flex;
align-items: center;
position: relative;
.previewWrapper {
border: 1px solid #d9d9d9 !important;
img {
width: 100%;
height: 100%;
margin-left: 0 !important;
cursor: pointer;
}
.operateWrapper {
display: none;
}
}
.previewWrapper:hover {
.operateWrapper {
display: flex;
position: absolute;
align-items: center;
justify-content: flex-end;
width: 30px;
height: 20px;
background-color: rgba(0, 0, 0, 0.3);
bottom: 4px;
right: 13px;
border-radius: 3px;
padding-right: 4px;
}
}
}
.upload-select-picture-card, .previewWrapper {
border: 1px dashed #d9d9d9;
width: 96px;
height: 96px;
padding: 0;
border-radius: 6px;
background-color: #fbfbfb;
text-align: center;
cursor: pointer;
-webkit-transition: border-color .3s ease;
-o-transition: border-color .3s ease;
transition: border-color .3s ease;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 8px;
margin-bottom: 8px;
span.rc-upload {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
.upload-select-picture-card:hover {
border-color: #2db7f5;
}
}

View File

@ -32,6 +32,11 @@ import SysConfig from "./pages/sysConfig";
import RuleConfig from "./pages/ruleConfig";
import Appconfig from "./pages/appConfig";
import FieldManagement from "./pages/fieldManagement";
import AnalysisOfSalaryStatistics from "./pages/analysisOfSalaryStatistics";
import EmployeeList from "./pages/employeeView";
import ReportView from "./pages/reportView";
import MySalaryView from "./pages/mySalary/mySalaryView";
import WatermarkPreview from "./pages/payroll/watermarkPreview";
import ExternalPersonManage from "./pages/externalPersonManage";
import stores from "./stores";
@ -51,6 +56,7 @@ const SocialSecurityBenefits = (props) => props.children;
const DataAcquisition = (props) => props.children;
// mySalary 我的薪资福利
// mySalaryView 我的薪资福利-查看工资单
// socialSecurityBenefits 社保福利
// programme 社保福利方案
// archives 社保福利档案
@ -79,6 +85,8 @@ const DataAcquisition = (props) => props.children;
// sysconfig-1 规则配置
// appconfig 应用配置
// fieldManagement 字段管理
// analysisOfSalaryStatistics 薪酬统计分析
// reportView 薪酬报表查看
// externalPersonManage 非系统人员管理
const Routes = (
@ -88,6 +96,7 @@ const Routes = (
onEnter={getLocaleLabel}
component={Home}>
<Route key="mySalary" path="mySalary" component={MySalary}/>
<Route key="mySalaryView" path="mySalary/:salaryInfoId" component={MySalaryView}/>
<Route
key="socialSecurityBenefits"
path="socialSecurityBenefits"
@ -132,6 +141,7 @@ const Routes = (
/>
<Route key="compareDetail" path="compareDetail" component={CompareDetail}/>
<Route key="payroll" path="payroll" component={Payroll}/>
<Route key="watermarkPreview" path="payroll/watermark/preview" component={WatermarkPreview}/>
<Route key="payrollGrant" path="payrollGrant" component={PayrollGrant}/>
<Route key="payrollDetail" path="payrollDetail" component={PayrollDetail}/>
<Route
@ -152,6 +162,9 @@ const Routes = (
<Route key="sysconfig-1" path="sysconfig-1" component={RuleConfig}/>
<Route key="appconfig" path="appconfig" component={Appconfig}/>
<Route key="fieldManagement" path="fieldManagement" component={FieldManagement}/>
<Route key="analysisOfSalaryStatistics" path="analysisOfSalaryStatistics" component={AnalysisOfSalaryStatistics}/>
<Route key="analysisOfSalaryStatisticsId" path="analysisOfSalaryStatistics/:employeeId" component={EmployeeList}/>
<Route key="reportView" path="reportView" component={ReportView}/>
<Route key="externalPersonManage" path="externalPersonManage" component={ExternalPersonManage}/>
</Route>
);

View File

@ -0,0 +1,101 @@
import { WeaLocaleProvider } from "ecCom";
const { getLabel } = WeaLocaleProvider;
export const condition = [
{
items: [
{
colSpan: 1,
checkbox: false,
checkboxValue: false,
conditionType: "SELECT",
domkey: ["dimType"],
fieldcol: 14,
label: getLabel(111, "维度类型"),
labelcol: 6,
options: [],
detailtype: 3,
rules: "required|string",
viewAttr: 3
},
{
colSpan: 1,
conditionType: "SELECT",
domkey: ["setting4Qualitative"],
fieldcol: 14,
label: getLabel(111, "统计维度"),
labelcol: 6,
options: [],
rules: "required|string",
viewAttr: 3
},
{
colSpan: 1,
conditionType: "INPUT",
domkey: ["dimName"],
fieldcol: 14,
label: getLabel(111, "统计维度名称"),
labelcol: 6,
value: "",
rules: "required|string",
viewAttr: 3
},
{
colSpan: 1,
conditionType: "SELECT",
domkey: ["dimCode"],
fieldcol: 14,
label: getLabel(111, "分组所属字段"),
labelcol: 6,
options: [],
viewAttr: 2,
helpfulTip: "",
hide: true
},
{
colSpan: 1,
conditionType: "TEXTAREA",
domkey: ["remark"],
fieldcol: 14,
label: getLabel(111, "描述"),
labelcol: 6,
value: "",
viewAttr: 2
}
],
title: getLabel(111, "基础设置"),
defaultshow: true
}
];
export const reportCondition = [
{
items: [
{
colSpan: 1,
conditionType: "INPUT",
domkey: ["reportName"],
fieldcol: 14,
label: getLabel(111, "报表名称"),
labelcol: 6,
value: "",
rules: "required|string",
viewAttr: 3
},
{
colSpan: 1,
conditionType: "SELECT",
domkey: ["dimensionIds"],
fieldcol: 14,
label: getLabel(111, "统计维度"),
labelcol: 6,
options: [],
rules: "required|string",
viewAttr: 3,
helpfulTip: "",
hide: true
}
],
title: "",
defaultshow: true
}
];

View File

@ -0,0 +1,205 @@
/*
* Author: 黎永顺
* name: 新增统计维度弹框
* Description:
* Date: 2023/4/11
*/
import React, { Component } from "react";
import { WeaDialog, WeaLocaleProvider, WeaSearchGroup } from "ecCom";
import { Button, message, Modal } from "antd";
import { dimensionGetForm, dimensionSave } from "../../../apis/statistics";
import { getSearchs } from "../../../util";
import GroupSpacingEditTable from "./groupSpacingEditTable";
import GroupIndividualEditTable from "./groupIndividualEditTable";
import "../index.less";
const { getLabel } = WeaLocaleProvider;
const keyObj = {
"RATION_GROUP_SPACING": "setting4RationGroupSpacing",
"RATION_GROUP_INDIVIDUAL": "setting4RationGroupIndividual"
};
class DimensionSlide extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
dimType: "QUALITATIVE",
setting4RationGroupSpacing: [],
setting4RationGroupIndividual: []
};
}
componentDidMount() {
this.props.initCondition();
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.visible !== this.props.visible && nextProps.formId) this.dimensionGetForm({ id: nextProps.formId });
if (nextProps.visible !== this.props.visible && !nextProps.formId) {
nextProps.form.updateFields({
dimType: "QUALITATIVE"
});
nextProps.onChangeCondition("QUALITATIVE");
}
if (nextProps.visible !== this.props.visible && !nextProps.visible) {
this.setState({
loading: false,
dimType: "QUALITATIVE",
setting4RationGroupSpacing: [],
setting4RationGroupIndividual: []
});
}
}
dimensionGetForm = (payload) => {
dimensionGetForm(payload).then(({ status, data }) => {
if (status) {
const { baseForm: { data: formData } } = data;
const setting = formData.setting ? JSON.parse(formData.setting) : {};
this.props.onChangeCondition(formData["dimType"], 1);
this.setState({
dimType: formData.dimType,
[keyObj[formData["dimType"]]]: setting
}, () => {
const fields = _.map(this.props.condition[0].items, it => {
return it.domkey[0];
});
fields.map(item => {
if (item !== "setting4Qualitative") {
this.props.form.updateFields({
[item]: formData[item] || ""
});
} else if (item === "setting4Qualitative" && formData.statsDim) {
this.props.form.updateFields({
setting4Qualitative: formData.statsDim
});
}
});
});
}
});
};
handleSave = () => {
const { dimType } = this.state;
const { condition, onCancel, formId } = this.props;
const { setting4Qualitative, dimCode, ...extraParams } = this.props.form.getFormParams();
let payload = { id: formId, ...extraParams };
if (dimType === "QUALITATIVE") {
if (!setting4Qualitative || !extraParams.dimName) {
Modal.warning({
title: getLabel(111, "信息确认"),
content: getLabel(111, "必要信息不完整,红色*为必填项!")
});
return;
}
const tjOptions = _.find(condition[0].items, item => item.domkey[0] === "setting4Qualitative").options;
const tjObj = _.find(tjOptions, item => item.key === setting4Qualitative);
payload = { ...payload, setting4Qualitative: { id: tjObj.key, name: tjObj.showname } };
} else {
if (!extraParams.dimName) {
Modal.warning({
title: getLabel(111, "信息确认"),
content: getLabel(111, "必要信息不完整,红色*为必填项!")
});
return;
}
if (dimType === "RATION_GROUP_SPACING") {
const { setting4RationGroupSpacing } = this.state;
const bool = _.every(setting4RationGroupSpacing, it => it.startValue !== "" && it.endValue !== "" && it.startValue <= it.endValue);
if (_.isEmpty(setting4RationGroupSpacing) || !bool) {
message.warning(getLabel(111, "请完善分组设置相关数据!分组设置不能为空,起始值结束值必填,且起始值需小于结束值!"));
return;
} else {
payload = {
...payload, dimCode,
setting4RationGroupSpacing: _.map(setting4RationGroupSpacing, (it, index) => ({
id: index + 1,
endValue: it.endValue,
startValue: it.startValue,
includeEnd: it.includeEnd === "1",
includeStart: it.includeStart === "1"
}))
};
}
} else if (dimType === "RATION_GROUP_INDIVIDUAL") {
const { setting4RationGroupIndividual } = this.state;
const bool = _.every(setting4RationGroupIndividual, it => it.value !== "");
if (_.isEmpty(setting4RationGroupIndividual) || !bool) {
message.warning(getLabel(111, "请完善分组设置相关数据!分组设置不能为空,且数值必填"));
return;
} else {
payload = {
...payload, dimCode,
setting4RationGroupIndividual: _.map(setting4RationGroupIndividual, (it, index) => ({ id: index + 1, ...it }))
};
}
}
}
this.setState({ loading: true });
dimensionSave(payload).then(({ status, errormsg }) => {
this.setState({ loading: false });
if (status) {
message.success(getLabel(111, "保存成功"));
onCancel(true);
this.props.form.resetForm();
} else {
message.error(errormsg || getLabel(111, "保存失败"));
}
}).catch(() => this.setState({ loading: false }));
};
formItemChange = (formObj) => {
const { onChangeCondition } = this.props;
const filedKey = _.keys(formObj)[0];
if (filedKey === "dimType") {
this.setState({
dimType: formObj[filedKey].value,
setting4RationGroupSpacing: [],
setting4RationGroupIndividual: []
}, () => onChangeCondition(formObj[filedKey].value));
}
};
handleConvertGroupDatasource = (data) => {
const { dimType } = this.state;
this.setState({ [keyObj[dimType]]: data });
};
render() {
const { loading, dimType, setting4RationGroupSpacing, setting4RationGroupIndividual } = this.state;
const { form, condition, formId } = this.props;
return (
<WeaDialog
{...this.props}
initLoadCss hasScroll
style={{ width: 900, height: 450 }}
className="dimensionSlideWrapper"
title={
<div className="dimensionTitle">
<span>{formId ? getLabel(111, "编辑统计维度") : getLabel(111, "新建统计维度")}</span>
<Button type="primary" onClick={this.handleSave} loading={loading}>{getLabel(111, "保存")}</Button>
</div>
}
>
{getSearchs(form, condition, 1, false, this.formItemChange)}
{
dimType !== "QUALITATIVE" &&
<WeaSearchGroup title={getLabel(111, "分组设置")} showGroup>
{
dimType === "RATION_GROUP_SPACING" &&
<GroupSpacingEditTable onChange={this.handleConvertGroupDatasource}
setting4RationGroupSpacing={setting4RationGroupSpacing}/>
}
{
dimType === "RATION_GROUP_INDIVIDUAL" &&
<GroupIndividualEditTable onChange={this.handleConvertGroupDatasource}
setting4RationGroupIndividual={setting4RationGroupIndividual}/>
}
</WeaSearchGroup>
}
</WeaDialog>
);
}
}
export default DimensionSlide;

View File

@ -0,0 +1,121 @@
/*
* Author: 黎永顺
* name: 统计维度管理列表
* Description:
* Date: 2023/4/11
*/
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTable } from "ecCom";
import { message, Modal } from "antd";
import { dimensionDelete, dimensionList } from "../../../apis/statistics";
import "../index.less";
const { getLabel } = WeaLocaleProvider;
class DimensionTable extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
dataSource: [],
pageInfo: {
current: 1, pageSize: 10, total: 0
}
};
}
componentDidMount() {
this.dimensionList();
}
dimensionList = (extra = {}) => {
const { pageInfo } = this.state;
this.setState({ loading: true });
dimensionList({ ...pageInfo, ...extra }).then(({ status, data }) => {
this.setState({ loading: false });
if (status) {
const { pageNum: current, pageSize, total, list: dataSource } = data;
this.setState({
dataSource,
pageInfo: {
...pageInfo,
current, pageSize, total
}
});
}
}).catch(() => this.setState({ loading: false }));
};
dimensionDelete = (payload) => {
Modal.confirm({
title: getLabel(111, "信息确认"),
content: getLabel(111, "确认要删除吗?"),
onOk: () => {
dimensionDelete(payload).then(({ status, errormsg }) => {
if (status) {
message.success(getLabel(111, "删除成功"));
this.dimensionList();
} else {
message.error(errormsg || getLabel(111, "删除失败"));
}
});
}
});
};
render() {
const { dataSource, loading, pageInfo } = this.state;
const { onEdit } = this.props;
const pagination = {
...pageInfo,
showTotal: total => `${getLabel(111, "共")} ${total} ${getLabel(111, "条")}`,
showQuickJumper: true,
showSizeChanger: true,
pageSizeOptions: ["10", "20", "50", "100"],
onShowSizeChange: (current, pageSize) => {
this.setState({
pageInfo: { ...pageInfo, current, pageSize }
}, () => this.dimensionList());
},
onChange: current => {
this.setState({
pageInfo: { ...pageInfo, current }
}, () => this.dimensionList());
}
};
const columns = [
{ dataIndex: "dimName", title: getLabel(111, "统计维度") },
{ dataIndex: "remark", title: getLabel(111, "描述") },
{ dataIndex: "dimType", title: getLabel(111, "维度类型") },
{
dataIndex: "operate", title: getLabel(111, "操作"),
render: (_, record) => {
return (
<span className="space10">
{
record.canEdit &&
<a href="javascript: void(0);" onClick={() => onEdit(record.id)}>{getLabel(111, "编辑")}</a>
}
{
record.canDelete &&
<a href="javascript: void(0);"
onClick={() => this.dimensionDelete([record.id])}>{getLabel(111, "删除")}</a>
}
</span>
);
}
}
];
return (
<WeaTable
rowKey="id"
className="dimensionTableWrapper"
dataSource={dataSource}
pagination={pagination}
loading={loading}
columns={columns}
/>
);
}
}
export default DimensionTable;

View File

@ -0,0 +1,103 @@
/*
* Author: 黎永顺
* name: 员工明细列表
* Description:
* Date: 2023/5/24
*/
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTable } from "ecCom";
import { statisticsEmployeeList } from "../../../apis/statistics";
import "../index.less";
const { getLabel } = WeaLocaleProvider;
class EmployeeDetails extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
dataSource: [],
columns: [],
pageInfo: {
current: 1,
pageSize: 10,
total: 0
}
};
}
componentDidMount() {
this.statisticsEmployeeList();
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.year !== this.props.year) this.statisticsEmployeeList(nextProps);
}
statisticsEmployeeList = (props) => {
const { pageInfo } = this.state;
const payload = {
year: props ? props.year : this.props.year,
keyword: props ? props.keyword : this.props.keyword,
...pageInfo
};
this.setState({ loading: true });
statisticsEmployeeList(payload).then(({ status, data }) => {
this.setState({ loading: false });
if (status) {
const { columns, list: dataSource, pageNum: current, total, pageSize } = data;
this.setState({
pageInfo: { ...pageInfo, current, pageSize, total },
dataSource,
columns: [...columns, {
title: "操作",
dataIndex: "operate",
width: 80,
render: (_, record) => {
return <a target="_blank"
href={`${window.location.origin}/spa/hrmSalary/static/index.html#/main/hrmSalary/analysisOfSalaryStatistics/${record.id}?name=${record.name}&dept=${record.department || ""}`}>{getLabel(111, "查看")}</a>;
}
}]
});
}
}).catch(() => this.setState({ loading: false }));
};
render() {
const { dataSource, loading, columns, pageInfo } = this.state;
const pagination = {
...pageInfo,
showTotal: total => `${getLabel(111, "共")} ${total} ${getLabel(111, "条")}`,
showQuickJumper: true,
showSizeChanger: true,
pageSizeOptions: ["10", "20", "50", "100"],
onShowSizeChange: (current, pageSize) => {
this.setState({
pageInfo: { ...pageInfo, current, pageSize }
}, () => {
this.statisticsEmployeeList();
});
},
onChange: current => {
this.setState({
pageInfo: { ...pageInfo, current }
}, () => {
this.statisticsEmployeeList();
});
}
};
return (
<WeaTable
rowKey="id"
className="employeeTableWrapper"
dataSource={dataSource}
pagination={pagination}
loading={loading}
columns={columns}
scroll={{ y: `calc(100vh - 174px)` }}
/>
);
}
}
export default EmployeeDetails;

View File

@ -0,0 +1,52 @@
/*
* Author: 黎永顺
* name: 分组设置-定量-单项式分组编辑表格
* Description:
* Date: 2023/4/12
*/
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTableEdit } from "ecCom";
const { getLabel } = WeaLocaleProvider;
class GroupIndividualEditTable extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: []
};
}
componentDidMount() {
const { setting4RationGroupIndividual } = this.props;
this.setState({
dataSource: setting4RationGroupIndividual
});
}
handleChangeTableData = (dataSource) => {
const { onChange } = this.props;
this.setState({ dataSource }, () => onChange(this.state.dataSource));
};
render() {
const { dataSource } = this.state;
const columns = [
{
title: getLabel(111, "分组设置值"),
dataIndex: "value",
key: "value",
com: [
{ label: "", key: "value", type: "INPUTNUMBER" }
]
}
];
return (
<WeaTableEdit
draggable={true} columns={columns} datas={dataSource}
showCopy={false} deleteConfirm onChange={this.handleChangeTableData}
/>
);
}
}
export default GroupIndividualEditTable;

View File

@ -0,0 +1,100 @@
/*
* Author: 黎永顺
* name: 分组设置-定量-组距式分组编辑表格
* Description:
* Date: 2023/4/12
*/
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTableEdit } from "ecCom";
const { getLabel } = WeaLocaleProvider;
class GroupSpacingEditTable extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: []
};
}
componentDidMount() {
const { setting4RationGroupSpacing } = this.props;
this.setState({
dataSource: _.map(setting4RationGroupSpacing, item => {
return {
...item,
includeStart: item.includeStart ? "1" : "0",
includeEnd: item.includeEnd ? "1" : "0"
};
})
});
}
handleChangeTableData = (dataSource) => {
const { onChange } = this.props;
this.setState({ dataSource }, () => onChange(this.state.dataSource));
};
render() {
const { dataSource } = this.state;
const columns = [
{
title: getLabel(111, "起始值"),
dataIndex: "startValue",
key: "startValue",
com: [
{ label: "", key: "startValue", type: "INPUTNUMBER" }
]
},
{
title: getLabel(111, "含"),
dataIndex: "includeStart",
key: "includeStart",
com: [
{
type: "CHECKBOX",
key: "includeStart",
otherParams: { content: getLabel(111, "含") }
}
]
},
{
title: getLabel(111, "至"),
dataIndex: "to",
key: "to",
com: [
{ label: "", type: "TEXT" }
]
},
{
title: getLabel(111, "结束值"),
dataIndex: "endValue",
key: "endValue",
com: [
{ label: "", key: "endValue", type: "INPUTNUMBER" }
]
},
{
title: getLabel(111, "含"),
dataIndex: "includeEnd",
key: "includeEnd",
com: [
{
type: "CHECKBOX",
key: "includeEnd",
otherParams: { content: getLabel(111, "含") }
}
]
}
];
return (
<WeaTableEdit
draggable={true} deleteConfirm columns={columns}
datas={_.map(dataSource, item => ({ ...item, to: getLabel(111, "至") }))}
showCopy={false} onChange={this.handleChangeTableData}
/>
);
}
}
export default GroupSpacingEditTable;

View File

@ -0,0 +1,19 @@
/*
* Author: 黎永顺
* name: 报表表单
* Description:
* Date: 2023/4/17
*/
import React, { Component } from "react";
import { getSearchs } from "../../../util";
class ReportForm extends Component {
render() {
const { form, condition } = this.props;
return (
<React.Fragment>{getSearchs(form, condition, 1, false)}</React.Fragment>
);
}
}
export default ReportForm;

View File

@ -0,0 +1,106 @@
/*
* Author: 黎永顺
* name: 统计表
* Description:
* Date: 2023/4/17
*/
import React, { Component } from "react";
import { WeaLocaleProvider } from "ecCom";
import { Button, Col, Dropdown, Menu, message, Modal, Row } from "antd";
import { reportStatisticsReportDelete, reportStatisticsReportList } from "../../../apis/statistics";
import "../index.less";
const SubMenu = Menu.SubMenu;
const { getLabel } = WeaLocaleProvider;
class ReportList extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: []
};
}
componentDidMount() {
this.reportStatisticsReportList();
}
handleOptsClick = ({ key }, id, dimensionId) => {
if (key === "delete") {
this.reportStatisticsReportDelete(id.split(","));
} else if (key === "edit") {
this.props.onEdit("addReport", id);
}
};
reportStatisticsReportDelete = (payload) => {
Modal.confirm({
title: getLabel(111, "信息确认"),
content: getLabel(111, "确认删除本条数据吗?"),
onOk: () => {
const { reportName = "" } = this.props;
reportStatisticsReportDelete(payload).then(({ status, errormsg }) => {
if (status) {
message.success(getLabel(111, "删除成功"));
this.reportStatisticsReportList({ reportName });
} else {
message.error(errormsg || getLabel(111, "删除失败"));
}
});
}
});
};
reportStatisticsReportList = (payload = {}) => {
reportStatisticsReportList(payload).then(({ status, data: dataSource }) => {
if (status) {
this.setState({ dataSource });
}
});
};
/*
* Author: 黎永顺
* Description: 报表查看
* Params:
* Date: 2023/4/20
*/
handleGoReportView = (id) => {
window.open(`${window.location.origin}/spa/hrmSalary/static/index.html#/main/hrmSalary/reportView?id=${id}`);
};
render() {
const { dataSource } = this.state;
return (
<Row gutter={16} className="reportRow">
{
_.isEmpty(dataSource) ? <div className="empty">{getLabel(111, "暂无数据")}</div> :
_.map(dataSource, it => {
const { reportName, dimension, id, dimensionId } = it;
return <Col className="gutter-row" span={6} onClick={() => this.handleGoReportView(id)}>
<div className="card-item">
<div className="cardLeft"><i className="icon-coms-fa"/></div>
<div className="cardCenter">
<span className="reportName">{reportName}</span>
<div className="dimension">
<div className="label">{getLabel(111, "统计维度")}</div>
<div className="value">{dimension}</div>
</div>
</div>
<div className="cardRight">
<Dropdown overlay={
<Menu onClick={e => this.handleOptsClick(e, id, dimensionId)}>
<Menu.Item key="edit">{getLabel(111, "编辑")}</Menu.Item>
<Menu.Item key="delete">{getLabel(111, "删除")}</Menu.Item>
</Menu>
}>
<Button type="ghost"><i className="icon-coms-more"/></Button>
</Dropdown>
</div>
</div>
</Col>;
})
}
</Row>
);
}
}
export default ReportList;

View File

@ -0,0 +1,70 @@
/*
* Author: 黎永顺
* name: 统计弹框
* Description:
* Date: 2023/4/10
*/
import React, { Component } from "react";
import { Button, message, Modal } from "antd";
import { WeaDialog, WeaLocaleProvider } from "ecCom";
import { reportStatisticsReportSave } from "../../../apis/ruleconfig";
import "../index.less";
const { getLabel } = WeaLocaleProvider;
class StatisticsModal extends Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
handleSaveReportList = () => {
const { form, id, onCancel } = this.props;
form.validateForm().then(f => {
if (f.isValid) {
const { dimensionIds, reportName } = form.getFormParams();
const payload = { id, reportName, dimensionIds: dimensionIds.split(",") };
this.setState({ loading: true });
reportStatisticsReportSave(payload).then(({ status, errormsg }) => {
this.setState({ loading: false });
if (status) {
onCancel(true);
message.success(getLabel(111, "保存成功"));
form.resetForm();
} else {
message.error(errormsg || getLabel(111, "保存失败"));
}
}).catch(() => this.setState({ loading: false }));
} else {
Modal.warning({
title: getLabel(111, "信息确认"),
content: getLabel(111, "必要信息不完整,红色*为必填项!")
});
}
});
};
render() {
const { loading } = this.state;
const { typeKey, onCancel } = this.props;
const buttons = typeKey === "addReport" ? [
<Button type="primary" onClick={this.handleSaveReportList} loading={loading}>{getLabel(111, "保存")}</Button>
] : [];
return (
<WeaDialog
{...this.props} hasScroll
style={typeKey === "addReport" ? { width: 600 } : { width: 640, height: 540 }}
buttons={buttons}
onCancel={onCancel}
initLoadCss
className="dimensionModalWrapper"
>
{this.props.children}
</WeaDialog>
);
}
}
export default StatisticsModal;

View File

@ -0,0 +1,312 @@
/*
* Author: 黎永顺
* name: 薪酬统计分析
* Description:
* Date: 2023/4/10
*/
import React, { Component } from "react";
import { inject, observer } from "mobx-react";
import { WeaDatePicker, WeaInputSearch, WeaLocaleProvider, WeaReqTop } from "ecCom";
import { Button } from "antd";
import { condition, reportCondition } from "./components/conditions";
import { commonEnumList, reportGetForm } from "../../apis/ruleconfig";
import { dimensionGetForm } from "../../apis/statistics";
import EmployeeDetails from "./components/employeeDetails";
import StatisticsModal from "./components/statisticsModal";
import DimensionSlide from "./components/dimensionSlide";
import DimensionTable from "./components/dimensionTable";
import ReportList from "./components/reportList";
import ReportForm from "./components/reportForm";
import moment from "moment";
import "./index.less";
const { getLabel } = WeaLocaleProvider;
@inject("taxAgentStore", "attendanceStore")
@observer
class Index extends Component {
constructor(props) {
super(props);
this.state = {
conditions: [],
convertConditions: [],
reportConditions: [],
selectedKey: "statistics",
reportName: "",
keyword: "",
year: moment().format("YYYY"),
slideReq: {
visible: false, formId: ""
},
modalReq: {
title: "", visible: false,
typeKey: "", id: ""
}
};
}
componentDidMount() {
this.initReportFormCondition();
}
initReportFormCondition = (payload = {}) => {
const { attendanceStore: { reportForm } } = this.props;
reportGetForm(payload).then(({ status, data }) => {
if (status) {
const { statsDimOptions, data: detailData } = data;
if (_.isEmpty(payload)) {
this.setState({
reportConditions: _.map(reportCondition, item => {
return {
...item,
items: _.map(item.items, child => {
if (child.domkey[0] === "dimensionIds") {
return {
...child,
options: _.map(statsDimOptions, dimTypeItem => ({
key: dimTypeItem.id,
showname: dimTypeItem.content
}))
};
}
return { ...child };
})
};
})
}, () => {
reportForm.initFormFields(this.state.reportConditions);
});
} else {
reportForm.updateFields({
reportName: detailData.reportName,
dimensionIds: detailData.dimension.join(",")
});
}
}
});
};
initCondition = async () => {
const { attendanceStore: { statisticsForm } } = this.props;
const [dimTypeEnum, dimCodeList] = await Promise.all([this.commonEnumList(), this.dimensionGetForm()]);
const { data: dimTypeData } = dimTypeEnum, { data: dimCodeData } = dimCodeList;
const { baseForm: { statsDimOptions, groupDimOptions, data: dimTypeValue } } = dimCodeData;
this.setState({
conditions: _.map(condition, item => {
return {
...item,
items: _.map(item.items, child => {
if (child.domkey[0] === "dimType") {
return {
...child,
value: dimTypeValue.dimType,
options: _.map(dimTypeData, dimTypeItem => ({
key: dimTypeItem.value,
showname: dimTypeItem.defaultLabel
}))
};
}
if (child.domkey[0] === "setting4Qualitative") {
return {
...child,
options: _.map(statsDimOptions, dimCodeItem => ({
key: dimCodeItem.id,
showname: dimCodeItem.content
}))
};
}
if (child.domkey[0] === "dimCode") {
return {
...child,
options: _.map(groupDimOptions, dimCodeItem => ({
key: dimCodeItem.id,
showname: dimCodeItem.content
}))
};
}
return { ...child };
})
};
})
}, () => {
this.setState({ convertConditions: this.state.conditions });
statisticsForm.initFormFields(this.state.conditions);
});
};
commonEnumList = () => {
const payload = {
enumClass: "com.engine.salary.report.enums.SalaryStatisticsDimensionTypeEnum"
};
return commonEnumList(payload);
};
dimensionGetForm = () => {
return dimensionGetForm();
};
handleChangeCondition = (val, viewAttr) => {
const { attendanceStore: { statisticsForm } } = this.props;
const helpfulTitle = val === "RATION_GROUP_SPACING" ?
"例:\n" +
" 若所属字段为【工龄】分组设置为【0-5】【5-10】统计项为【税前薪资】对应的统计规则为【求和】 则统计结果为【工龄】为【0-5】的所有人的【税前薪资】求和【工龄】为【5-10】的所有人的【税前薪资】求和\n" +
"若未选择所属字段分组设置为【0-10,000.00】【10,000.00-20,000.00】;若统计项为【税前薪资】,对应的统计规则为【计数】; 则统计结果为【税前薪资】为【0-10,000.00】有多少人【税前薪资】为【10,000.00-20,000.00】有多少人;" :
val === "RATION_GROUP_INDIVIDUAL" ?
"例:\n" +
" 若所属字段为【职级】分组设置为【1】【2】【3】统计项为【税前薪资】对应的统计规则为【平均值】 则统计结果为【职级】为【1】的所有人的【税前薪资】的平均值【职级】为【2】的所有人的【税前薪资】的平均值【职级】为【3】的所有人的【税前薪资】的平均值\n" +
"若未选择所属字段分组设置为【1】【2】【3】若统计项为【绩效】对应的统计规则为【计数】 则统计结果为【绩效】为【1】有多少人绩效为【2】有多少人绩效为【3】有多少人" : "";
if (val === "QUALITATIVE") {
this.setState({
conditions: _.map(this.state.convertConditions, item => {
return {
...item,
items: _.map(_.filter(item.items, child => child.domkey[0] !== "dimCode"), it => {
if (it.domkey[0] === "dimType") {
return { ...it, value: val, viewAttr: viewAttr ? viewAttr : it.viewAttr };
}
return { ...it };
})
};
})
}, () => {
statisticsForm.setCondition(this.state.conditions);
});
} else {
this.setState({
conditions: _.map(this.state.convertConditions, item => {
return {
...item,
items: _.map(_.filter(item.items, child => child.domkey[0] !== "setting4Qualitative"), it => {
if (it.domkey[0] === "dimType") {
return { ...it, value: val, viewAttr: viewAttr ? viewAttr : it.viewAttr };
} else if (it.domkey[0] === "dimCode") {
return { ...it, helpfulTitle };
}
return { ...it };
})
};
})
}, () => {
statisticsForm.setCondition(this.state.conditions);
});
}
};
handleReqBtnsClick = (key, id = "") => {
if (key === "search") {
const { reportName } = this.state;
this.reportListRef.reportStatisticsReportList({ reportName });
} else {
const { modalReq } = this.state;
const title = key === "dimension" ?
<div className="dimensionTitle">
<span>{getLabel(111, "统计维度管理")}</span>
<Button type="primary" onClick={() => this.handleAddDimension()}>{getLabel(111, "新建统计维度")}</Button>
</div>
: getLabel(111, id ? "编辑报表" : "新建报表");
this.setState({
modalReq: {
...modalReq, id, title,
visible: true, typeKey: key
}
}, () => id && this.initReportFormCondition({ id }));
}
};
handleCancel = (refresh = false) => {
const { attendanceStore: { reportForm } } = this.props;
const { modalReq } = this.state;
this.setState({
modalReq: {
...modalReq, visible: false, id: ""
}
}, () => {
const { selectedKey, reportName, modalReq: { typeKey } } = this.state;
selectedKey === "statistics" && reportForm.resetForm();
typeKey === "dimension" && this.initReportFormCondition();
refresh && selectedKey === "statistics" && this.reportListRef.reportStatisticsReportList({ reportName });
});
};
handleAddDimension = (formId = "") => {
const { slideReq } = this.state;
this.setState({
slideReq: {
...slideReq, visible: true,
formId
}
});
};
handleClose = (initTable = false) => {
const { attendanceStore: { statisticsForm } } = this.props;
const { slideReq } = this.state;
this.setState({
slideReq: {
...slideReq, visible: false, formId: ""
}
}, () => {
statisticsForm.resetForm();
initTable && this.dimensionTableRef.dimensionList();
});
};
render() {
const { taxAgentStore: { statisticsReportBtn }, attendanceStore: { statisticsForm, reportForm } } = this.props;
const { selectedKey, modalReq, slideReq, conditions, reportConditions, reportName, keyword, year } = this.state;
const buttons = selectedKey === "statistics" ? [
<Button type="primary" onClick={() => this.handleReqBtnsClick("addReport")}>{getLabel(111, "新建报表")}</Button>,
<Button type="ghost"
onClick={() => this.handleReqBtnsClick("dimension")}>{getLabel(111, "维度统计管理")}</Button>,
<WeaInputSearch placeholder={getLabel(111, "请输入报表名称")} className="search"
value={reportName}
onChange={reportName => this.setState({ reportName })}
onSearch={() => this.handleReqBtnsClick("search")}/>
] : [
<span className="employeeYearWrapper">
<span>{getLabel(111, "年薪资核算人员明细:")}</span>
<WeaDatePicker value={year} format="YYYY" onChange={year => this.setState({ year })}/>
</span>,
<WeaInputSearch placeholder={getLabel(111, "请输入姓名、工号、身份证号")} className="search"
value={keyword}
onChange={keyword => this.setState({ keyword })}
onSearch={() => this.employeeListRef.statisticsEmployeeList()}/>
];
const tabs = [
{ key: "statistics", title: getLabel(111, "统计表") },
{ key: "detail", title: getLabel(111, "员工明细") }
];
return (
<WeaReqTop
title={getLabel(111, "薪酬统计报表")} icon={<i className="icon-coms-fa"/>} selectedKey={selectedKey}
iconBgcolor="#F14A2D" tabDatas={tabs} className="xc_tj_fx_wrapper" showDropIcon={false}
buttons={(!statisticsReportBtn && selectedKey === "statistics") ? buttons.slice(-1) : buttons} buttonSpace={10}
onChange={selectedKey => this.setState({ selectedKey }, () => this.state.selectedKey === "statistics" && this.initReportFormCondition())}
>
{
selectedKey === "statistics" ?
<ReportList
ref={dom => this.reportListRef = dom}
reportName={reportName}
onEdit={this.handleReqBtnsClick}
/> : <EmployeeDetails
ref={dom => this.employeeListRef = dom}
keyword={keyword} year={year}
/>
}
<StatisticsModal {...modalReq} onCancel={this.handleCancel} form={reportForm}>
{
modalReq.typeKey === "dimension" &&
<DimensionTable ref={dom => this.dimensionTableRef = dom}
onEdit={id => this.handleAddDimension(id)}
/>
}
{
modalReq.typeKey === "addReport" &&
<ReportForm form={reportForm} condition={reportConditions}/>
}
</StatisticsModal>
<DimensionSlide
{...slideReq} onCancel={this.handleClose}
form={statisticsForm} condition={conditions}
initCondition={this.initCondition} onChangeCondition={this.handleChangeCondition}
/>
</WeaReqTop>
);
}
}
export default Index;

View File

@ -0,0 +1,178 @@
.xc_tj_fx_wrapper {
.search {
top: -3px;
margin-right: 10px;
width: 220px;
}
.employeeYearWrapper {
display: flex;
align-items: center;
& > span:first-child {
margin-right: 4px;
}
}
.wea-new-top-req-content {
background: #FFF;
.reportRow {
padding: 16px;
.gutter-row {
margin-bottom: 16px;
border-radius: 6px;
.card-item {
border-radius: 6px;
display: flex;
height: 90px;
justify-content: space-between;
padding: 22px 0 22px 16px;
border: 1px solid #e5e5e5;
.cardLeft {
display: flex;
align-items: center;
justify-content: center;
i {
padding: 10px;
color: #FFF;
font-size: 20px;
border-radius: 50%;
background-color: #ff666a;
}
}
.cardCenter {
display: flex;
flex: 1;
flex-direction: column;
justify-content: space-between;
margin-left: 10px;
.reportName {
font-size: 14px;
color: #111;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dimension {
display: flex;
.label {
height: 12px;
font-size: 12px;
color: #999;
line-height: 12px;
font-weight: 400;
}
.value {
height: 12px;
font-size: 12px;
color: #111;
line-height: 12px;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.cardRight {
display: flex;
align-items: center;
justify-content: center;
.ant-btn-ghost {
color: #999;
border: 1px solid transparent;
}
.ant-btn-ghost:focus, .ant-btn-ghost:hover,
.ant-btn-ghost.active, .ant-btn-ghost:active {
color: #2baee9;
background-color: #FFF;
border: 1px solid #e5e5e5;
}
}
}
}
.card-item:hover {
cursor: pointer;
box-shadow: 0 3px 12px 0 rgba(0, 0, 0, .12);
}
}
.empty {
font-size: 16px;
width: 100%;
text-align: center;
margin-top: 26px;
}
}
}
//统计维度弹框
.dimensionModalWrapper, .dimensionSlideWrapper {
.dimensionTitle {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.dimensionTableWrapper {
.space10 {
a:first-child {
margin-right: 10px;
}
}
}
}
.dimensionSlideWrapper, .dimensionModalWrapper {
.wea-search-group {
.wea-select, .ant-select, .ant-select-selection {
width: 100%;
}
}
}
//员工明细
.employeeTableWrapper {
.operates i.icon-coms-more {
padding: 5px 0;
display: inline-block;
width: 40px;
font-size: 20px;
color: #333;
cursor: pointer;
font-weight: 400;
}
}
.operatePopover {
.ant-popover-inner {
min-width: 100px !important;
}
.ant-popover-inner-content {
padding: 0;
.ant-menu {
border-right: none;
}
}
}

View File

@ -1,8 +1,8 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { Button, DatePicker, Dropdown, Menu, message, Modal, Tag } from "antd";
import { WeaInputSearch, WeaNewScroll, WeaTop } from "ecCom";
import { renderNoright } from "../../util"; // 渲染form数据的方法因为多个页面都会使用所以抽的公共方法在util中
import { WeaInputSearch, WeaLocaleProvider, WeaNewScroll, WeaTop } from "ecCom";
import { renderNoright } from "../../util";
import CustomTab from "../../components/customTab";
import moment from "moment";
import BaseFormModal from "./baseFormModal";
@ -10,6 +10,7 @@ import CustomPaginationTable from "../../components/customPaginationTable";
import ProgressModal from "../../components/progressModal";
import "./index.less";
const { getLabel } = WeaLocaleProvider;
const MonthPicker = DatePicker.MonthPicker;
@inject("calculateStore", "taxAgentStore")
@ -185,16 +186,11 @@ export default class Calculate extends React.Component {
</div>;
};
}
if (item.title == "操作" && showOperateBtn) {
if (item.dataIndex === "operate" && showOperateBtn) {
item.width = 150;
item.render = (text, record) => {
const accountBtn = _.filter(
record.operate,
it => it.text == "核算" || it.text == "重新核算"
);
const notAccountBtn = _.filter(
record.operate,
it => it.text != "核算" && it.text != "重新核算"
);
const accountBtn = _.take(record.operate, 2);
const notAccountBtn = _.drop(record.operate, 2);
let operateBtn = [];
if (!_.isEmpty(accountBtn)) {
operateBtn.push(
@ -206,13 +202,8 @@ export default class Calculate extends React.Component {
style={{ display: "inline-block", marginRight: 8 }}>
<a
href="javascript:void(0);"
onClick={() => {
if (it.text == "核算" || it.text == "重新核算") {
it.text == "核算"
? this.handleAccount(record)
: this.handleReaccount(record);
}
}}>
style={(idx === 1 && it.text.length === 2) ? { padding: "0 12px" } : {}}
onClick={() => this.handleOperateClick(it.index, record)}>
{it.text}
</a>
</div>
@ -228,31 +219,14 @@ export default class Calculate extends React.Component {
{notAccountBtn.map(cz =>
<Menu.Item>
<a
onClick={() => {
if (cz.text == "核算") {
this.handleAccount(record);
} else if (cz.text == "删除") {
this.handleDeleteItem(record);
} else if (cz.text == "归档") {
this.handleFile(record);
} else if (cz.text == "重新核算") {
this.handleReaccount(record);
} else if (cz.text == "查看") {
this.handleDetail(record);
} else if (cz.text == "回算") {
this.handleBackCalculate(record);
}
}}>
onClick={() => this.handleOperateClick(cz.index, record)}>
{cz.text}
</a>
</Menu.Item>
)}
</Menu>
}>
<i
className="icon-coms-more"
style={{ color: "#4d7ad8", cursor: "pointer" }}
/>
<a href="javascript:void(0);"><i className="icon-coms-more"/></a>
</Dropdown>
);
}
@ -260,7 +234,23 @@ export default class Calculate extends React.Component {
};
}
});
return showOperateBtn ? columns : _.filter(columns, it => it.title != "操作");
return showOperateBtn ? columns : _.filter(columns, it => it.title !== "操作");
};
handleOperateClick = (index, record) => {
if (index === "0") {
this.handleAccount(record);
} else if (index === "1") {
this.handleDeleteItem(record);
} else if (index === "2") {
this.handleFile(record);
} else if (index === "4") {
this.handleReaccount(record);
} else if (index === "3") {
this.handleDetail(record);
} else if (index === "5") {
this.handleBackCalculate(record);
}
};
// 分页
@ -290,56 +280,13 @@ export default class Calculate extends React.Component {
render() {
const { calculateStore, taxAgentStore: { showOperateBtn } } = this.props;
const {
salaryListDataSource,
salaryListColumns,
loading,
hasRight,
form,
condition,
tableStore,
showSearchAd,
getTableDatas,
doSearch,
setShowSearchAd,
salaryListPageInfo
} = calculateStore;
const { salaryListDataSource, loading, hasRight, salaryListPageInfo } = calculateStore;
const { modalParam } = this.state;
if (!hasRight && !loading) {
// 无权限处理
return renderNoright();
}
const rightMenu = [
// 右键菜单
{
key: "BTN_COLUMN",
icon: <i className="icon-coms-Custom"/>,
content: "显示列定制",
onClick: this.showColumn
}
];
const collectParams = {
// 收藏功能配置
favname: "薪资核算",
favouritetype: 1,
objid: 0,
link: "wui/index.html#/ns_demo03/index",
importantlevel: 1
};
const adBtn = [
// 高级搜索内部按钮
<Button type="primary" onClick={doSearch}>
搜索
</Button>,
<Button type="ghost" onClick={() => form.resetForm()}>
重置
</Button>,
<Button type="ghost" onClick={() => setShowSearchAd(false)}>
取消
</Button>
];
const renderRightOperation = () => {
const { startDate, endDate } = this.state;
return (
@ -393,13 +340,10 @@ export default class Calculate extends React.Component {
<div className="mySalaryBenefitsWrapper">
{/* 收藏功能: 配置之后显示 收藏、帮助、显示页面地址 这3个功能 */}
<WeaTop
title="薪资核算" // 文字
icon={<i className="icon-coms-fa"/>} // 左侧图标
iconBgcolor="#F14A2D" // 左侧图标背景色
showDropIcon={false} // 是否显示下拉按钮
dropMenuDatas={rightMenu} // 下拉菜单(和页面的右键菜单相同)
dropMenuProps={{ collectParams }}>
{/* 收藏功能: 配置之后显示 收藏、帮助、显示页面地址 这3个功能 */}
title="薪资核算"
icon={<i className="icon-coms-fa"/>}
iconBgcolor="#F14A2D"
showDropIcon={false}>
<CustomTab searchOperationItem={renderRightOperation()}/>
<div className="tableWrapper">
<WeaNewScroll height="100%">

View File

@ -4,6 +4,12 @@
}
.formItem {
display: flex;
.ant-col-8 {
line-height: 30px;
}
.wea-select, .ant-select {
width: 100%;
}

View File

@ -4,6 +4,8 @@ import { Badge, Button, message } from "antd";
import { inject, observer } from "mobx-react";
import SelectFieldModal from "./selectFieldModal";
import { getQueryString } from "../../../../util/url";
import AddHeaderFieldsModal from "./addHeaderFieldsModal";
import { cacheImportField } from "../../../../apis/calculate";
@inject("calculateStore", "standingBookStore")
@observer
@ -16,7 +18,10 @@ export default class AcctResultImportModal extends React.Component {
salaryItemIds: ""
},
step: 0,
selectFieldVisible: false
selectFieldVisible: false,
addHeadFields: {
visible: false, itemsByGroup: []
}
};
}
@ -24,11 +29,6 @@ export default class AcctResultImportModal extends React.Component {
const { id } = this.props;
if (id) {
this.getImportField();
// let modalParam = { ...this.state.modalParam };
// modalParam.salaryAcctRecordId = id;
// this.setState({
// modalParam
// });
} else {
this.setState({
modalParam: { ...this.state.modalParam, salaryAcctRecordId: "123" }
@ -36,18 +36,31 @@ export default class AcctResultImportModal extends React.Component {
}
}
getImportField=()=>{
getImportField = () => {
const { calculateStore: { getImportField }, id } = this.props;
const { addHeadFields } = this.props;
getImportField(id).then(data => {
this.setState({
modalParam:{
addHeadFields: {
...addHeadFields,
itemsByGroup: _.map(data.itemsByGroup, item => {
return {
...item,
salaryItems: _.map(item.salaryItems, it => ({
...it,
checked: false
}))
};
})
},
modalParam: {
...this.state.modalParam,
salaryAcctRecordId: id,
salaryItemIds: data.checkItems.join(",")
}
});
});
}
};
// 获取模板
handleAccResultTemplateLink() {
@ -98,24 +111,31 @@ export default class AcctResultImportModal extends React.Component {
}
// 渲染第一步表单
renderFormComponent() {
renderFormComponent = () => {
return <Badge
count={!_.isEmpty(this.state.modalParam.salaryItemIds) ? this.state.modalParam.salaryItemIds.split(",").length : 0}>
<Button onClick={() => {
this.handleSelectedField();
}}>请选择表单字段</Button>
<Button onClick={this.handleSelectedField}>请选择表单字段</Button>
</Badge>;
}
};
// 选择表单字段
handleSelectedField() {
this.setState({
selectFieldVisible: true
});
}
handleSelectedField = () => {
if (window.location.hash.indexOf("calculateDetail") !== -1) {
this.setState({
addHeadFields: {
...this.state.addHeadFields,
visible: true
}
});
} else {
this.setState({
selectFieldVisible: true
});
}
};
// 添加表头字段
handleAdd(fieldDate) {
handleAdd = (fieldDate) => {
let salaryItemIdsList = [];
if (!_.isEmpty(fieldDate.formulaItems)) {
fieldDate.formulaItems.map(item => {
@ -149,7 +169,7 @@ export default class AcctResultImportModal extends React.Component {
modalParam
});
this.props.onAdd(fieldDate);
}
};
// 初始化Import数据
handleImportModalInit() {
@ -197,7 +217,7 @@ export default class AcctResultImportModal extends React.Component {
importInsuranceAcctDetail,
importBalanceInsuranceDetail
} = standingBookStore;
const { step, selectFieldVisible, modalParam } = this.state;
const { step, modalParam, selectFieldVisible, addHeadFields } = this.state;
return (
<div>
{
@ -223,7 +243,7 @@ export default class AcctResultImportModal extends React.Component {
!isStandingBook ?
fetchImportAcctResult(params) :
standingBookType === "difference" ?
importBalanceInsuranceDetail({...params, billMonth}) :
importBalanceInsuranceDetail({ ...params, billMonth }) :
importInsuranceAcctDetail(params);
}}
templateLink={() => {
@ -253,6 +273,24 @@ export default class AcctResultImportModal extends React.Component {
}}
/>
}
<AddHeaderFieldsModal {...addHeadFields} selectItems={modalParam.salaryItemIds}
onCancel={() => this.setState({ addHeadFields: { ...addHeadFields, visible: false } })}
onAdd={(salaryItemIds) => this.setState({
addHeadFields: {
...addHeadFields,
visible: false
},
modalParam: {
...modalParam,
salaryItemIds: salaryItemIds.join(",")
}
}, () => {
const { salaryItemIds } = this.state.modalParam;
cacheImportField({
salaryItems: salaryItemIds ? salaryItemIds.split(",") : []
}).then();
})}
/>
</div>
);
}

View File

@ -0,0 +1,105 @@
/*
* Author: 黎永顺
* name: 表头字段添加
* Description:
* Date: 2023/5/17
*/
import React, { Component } from "react";
import { Button, Col, Row } from "antd";
import { WeaCheckbox, WeaDialog, WeaLocaleProvider, WeaSearchGroup } from "ecCom";
import "./index.less";
const { getLabel } = WeaLocaleProvider;
class AddHeaderFieldsModal extends Component {
constructor(props) {
super(props);
this.state = {
itemsCheckeds: [],
showOnlyChecked: false
};
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.visible !== this.props.visible && nextProps.visible) {
this.setState({
itemsCheckeds: nextProps.selectItems ? _.map(nextProps.selectItems.split(","), it => Number(it)) : []
});
}
}
handleShowOnlyChecked = (showOnlyChecked) => this.setState({ showOnlyChecked: !!Number(showOnlyChecked) });
handleSelectGroupAll = (groupId, checked) => {
const { itemsCheckeds } = this.state;
const { itemsByGroup } = this.props;
_.map(itemsByGroup, item => {
if (item.salarySobItemGroupId === groupId) {
if (!!Number(checked)) {
this.setState({
itemsCheckeds: [...itemsCheckeds, ..._.map(item.salaryItems, child => child.salaryItemId)]
});
} else {
this.setState({
itemsCheckeds: _.differenceWith(itemsCheckeds, _.map(item.salaryItems, child => child.salaryItemId), _.isEqual)
});
}
}
});
};
render() {
const { showOnlyChecked, itemsCheckeds } = this.state;
const { itemsByGroup } = this.props;
let dataSource = _.map(itemsByGroup, item => {
return {
...item,
salaryItems: _.map(item.salaryItems, child => {
return { ...child, checked: itemsCheckeds.includes(child.salaryItemId) };
})
};
});
if (showOnlyChecked) {
dataSource = _.map(dataSource, item => {
return { ...item, salaryItems: _.filter(item.salaryItems, it => !!it.checked) };
});
}
return (
<WeaDialog
{...this.props} hasScroll initLoadCss
scalable title={getLabel(111, "添加表头字段")}
style={{ width: 700, height: 484 }} className="addHeaderFieldsWrapper"
buttons={[
<Button type="primary" onClick={() => this.props.onAdd(itemsCheckeds)}>{getLabel(111, "添加")}</Button>,
<Button type="ghost" onClick={this.props.onCancel}>{getLabel(111, "取消")}</Button>
]}
bottomLeft={<WeaCheckbox content={getLabel(111, "只显示已选中字段")}
onChange={this.handleShowOnlyChecked}/>}
>
{
_.map(dataSource, item => {
const { salarySobItemGroupName, salaryItems, salarySobItemGroupId } = item;
const value = _.every(salaryItems, it => !!it.checked) ? "1" : "0";
return <WeaSearchGroup showGroup needTigger
title={<WeaCheckbox content={salarySobItemGroupName} value={value}
onChange={(val) => this.handleSelectGroupAll(salarySobItemGroupId, val)}/>}>
<Row gutter={16}>
{
!_.isEmpty(salaryItems) ?
_.map(salaryItems, it => {
const { salaryItemId, salaryItemName, checked } = it;
return <Col span={8} style={{ marginBottom: 16 }}>
<WeaCheckbox content={salaryItemName} value={checked ? "1" : "0"}
onChange={() => this.setState({ itemsCheckeds: _.xorWith(itemsCheckeds, [salaryItemId], _.isEqual) })}/>
</Col>;
}) : <Col span={24} style={{ minHeight: 20, padding: "5%", textAlign: "center" }}>暂无数据</Col>
}
</Row>
</WeaSearchGroup>;
})
}
</WeaDialog>
);
}
}
export default AddHeaderFieldsModal;

View File

@ -0,0 +1,11 @@
.addHeaderFieldsWrapper {
.wea-search-group {
.wea-title {
padding-left: 0 !important;
}
.wea-content {
padding: 8px 16px 0;
}
}
}

View File

@ -6,8 +6,10 @@ import CustomTab from "../../components/customTab";
import { inject, observer } from "mobx-react";
import CompareDetailImportModal from "./compareDetailImportModal";
import CustomPaginationTable from "../../components/customPaginationTable";
import { salaryacctAcctresultCheckAuth } from "../../apis/calculate";
import Authority from "../mySalary/authority";
@inject("calculateStore")
@inject("calculateStore", "taxAgentStore")
@observer
export default class CompareDetail extends React.Component {
constructor(props) {
@ -17,7 +19,8 @@ export default class CompareDetail extends React.Component {
onlyDiffEmployee: true,
onlyDiffSalaryItem: true,
importModalVisible: false,
searchValue: ""
searchValue: "",
calculateAuth: false
};
this.pageInfo = { current: 1, pageSize: 10 };
}
@ -33,8 +36,23 @@ export default class CompareDetail extends React.Component {
current: 1
};
fetchComparisonResultList(params);
this.salaryacctAcctresultCheckAuth({ salaryAcctRecordId: getQueryString("id") })
}
salaryacctAcctresultCheckAuth = (params) => {
const { taxAgentStore: { getPermission } } = this.props;
getPermission().then(({ data }) => {
const { isOpenDevolution } = data;
if (isOpenDevolution) {
salaryacctAcctresultCheckAuth(params).then(({ status, data }) => {
this.setState({ calculateAuth: data && status });
});
} else {
this.setState({ calculateAuth: true });
}
});
};
getColumns = (columns) => {
let newColumns = [...columns];
newColumns.map(item => {
@ -56,6 +74,8 @@ export default class CompareDetail extends React.Component {
</div>
);
};
} else {
item.fixed = "left";
}
});
return newColumns;
@ -167,7 +187,7 @@ export default class CompareDetail extends React.Component {
comparisonResultColumns
}
} = this.props;
const { importModalVisible, searchValue } = this.state;
const { importModalVisible, searchValue, calculateAuth } = this.state;
const renderRightOperation = () => {
return (
<div style={{ display: "inline-block" }}>
@ -201,60 +221,63 @@ export default class CompareDetail extends React.Component {
);
};
return (
<div className="compareDetail">
<CustomTab
searchOperationItem={
renderRightOperation()
}
leftOperation={
renderLeftOperation()
}
/>
<div className="titleBarWrapper">
<div className="titleBar">
<span className="leftTitle">公式=</span>
<span className="rightTitle">系统值线下值<span style={{ color: "red" }}>差值</span></span>
<Authority ecId={`${this && this.props && this.props.ecId || ""}_Authority@lulowc`}
store={{ loading: false, hasRight: calculateAuth }}>
<div className="compareDetail">
<CustomTab
searchOperationItem={
renderRightOperation()
}
leftOperation={
renderLeftOperation()
}
/>
<div className="titleBarWrapper">
<div className="titleBar">
<span className="leftTitle">公式=</span>
<span className="rightTitle">系统值线下值<span style={{ color: "red" }}>差值</span></span>
</div>
</div>
</div>
<div className="tableWrapper">
<CustomPaginationTable
loading={loading}
dataSource={comparisonResultPageInfo.list ? comparisonResultPageInfo.list : []}
columns={this.getColumns(comparisonResultColumns ? comparisonResultColumns : [])}
scroll={{
x: this.getColumns(comparisonResultColumns ? comparisonResultColumns : []).length * 150,
y: `calc(100vh - 199px)`
}}
total={comparisonResultPageInfo.total}
current={comparisonResultPageInfo.pageNum}
pageSize={this.pageInfo.pageSize}
onPageChange={(value) => {
this.pageInfo.current = value;
this.handleDataPageChange(value);
}}
onShowSizeChange={(current, pageSize) => {
this.pageInfo = { current, pageSize };
this.handleShowSizeChange(this.pageInfo);
}}
/>
</div>
<div className="tableWrapper">
<CustomPaginationTable
loading={loading}
dataSource={comparisonResultPageInfo.list ? comparisonResultPageInfo.list : []}
columns={this.getColumns(comparisonResultColumns ? comparisonResultColumns : [])}
scroll={{
x: this.getColumns(comparisonResultColumns ? comparisonResultColumns : []).length * 150,
y: `calc(100vh - 199px)`
}}
total={comparisonResultPageInfo.total}
current={comparisonResultPageInfo.pageNum}
pageSize={this.pageInfo.pageSize}
onPageChange={(value) => {
this.pageInfo.current = value;
this.handleDataPageChange(value);
}}
onShowSizeChange={(current, pageSize) => {
this.pageInfo = { current, pageSize };
this.handleShowSizeChange(this.pageInfo);
}}
/>
</div>
{
importModalVisible && <CompareDetailImportModal
visiable={importModalVisible}
id={this.id}
onFinish={() => {
this.handleComparisonFinish();
}}
onCancel={() => {
this.setState({
importModalVisible: false
});
}}
/>
}
</div>
{
importModalVisible && <CompareDetailImportModal
visiable={importModalVisible}
id={this.id}
onFinish={() => {
this.handleComparisonFinish();
}}
onCancel={() => {
this.setState({
importModalVisible: false
});
}}
/>
}
</div>
</Authority>
);
}
}

View File

@ -1,7 +1,7 @@
import React from "react";
import ImportModal from "../../components/importModal";
import { inject, observer } from "mobx-react";
import { getQueryString } from "../../util/url";
import { convertToUrlString, getQueryString } from "../../util/url";
@inject("calculateStore", "standingBookStore")
@observer
@ -35,7 +35,12 @@ export default class CompareDetailImportModal extends React.Component {
if (this.props.id) {
url = "/api/bs/hrmsalary/salaryacct/comparisonresult/importtemplate/export?salaryAcctRecordId=" + this.props.id;
} else {
url = `/api/bs/hrmsalary/siaccount/comparisonwelfare/importtemplate/export`;
const payload = {
billMonth: getQueryString("billMonth"),
paymentOrganization: getQueryString("paymentOrganization"),
paymentStatus: 0
};
url = `/api/bs/hrmsalary/siaccount/comparisonwelfare/importtemplate/export?${convertToUrlString(payload)}`;
}
window.open(url);
}

View File

@ -1,10 +1,9 @@
import React from "react";
import { WeaHelpfulTip, WeaInput, WeaTab } from "ecCom";
import { WeaHelpfulTip, WeaTab } from "ecCom";
import IssuedAndReissueTable from "./issuedAndReissueTable";
import { Col, Row } from "antd";
import PayrollItemsTable from "./payrollItemsTable";
import { inject, observer } from "mobx-react";
import { toJS } from "mobx";
import cs from "classnames";
import "./index.less";
@inject("calculateStore")
@ -22,25 +21,23 @@ export default class EditSalaryDetail extends React.Component {
acctresultDetail(this.props.id);
}
handleItemValueChange = (field, value, isInput) => {
console.log(field, value, isInput);
handleItemValueChange = (field, value, isInput, groupId) => {
const { calculateStore: { acctresultDetailForm, setAcctresultDetailForm } } = this.props;
let form = { ...acctresultDetailForm };
if (isInput === "inputItems") {
form.inputItems = acctresultDetailForm.inputItems.map(item => {
item = { ...item };
if (item.salaryItemName === field) {
item.resultValue = value;
if (isInput === "itemsByGroup") {
form.itemsByGroup = acctresultDetailForm.itemsByGroup.map(item => {
if (item.salarySobItemGroupId === groupId) {
return {
...item,
salaryItems: _.map(item.salaryItems, it => {
if (it.salaryItemId === field) {
return { ...it, resultValue: value };
}
return { ...it };
})
};
}
return item;
});
} else if (isInput === "formulaItems") {
form.formulaItems = acctresultDetailForm.formulaItems.map(item => {
item = { ...item };
if (item.salaryItemName === field) {
item.resultValue = value;
}
return item;
return { ...item };
});
} else if (isInput === "issuedAndReissueItems") {
form.issuedAndReissueItems = acctresultDetailForm.issuedAndReissueItems.map(item => {
@ -53,7 +50,6 @@ export default class EditSalaryDetail extends React.Component {
}
setAcctresultDetailForm(form);
};
renderTableTr = (data, isInput) => {
const tables = [];
const len = data.length;
@ -77,10 +73,10 @@ export default class EditSalaryDetail extends React.Component {
return tables;
};
render() {
const { calculateStore: { acctresultDetailForm } } = this.props;
const { selectedKey } = this.state;
const { itemsByGroup = [] } = toJS(acctresultDetailForm);
const topTab = [
{
title: "正常工资薪金所得",
@ -96,14 +92,8 @@ export default class EditSalaryDetail extends React.Component {
<div className="detailItemWrapper">
<div>
<span className="itemTitle">基本信息</span>
<WeaHelpfulTip
style={{ marginLeft: "10px" }}
width={200}
title="根据账套设置显示"
placement="topLeft"
/>
<WeaHelpfulTip style={{ marginLeft: "10px" }} title="提示:基本信息根据账套设置显示" placement="topLeft"/>
</div>
<div className="itemContent">
{
!_.isEmpty(acctresultDetailForm.employeeInfos) &&
@ -123,69 +113,9 @@ export default class EditSalaryDetail extends React.Component {
/>
}
{
selectedKey === "0" &&
<div>
<div className="detailItemWrapper">
<span className="itemTitle">输入项</span>
<div className="itemContent">
<Row>
{
acctresultDetailForm.inputItems && acctresultDetailForm.inputItems.map((item, index) => {
const len = acctresultDetailForm.inputItems.length;
return (
<Col span={8}>
<Row>
<Col span={12}
className={cs("itemLabel", { "borderB-none": Math.ceil((index + 1) / 3) === len / 3 })}>{item.salaryItemName}</Col>
<Col span={12} className={cs("itemValue", {
"borderB-none": Math.ceil((index + 1) / 3) === len / 3,
"borderR-none": (index + 1) % 3 === 0
})}><WeaInput value={item.resultValue} disabled={!item.canEdit} onChange={(value) => {
this.handleItemValueChange(item.salaryItemName, value, "inputItems");
}}/></Col>
</Row>
</Col>
);
})
}
</Row>
</div>
</div>
<div className="detailItemWrapper">
<span className="itemTitle">
<span>公式项</span>
<WeaHelpfulTip
style={{ marginLeft: "10px" }}
width={200}
title="提示:修改后,若点击核算,将按照公式核算,覆盖修改的数据"
placement="topLeft"
/>
</span>
<div className="itemContent">
<Row>
{
acctresultDetailForm.formulaItems && acctresultDetailForm.formulaItems.map((item, index) => {
const len = acctresultDetailForm.formulaItems.length;
return (
<Col span={8}>
<Row>
<Col span={12}
className={cs("itemLabel", { "borderB-none": Math.ceil((index + 1) / 3) === len / 3 })}>{item.salaryItemName}</Col>
<Col span={12} className={cs("itemValue", {
"borderB-none": Math.ceil((index + 1) / 3) === len / 3,
"borderR-none": (index + 1) % 3 === 0
})}><WeaInput value={item.resultValue} disabled={!item.canEdit} onChange={(value) => {
this.handleItemValueChange(item.salaryItemName, value, "formulaItems");
}}/></Col>
</Row>
</Col>
);
})
}
</Row>
</div>
</div>
</div>
selectedKey === "0" && _.map(itemsByGroup, item => {
return <PayrollItemsTable {...item} onChangeIssueReissueValue={this.handleItemValueChange}/>;
})
}
{
selectedKey === "1" &&

View File

@ -7,10 +7,13 @@ import { WeaBrowser, WeaCheckbox, WeaDropdown, WeaFormItem, WeaInput, WeaSearchG
import { convertToUrlString, getQueryString } from "../../util/url";
import AcctResultImportModal from "./acctResult/importModal/acctResultImportModal";
import ProgressModal from "../../components/progressModal";
import { salaryacctAcctresultCheckAuth } from "../../apis/calculate";
import Authority from "../mySalary/authority";
const { ButtonSelect } = WeaDropdown;
@inject("calculateStore", "salaryFileStore")
@inject("calculateStore", "salaryFileStore", "taxAgentStore")
@observer
export default class CalculateDetail extends React.Component {
constructor(props) {
@ -19,10 +22,11 @@ export default class CalculateDetail extends React.Component {
showSearchAd: false,
searchItemsValue: {
employeeName: "",
workcode: "",
departmentIds: "",
positionIds: "",
subcompanyIds: "",
status: "",
statuses: "",
consolidatedTaxation: "0"
},
selectedKey: "0",
@ -30,37 +34,55 @@ export default class CalculateDetail extends React.Component {
acctResultImportVisiable: false,
progressVisible: false,
progress: 0,
accountIds: []
accountIds: [],
accountExceptInfo: "",
calculateAuth: false
};
this.id = "";
this.timer;
this.timer = null;
}
componentWillMount() {
async componentWillMount() {
let id = getQueryString("id");
this.id = id;
const { calculateStore: { checkTaxAgent }, salaryFileStore } = this.props;
const { commonEnumList } = salaryFileStore;
this.salaryacctAcctresultCheckAuth({ salaryAcctRecordId: id });
checkTaxAgent(this.id);
let modalParam = { ...this.state.modalParam, salaryAcctRecordId: id };
this.setState({ modalParam });
commonEnumList("user", { enumClass: "com.engine.salary.enums.salarysob.SalaryEmployeeStatusEnum" });
}
salaryacctAcctresultCheckAuth = (params) => {
const { taxAgentStore: { getPermission } } = this.props;
getPermission().then(({ data }) => {
const { isOpenDevolution } = data;
if (isOpenDevolution) {
salaryacctAcctresultCheckAuth(params).then(({ status, data }) => {
this.setState({ calculateAuth: data && status });
});
} else {
this.setState({ calculateAuth: true });
}
});
};
Input = (value, key) => {
const { employeeName } = this.state.searchItemsValue;
const { employeeName, workcode } = this.state.searchItemsValue;
return (
<WeaFormItem
label={value}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput value={employeeName} onChange={(val) => this.setState({
searchItemsValue: {
...this.state.searchItemsValue,
[key]: val
}
})}/>
<WeaInput value={key === "employeeName" ? employeeName : workcode}
onChange={(val) => this.setState({
searchItemsValue: {
...this.state.searchItemsValue,
[key]: val
}
})}/>
</WeaFormItem>
);
};
@ -93,7 +115,7 @@ export default class CalculateDetail extends React.Component {
);
};
Select = (value, key) => {
const { status } = this.state.searchItemsValue;
const { statuses } = this.state.searchItemsValue;
return (
<WeaFormItem
label={value}
@ -101,10 +123,13 @@ export default class CalculateDetail extends React.Component {
wrapperCol={{ span: 18 }}
>
<WeaSelect
value={status}
multiple
value={statuses}
options={[
{ key: "", showname: "" }, { key: "ALL", showname: "全部" },
{ key: "NORMAL", showname: "在职" }, { key: "UNAVAILABLE", showname: "离职" }
{ key: "0", showname: "试用" }, { key: "1", showname: "正式" },
{ key: "2", showname: "临时" }, { key: "3", showname: "试用延期" },
{ key: "4", showname: "解雇" }, { key: "5", showname: "离职" },
{ key: "6", showname: "退休" }
]}
onChange={(val) => this.setState({ searchItemsValue: { ...this.state.searchItemsValue, [key]: val } })}/>
</WeaFormItem>
@ -160,7 +185,8 @@ export default class CalculateDetail extends React.Component {
this.timer = null;
this.setState({
progressVisible: false,
accountIds: []
accountIds: [],
accountExceptInfo: data.message
});
message.success("核算完成");
// acctResultList({ salaryAcctRecordId: this.id });
@ -181,7 +207,8 @@ export default class CalculateDetail extends React.Component {
this.timer = null;
this.setState({
progressVisible: false,
accountIds: []
accountIds: [],
accountExceptInfo: data.message
});
message.error(data.message);
}
@ -189,8 +216,6 @@ export default class CalculateDetail extends React.Component {
});
}, 1000);
});
},
onCancel() {
}
});
};
@ -208,8 +233,11 @@ export default class CalculateDetail extends React.Component {
this.id
);
} else if (e.key == "3") {
const { searchItemsValue } = this.state;
const { consolidatedTaxation, ...extra } = searchItemsValue;
const payload = { ...extra, consolidatedTaxation: consolidatedTaxation === "0" ? "" : consolidatedTaxation };
window.open(
`/api/bs/hrmsalary/salaryacct/acctresult/export?salaryAcctRecordId=${this.id}&ids=&${convertToUrlString(this.state.searchItemsValue)}`
`/api/bs/hrmsalary/salaryacct/acctresult/export?salaryAcctRecordId=${this.id}&ids=&${convertToUrlString(payload)}`
);
}
};
@ -246,8 +274,18 @@ export default class CalculateDetail extends React.Component {
}
}
downloadTxtfile = (value) => {
const element = document.createElement("a");
const file = new Blob([value], { type: "text/plain" });
element.href = URL.createObjectURL(file);
element.download = "核算异常信息.txt";
document.body.appendChild(element);
element.click();
};
render() {
const { selectedKey, acctResultImportVisiable, showSearchAd } = this.state;
const { selectedKey, acctResultImportVisiable, showSearchAd, calculateAuth } = this.state;
const { taxAgentStore: { payrollPermission } } = this.props;
const menu = (
<Menu onClick={this.handleMenuClick.bind(this)}>
<Menu.Item key="1">导入</Menu.Item>
@ -257,7 +295,8 @@ export default class CalculateDetail extends React.Component {
);
const renderRightOperation = () => {
return [
const { accountExceptInfo } = this.state;
let buttons = [
<ButtonSelect
datas={[
{ key: "ALL", show: "核算所有人", selected: true },
@ -270,6 +309,10 @@ export default class CalculateDetail extends React.Component {
更多
</Dropdown.Button>
];
accountExceptInfo && buttons.unshift(<Button type="ghost" shape="circle-outline" icon="download"
title="下载核算异常信息"
onClick={() => this.downloadTxtfile(accountExceptInfo)}/>);
return buttons;
};
const topTab = [
@ -295,9 +338,10 @@ export default class CalculateDetail extends React.Component {
<Button type="ghost" onClick={() => this.setState({
searchItemsValue: {
employeeName: "",
workcode: "",
departmentIds: "",
positionIds: "",
status: "",
statuses: "",
consolidatedTaxation: "0"
}
})}>
@ -311,66 +355,70 @@ export default class CalculateDetail extends React.Component {
const renderSearch = () => {
const searchItems = [
{ com: this.Input("姓名", "employeeName") },
{ com: this.Input("工号", "workcode") },
{ com: this.Browser("分部", "subcompanyIds") },
{ com: this.Browser("部门", "departmentIds") },
{ com: this.Browser("岗位", "positionIds") },
{ com: this.Select("状态", "status") },
{ com: this.Select("状态", "statuses") },
{ com: this.Checkbox("合并计税", "consolidatedTaxation") }
];
return <WeaSearchGroup title={"基本信息"} items={searchItems} showGroup/>;
};
return (
<div style={{ overflowY: "hidden", height: "100%" }}>
<WeaTab
datas={topTab}
selectedKey={selectedKey}
keyParam="viewcondition"
onChange={v => this.setState({ selectedKey: v })}
searchType={selectedKey == 1 ? ["base", "advanced"] : []} // base基础搜索框 advanced显示高级搜索按钮
showSearchAd={showSearchAd} // 是否展开高级搜索面板
setShowSearchAd={(bool) => this.setState({ showSearchAd: bool })} //高级搜索面板受控
searchsAd={renderSearch()} // 高级搜索内部数据getSearchs(form, toJS(condition), 2)
buttonsAd={adBtn} // 高级搜索内部按钮
onSearch={() => this.handleSearch(this.state.searchItemsValue)} // 点搜索按钮时的回调
buttons={selectedKey == 1 ? renderRightOperation() : []}
searchsBasePlaceHolder={"请输入姓名"}
onSearchChange={(v) =>
this.setState({
searchItemsValue: {
...this.state.searchItemsValue,
employeeName: v
}
})
} // 在搜索框中输入的文字改变时的回调: 这里需要同步高级搜索和外部搜索框的值form.updateFields({ username: v })
searchsBaseValue={this.state.searchItemsValue.employeeName} // 外部input搜索值受控: 这里和高级搜索的requestname同步form.getFormParams().username
/>
{selectedKey == 0 && <UserSure/>}
{selectedKey == 1 && <SalaryDetail onChangeAccountIds={(ids) => this.setState({ accountIds: ids })}
employeeName={this.state.searchValue}/>}
{acctResultImportVisiable &&
<AcctResultImportModal
visiable={acctResultImportVisiable}
fieldData={this.state.fieldData}
onAdd={fieldData => {
this.handleAcctModalAdd(fieldData);
}}
onCancel={() =>
<Authority ecId={`${this && this.props && this.props.ecId || ""}_Authority@lulowc`}
store={{ loading: false, hasRight: payrollPermission && calculateAuth }}>
<div style={{ overflowY: "hidden", height: "100%" }}>
<WeaTab
datas={topTab}
selectedKey={selectedKey}
keyParam="viewcondition"
onChange={v => this.setState({ selectedKey: v })}
searchType={selectedKey == 1 ? ["base", "advanced"] : []} // base基础搜索框 advanced显示高级搜索按钮
showSearchAd={showSearchAd} // 是否展开高级搜索面板
setShowSearchAd={(bool) => this.setState({ showSearchAd: bool })} //高级搜索面板受控
searchsAd={renderSearch()} // 高级搜索内部数据getSearchs(form, toJS(condition), 2)
buttonsAd={adBtn} // 高级搜索内部按钮
onSearch={() => this.handleSearch(this.state.searchItemsValue)} // 点搜索按钮时的回调
buttons={selectedKey == 1 ? renderRightOperation() : []}
searchsBasePlaceHolder={"请输入姓名"}
onSearchChange={(v) =>
this.setState({
acctResultImportVisiable: false,
fieldData: {}
})}
id={this.id}
/>}
{this.state.progressVisible &&
<ProgressModal
visible={this.state.progressVisible}
onCancel={() => {
this.setState({ progressVisible: false, progress: 0 });
}}
progress={this.state.progress}
/>}
</div>
searchItemsValue: {
...this.state.searchItemsValue,
employeeName: v
}
})
} // 在搜索框中输入的文字改变时的回调: 这里需要同步高级搜索和外部搜索框的值form.updateFields({ username: v })
searchsBaseValue={this.state.searchItemsValue.employeeName} // 外部input搜索值受控: 这里和高级搜索的requestname同步form.getFormParams().username
/>
{selectedKey == 0 && <UserSure/>}
{selectedKey == 1 && <SalaryDetail onChangeAccountIds={(ids) => this.setState({ accountIds: ids })}
employeeName={this.state.searchValue}/>}
{acctResultImportVisiable &&
<AcctResultImportModal
visiable={acctResultImportVisiable}
fieldData={this.state.fieldData}
onAdd={fieldData => {
this.handleAcctModalAdd(fieldData);
}}
onCancel={() =>
this.setState({
acctResultImportVisiable: false,
fieldData: {}
})}
id={this.id}
/>}
{this.state.progressVisible &&
<ProgressModal
visible={this.state.progressVisible}
onCancel={() => {
this.setState({ progressVisible: false, progress: 0 });
}}
progress={this.state.progress}
/>}
</div>
</Authority>
);
}
}

View File

@ -80,8 +80,7 @@
}
.editSalaryDetail {
padding: 20px;
padding-bottom: 40px;
padding: 20px 20px 40px;
.detailItemWrapper {
.itemTitle {
@ -127,43 +126,15 @@
}
}
}
& > .ant-row {
border: 1px solid rgba(0, 0, 0, .06);
}
.itemLabel {
background-color: #fafafa;
padding: 12px 6px;
height: 45px;
display: flex;
align-items: center;
justify-content: flex-start;
border-right: 1px solid rgba(0, 0, 0, .06);
border-bottom: 1px solid rgba(0, 0, 0, .06);
}
.borderB-none {
border-bottom: none !important;
}
.borderR-none {
border-right: none !important;
}
.itemValue {
padding: 12px 6px;
display: flex;
align-items: center;
height: 45px;
border-right: 1px solid rgba(0, 0, 0, .06);
border-bottom: 1px solid rgba(0, 0, 0, .06);
}
}
}
.itemRow {
line-height: 40px;
.wea-search-group {
padding: 0 !important;
.wea-title {
padding: 0 !important;
}
}
}
@ -254,7 +225,6 @@
z-index: 99;
top: 10px !important;
}
}
@media (min-width: 1260px) {

View File

@ -40,7 +40,7 @@ class IssuedAndReissueTable extends Component {
}
},
{
dataIndex: "salaryBackItemFormula",
dataIndex: "itemFormulaContent",
title: <span>
<span style={{ marginRight: 8 }}>核算公式</span>
<WeaHelpfulTip

View File

@ -0,0 +1,82 @@
/*
* Author: 黎永顺
* name: 薪资项目表格
* Description:
* Date: 2023/5/16
*/
import React, { Component } from "react";
import { WeaHelpfulTip, WeaInput, WeaInputNumber, WeaLocaleProvider, WeaSearchGroup, WeaTable } from "ecCom";
const { getLabel } = WeaLocaleProvider;
class PayrollItemsTable extends Component {
render() {
const {
salarySobItemGroupId,
salarySobItemGroupName,
salaryItems: dataSource,
onChangeIssueReissueValue
} = this.props;
const columns = [
{
dataIndex: "salaryItemName",
title: getLabel(111, "薪资项目"),
width: "15%",
render: (text) => {
return <span className="tdEllipsis" title={text}>{text}</span>;
}
},
{
dataIndex: "resultValue",
title: <span>
<span style={{ marginRight: 8 }}>{getLabel(111, "项目值")}</span>
<WeaHelpfulTip
title={getLabel(111, "1.若薪资项目有公式,手动编辑项目值后,则默认将手动编辑的项目值锁定;点击锁定图标,解锁手动编辑的项目值,公式生效,点击保存按照公式重新核算;重新核算后,不显示解锁图标。")}
placement="top" width={250}
/>
</span>,
width: "20%",
render: (text, record) => {
const { canEdit, dataType } = record;
return dataType === "number" ? <WeaInputNumber
disabled={!canEdit}
precision={2}
value={text || 0}
onChange={(value) => onChangeIssueReissueValue(record.salaryItemId, value, "itemsByGroup", salarySobItemGroupId)}
/> : <WeaInput
disabled={!canEdit}
value={text}
onChange={(value) => onChangeIssueReissueValue(record.salaryItemId, value, "itemsByGroup", salarySobItemGroupId)}
/>;
}
},
{
dataIndex: "itemFormulaContent",
title: <span>
<span style={{ marginRight: 8 }}>{getLabel(111, "核算公式")}</span>
<WeaHelpfulTip
title={getLabel(111, "若薪资项目有公式,且项目值手动编辑修改过并点击锁定图标,则公式失效;若解除锁定,则项目公式重新生效;")}
placement="top" width={250}
/>
</span>,
width: "65%",
render: (text, record) => {
return <span className="tdEllipsis" title={text}>{_.isNil(text) ? "输入" : text}</span>;
}
}
];
return (
<WeaSearchGroup title={salarySobItemGroupName} showGroup needTigger>
<WeaTable
rowKey="salaryItemId"
dataSource={dataSource}
columns={columns}
bordered
pagination={false}
/>
</WeaSearchGroup>
);
}
}
export default PayrollItemsTable;

View File

@ -1,4 +1,5 @@
import React from "react";
import { toJS } from "mobx";
import CustomTab from "../../components/customTab";
import { Dropdown, Menu, message } from "antd";
import { WeaHelpfulTip, WeaInputSearch, WeaSlideModal } from "ecCom";
@ -16,7 +17,8 @@ export default class PlaceOnFileDetail extends React.Component {
this.state = {
slideVisiable: false,
selectedRowKeys: [],
searchValue: ""
searchValue: "",
columnIndex: ""
};
this.id = "";
}
@ -38,11 +40,11 @@ export default class PlaceOnFileDetail extends React.Component {
handleClick = ({ data }) => {
const childFrameObj = document.getElementById("atdTable");
const salaryAcctRecordId = getQueryString("id");
const { type, data: { id, data: record } = {} } = data;
const { type, data: { id, data: record, extraId = "" } = {} } = data;
if (type === "PR") {
if (id === "BATCHDELETE") {
this.setState({ selectedRowKeys: record });
}else if (id === "PAGEINFO") {
} else if (id === "PAGEINFO") {
const { pageNum: current, size: pageSize } = record;
this.pageInfo = { current, pageSize };
const payload = {
@ -57,6 +59,10 @@ export default class PlaceOnFileDetail extends React.Component {
}
};
childFrameObj.contentWindow.postMessage(JSON.stringify(payload), "*");
} else if (id === "COLUMNINDEX") {
if (!extraId) {
this.setState({ columnIndex: record });
}
}
} else {
const payload = {
@ -106,9 +112,8 @@ export default class PlaceOnFileDetail extends React.Component {
render() {
const { calculateStore } = this.props;
const { baseSalarySobCycle } = calculateStore;
const { slideVisiable } = this.state;
const { baseSalarySobCycle, columnDescList } = calculateStore;
const { slideVisiable, columnIndex } = this.state;
const menu = (
<Menu onClick={(e) => this.handleMenuClick(e)}>
@ -139,7 +144,7 @@ export default class PlaceOnFileDetail extends React.Component {
renderRightOperation()
}
/>
<div className="tabWrapper">
<div className="tabWrapper" style={{ borderBottom: "none" }}>
<span>薪资所属月{baseSalarySobCycle.salaryMonth}</span>
<WeaHelpfulTip
width={100}
@ -154,6 +159,10 @@ export default class PlaceOnFileDetail extends React.Component {
placement="topLeft"
/>
</div>
<div className="tabWrapper">
<span>公式=</span>
<span>{toJS(columnDescList)[columnIndex] && toJS(columnDescList)[columnIndex].formulaContent}</span>
</div>
<div className="tableWrapper">
<iframe
style={{ border: 0, width: "100%", height: "100%" }}

View File

@ -16,6 +16,7 @@ export default class SalaryDetail extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
progressVisible: false,
progress: 0,
columnIndex: "",
@ -177,13 +178,12 @@ export default class SalaryDetail extends React.Component {
}
// 侧边栏保存
handleEditSlideSave() {
handleEditSlideSave = () => {
const { calculateStore } = this.props;
const { saveAcctResult } = calculateStore;
this.setState({
slideVisiable: false
});
this.setState({ loading: true });
saveAcctResult(this.recordId).then(() => {
this.setState({ loading: false });
const childFrameObj = document.getElementById("atdTable");
const salaryAcctRecordId = getQueryString("id");
const payload = {
@ -198,11 +198,11 @@ export default class SalaryDetail extends React.Component {
childFrameObj.contentWindow.postMessage(JSON.stringify(payload), "*");
// acctResultList({ salaryAcctRecordId: this.id });
});
}
};
render() {
const { slideVisiable, columnIndex } = this.state;
const { slideVisiable, columnIndex, loading } = this.state;
const { calculateStore, taxAgentStore: { showOperateBtn } } = this.props;
const { baseSalarySobCycle, columnDescList } = calculateStore;
@ -271,7 +271,8 @@ export default class SalaryDetail extends React.Component {
subtitle="编辑薪资"
editable={true}
showOperateBtn={showOperateBtn}
onSave={() => this.handleEditSlideSave()}
onSave={this.handleEditSlideSave}
loading={loading}
/>
}
content={<EditSalaryDetail id={this.recordId}/>}

View File

@ -14,9 +14,10 @@ export default class UserSure extends React.Component {
showSearchAd: false,
searchItemsValue: {
employeeName: "",
workcode: "",
departmentIds: "",
positionIds: "",
status: ""
statuses: ""
},
selectedKey: "0",
selectedRowKeys: [], // table 选中项
@ -41,19 +42,20 @@ export default class UserSure extends React.Component {
}
Input = (value, key) => {
const { employeeName } = this.state.searchItemsValue;
const { employeeName, workcode } = this.state.searchItemsValue;
return (
<WeaFormItem
label={value}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput value={employeeName} onChange={(val) => this.setState({
searchItemsValue: {
...this.state.searchItemsValue,
[key]: val
}
})}/>
<WeaInput value={key === "employeeName" ? employeeName : workcode}
onChange={(val) => this.setState({
searchItemsValue: {
...this.state.searchItemsValue,
[key]: val
}
})}/>
</WeaFormItem>
);
};
@ -76,7 +78,7 @@ export default class UserSure extends React.Component {
);
};
Select = (value, key) => {
const { status } = this.state.searchItemsValue;
const { statuses } = this.state.searchItemsValue;
return (
<WeaFormItem
label={value}
@ -84,10 +86,13 @@ export default class UserSure extends React.Component {
wrapperCol={{ span: 18 }}
>
<WeaSelect
value={String(status)}
multiple
value={String(statuses)}
options={[
{ key: "", showname: "" }, { key: "ALL", showname: "全部" },
{ key: "NORMAL", showname: "在职" }, { key: "UNAVAILABLE", showname: "离职" }
{ key: "0", showname: "试用" }, { key: "1", showname: "正式" },
{ key: "2", showname: "临时" }, { key: "3", showname: "试用延期" },
{ key: "4", showname: "解雇" }, { key: "5", showname: "离职" },
{ key: "6", showname: "退休" }
]}
onChange={(val) => this.setState({ searchItemsValue: { ...this.state.searchItemsValue, [key]: val } })}/>
</WeaFormItem>
@ -340,7 +345,7 @@ export default class UserSure extends React.Component {
employeeName: "",
departmentIds: "",
positionIds: "",
status: ""
statuses: ""
}
})}>
重置
@ -353,9 +358,10 @@ export default class UserSure extends React.Component {
const renderSearch = () => {
const searchItems = [
{ com: this.Input("姓名", "employeeName") },
{ com: this.Input("工号", "workcode") },
{ com: this.Browser("部门", "departmentIds") },
{ com: this.Browser("岗位", "positionIds") },
{ com: this.Select("状态", "status") }
{ com: this.Select("状态", "statuses") }
];
return <WeaSearchGroup title={"基本信息"} items={searchItems} showGroup/>;
};

View File

@ -142,13 +142,13 @@ class AttendanceDataComp extends Component {
}
});
};
handleViewAttendanceData = ({ id, salaryCycle }) => {
handleViewAttendanceData = ({ id, attendCycle }) => {
const { attendanceViewPayload } = this.state;
this.setState({
attendanceViewPayload: {
...attendanceViewPayload,
visible: true, attendQuoteId: id,
salaryYearMonth: salaryCycle
salaryYearMonth: attendCycle
}
});
};

View File

@ -102,8 +102,8 @@ class AttendanceDataViewSlide extends Component {
className="attendanceSlideWrapper"
top={0}
measureT="%"
width={800}
measureX="px"
width={80}
measureX="%"
height={100}
measureY="%"
direction="right"
@ -131,7 +131,7 @@ class AttendanceDataViewSlide extends Component {
dataSource={dataSource}
pagination={pagination}
loading={loading.query}
xWidth={columns.length * 120}
xWidth={columns.length * 180}
/>
</div>
}

View File

@ -56,17 +56,17 @@ class Index extends Component {
};
handleChangeSalaryMonth = (salaryMonth) => this.setState({ salaryMonth }, () => this.attendanceTableRef.getAttendanceList({ salaryYearMonth: _.compact(this.state.salaryMonth) }));
handleAddAttendFileds = () => this.fieldMangRef.handleTriggerAttendFileds();
handleImportAttendanceData= ()=>{
handleImportAttendanceData = () => {
this.attendanceTableRef.handleImportAttendanceData({
visiable: true, params: {}, step: 0,
columns: [], slideDataSource: [], importResult: []
});
}
handleQuoteAttendanceData= ()=>{
};
handleQuoteAttendanceData = () => {
this.attendanceTableRef.handleQuoteAttendanceData({
visible: true, title: "引用考勤数据"
});
}
};
render() {
const { selectedKey, salaryMonth, fieldName } = this.state;
@ -82,7 +82,7 @@ class Index extends Component {
return (
<div className="attendanceRefWrapper">
<WeaTab
datas={topTab} keyParam="viewcondition" selectedKey={selectedKey} buttons={buttons}
datas={topTab} keyParam="viewcondition" selectedKey={selectedKey} buttons={showOperateBtn ? buttons : []}
searchType={selectedKey === "FIELD" ? ["base"] : []} searchsBasePlaceHolder="请输入字段名称"
onChange={v => this.setState({ selectedKey: v })}
searchsBaseValue={fieldName} onSearchChange={fieldName => this.setState({ fieldName })}

View File

@ -2,12 +2,12 @@
.accumulated {
.wea-form-cell-wrapper {
& > div:first-child {
width: 10% !important;
height: 46px !important;
line-height: 46px;
}
& > div:nth-child(2) {
width: 40% !important;
//width: 40% !important;
.wea-form-item-wrapper {
display: flex !important;
@ -20,7 +20,7 @@
}
& > div:last-child {
width: 40% !important;
//width: 40% !important;
}
}
}

View File

@ -18,6 +18,7 @@ class TableRecord extends Component {
loading: {
query: false
},
width: 0,
dataSource: [],
columns: [],
selectedRowKeys: [],
@ -37,13 +38,23 @@ class TableRecord extends Component {
}
componentDidMount() {
this.setState({ width: window.innerWidth });
this.convertData(this.props);
window.addEventListener("resize", this.resizeWidth);
}
componentWillUnmount() {
window.removeEventListener("resize", this.resizeWidth);
}
componentWillReceiveProps(nextProps, nextContext) {
this.convertData(nextProps);
}
resizeWidth = (e) => {
this.setState({ width: e.target.innerWidth });
};
convertData = (props) => {
const { recordPayload } = this.state;
const { record, screenParams } = props;
@ -58,7 +69,7 @@ class TableRecord extends Component {
},
pageInfo: {
current: 1, pageSize: 10, total: 0
},
}
}, () => this.getTableRecordData());
};
@ -116,7 +127,7 @@ class TableRecord extends Component {
render() {
const { className, screenParams, taxAgentOption, record } = this.props;
const { columns, dataSource, loading, selectedRowKeys, pageInfo, recordPayload } = this.state;
const { columns, dataSource, loading, selectedRowKeys, pageInfo, recordPayload, width } = this.state;
const rowSelection = {
selectedRowKeys,
onChange: (selectedRowKeys) => this.setState({ selectedRowKeys })
@ -172,7 +183,7 @@ class TableRecord extends Component {
<div className="tableRecordWrapper">
{
!_.isEmpty(screenParams) &&
<WeaSearchGroup className={className} showGroup needTigger={false} items={items} col={3}/>
<WeaSearchGroup className={className} showGroup needTigger={false} items={items} col={width > 1280 ? 3 : 2}/>
}
<UnifiedTable
rowKey="id"
@ -186,6 +197,7 @@ class TableRecord extends Component {
dataSource={dataSource}
pagination={pagination}
loading={loading.query}
xWidth={columns.length * 180}
/>
</div>
);

View File

@ -399,66 +399,73 @@ export const dataCollectCondition = [
{
items: [
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpChildEducation"],
fieldcol: 14,
label: "累计子女教育",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpContinuingEducation"],
fieldcol: 14,
label: "累计继续教育",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpHousingLoanInterest"],
fieldcol: 14,
label: "累计住房贷款利息",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpHousingRent"],
fieldcol: 14,
label: "累计住房租金",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpSupportElderly"],
fieldcol: 14,
label: "累计赡养老人",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpIllnessMedical"],
fieldcol: 14,
label: "累计大病医疗",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpInfantCare"],
fieldcol: 14,
label: "累计婴幼儿照护",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
}
],

View File

@ -45,18 +45,18 @@
}
.linkWapper {
a {
color: #4d7ad8;
margin-right: 8px;
}
//a {
// color: #4d7ad8;
// margin-right: 8px;
//}
i {
cursor: pointer;
}
a:hover {
text-decoration: none;
}
//a:hover {
// text-decoration: none;
//}
}
}

View File

@ -69,156 +69,173 @@ export const dataCollectCondition = [
{
items: [
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpIncome"],
fieldcol: 14,
label: "累计收入额",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpSubtraction"],
fieldcol: 14,
label: "累计减除费用",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpSocialSecurityTotal"],
fieldcol: 14,
label: "累计社保个人合计",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpAccumulationFundTotal"],
fieldcol: 14,
label: "累计公积金个人合计",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpChildEducation"],
fieldcol: 14,
label: "累计子女教育",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpContinuingEducation"],
fieldcol: 14,
label: "累计继续教育",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpHousingLoanInterest"],
fieldcol: 14,
label: "累计住房贷款利息",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpHousingRent"],
fieldcol: 14,
label: "累计住房租金",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpSupportElderly"],
fieldcol: 14,
label: "累计赡养老人",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpIllnessMedical"],
fieldcol: 14,
label: "累计大病医疗",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpEnterpriseAndOther"],
fieldcol: 14,
label: "累计企业(职业)年金及其他福利",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpOtherDeduction"],
fieldcol: 14,
label: "累计其他免税扣除",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpTaxExemptIncome"],
fieldcol: 14,
label: "累计免税收入",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpAllowedDonation"],
fieldcol: 14,
label: "累计准予扣除的捐赠额",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpTaxSavings"],
fieldcol: 14,
label: "累计减免税额",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpAdvanceTax"],
fieldcol: 14,
label: "累计已预扣预缴税额",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["addUpInfantCare"],
fieldcol: 14,
label: "累计婴幼儿照护",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
}
],

View File

@ -101,19 +101,22 @@ class DataTables extends Component {
} else if (dataIndex === "operate") {
return {
...item,
width: 150,
render: (text, record) => (
<div className="linkWapper">
{
!isSpecial &&
<React.Fragment>
<a href="javaScript:void(0);" onClick={() => onViewDetails(record)}>查看明细</a>
<a href="javaScript:void(0);" style={{ marginRight: 12 }}
onClick={() => onTableOperate({ key: "handleAddData" }, record)}>编辑</a>
<a href="javaScript:void(0);" style={{ marginRight: 12 }}
onClick={() => onViewDetails(record)}>查看明细</a>
{
showOperateBtn &&
<Popover
overlayClassName="moreIconWrapper"
placement="bottomRight"
content={<Menu onClick={(e) => onTableOperate(e, record)}>
<Menu.Item key="handleAddData">编辑</Menu.Item>
<Menu.Item key="deleteSelectAddUpDeduction">删除</Menu.Item>
</Menu>} title="">
<i className="icon-coms-more"/>
@ -127,7 +130,7 @@ class DataTables extends Component {
{
showOperateBtn &&
<React.Fragment>
<a href="javaScript:void(0);"
<a href="javaScript:void(0);" style={{ marginRight: 12 }}
onClick={() => onTableOperate({ key: "handleAddData" }, record)}>编辑</a>
<a href="javaScript:void(0);"
onClick={() => onTableOperate({ key: "deleteSelectAddUpDeduction" }, record)}>删除</a>
@ -154,7 +157,7 @@ class DataTables extends Component {
dataSource={dataSource}
pagination={pagination}
loading={loading.query}
xWidth={getColumns.length * 150}
xWidth={getColumns.length * 160}
/>;
}
}

View File

@ -106,8 +106,8 @@ class Layout extends Component {
visible={visible}
top={0}
measureT="%"
width={1000}
measureX="px"
width={80}
measureX="%"
height={100}
measureY="%"
direction="right"

View File

@ -69,48 +69,53 @@ export const dataCollectCondition = [
{
items: [
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["businessHealthyInsurance"],
fieldcol: 14,
label: "商业健康保险",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["taxDelayEndowmentInsurance"],
fieldcol: 14,
label: "税延养老保险",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["otherDeduction"],
fieldcol: 14,
label: "其他",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["deductionAllowedDonation"],
fieldcol: 14,
label: "准予扣除的捐赠额",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["privatePension"],
fieldcol: 14,
label: "个人养老金",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
}
],

View File

@ -11,18 +11,18 @@
}
.linkWapper {
a {
color: #4d7ad8;
margin-right: 8px;
}
//a {
// color: #4d7ad8;
// margin-right: 8px;
//}
i {
cursor: pointer;
}
a:hover {
text-decoration: none;
}
//a:hover {
// text-decoration: none;
//}
}
}

View File

@ -2,66 +2,73 @@ export const condition = [
{
items: [
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["childrenEducation"],
fieldcol: 14,
label: "子女教育",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["continuingEducation"],
fieldcol: 14,
label: "继续教育",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["housingLoanInterest"],
fieldcol: 14,
label: "住房贷款利息",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["housingRent"],
fieldcol: 14,
label: "住房租金",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["supportingElder"],
fieldcol: 14,
label: "赡养老人",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["seriousIllnessTreatment"],
fieldcol: 14,
label: "大病医疗",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
},
{
conditionType: "INPUT",
conditionType: "INPUTNUMBER",
domkey: ["infantCare"],
fieldcol: 14,
label: "婴幼儿照护",
labelcol: 8,
value: "",
precision: 2,
viewAttr: 2
}
],

View File

@ -1,9 +1,19 @@
import React from "react";
import { WeaDatePicker, WeaDialog, WeaError, WeaFormItem, WeaHelpfulTip, WeaSelect } from "ecCom";
import {
WeaDatePicker,
WeaDialog,
WeaError,
WeaFormItem,
WeaHelpfulTip,
WeaLocaleProvider,
WeaSelect,
WeaTextarea
} from "ecCom";
import { Button } from "antd";
import { inject, observer } from "mobx-react";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
@inject("declareStore", "taxAgentStore")
@observer
export default class GenerateModal extends React.Component {
@ -12,6 +22,7 @@ export default class GenerateModal extends React.Component {
this.state = {
date: "",
taxAgentId: "",
description: "",
loading: false
};
}
@ -19,7 +30,7 @@ export default class GenerateModal extends React.Component {
// 生成申报表
handleGenerate = () => {
const { declareStore: { saveDeclare } } = this.props;
const { date, taxAgentId } = this.state;
const { date, taxAgentId, description } = this.state;
if (_.isEmpty(date) && _.isEmpty(taxAgentId)) {
this.refs.weaError.showError();
this.refs.weaError1.showError();
@ -36,7 +47,7 @@ export default class GenerateModal extends React.Component {
return;
}
this.setState({ loading: true });
saveDeclare({ salaryMonthStr: date, taxAgentId }).then(() => {
saveDeclare({ salaryMonthStr: date, taxAgentId, description }).then(() => {
this.setState({ loading: false });
this.props.onGenerate();
}).catch(() => {
@ -116,13 +127,23 @@ export default class GenerateModal extends React.Component {
}}
/>
<WeaHelpfulTip
style={{ position: "absolute", bottom: "8px", right: 0 }}
style={{ position: "absolute", bottom: 8, right: -35 }}
width={200}
title="提示:可选择单个个税扣缴义务人进行申报,若不选择,则批量对管理下的所有个税扣缴义务人进行申报;"
placement="topLeft"
/>
</WeaError>
</WeaFormItem>
<WeaFormItem
label={getLabel(536726, "备注")}
style={{ marginBottom: 10 }}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}>
<WeaTextarea
value={this.state.description}
onChange={(description) => this.setState({ description })}
/>
</WeaFormItem>
</div>
</WeaDialog>
);

View File

@ -1,13 +1,15 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { Button, DatePicker } from "antd";
import { WeaNewScroll, WeaTop } from "ecCom";
import { Button, DatePicker, message, Modal } from "antd";
import { WeaLocaleProvider, WeaNewScroll, WeaTop } from "ecCom";
import CustomTab from "../../components/customTab";
import CustomTable from "../../components/customTable";
import GenerateModal from "./generateModal";
import { getDeclareList } from "../../apis/declare";
import { getDeclareList, withDrawTaxDeclaration } from "../../apis/declare";
import { sysConfCodeRule } from "../../apis/ruleconfig";
import moment from "moment";
const getLabel = WeaLocaleProvider.getLabel;
const { MonthPicker } = DatePicker;
@inject("taxAgentStore")
@observer
@ -15,6 +17,7 @@ export default class Declare extends React.Component {
constructor(props) {
super(props);
this.state = {
showWithDrawBtn: false,
declarationModalVisible: false,
startDate: moment(new Date()).startOf("year").format("YYYY-MM"),
endDate: moment(new Date()).startOf("month").format("YYYY-MM"),
@ -32,6 +35,7 @@ export default class Declare extends React.Component {
componentWillMount() {
const { taxAgentStore: { getTaxAgentSelectListAsAdmin } } = this.props;
this.getDeclareList();
this.sysConfCodeRule();
getTaxAgentSelectListAsAdmin();
}
@ -56,7 +60,21 @@ export default class Declare extends React.Component {
}
}).catch(() => this.setState({ loading: false }));
};
sysConfCodeRule = () => {
sysConfCodeRule({ code: "WITHDRAW_TAX_DECLARATION" }).then(({ status, data }) => {
if (status && data === "1") this.setState({ showWithDrawBtn: data === "1" });
});
};
withDrawTaxDeclaration = (taxDeclarationId) => {
withDrawTaxDeclaration({ taxDeclarationId }).then(({ status, errormsg }) => {
if (status) {
message.success(getLabel(111, "撤回成功"));
this.getDeclareList();
} else {
message.error(errormsg || getLabel(111, "撤回失败"));
}
});
};
// 日期区间改变事件
handleRangePickerChange = (type, value) => {
this.setState({
@ -81,7 +99,7 @@ export default class Declare extends React.Component {
render() {
const { taxAgentStore: { showOperateBtn } } = this.props;
const { loading, columns, dataSource, pageInfo } = this.state;
const { loading, columns, dataSource, pageInfo, showWithDrawBtn } = this.state;
const renderRightOperation = () => {
const { startDate, endDate } = this.state;
return (
@ -135,15 +153,32 @@ export default class Declare extends React.Component {
dataIndex: "operate",
render: (text, record) => {
return (
<a href="javascript:void(0);"
onClick={() => {
window.open(
"/spa/hrmSalary/static/index.html#/main/hrmSalary/generateDeclarationDetail?id=" +
record.id
);
}}>
查看
</a>
<React.Fragment>
<a href="javascript:void(0);"
onClick={() => {
window.open(
"/spa/hrmSalary/static/index.html#/main/hrmSalary/generateDeclarationDetail?id=" +
record.id
);
}}>
查看
</a>
{
showWithDrawBtn &&
<a
href="javascript:void(0);" style={{ marginLeft: 10 }}
onClick={() => {
Modal.confirm({
title: getLabel(111, "信息确认"),
content: getLabel(111, "确认撤回该条数据吗?"),
onOk: () => this.withDrawTaxDeclaration(record.id)
});
}}
>
{getLabel(111, "撤回")}
</a>
}
</React.Fragment>
);
}
}

View File

@ -15,7 +15,7 @@
.wea-select {
.ant-select {
width: 90% !important;
width: 100% !important;
.ant-select-selection {
border-radius: 0 !important;

View File

@ -0,0 +1,175 @@
/*
* Author: 黎永顺
* name: 员工明细查看
* Description:
* Date: 2023/5/24
*/
import React, { Component } from "react";
import { WeaLocaleProvider, WeaSelect, WeaTop } from "ecCom";
import { WeaTableNew } from "comsMobx";
import { toJS } from "mobx";
import { Spin } from "antd";
import { inject, observer } from "mobx-react";
import { MonthRangePicker } from "../reportView/components/statisticalMicroSettingsSlide";
import { optionAddWhole } from "../../util/options";
import moment from "moment";
import "./index.less";
const WeaTableComx = WeaTableNew.WeaTable;
const { getLabel } = WeaLocaleProvider;
@inject("taxAgentStore", "payrollFilesStore")
@observer
class Index extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
taxAgentId: "",
countResult: {},
salaryMonth: [moment().startOf("year").format("YYYY-MM"), moment().format("YYYY-MM")],
dataSource: [],
pageInfo: {
current: 1,
pageSize: 10,
total: 0
}
};
}
componentWillMount() {
const { taxAgentStore: { fetchTaxAgentOption } } = this.props;
fetchTaxAgentOption();
}
componentDidMount() {
this.statisticsEmployeeDetailList();
window.addEventListener("message", this.handleReceive, false);
}
handleReceive = ({ data }) => {
const { type, payload: { id, params } = {} } = data;
const { dataSource, pageInfo, countResult } = this.state;
const { payrollFilesStore: { employeeTableStore } } = this.props;
const columns = _.filter(toJS(employeeTableStore.columns), (item) => item.display === "true" && item.dataIndex !== "acctTimes");
if (type === "init") {
this.postMessageToChild({
columns: _.map(columns, (it, idx) => ({
...it,
width: (it.dataIndex === "taxAgent" || it.dataIndex === "salarySob") ? 176 : it.oldWidth,
fixed: (idx === 1 || idx === 0 || idx === 2) ? "left" : "",
ellipsis: true
})), dataSource, countResult,
showSum: true, pageInfo
});
} else if (type === "turn") {
if (id === "PAGEINFO") {
const { pageNum: current, size: pageSize } = params;
this.setState({ pageInfo: { ...pageInfo, current, pageSize } }, () => this.statisticsEmployeeDetailList());
}
}
};
postMessageToChild = (payload) => {
const childFrameObj = document.getElementById("atdTable");
const { dataSource, columns, showSum, pageInfo, countResult } = payload;
childFrameObj && childFrameObj.contentWindow.postMessage(JSON.stringify({
dataSource, columns, showSum, pageInfo, countResult
}), "*");
};
statisticsEmployeeDetailList = () => {
const { params: { employeeId }, payrollFilesStore: { statisticsEmployeeDetailList } } = this.props;
const { taxAgentId, salaryMonth, pageInfo } = this.state;
const payload = {
employeeId, taxAgentId,
salaryMonth: salaryMonth.map(item => moment(item).format("YYYY-MM-DD")),
...pageInfo
};
this.setState({ loading: true });
statisticsEmployeeDetailList(payload).then(({ status, data }) => {
this.setState({ loading: false });
if (status) {
const { countResult, pageInfo: { list, pageNum: current, pageSize, total } } = data;
this.setState({
countResult,
dataSource: list || [],
pageInfo: { ...pageInfo, current, pageSize, total }
}, () => {
// this.postMessageToChild({
// columns: this.state.columns,
// dataSource: this.state.dataSource,
// showSum: false, pageInfo: this.state.pageInfo
// });
});
}
}).catch(() => this.setState({ loading: false }));
};
getColumns = () => {
const { dataSource, pageInfo, countResult } = this.state;
const { payrollFilesStore: { employeeTableStore } } = this.props;
const columns = _.filter(toJS(employeeTableStore.columns), (item) => item.display === "true" && item.dataIndex !== "acctTimes");
this.postMessageToChild({
columns: _.map(columns, (it, idx) => ({
...it,
width: (it.dataIndex === "taxAgent" || it.dataIndex === "salarySob") ? 176 : it.oldWidth,
fixed: (idx === 1 || idx === 0 || idx === 2) ? "left" : "",
ellipsis: true
})), dataSource, countResult,
showSum: true, pageInfo
});
};
render() {
const {
location,
taxAgentStore: { showOperateBtn, taxAgentOption },
payrollFilesStore: { employeeTableStore }
} = this.props;
const { salaryMonth, taxAgentId, loading } = this.state;
const { query: { dept, name } } = location;
const btns = [
<MonthRangePicker viewAttr={2} dateRange={salaryMonth}
onChange={v => this.setState({ salaryMonth: v }, () => this.statisticsEmployeeDetailList())}/>,
<WeaSelect options={optionAddWhole(taxAgentOption)} value={taxAgentId} style={{ width: 200 }}
onChange={v => this.setState({ taxAgentId: v }, () => this.statisticsEmployeeDetailList())}/>
];
const dropMenuDatas = [
{
key: "BTN_COLUMN",
icon: <i className="icon-coms-Custom"/>,
content: "显示列定制",
onClick: () => {
employeeTableStore.setColSetVisible(true);
employeeTableStore.tableColSet(true);
}
}
];
return (
<WeaTop
title={<span><span style={{ marginRight: 8 }}>{name}</span><span>{dept}</span></span>}
icon={<i className="icon-coms-fa"/>} buttons={showOperateBtn ? btns : []}
iconBgcolor="#F14A2D" showDropIcon={true} dropMenuDatas={dropMenuDatas}
>
<div className="employeeDetailWrapper">
<Spin spinning={loading}>
<iframe
style={{ border: 0, width: "100%", height: "100%" }}
// src="http://localhost:7607/#/commonTable"
src="/spa/hrmSalary/hrmSalaryCalculateDetail/index.html#/commonTable"
id="atdTable"
/>
</Spin>
</div>
<WeaTableComx
style={{ display: "none" }}
comsWeaTableStore={employeeTableStore}
needScroll={true}
columns={this.getColumns()}
/>
</WeaTop>
);
}
}
export default Index;

View File

@ -0,0 +1,9 @@
.employeeDetailWrapper {
height: 100%;
padding: 10px 10px 0 10px;
.ant-spin-nested-loading,
.ant-spin-container {
height: 99%;
}
}

View File

@ -0,0 +1,30 @@
import React, { Component } from "react";
import { Button, Modal } from "antd";
import ExcelEditor from "../../components/excelEditor";
class Index extends Component {
constructor(props) {
super(props);
this.state = {
title: "DialogTitle",
visible: false,
lvisible: false
};
}
render() {
return (
<div>
<ExcelEditor onChange={()=>{}}/>
<Button type="primary" onClick={() => this.setState({ visible: true })}>显示对话框</Button>
<Modal title="第一个 Modal" visible={this.state.visible}
onCancel={() => this.setState({ visible: false })}
>
<ExcelEditor onChange={()=>{}}/>
</Modal>
</div>
);
}
}
export default Index;

View File

@ -6,7 +6,7 @@
*/
import React, { Component } from "react";
import { inject, observer } from "mobx-react";
import { WeaCheckbox, WeaFormItem, WeaHelpfulTip, WeaInput, WeaSelect, WeaSlideModal, WeaTextarea } from "ecCom";
import { WeaCheckbox, WeaFormItem, WeaHelpfulTip, WeaInput, WeaSelect, WeaSlideModal, WeaTextarea, WeaInputNumber } from "ecCom";
import { message, Modal } from "antd";
import SlideModalTitle from "../../../components/slideModalTitle";
import { getSalaryFieldForm, saveSalaryField } from "../../../apis/fieldManage";
@ -29,6 +29,7 @@ class FieldSlide extends Component {
dataType: "number",
roundingMode: "1",
pattern: "2",
sortedIndex: "",
description: ""
};
}
@ -56,6 +57,7 @@ class FieldSlide extends Component {
useInEmployeeSalary,
dataType,
description,
sortedIndex,
sharedType,
roundingMode,
taxAgentIds,
@ -68,6 +70,7 @@ class FieldSlide extends Component {
useDefault: useDefault ? useDefault.toString() : "0",
dataType,
description,
sortedIndex,
sharedType: sharedType ? sharedType.toString() : "0",
roundingMode: roundingMode ? roundingMode.toString() : "0",
taxAgentIds,
@ -120,6 +123,7 @@ class FieldSlide extends Component {
useInEmployeeSalary,
dataType,
description,
sortedIndex,
sharedType,
roundingMode,
taxAgentIds,
@ -131,6 +135,7 @@ class FieldSlide extends Component {
useDefault: Number(useDefault),
dataType,
description,
sortedIndex,
sharedType,
roundingMode: Number(roundingMode),
taxAgentIds,
@ -168,6 +173,7 @@ class FieldSlide extends Component {
dataType: "number",
roundingMode: "1",
pattern: "2",
sortedIndex: "",
description: ""
});
};
@ -191,6 +197,7 @@ class FieldSlide extends Component {
dataType,
roundingMode,
pattern,
sortedIndex,
description
} = this.state;
return (
@ -283,6 +290,10 @@ class FieldSlide extends Component {
onChange={value => this.handleChangeFields("pattern", value)}
/>
</WeaFormItem>
<WeaFormItem label="显示顺序" labelCol={{ span: 6 }} wrapperCol={{ span: 12 }}>
<WeaInputNumber value={sortedIndex} precision={0}
onChange={value => this.handleChangeFields("sortedIndex", value)}/>
</WeaFormItem>
<WeaFormItem label="备注" labelCol={{ span: 6 }} wrapperCol={{ span: 12 }}>
<WeaTextarea
value={description}

View File

@ -222,13 +222,13 @@
.mySalaryBenefitsWrapper {
.linkWapper {
a {
color: #4d7ad8;
}
//a {
// color: #4d7ad8;
//}
a:hover {
text-decoration: none;
}
//a:hover {
// text-decoration: none;
//}
}
}

View File

@ -304,7 +304,7 @@ export default class SlideBaseForm extends React.Component {
<WeaCheckbox
value={true}
viewAttr={1}
content="【入职日期≤薪资周期止】且【离职日期≥薪资周期起】"
content="【起薪日期≤薪资周期止】且【最后发薪日期≥薪资周期起】"
/>
</Col>
</Row>

View File

@ -8,10 +8,16 @@ import React, { Component } from "react";
import { WeaCheckbox, WeaFormItem, WeaHelpfulTip, WeaInput, WeaSelect, WeaTextarea } from "ecCom";
import { Col, Row } from "antd";
import { inject, observer } from "mobx-react";
import {toJS} from 'mobx';
import { baseSettingFormItem } from "../config";
import { getLedgerBasicForm } from "../../../apis/ledger";
import { getAddMonthYearMonth, getCurrentYearMonth, getSubtractMonthYearMonth } from "../../../util/date";
import {
generateBasicInfo,
getAddMonthYearMonth,
getCurrentYearMonth,
getMonthDays,
getSubtractMonthYearMonth,
prefixAddZero
} from "../../../util/date";
import { commonEnumList } from "../../../apis/ruleconfig";
import moment from "moment";
import "./index.less";
@ -178,7 +184,7 @@ class LedgerBaseSetting extends Component {
type === "CHECKBOX" ?
<React.Fragment>
<WeaCheckbox value={true} viewAttr={1}
content="【入职日期≤薪资周期止】且【离职日期≥薪资周期起】"/>
content="【起薪日期≤薪资周期止】且【最后发薪日期≥薪资周期起】"/>
<WeaHelpfulTip width={200} title="提示:最后发薪日期为空,默认为无穷大" placement="topLeft"/>
</React.Fragment> :
type === "SELECT" ?
@ -206,9 +212,8 @@ export default LedgerBaseSetting;
const CustomSelect = (props) => {
const { list, baseInfo, onChange, inputStr } = props;
const { salaryCycleType, salaryCycleFromDay, attendCycleType, attendCycleFromDay, canEdit } = baseInfo;
const salaryCycleStrObj = initPeriodStr("inputStr", salaryCycleType, salaryCycleFromDay);
const attendCycleStrObj = initPeriodStr("inputStr", attendCycleType, attendCycleFromDay);
const { canEdit } = baseInfo;
const selectInfo = buildEditBasicInfo(baseInfo);
return <Row gutter={10} key={inputStr}>
{
_.map(list, item => {
@ -221,20 +226,12 @@ const CustomSelect = (props) => {
})
}
<Col span={12}
className="desc">{inputStr === "salaryCycleStrObj" ? salaryCycleStrObj.inputStr : attendCycleStrObj.inputStr}</Col>
className="desc">{inputStr === "salaryCycleStrObj" ? selectInfo.salaryCycleInfo.salaryPeriodTip : selectInfo.attendCycleInfo.attendancePeriodTip}</Col>
</Row>;
};
const MonthCycleDesc = (props) => {
const {
taxCycleType,
socialSecurityCycleType,
salaryCycleFromDay,
salaryCycleType,
attendCycleType,
attendCycleFromDay
} = props;
const salaryCycleStrObj = initPeriodStr("salaryCycleStr", salaryCycleType, salaryCycleFromDay);
const attendCycleStrObj = initPeriodStr("attendCycleStr", attendCycleType, attendCycleFromDay);
const { taxCycleType, socialSecurityCycleType } = props;
const selectInfo = buildEditBasicInfo({ ...props });
return <div className="baseSettingRight">
<div className="title">月份周期说明</div>
<div className="descContent">
@ -245,28 +242,131 @@ const MonthCycleDesc = (props) => {
<div>根据您当前的选择相应的周期为</div>
<div className="descTitle">薪资周期</div>
<div>
<span className="notice">{getStartDate(salaryCycleType, salaryCycleFromDay)}</span>
<span className="notice">{salaryCycleStrObj.date}</span>
<span className="notice">{selectInfo.salaryCycleInfo.salaryPeriodStart}</span>
<span className="notice">{selectInfo.salaryCycleInfo.salaryPeriodEnd}</span>
</div>
<div className="descTitle">税款所属期</div>
<div className="notice">{getMonth(taxCycleType)}</div>
<div className="descTitle">考勤取值周期</div>
<div>
<span className="notice">{getStartDate(attendCycleType, attendCycleFromDay)}</span>
<span className="notice">{attendCycleStrObj.date}</span>
<span className="notice">{selectInfo.attendCycleInfo.attendancePeriodStart}</span>
<span className="notice">{selectInfo.attendCycleInfo.attendancePeriodEnd}</span>
</div>
<div className="descTitle">福利台账月份</div>
<div>引用<span className="notice">{getMonth(socialSecurityCycleType)}</span></div>
</div>
</div>;
};
// 获取开始日期
const getStartDate = (salaryCycleType, day) => {
day = Number(day);
return getMonth(salaryCycleType) + "-" + (day < 10 ? "0" + day : day);
const buildEditBasicInfo = (editBasicInfo) => {
const { attendCycleType, salaryCycleType } = editBasicInfo;
const now = new Date();
let nowYear = now.getFullYear();
let nowMonth = now.getMonth() + 1;
let tmpV = {};
// 薪资联动
switch (salaryCycleType) {
case "1" :
tmpV["salaryCycleInfo"] = buildSalaryInfo(editBasicInfo, -2, nowYear, nowMonth);
break;
case "2" :
tmpV["salaryCycleInfo"] = buildSalaryInfo(editBasicInfo, -1, nowYear, nowMonth);
break;
case "3" :
tmpV["salaryCycleInfo"] = buildSalaryInfo(editBasicInfo, 0, nowYear, nowMonth);
break;
case "4" :
tmpV["salaryCycleInfo"] = buildSalaryInfo(editBasicInfo, 1, nowYear, nowMonth);
break;
}
// 考勤联动
switch (attendCycleType) {
case "1" :
tmpV["attendCycleInfo"] = buildAttendanceInfo(editBasicInfo, -2, nowYear, nowMonth);
break;
case "2" :
tmpV["attendCycleInfo"] = buildAttendanceInfo(editBasicInfo, -1, nowYear, nowMonth);
break;
case "3" :
tmpV["attendCycleInfo"] = buildAttendanceInfo(editBasicInfo, 0, nowYear, nowMonth);
break;
case "4" :
tmpV["attendCycleInfo"] = buildAttendanceInfo(editBasicInfo, 1, nowYear, nowMonth);
break;
}
return tmpV;
};
/*
* Author: 黎永顺
* Description:构建薪资周期联动信息
* Params:
* Date: 2023/4/17
*/
const buildSalaryInfo = (editBasicInfo, monthCal, nowYear, nowMonth) => {
const { salaryCycleFromDay } = editBasicInfo;
let salaryCycleFromDayNum = Number(salaryCycleFromDay), customInfo = {};
const basicInfo = generateBasicInfo(monthCal, nowYear, nowMonth);
const { nowMonthStr, nextMonthStr, year, month } = basicInfo;
customInfo.salaryYear = year;
customInfo.salaryMonth = month;
if (salaryCycleFromDayNum === 1) {
customInfo.salaryPeriodTip = "至" + nowMonthStr + "最后一天";
customInfo.salaryPeriodStart = customInfo.salaryYear + "-"
+ prefixAddZero(customInfo.salaryMonth, 2) + "-01";
customInfo.salaryPeriodEnd = customInfo.salaryYear + "-"
+ prefixAddZero(customInfo.salaryMonth, 2) + "-"
+ prefixAddZero(getMonthDays(customInfo.salaryYear, customInfo.salaryMonth), 2);
} else {
customInfo.salaryPeriodTip = "至" + nextMonthStr + (salaryCycleFromDayNum - 1) + "号";
customInfo.salaryPeriodStart = customInfo.salaryYear + "-"
+ prefixAddZero(customInfo.salaryMonth, 2) + "-" + prefixAddZero(salaryCycleFromDayNum, 2);
let year = customInfo.salaryYear;
let month = customInfo.salaryMonth;
if (month === "12") {
year = Number(year) + 1;
month = 1;
} else {
month = Number(month) + 1;
}
customInfo.salaryPeriodEnd = year + "-"
+ prefixAddZero(month, 2) + "-"
+ prefixAddZero(salaryCycleFromDayNum - 1, 2);
}
return customInfo;
};
const buildAttendanceInfo = (editBasicInfo, monthCal, nowYear, nowMonth) => {
const { attendCycleFromDay } = editBasicInfo;
let attendCycleFromDayNum = Number(attendCycleFromDay), customInfo = {};
const basicInfo = generateBasicInfo(monthCal, nowYear, nowMonth);
const { nowMonthStr, nextMonthStr } = basicInfo;
let year = basicInfo.year;
let month = basicInfo.month;
if (attendCycleFromDayNum === 1) {
customInfo.attendancePeriodTip = "至" + nowMonthStr + "最后一天";
customInfo.attendancePeriodStart = year + "-"
+ prefixAddZero(month, 2) + "-01";
customInfo.attendancePeriodEnd = year + "-"
+ prefixAddZero(month, 2) + "-"
+ prefixAddZero(getMonthDays(year, month), 2);
} else {
customInfo.attendancePeriodTip = "至" + nextMonthStr + (attendCycleFromDayNum - 1) + "号";
customInfo.attendancePeriodStart = year + "-"
+ prefixAddZero(month, 2) + "-" + prefixAddZero(attendCycleFromDayNum, 2);
if (month === "12") {
year = (Number(year) + 1).toString();
month = "1";
} else {
month = (Number(month) + 1).toString();
}
customInfo.attendancePeriodEnd = year + "-"
+ prefixAddZero(month, 2) + "-"
+ prefixAddZero(attendCycleFromDayNum - 1, 2);
}
return customInfo;
};
const getMonth = (salaryCycleType) => {
switch (salaryCycleType) {
case "1": // 上上月
@ -279,62 +379,3 @@ const getMonth = (salaryCycleType) => {
return getAddMonthYearMonth(1);
}
};
const initPeriodStr = (periodStrType, types, fromDay) => {
let str = "", tmpDate = null;
switch (types) {
case "1":
tmpDate = moment().subtract(2, "month");
const is_31H = moment(tmpDate, "YYYY-MM").daysInMonth() === 31;
if (fromDay == 1) {
tmpDate = moment().subtract(2, "month").endOf("month");
str = `至上上月最后一天`;
} else {
tmpDate = moment(new Date(`${moment(tmpDate).format("YYYY-MM")}-0${fromDay}`))
.add(is_31H ? 30 : 27, "days");
str = `至上月${moment(tmpDate).date()}`;
}
break;
case "2":
tmpDate = moment().subtract(1, "month");
const is_31 = moment(tmpDate, "YYYY-MM").daysInMonth() === 31;
if (fromDay == 1) {
tmpDate = moment().subtract(1, "month").endOf("month");
str = `至上月最后一天`;
} else {
tmpDate = moment(new Date(`${moment(tmpDate).format("YYYY-MM")}-0${fromDay}`))
.add(is_31 ? 30 : 27, "days");
str = `至本月${moment(tmpDate).date()}`;
}
break;
case "3":
tmpDate = moment().add(0, "month");
const is_31K = moment(tmpDate, "YYYY-MM").daysInMonth() === 31;
if (fromDay == 1) {
tmpDate = moment().endOf("month");
str = `至本月最后一天`;
} else {
tmpDate = moment(new Date(`${moment(tmpDate).format("YYYY-MM")}-0${fromDay}`))
.add(is_31K ? 30 : 27, "days");
str = `至下月${moment(tmpDate).date()}`;
}
break;
case "4":
tmpDate = moment().add(1, "month");
const is_31L = moment(tmpDate, "YYYY-MM").daysInMonth() === 31;
if (fromDay == 1) {
tmpDate = moment().add(1, "month").endOf("month");
str = `至下月最后一天`;
} else {
tmpDate = moment(new Date(`${moment(tmpDate).format("YYYY-MM")}-0${fromDay}`))
.add(is_31L ? 30 : 29, "days");
str = `至下下月${moment(tmpDate).date()}`;
}
break;
default:
break;
}
return {
[periodStrType]: str,
date: moment(tmpDate).format("YYYY-MM-DD")
};
};

View File

@ -260,10 +260,15 @@ class LedgerSalaryItem extends Component {
itemGroups: _.map(itemGroups, it => {
if (id === it.uuid) {
return {
...it, items: [...it.items, ..._.map(items, child => {
...it, items: _.map([..._.map(items, child => {
const { id: itemsId, ...extraItems } = child;
return { ...extraItems, salaryItemGroupId: it.uuid };
})]
}), ...it.items], (childItem, childItemIndex) => {
return {
...childItem,
sortedIndex: childItemIndex
};
})
};
}
return { ...it };

View File

@ -13,6 +13,7 @@ export default class LedgerSalaryItemAddModal extends React.Component {
name: "",
selectedRowKeys: [],
dataSource: [],
dataSourceCopy: [],
columns: [],
pageInfo: {
current: 1,
@ -24,15 +25,17 @@ export default class LedgerSalaryItemAddModal extends React.Component {
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.visible !== this.props.visivle && nextProps.visible) {
this.setState({ selectedRowKeys: [] }, () => {
this.setState({ selectedRowKeys: [], dataSourceCopy: [] }, () => {
this.listSalaryItem();
});
} else {
this.setState({ pageInfo: { current: 1, pageSize: 10, total: 0 } });
}
}
listSalaryItem = () => {
listSalaryItem = (extra = {}) => {
const { itemGroups } = this.props;
const { name, pageInfo, loading } = this.state;
const { name, pageInfo, loading, dataSourceCopy } = this.state;
let excludeIds = [];
itemGroups.map(item => {
item.items && item.items.map(i => {
@ -42,16 +45,19 @@ export default class LedgerSalaryItemAddModal extends React.Component {
const payload = {
excludeIds,
name,
...pageInfo
...pageInfo,
...extra
};
this.setState({ loading: { ...loading, query: true } });
listSalaryItem(payload).then(({ status, data }) => {
this.setState({ loading: { ...loading, query: false } });
if (status) {
const { pageNum: current, pageSize, total, columns, list: dataSource } = data;
const tmpV = !_.isEmpty(dataSource) ? dataSource : [];
this.setState({
dataSourceCopy: [...dataSourceCopy, ...tmpV],
pageInfo: { ...pageInfo, current, pageSize, total },
dataSource,
dataSource: tmpV,
columns
});
}
@ -80,11 +86,11 @@ export default class LedgerSalaryItemAddModal extends React.Component {
};
handleAdd = () => {
const { dataSource, selectedRowKeys } = this.state;
const { dataSourceCopy, selectedRowKeys } = this.state;
const { onAddSalaryItems, id, onCancel, itemGroups } = this.props;
const arrItems = _.find(itemGroups, it => it.uuid === id).items || [];
let selectItems = [];
dataSource.map((item) => {
_.uniqWith(dataSourceCopy, _.isEqual).map((item) => {
item = { ...item };
selectedRowKeys.map((key, keyIdx) => {
if (item.id === key) {
@ -133,7 +139,7 @@ export default class LedgerSalaryItemAddModal extends React.Component {
placeholder="请输入薪资项目名称"
value={name}
onChange={(name) => this.setState({ name })}
onSearch={() => this.listSalaryItem()}
onSearch={() => this.listSalaryItem({ current: 1 })}
/>
</div>
<WeaTable

View File

@ -15,7 +15,7 @@ export default class LedgerSalaryItemPreviewModal extends React.Component {
_.map(_.filter(itemGroups, it => !_.isEmpty(it.items)), child => {
let columnItem = {
title: child.name,
children: child.items.map(i => {
children: _.filter(child.items, t => t.itemHide !== "1").map(i => {
return {
title: i.name,
dataIndex: i.id,
@ -23,7 +23,7 @@ export default class LedgerSalaryItemPreviewModal extends React.Component {
};
})
};
columns.push(columnItem);
columnItem.children.length > 0 && columns.push(columnItem);
});
return { columns };
};

View File

@ -38,10 +38,10 @@ class LedgerTable extends Component {
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.doSearch !== this.props.doSearch) this.getLedgerList({current: 1});
if (nextProps.doSearch !== this.props.doSearch) this.getLedgerList({ current: 1 });
}
getLedgerList = (extra={}) => {
getLedgerList = (extra = {}) => {
const { name } = this.props;
const { pageInfo } = this.state;
const payload = { name, ...pageInfo, ...extra };
@ -74,17 +74,22 @@ class LedgerTable extends Component {
/>;
};
} else if (dataIndex === "operate") {
item.width = 120;
item.width = 150;
item.render = (text, record) => {
return <div className="optWrapper">
<a href="javascript:void(0);" className="mr10" onClick={()=> onEditLedger(record)}>{showOperateBtn ? "编辑" : "查看"}</a>
<a href="javascript:void(0);" className="mr10"
onClick={() => onEditLedger(record)}>{showOperateBtn ? "编辑" : "查看"}</a>
{
showOperateBtn &&
<a href="javascript:void(0);" className="mr10"
onClick={() => this.handleMenuClick({ key: "copy" }, record)}>复制</a>
}
{
showOperateBtn &&
<Popover
overlayClassName="moreIconWrapper"
placement="bottomRight"
content={<Menu onClick={(e) => this.handleMenuClick(e, record)}>
<Menu.Item key="copy">复制</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>} title="">
<i className="icon-coms-more"/>

View File

@ -1,10 +1,16 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { getQueryString } from "../../util/url";
import { WeaDialog, WeaError, WeaInput } from "ecCom";
import { Button, message } from "antd";
import Authority from "../mySalary/authority";
import ComputerTemplate from "../payroll/templatePreview/computerTemplate";
import PhoneTemplate from "../payroll/templatePreview/phoneTemplate";
import "../payroll/templatePreview/index.less";
import * as API from "../../apis/mySalaryBenefits";
import { payrollCheckType } from "../../apis/payroll";
import "./index.less";
import CaptchaModal from "../../components/captchaModal";
@inject("mySalaryStore")
@observer
@ -12,6 +18,9 @@ export default class MobilePayroll extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
captchaVisible: false,
authCode: "",
mySalaryBillData: {
employeeInformation: {},
salaryTemplate: []
@ -20,15 +29,55 @@ export default class MobilePayroll extends React.Component {
this.id = "";
}
componentWillMount() {
async componentWillMount() {
const type = getQueryString("type");
this.id = getQueryString("id");
const { mySalaryStore: { init } } = this.props;
// type !== "phone" && init(false);
init(false);
this.getMySalaryBill(this.id);
const { data, status } = await payrollCheckType();
if (type !== "phone") {
if (status && data === "PWD") {
init(false, () => this.getMySalaryBill(this.id));
} else {
this.setState({ captchaVisible: true });
}
}
type === "phone" && this.initMobile();
}
initMobile = () => {
const { mySalaryStore: { setInitEmVerify } } = this.props;
// if (window.em) {
API.isNeedSecondPwdVerify({ mouldCode: "HRM", itemCode: "SALARY" }).then(({ status, isNeedSecondAuth }) => {
if (status && isNeedSecondAuth) {
this.setState({ visible: true });
} else {
this.getMySalaryBill(getQueryString("id"));
setInitEmVerify();
}
});
// } else {
// setInitEmVerify();
// }
};
doSecondAuth = () => {
const { mySalaryStore: { setInitEmVerify } } = this.props;
if (!this.state.authCode) {
this.refs.weaError.showError();
return;
}
API.doSecondAuth({
authCode: this.state.authCode, mouldCode: "HRM", itemCode: "SALARY"
}).then(({ status, checkStatus, checkMsg }) => {
if (status && checkStatus === "1") {
message.success(checkMsg);
setInitEmVerify();
this.setState({ visible: false });
this.getMySalaryBill(getQueryString("id"));
} else {
message.error(checkMsg);
}
});
};
getMySalaryBill = (salaryInfoId) => {
const { mySalaryStore: { getMySalaryBill } } = this.props;
const params = this.getUrlkey();
@ -57,7 +106,8 @@ export default class MobilePayroll extends React.Component {
};
render() {
const { mySalaryBillData } = this.state;
const { mySalaryStore: { clearLoading } } = this.props;
const { mySalaryBillData, visible, captchaVisible } = this.state;
const type = getQueryString("type");
const employeeInformation = mySalaryBillData.employeeInformation ? mySalaryBillData.employeeInformation : {};
const salaryGroups = mySalaryBillData.salaryGroups ? mySalaryBillData.salaryGroups : [];
@ -67,18 +117,32 @@ export default class MobilePayroll extends React.Component {
overflowY: "hidden",
paddingBottom: "20px"
}}>
<WeaDialog
onCancel={() => this.setState({ visible: false }, () => clearLoading())}
title="请输入二次验证密码" visible={visible} initLoadCss
className="verifyWrapper"
hasScroll buttons={[
<Button type="primary" size="small" onClick={this.doSecondAuth}>确定</Button>
]}
>
<WeaError tipPosition="bottom" ref="weaError" error="此项必填">
<WeaInput value={this.state.authCode} onChange={authCode => this.setState({ authCode })}/>
</WeaError>
</WeaDialog>
{
type === "phone" ?
<div className="templatePreview">
<div className="contentWrapper">
<PhoneTemplate
isPreview
isMsgPreview
salaryTemplateShowSet={JSON.stringify(mySalaryBillData.salaryTemplate)}
salaryItemSet={!_.isEmpty(salaryGroups) ? JSON.stringify([employeeInformation, ...salaryGroups]) : []}
/>
<Authority ecId={`${this && this.props && this.props.ecId || ""}_Authority@lulowc`}
store={this.props.mySalaryStore}>
<div className="templatePreview">
<div className="contentWrapper">
<PhoneTemplate
isPreview
salaryTemplateShowSet={JSON.stringify(mySalaryBillData.salaryTemplate)}
salaryItemSet={!_.isEmpty(salaryGroups) ? JSON.stringify([employeeInformation, ...salaryGroups]) : []}
/>
</div>
</div>
</div>
</Authority>
:
<Authority ecId={`${this && this.props && this.props.ecId || ""}_Authority@lulowc`}
store={this.props.mySalaryStore}>
@ -86,7 +150,6 @@ export default class MobilePayroll extends React.Component {
<div className="contentWrapper">
<ComputerTemplate
isPreview
isMsgPreview
salaryTemplateShowSet={JSON.stringify(mySalaryBillData.salaryTemplate)}
salaryItemSet={!_.isEmpty(salaryGroups) ? JSON.stringify([employeeInformation, ...salaryGroups]) : JSON.stringify([])}
/>
@ -94,6 +157,11 @@ export default class MobilePayroll extends React.Component {
</div>
</Authority>
}
<CaptchaModal
visible={captchaVisible} id={getQueryString("id")}
onCancel={() => this.setState({ captchaVisible: false })}
onConfirm={() => this.props.mySalaryStore.setInitEmVerify()}
/>
</div>
);
}

View File

@ -0,0 +1,17 @@
.verifyWrapper {
.ant-modal-content {
width: 80vw !important;
.ant-modal-body {
padding: 10% !important;
.wea-dialog-body, .wea-new-scroll {
height: 75px !important;
.wea-error {
width: 100%;
}
}
}
}
}

View File

@ -1,15 +1,15 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { DatePicker } from "antd";
import { WeaNewScroll, WeaTop } from "ecCom";
import { WeaLocaleProvider, WeaNewScroll, WeaTop } from "ecCom";
import { renderNoright } from "../../util"; // 渲染form数据的方法因为多个页面都会使用所以抽的公共方法在util中
import CustomTab from "../../components/customTab";
import moment from "moment";
import PayrollModal from "./payrollModal";
import Authority from "./authority";
import CustomPaginationTable from "../../components/customPaginationTable";
import "./index.less";
const { getLabel } = WeaLocaleProvider;
const { RangePicker } = DatePicker;
@inject("mySalaryStore")
@ -28,9 +28,9 @@ export default class MySalary extends React.Component {
this.historyPageInfo = { current: 1, pageSize: 10 };
}
componentWillMount() {
const { mySalaryStore: { init } } = this.props;
init();
componentDidMount() {
const { mySalaryStore: { mySalaryBillList } } = this.props;
mySalaryBillList([moment().startOf("year").format("YYYY-MM"), moment().format("YYYY-MM")]);
}
// 查看工资单
@ -61,9 +61,8 @@ export default class MySalary extends React.Component {
dataIndex: "operate",
render: (text, record) => {
return (
<a onClick={() => {
this.handleView(record);
}}>查看</a>
<a target="_blank"
href={`${window.location.origin}/spa/hrmSalary/static/index.html#/main/hrmSalary/mySalary/${record.id}`}>{getLabel(33564, "查看")}</a>
);
}
});
@ -114,7 +113,6 @@ export default class MySalary extends React.Component {
myBillPageInfo
} = mySalaryStore;
const { salaryBillVisible, salaryInfoId, salaryRange } = this.state;
if (!hasRight && !loading) return renderNoright();
const topTab = [
{
@ -141,64 +139,62 @@ export default class MySalary extends React.Component {
};
return (
<div className="mySalaryBenefitsWrapper">
<Authority ecId={`${this && this.props && this.props.ecId || ""}_Authority@lulowc`} store={mySalaryStore}>
<WeaTop
title="我的薪资福利" // 文字
icon={<i className="icon-coms-fa"/>} // 左侧图标
iconBgcolor="#F14A2D" // 左侧图标背景色
showDropIcon={false} // 是否显示下拉按钮
>
<CustomTab
topTab={topTab}
searchOperationItem={renderSearchOperationItem()}
onChange={(v) => {
this.handleTabChange(v);
this.setState({ selectedKey: v });
}}
/>
<div className="tableWrapper">
<WeaNewScroll height="100%">
{
this.state.selectedKey === "0" &&
<CustomPaginationTable
loading={loading}
columns={this.getColumns()}
dataSource={myBillDataSource ? myBillDataSource : []}
total={myBillPageInfo.total}
current={myBillPageInfo.pageNum}
pageSize={this.pageInfo.pageSize}
onPageChange={(value) => {
this.pageInfo.current = value;
this.handlePageChange();
}}
onShowSizeChange={(current, pageSize) => {
this.pageInfo = { current, pageSize };
this.handlePageChange();
}}
/>
}
{
this.state.selectedKey === "2" &&
<CustomPaginationTable
columns={recordListColumns}
dataSource={recordListDataSource}
total={recordListPageInfo.total}
current={recordListPageInfo.pageNum}
pageSize={this.historyPageInfo.pageSize}
onPageChange={(value) => {
this.historyPageInfo.current = value;
this.handleHistoryPageChange();
}}
onShowSizeChange={(current, pageSize) => {
this.historyPageInfo = { current, pageSize };
this.handleHistoryPageChange();
}}
/>
}
</WeaNewScroll>
</div>
</WeaTop>
</Authority>
<WeaTop
title="我的薪资福利" // 文字
icon={<i className="icon-coms-fa"/>} // 左侧图标
iconBgcolor="#F14A2D" // 左侧图标背景色
showDropIcon={false} // 是否显示下拉按钮
>
<CustomTab
topTab={topTab}
searchOperationItem={renderSearchOperationItem()}
onChange={(v) => {
this.handleTabChange(v);
this.setState({ selectedKey: v });
}}
/>
<div className="tableWrapper">
<WeaNewScroll height="100%">
{
this.state.selectedKey === "0" &&
<CustomPaginationTable
loading={loading}
columns={this.getColumns()}
dataSource={myBillDataSource ? myBillDataSource : []}
total={myBillPageInfo.total}
current={myBillPageInfo.pageNum}
pageSize={this.pageInfo.pageSize}
onPageChange={(value) => {
this.pageInfo.current = value;
this.handlePageChange();
}}
onShowSizeChange={(current, pageSize) => {
this.pageInfo = { current, pageSize };
this.handlePageChange();
}}
/>
}
{
this.state.selectedKey === "2" &&
<CustomPaginationTable
columns={recordListColumns}
dataSource={recordListDataSource}
total={recordListPageInfo.total}
current={recordListPageInfo.pageNum}
pageSize={this.historyPageInfo.pageSize}
onPageChange={(value) => {
this.historyPageInfo.current = value;
this.handleHistoryPageChange();
}}
onShowSizeChange={(current, pageSize) => {
this.historyPageInfo = { current, pageSize };
this.handleHistoryPageChange();
}}
/>
}
</WeaNewScroll>
</div>
</WeaTop>
{
salaryBillVisible && <PayrollModal
visible={salaryBillVisible}

View File

@ -0,0 +1,73 @@
/*
* Author: 黎永顺
* name: 查看我的薪资-工资单
* Description:
* Date: 2023/6/14
*/
import React, { Component } from "react";
import { inject, observer } from "mobx-react";
import Authority from "./authority";
import ComputerTemplate from "../payroll/templatePreview/computerTemplate";
import { payrollCheckType } from "../../apis/payroll";
import CaptchaModal from "../../components/captchaModal";
import "../payroll/templatePreview/index.less";
@inject("mySalaryStore")
@observer
class MySalaryView extends Component {
constructor(props) {
super(props);
this.state = {
captchaVisible: false,
mySalaryStore: {}
};
}
async componentDidMount() {
const { mySalaryStore: { init, getMySalaryBill }, params: { salaryInfoId } } = this.props;
const { data, status } = await payrollCheckType();
if (status && data === "PWD") {
init(false, () => {
getMySalaryBill(Number(salaryInfoId)).then(data => {
this.setState({ mySalaryStore: data });
});
});
} else {
this.setState({ captchaVisible: true });
}
}
render() {
const { captchaVisible, mySalaryStore } = this.state;
const { params: { salaryInfoId } } = this.props;
if (_.isEmpty(mySalaryStore)) {
return <div></div>;
}
const employeeInformation = !_.isEmpty(mySalaryStore) && mySalaryStore.employeeInformation;
const salaryGroups = !_.isEmpty(mySalaryStore) && mySalaryStore.salaryGroups;
const salaryTemplateShowSet = !_.isEmpty(mySalaryStore) && mySalaryStore.salaryTemplate;
return (
<React.Fragment>
<Authority ecId={`${this && this.props && this.props.ecId || ""}_Authority@lulowc`}
store={this.props.mySalaryStore}>
<div style={{ height: "100%", overflow: "auto" }}>
<div className="templatePreview">
<ComputerTemplate
isPreview isMsgPreview
salaryTemplateShowSet={salaryTemplateShowSet ? JSON.stringify(salaryTemplateShowSet) : []}
salaryItemSet={!_.isEmpty(salaryGroups) ? JSON.stringify([employeeInformation, ...salaryGroups]) : []}
/>
</div>
</div>
</Authority>
<CaptchaModal
visible={captchaVisible} id={salaryInfoId}
onCancel={() => this.setState({ captchaVisible: false })}
onConfirm={() => mySalaryStore.setInitEmVerify()}
/>
</React.Fragment>
);
}
}
export default MySalaryView;

View File

@ -1,6 +1,6 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { message, Tag } from "antd";
import { Dropdown, Menu, message, Tag } from "antd";
import moment from "moment";
import CustomPaginationTable from "../../components/customPaginationTable";
import "../calculate/index.less";
@ -91,8 +91,9 @@ export default class SalarySendList extends React.Component {
{
title: "操作",
key: "operate",
width: 150,
render: (text, record) => {
const { sendNum, sendTotal, salaryAcctType, haveBackCalc } = record;
const { sendNum, sendTotal, salaryAcctType, haveBackCalc, canSeeDetail } = record;
//显示发放
const showGrant = haveBackCalc === 1 && salaryAcctType === 0;
return (
@ -100,13 +101,20 @@ export default class SalarySendList extends React.Component {
<a href="javascript:void(0);" onClick={() => this.handleGrant(record)}
style={{ marginRight: 10 }}>发放</a>
{
!showGrant &&
canSeeDetail &&
<a href="javascript:void(0);" onClick={() => this.handleShowDetail(record)}
style={{ marginRight: 10 }}>查看详情</a>
}
{
sendNum !== sendTotal && !showGrant &&
<a href="javascript:void(0);" onClick={() => this.handleUpdateTemplate(record)}>更新模板</a>
<Dropdown
overlay={
<Menu onClick={() => this.handleUpdateTemplate(record)}>
<Menu.Item key="delete">更新模板</Menu.Item>
</Menu>
}>
<i className="icon-coms-more more"/>
</Dropdown>
}
</React.Fragment>
);

View File

@ -0,0 +1,14 @@
import { WeaLocaleProvider } from "ecCom";
const getLabel = WeaLocaleProvider.getLabel;
export const commonVariables = [
{ id: "HRM_Name", name: getLabel(111, "当前操作者姓名")},
{ id: "HRM_Num", name: getLabel(111, "当前操作者编号")},
{ id: "HRM_Mobile", name: getLabel(111, "当前操作者移动电话")},
{ id: "HRM_Email", name: getLabel(111, "当前操作者电子邮件")},
{ id: "HRM_CurrentOperatorId", name: getLabel(111, "当前操作者人员id")},
{ id: "HRM_Department", name: getLabel(111, "当前操作者部门")},
{ id: "HRM_SecondDepartment", name: getLabel(111, "分部")},
{ id: "HRM_CurrentDate", name: getLabel(111, "当前日期")},
{ id: "HRM_CurrentTime", name: getLabel(111, "当前时间")},
];

View File

@ -46,3 +46,124 @@
}
}
}
.waterMarkSetWrapper, .wmContentWrapper {
.rodal {
.rodal-dialog {
& > div:nth-child(2) {
height: calc(100% - 52px) !important;
padding-bottom: 0 !important;
}
}
}
.waterMark-select-header {
padding: 0 5px;
}
.wea-transfer-list-wrapper {
.transfer-tree {
li {
cursor: pointer;
margin: 10px 0;
}
}
}
.wea-slide-modal-content {
padding-bottom: 65px;
}
.wmTitle {
float: left;
margin-left: 16px;
}
.slideBottom {
display: flex;
justify-content: flex-end;
padding: 16px 25px;
border-top: 1px solid #e5e5e5;
position: absolute;
width: 100%;
bottom: 0;
background: #f4f4f4;
button:first-child {
margin-right: 16px;
}
}
.waterMarkWrapper {
padding-top: 16px;
}
.wmContGroup {
.wea-title {
border: 1px solid #e5e5e5;
border-bottom: none;
}
.wea-content {
padding-top: 0;
}
.content-box {
padding: 16px;
.ant-col-18 {
height: 319px;
}
}
.wea-form-cell-wrapper {
border-bottom: none;
}
}
.mt16 {
.wea-form-cell-wrapper {
border: 1px solid #e5e5e5;
}
}
.wea-form-cell-wrapper {
border: 1px solid #e5e5e5;
border-bottom: none;
}
.wea-form-item {
padding: 5px 16px;
border-bottom: 1px solid #e5e5e5;
}
.textSetting {
display: flex;
align-items: center;
margin-top: 7px;
min-width: 200px;
.icon-coms-Flow-setting {
font-size: 16px;
color: #666;
cursor: pointer;
}
img {
margin-left: 5px;
}
}
.previewBtn {
cursor: pointer;
color: #2db7f5;
position: relative;
margin-left: 10px;
}
.txtPrew {
margin-left: 20px !important;
}
}

View File

@ -0,0 +1,201 @@
/*
* Author: 黎永顺
* name: 水印设置-弹框
* Description:
* Date: 2023/6/13
*/
import React, { Component } from "react";
import {
WeaError,
WeaFormItem,
WeaHelpfulTip,
WeaInputNumber,
WeaLocaleProvider,
WeaSearchGroup,
WeaSelect,
WeaSlideModal
} from "ecCom";
import { Button } from "antd";
import ImageUploadList from "../../../components/upload";
import WmContentSetModal from "./wmContentSetModal";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
class WaterMarkSetModal extends Component {
constructor(props) {
super(props);
this.state = {
wmClassify: "text", wmNoTransparent: 0,
wmRotate: 0, wmImg: null, wmcontSet: {
visible: false, textSet: {}
}
};
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.visible !== this.props.visible && nextProps.visible) {
const { watermarkSetting } = nextProps;
const {
wmClassify = "text",
wmNoTransparent = 0,
wmRotate = 0,
wmImg,
wmOriginText,
wmHeight,
wmWidth,
pureWmText,
wmSelectedFieldIds,
wmText
} = watermarkSetting;
if (wmClassify === "text") {
this.setState({
wmClassify, wmNoTransparent, wmRotate,
wmcontSet: {
...this.state.wmcontSet, textSet: wmOriginText ? {
wmOriginText, wmHeight, wmWidth, pureWmText, wmSelectedFieldIds, wmText
} : {}
}
});
} else {
this.setState({
wmClassify, wmNoTransparent, wmRotate, wmImg
});
}
}
}
handleCustomSave = () => {
const { wmClassify, wmImg, wmRotate, wmNoTransparent, wmcontSet } = this.state;
if ((wmClassify === "text" && _.isEmpty(wmcontSet.textSet)) || (wmClassify !== "text" && !wmImg)) {
this.refs.watermarkContError.showError();
return;
}
if (wmClassify === "text") {
this.props.onChange({
wmSetting: {
wmClassify, ...wmcontSet.textSet,
wmNoTransparent, wmRotate
}
});
} else {
this.props.onChange({
wmSetting: {
wmClassify, wmImg,
wmNoTransparent, wmRotate
}
});
}
this.props.onClose();
};
render() {
const { wmClassify, wmNoTransparent, wmRotate, wmImg, wmcontSet } = this.state;
return (
<WeaSlideModal
{...this.props} className="waterMarkSetWrapper"
title={<span className="wmTitle">{getLabel(111, "水印设置")}</span>}
direction="right" top={0} width={800} height={100}
measureT="%" measureX="px" measureY="%"
content={
<React.Fragment>
<WeaSearchGroup showGroup needTigger={false} className="waterMarkWrapper">
<WeaFormItem label={getLabel(111, "水印类型")} labelCol={{ span: 5 }} wrapperCol={{ span: 10 }}>
<div style={{ display: "flex", alignItems: "center" }}>
<WeaSelect
value={wmClassify} detailtype={3}
options={[
{ key: "text", showname: getLabel(111, "文本") },
{ key: "image", showname: getLabel(111, "图片") }
]}
onChange={wmClassify => this.setState({ wmClassify })}
/>
<WeaHelpfulTip title={getLabel(111, "邮件发送不支持图片水印")} placement="topLeft"
style={{ marginLeft: 10 }}/>
</div>
</WeaFormItem>
<WeaFormItem label={getLabel(111, "水印类型")} labelCol={{ span: 5 }} wrapperCol={{ span: 10 }}>
{
wmClassify === "text" ?
<WeaError tipPosition="bottom" ref="watermarkContError" error={getLabel(385869, "此项必填")}>
<div className="textSetting">
<i className="icon-coms-Flow-setting"
onClick={() => this.setState({ wmcontSet: { ...wmcontSet, visible: true } })}/>
{
_.isEmpty(wmcontSet.textSet) ? <img src="/images/BacoError_wev9.png" alt=""/> :
<span className="previewBtn txtPrew"
onClick={() => {
window.open(`${window.location.origin}/spa/hrmSalary/static/index.html#/main/hrmSalary/payroll/watermark/preview`, "_blank");
}}
>
<i className="icon-coms-Selected" style={{
"color": "#093",
"marginRight": "5px"
}}/>
预览
</span>
}
</div>
</WeaError> :
<WeaError tipPosition="bottom" ref="watermarkContError" error={getLabel(385869, "此项必填")}>
<div className="textSetting">
<ImageUploadList onChange={wmImg => this.setState({ wmImg }, () => {
window.localStorage.setItem("wmSetting", JSON.stringify({
wmSetting: {
wmClassify, wmRotate, wmNoTransparent,
...this.state.wmImg
}
}));
})} wmImg={wmImg}/>
{
!wmImg ? <img src="/images/BacoError_wev9.png" alt=""/> :
<span className="previewBtn" onClick={() => {
window.open(`${window.location.origin}/spa/hrmSalary/static/index.html#/main/hrmSalary/payroll/watermark/preview`, "_blank");
}}>预览</span>
}
</div>
</WeaError>
}
</WeaFormItem>
<WeaFormItem label={getLabel(111, "不透明(百分比)")} labelCol={{ span: 5 }} wrapperCol={{ span: 10 }}>
<WeaInputNumber
min={0} max={80} precision={2} value={wmNoTransparent}
onChange={wmNoTransparent => this.setState({ wmNoTransparent })}
/>
</WeaFormItem>
<WeaFormItem label={getLabel(111, "旋转角度(逆时针)")} labelCol={{ span: 5 }} wrapperCol={{ span: 10 }}>
<WeaInputNumber
min={0} max={360} precision={2} value={wmRotate}
onChange={wmRotate => this.setState({ wmRotate })}
/>
</WeaFormItem>
</WeaSearchGroup>
<div className="slideBottom">
<Button type="primary" onClick={this.handleCustomSave}>{getLabel(111, "确定")}</Button>
<Button type="ghost" onClick={this.props.onClose}>{getLabel(111, "取消")}</Button>
</div>
{/* 水印内容设置弹框*/}
<WmContentSetModal {...wmcontSet}
onClose={textSet => this.setState({
wmcontSet: {
...wmcontSet,
visible: false,
textSet
}
}, () => {
window.localStorage.setItem("wmSetting", JSON.stringify({
wmSetting: {
wmClassify, wmRotate, wmNoTransparent,
...this.state.wmcontSet.textSet
}
}));
})}
/>
</React.Fragment>
}
/>
);
}
}
export default WaterMarkSetModal;

View File

@ -0,0 +1,188 @@
/*
* Author: 黎永顺
* name: 水印内容设置
* Description:
* Date: 2023/6/14
*/
import React, { Component } from "react";
import {
WeaFormItem,
WeaHelpfulTip,
WeaInputNumber,
WeaInputSearch,
WeaLocaleProvider,
WeaRichText,
WeaSearchGroup,
WeaSlideModal,
WeaTransfer
} from "ecCom";
import { Button, Col, message, Row } from "antd";
import { commonVariables } from "./config";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
const WeaTransferList = WeaTransfer.list;
class WmContentSetModal extends Component {
constructor(props) {
super(props);
this.state = {
wmWidth: 100,
wmHeight: 100,
wmOriginText: "",
searchV: ""
};
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.visible !== this.props.visible) {
this.setState({
wmWidth: nextProps.textSet.wmWidth || 100,
wmHeight: nextProps.textSet.wmHeight || 100,
wmOriginText: nextProps.textSet.wmOriginText || ""
});
} else {
this.setState({
wmWidth: 100,
wmHeight: 100,
wmOriginText: "",
searchV: ""
});
}
}
handleSaveWMContent = () => {
const html = this.refs.TextContentRichText.getData().replace(/\n/ig, "");
if (!html) {
message.warning(getLabel(111, "请输入水印内容!"));
return;
}
const { wmWidth, wmHeight } = this.state;
this.props.onClose({
wmWidth, wmHeight,
wmSelectedFieldIds: this.getHtmlAttrVal(html),
pureWmText: this.convertToPlain(html),
wmOriginText: html, wmText: this.convertToWMText(html)
});
};
convertToWMText = (html) => {
_.map(commonVariables, item => {
const { id, name } = item;
const reg = eval("/" + name + "/g");
html = html.replace(reg, `$${id}`).replace(/ data-id=\"(.*?)\"/g, "");
});
return html.replace(/ contenteditable="false"/g, "");
};
getHtmlAttrVal = (html) => {
let attrAndValueArr = html.match(/ data-id=\"(.*?)\"/g);
let valueArr = []; // 放所有该属性的值
if (!_.isEmpty(attrAndValueArr)) {
for (let i = 0; i < attrAndValueArr.length; i++) {
valueArr.push(attrAndValueArr[i].replace(/ data-id=/g, "").replace(/\"/g, ""));
}
}
return valueArr;
};
convertToPlain = (html) => {
let tempDivElement = document.createElement("div");
tempDivElement.innerHTML = html;
return tempDivElement.textContent || tempDivElement.innerText || "";
};
renderItem = (item = {}) => {
return <span>{item.name}</span>;
};
selectHeader() {
return (
<div className={"waterMark-select-header"}>
<WeaInputSearch onSearchChange={(v) => {
this.setState({ searchV: v });
}}/>
</div>
);
}
render() {
const { wmWidth, wmHeight, wmOriginText, searchV } = this.state;
const ckConfig = {
toolbar: [
{ name: "paragraph", items: ["JustifyLeft", "JustifyCenter", "JustifyRight"] },
{ name: "styles", items: ["Font", "FontSize"] },
{ name: "colors", items: ["TextColor"] }
],
removePlugins: "resize",
height: 280
};
const tempOptions = _.filter(commonVariables, (item) => {
const { name } = item;
let flag = true;
if (searchV && name) {
flag = name.indexOf(searchV) > -1;
}
return flag;
});
return (
<WeaSlideModal
{...this.props} className="wmContentWrapper" onClose={() => this.props.onClose(this.props.textSet)}
title={<span className="wmTitle">{getLabel(111, "水印内容设置")}</span>}
direction="right" top={0} width={800} height={100}
measureT="%" measureX="px" measureY="%"
content={
<React.Fragment>
<WeaSearchGroup
title={<span><span style={{ marginRight: 10 }}>{getLabel(111, "水印格式设置")}</span><WeaHelpfulTip
title={getLabel(111, "水印最小100px*100px")} placement="topLeft"/></span>}
showGroup needTigger={false} className="waterMarkWrapper wmContGroup">
<WeaFormItem label={getLabel(111, "水印宽度") + "px"} labelCol={{ span: 5 }} wrapperCol={{ span: 10 }}>
<WeaInputNumber
min={100} precision={3} value={wmWidth}
onChange={wmWidth => this.setState({ wmWidth })}
/>
</WeaFormItem>
<WeaFormItem label={getLabel(111, "水印高度") + "px"} labelCol={{ span: 5 }} wrapperCol={{ span: 10 }}>
<WeaInputNumber
min={100} precision={3} value={wmHeight}
onChange={wmHeight => this.setState({ wmHeight })}
/>
</WeaFormItem>
</WeaSearchGroup>
<WeaSearchGroup
title={getLabel(111, "内容")}
showGroup needTigger={false} className="waterMarkWrapper wmContGroup mt16">
<Row className="content-box" gutter={10}>
<Col span={18}>
<WeaRichText ckConfig={ckConfig} value={wmOriginText} ref={"TextContentRichText"}/>
</Col>
<Col span={6}>
<WeaTransferList
header={this.selectHeader()}
data={tempOptions}
renderItem={this.renderItem}
checkedCb={(keys) => {
let result = _.filter(commonVariables, (item) => item.id === keys[0]);
if (result && result.length > 0) {
this.refs.TextContentRichText.insertHTML(`&nbsp;<span contenteditable="false" data-id="${result[0].id}">${result[0].name}</span>&nbsp;`);
}
}}
height={280}
checkedKeys={[]}
/>
</Col>
</Row>
</WeaSearchGroup>
<div className="slideBottom">
<Button type="primary"
onClick={this.handleSaveWMContent}>{getLabel(111, "保存")}</Button>
<Button type="ghost"
onClick={() => this.props.onClose(this.props.textSet)}>{getLabel(111, "取消")}</Button>
</div>
</React.Fragment>
}
/>
);
}
}
export default WmContentSetModal;

View File

@ -3,8 +3,16 @@ import { inject, observer } from "mobx-react";
import { toJS } from "mobx";
import { Button, DatePicker, message, Modal } from "antd";
import moment from "moment";
import { WeaHelpfulTip, WeaInputSearch, WeaNewScroll, WeaSelect, WeaSlideModal, WeaTop } from "ecCom";
import { renderLoading } from "../../util"; // 渲染form数据的方法因为多个页面都会使用所以抽的公共方法在util中
import {
WeaHelpfulTip,
WeaInputSearch,
WeaLocaleProvider,
WeaNewScroll,
WeaSelect,
WeaSlideModal,
WeaTop
} from "ecCom";
import { renderLoading } from "../../util";
import CustomTab from "../../components/customTab";
import StepSlide from "../../components/stepSlide";
import BaseInformForm from "./stepForm/baseInformForm";
@ -12,11 +20,13 @@ import ShowSettingForm from "./stepForm/showSettingForm";
import SlideModalTitle from "../../components/slideModalTitle";
import TemplateSettingList from "./templateSettingList";
import TemplateSettingForm from "./stepForm/tmplateSettingForm";
import TemplateBaseSettings from "./templateBaseSettings";
import CopyModal from "./copyModal";
import SalarySendList from "./SalarySendList";
import { getReplenishForm } from "../../apis/payroll";
import "../dataAcquisition/cumDeduct/index.less";
const getLabel = WeaLocaleProvider.getLabel;
const { MonthPicker } = DatePicker;
@inject("payrollStore", "taxAgentStore")
@ -38,7 +48,8 @@ export default class Payroll extends React.Component {
templateCurrentId: "",
copyModalVisible: false,
startDate: moment(new Date()).startOf("year").format("YYYY-MM"),
endDate: moment(new Date()).startOf("month").format("YYYY-MM")
endDate: moment(new Date()).startOf("month").format("YYYY-MM"),
loading: false
};
this.recordId = "";
this.salaryYearMonth = [moment(new Date()).startOf("year").format("YYYY-MM"), moment(new Date()).startOf("month").format("YYYY-MM")];
@ -243,7 +254,15 @@ export default class Payroll extends React.Component {
render() {
const { payrollStore, taxAgentStore: { showOperateBtn } } = this.props;
const { loading, hasRight, templateStore, deletePayroll, templateBaseData } = payrollStore;
const {
loading,
hasRight,
templateTableSelectedRowKeys,
setTemplateTableSelectedRowKeys,
deletePayroll,
templateBaseData,
setTemplateTablePageInfo
} = payrollStore;
const { currentStep, selectedTab, templateSearchValue, templateSelect, startDate, endDate } = this.state;
if (!hasRight && !loading) { // 无权限处理
return renderLoading();
@ -256,6 +275,10 @@ export default class Payroll extends React.Component {
{
title: "工资单模板设置",
viewcondition: "1"
},
{
title: getLabel(111, "工资单模板基础设置"),
viewcondition: "2"
}
];
const renderRightOperation = () => {
@ -302,7 +325,7 @@ export default class Payroll extends React.Component {
style={{ marginLeft: 10 }}
type="ghost"
onClick={() => {
const selectedRowKeys = toJS(templateStore.selectedRowKeys);
const selectedRowKeys = toJS(templateTableSelectedRowKeys);
if (!selectedRowKeys.length) {
message.info("未选中任何数据!");
return;
@ -328,11 +351,18 @@ export default class Payroll extends React.Component {
<WeaInputSearch style={{ marginleft: "10px" }} placeholder="请输入工资单名称" value={templateSearchValue}
onChange={(value) => {
this.setState({ templateSearchValue: value });
}} onSearch={(value) => {
this.handleTemplateSearch(value);
}}/>
}}
onSearch={(value) => {
this.handleTemplateSearch(value);
}}
/>
</div>
);
} else if (this.state.selectedKey === "2") {
return <Button type="primary"
onClick={() => this.baseSetRef.salaryBillBaseSetSave()}
loading={this.state.loading}
>{getLabel(111, "保存")}</Button>;
}
};
const steps = ["基础设置", "正常核算工资单模板", "补发工资单模版"];
@ -371,7 +401,14 @@ export default class Payroll extends React.Component {
topTab={topTab}
searchOperationItem={renderRightOperation()}
onChange={(v) => {
this.setState({ selectedKey: v, stepSlideVisible: false, editSlideVisible: false });
this.setState({
selectedKey: v,
stepSlideVisible: false,
editSlideVisible: false
}, () => {
setTemplateTablePageInfo({ current: 1 });
setTemplateTableSelectedRowKeys([]);
});
}}
/>
<div className="tableWrapper">
@ -405,6 +442,13 @@ export default class Payroll extends React.Component {
onDelete={(record) => this.handleTemplateListDelete(record)}
/>
}
{
this.state.selectedKey === "2" &&
<TemplateBaseSettings
ref={dom => this.baseSetRef = dom}
onChangeLoading={loading => this.setState({ loading })}
/>
}
</WeaNewScroll>
</div>
</WeaTop>

View File

@ -0,0 +1,22 @@
.waterMarkWrapper {
.wea-form-cell-wrapper {
border: 1px solid #e5e5e5;
border-bottom: none;
}
.wea-form-item {
padding: 5px 16px;
border-bottom: 1px solid #e5e5e5;
.waterMarkTitle {
margin-left: 10px;
cursor: pointer;
color: #2db7f5;
position: absolute;
display: inline-block;
width: 48px;
top: 50%;
margin-top: -10px;
}
}
}

View File

@ -5,8 +5,7 @@ import { Button, Spin } from "antd";
import { getQueryString } from "../../../util/url";
import { removePropertyCondition } from "../../../util/response";
import { getSearchs } from "../../../util";
import { getPayrollDetailList, getPayrollDetailSa, getPayrollInfo, salaryBillSendSum } from "../../../apis/payroll";
import { sysConfCodeRule } from "../../../apis/ruleconfig";
import { getPayrollDetailList, getPayrollDetailSa, getPayrollInfo } from "../../../apis/payroll";
import "./index.less";
@inject("payrollStore")
@ -17,8 +16,7 @@ export default class PayrollDetail extends React.Component {
this.state = {
salarySendDetailBaseInfo: {}, loading: false,
condition: [], dataSource: [], columns: [],
pageInfo: { current: 1, pageSize: 10, total: 0 },
salaryBillSendSum: {}, showSum: false
pageInfo: { current: 1, pageSize: 10, total: 0 }
};
}
@ -54,16 +52,11 @@ export default class PayrollDetail extends React.Component {
}
}
if (type === "init") {
const { status, data: sysData } = await this.sysConfCodeRule();
const { data: { sumRow } } = await this.salaryBillSendSum();
const salaryBillSendSum = _.reduce(_.keys(sumRow), (pre, cur) => (_.assign(pre, { [`${cur}_salaryItem`]: sumRow[cur] })), {});
this.setState({ showSum: status && sysData === "1", salaryBillSendSum });
childFrameObj.contentWindow.postMessage(JSON.stringify({
dataSource,
columns,
pageInfo,
showSum: status && sysData === "1",
salaryBillSendSum
sumpayload: { salarySendId: getQueryString("id") }
}), "*");
this.getPayrollDetailList({ child: type });
}
@ -110,25 +103,18 @@ export default class PayrollDetail extends React.Component {
})),
pageInfo: { ...pageInfo, current, pageSize, total }
}, () => {
const { pageInfo, dataSource, columns, salaryBillSendSum, showSum } = this.state;
const { pageInfo, dataSource, columns } = this.state;
(child === "PAGEINFO" || child === "init") &&
childFrameObj.contentWindow.postMessage(JSON.stringify({
dataSource,
columns,
pageInfo, showSum,
salaryBillSendSum
pageInfo,
sumpayload: { salarySendId: getQueryString("id") }
}), "*");
});
}
}).catch(() => this.setState({ loading: false }));
};
salaryBillSendSum = () => {
const salarySendId = getQueryString("id");
return salaryBillSendSum({ salarySendId });
};
sysConfCodeRule = () => {
return sysConfCodeRule({ code: "OPEN_ACCT_RESULT_SUM" });
};
handleExportAll = () => {
const salarySendId = getQueryString("id");
const url = `${window.location.origin}/api/bs/hrmsalary/salaryBill/send/exportDetailList?salarySendId=${salarySendId}`;

View File

@ -1,14 +1,17 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { toJS } from "mobx";
import { WeaDropdown, WeaHelpfulTip, WeaTab, WeaTop } from "ecCom";
import { WeaDropdown, WeaHelpfulTip, WeaLocaleProvider, WeaTab, WeaTop } from "ecCom";
import { Button, Dropdown, Menu, message } from "antd";
import "./index.less";
import { getQueryString } from "../../../util/url";
import { getSearchs, renderLoading } from "../../../util";
import CustomPaginationTable from "../../../components/customPaginationTable";
import PayrollPartTable from "./payrollPartTable";
import { getPayrollIssuanceProgressBar } from "../../../apis/payroll";
import ProgressModal from "../../../components/progressModal";
const getLabel = WeaLocaleProvider.getLabel;
const { ButtonSelect } = WeaDropdown;
@inject("payrollStore")
@ -20,6 +23,8 @@ export default class PayrollGrant extends React.Component {
selectedRowKeys: [],
currentId: "",
selectedKey: "0",
progressVisible: false,
progress: 0,
payrollPartModalParams: {
visible: false,
title: "工资单发放",
@ -28,6 +33,7 @@ export default class PayrollGrant extends React.Component {
}
};
this.pageInfo = { current: 1, pageSize: 10 };
this.timer = null;
}
componentWillMount() {
@ -66,6 +72,7 @@ export default class PayrollGrant extends React.Component {
// 发放
handleGrant = (record) => {
this.setState({ progress: 0 });
const { payrollStore } = this.props;
const { currentId, selectedKey } = this.state;
const { grantPayroll, getInfoList } = payrollStore;
@ -73,14 +80,39 @@ export default class PayrollGrant extends React.Component {
...record,
salarySendId: currentId
}).then(() => {
getInfoList({
salarySendId: currentId,
isGranted: selectedKey !== "0",
current: this.pageInfo.current,
pageSize: this.pageInfo.pageSize
this.setState({ progressVisible: true });
if (this.timer) clearInterval(this.timer);
this.timer = setInterval(() => {
getPayrollIssuanceProgressBar(currentId).then(({ data, status }) => {
let progress = data.progress;
if (progress === 1 && this.timer) {
clearInterval(this.timer);
this.timer = null;
this.setState({
progressVisible: false,
progress: 0
});
message.success(data.message);
getInfoList({
salarySendId: currentId,
isGranted: selectedKey !== "0",
current: this.pageInfo.current,
pageSize: this.pageInfo.pageSize
});
this.handleClose();
});
this.handleClose();
} else if (!data.status) {
clearInterval(this.timer);
this.timer = null;
this.setState({
progressVisible: false,
progress: 0
});
message.error(data.message);
}
this.setState({ progress: Number(progress) * 100 });
});
}, 1000);
});
};
@ -159,6 +191,7 @@ export default class PayrollGrant extends React.Component {
};
// 全部发送
handleGrantAll = () => {
this.setState({ progress: 0 });
const { payrollStore } = this.props;
const { currentId, selectedKey } = this.state;
const { grantPayroll, getInfoList } = payrollStore;
@ -166,22 +199,73 @@ export default class PayrollGrant extends React.Component {
ids: [],
salarySendId: currentId
}).then(() => {
getInfoList({
salarySendId: currentId,
isGranted: selectedKey !== "0"
});
this.setState({ progressVisible: true });
if (this.timer) clearInterval(this.timer);
this.timer = setInterval(() => {
getPayrollIssuanceProgressBar(currentId).then(({ data, status }) => {
let progress = data.progress;
if (progress === 1 && this.timer) {
clearInterval(this.timer);
this.timer = null;
this.setState({
progressVisible: false,
progress: 0
});
message.success(data.message);
getInfoList({
salarySendId: currentId,
isGranted: selectedKey !== "0"
});
} else if (!data.status) {
clearInterval(this.timer);
this.timer = null;
this.setState({
progressVisible: false,
progress: 0
});
message.error(data.message);
}
this.setState({ progress: Number(progress) * 100 });
});
}, 1000);
});
};
// 发放所选
fetchGrantPayRoll = (payload) => {
this.setState({ progress: 0 });
const { selectedKey, currentId } = this.state;
const { payrollStore: { grantPayroll, getInfoList } } = this.props;
grantPayroll(payload).then(() => {
getInfoList({
salarySendId: currentId,
isGranted: selectedKey !== "0"
});
this.setState({ selectedRowKeys: [] });
this.setState({ progressVisible: true });
if (this.timer) clearInterval(this.timer);
this.timer = setInterval(() => {
getPayrollIssuanceProgressBar(currentId).then(({ data, status }) => {
let progress = data.progress;
if (progress === 1 && this.timer) {
clearInterval(this.timer);
this.timer = null;
this.setState({
progressVisible: false,
progress: 0
});
message.success(data.message);
getInfoList({
salarySendId: currentId,
isGranted: selectedKey !== "0"
});
this.setState({ selectedRowKeys: [] });
} else if (!data.status) {
clearInterval(this.timer);
this.timer = null;
this.setState({
progressVisible: false,
progress: 0
});
message.error(data.message);
}
this.setState({ progress: Number(progress) * 100 });
});
}, 1000);
});
};
@ -218,7 +302,7 @@ export default class PayrollGrant extends React.Component {
const { payrollStore } = this.props;
const { salaryGrantTableStore: columns, salarySendDetailBaseInfo } = payrollStore;
const notShowGrantOrWithdraw = salarySendDetailBaseInfo.haveBackCalc === 1 && salarySendDetailBaseInfo.salaryAcctType === "0";
return [
return _.map([
...toJS(columns),
{
title: "操作",
@ -226,7 +310,7 @@ export default class PayrollGrant extends React.Component {
dataIndex: "",
display: true,
render: (text, record) => {
if (record.sendStatus === "已发放" && !notShowGrantOrWithdraw) {
if (record.sendStatus === "1" && salarySendDetailBaseInfo.canSend) {
return (
<a
href="javascript:void(0);"
@ -234,7 +318,7 @@ export default class PayrollGrant extends React.Component {
撤回
</a>
);
} else if (!notShowGrantOrWithdraw) {
} else if (salarySendDetailBaseInfo.canSend) {
return (
<a
href="javascript:void(0);"
@ -245,7 +329,17 @@ export default class PayrollGrant extends React.Component {
}
}
}
];
], item => {
if (item.dataIndex === "sendStatus") {
return {
...item,
render: (text, record) => {
return <span>{record.sendStatus === "0" ? getLabel(111, "未发放") : record.sendStatus === "1" ? getLabel(111, "已发放") : getLabel(111, "已撤回")}</span>;
}
};
}
return { ...item };
});
};
getSearchsAdQuick() {
@ -276,7 +370,7 @@ export default class PayrollGrant extends React.Component {
更多
</Dropdown.Button>
];
if (selectedKey === "0" && !notShowGrantOrWithdraw) {
if (selectedKey === "0" && salarySendDetailBaseInfo.canSend) {
btnDom = [
<ButtonSelect
datas={[
@ -284,13 +378,13 @@ export default class PayrollGrant extends React.Component {
{ key: "SELECT", show: "发放所选", selected: false },
{ key: "PART", show: "部分发放", selected: false }
]}
btnProps={{loading: btnLoading}}
btnProps={{ loading: btnLoading }}
btnOnClick={this.sendPayroll}
menuOnClick={(key) => this.sendPayroll(key)}
/>,
...btnDom
];
} else if (selectedKey === "1" && !notShowGrantOrWithdraw) {
} else if (selectedKey === "1" && salarySendDetailBaseInfo.canSend) {
btnDom = [
<ButtonSelect
datas={[
@ -298,7 +392,7 @@ export default class PayrollGrant extends React.Component {
{ key: "recallSelected", show: "撤回所选", selected: false },
{ key: "partialWithdrawal", show: "部分撤回", selected: false }
]}
btnProps={{loading: btnLoading}}
btnProps={{ loading: btnLoading }}
btnOnClick={this.withdrawalPayroll}
menuOnClick={(key) => this.withdrawalPayroll(key)}
/>,
@ -505,6 +599,18 @@ export default class PayrollGrant extends React.Component {
onWithdraw={this.handleWithdraw}
onGrant={this.handleGrant}
/>
{
this.state.progressVisible &&
<ProgressModal
visible={this.state.progressVisible}
onCancel={() => {
this.setState({ progressVisible: false, progress: 0 });
clearInterval(this.timer);
this.timer = null;
}}
progress={this.state.progress}
/>
}
</div>
);
}

View File

@ -1,9 +1,14 @@
import React from "react";
import { WeaFormItem, WeaInput, WeaSearchGroup, WeaSelect } from "ecCom";
import { WeaCheckbox, WeaFormItem, WeaInput, WeaLocaleProvider, WeaSearchGroup, WeaSelect, WeaTimePicker } from "ecCom";
import { inject, observer } from "mobx-react";
import { getReplenishRuleSetOptions } from "../../../apis/payroll";
import { commonEnumList } from "../../../apis/payrollFiles";
import moment from "moment";
import { toJS } from "mobx";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
@inject("payrollStore")
@observer
export default class BaseInformForm extends React.Component {
@ -13,6 +18,7 @@ export default class BaseInformForm extends React.Component {
inited: false,
options: [],
replenishRuleOptions: [],
salaryMonthOptions: [],
request: {}
};
}
@ -21,6 +27,7 @@ export default class BaseInformForm extends React.Component {
const { payrollStore } = this.props;
const { getPayrollBaseForm } = payrollStore;
const templateBaseData = window.localStorage.getItem("template-basedata") || "{}";
this.commonEnumList();
getPayrollBaseForm(this.props.id).then(data => {
this.setState(
{
@ -31,8 +38,11 @@ export default class BaseInformForm extends React.Component {
}, ...toJS(data.salarySobOptions)],
request: {
...data.templateBaseData,
msgStatus: !this.props.id ? "1" : data.templateBaseData.msgStatus,
reissueRule: data.templateBaseData.replenishRule ? "1" : "0",
...JSON.parse(templateBaseData)
...JSON.parse(templateBaseData),
sendEmail: "",
autoSendStatus: !_.isNil(data.templateBaseData.autoSendStatus) ? data.templateBaseData.autoSendStatus : false
}
}, () => {
this.props.onChange && this.props.onChange(this.state.request);
@ -45,7 +55,7 @@ export default class BaseInformForm extends React.Component {
JSON.parse(templateBaseData).salarySob && this.getReplenishRuleSetOptions({ salarySobId: JSON.parse(templateBaseData).salarySob });
}
hanldeChange = (params) => {
handleChange = (params) => {
let request = { ...this.state.request, ...params };
this.setState({
request
@ -67,89 +77,191 @@ export default class BaseInformForm extends React.Component {
}
});
};
commonEnumList = () => {
commonEnumList({ enumClass: "com.engine.salary.enums.salarysend.SalaryAutoSendCycleTypeEnum" })
.then(({ status, data }) => {
if (status && !_.isEmpty(data)) {
this.setState({
salaryMonthOptions: _.map(data, it => ({ key: it.value.toString(), showname: it.defaultLabel }))
});
}
});
};
render() {
const { request, options, replenishRuleOptions } = this.state;
const { salarySob, name, description, replenishName, replenishRule, reissueRule } = request;
const { request, options, replenishRuleOptions, salaryMonthOptions } = this.state;
const {
salarySob,
name,
description,
replenishName,
replenishRule,
reissueRule,
msgStatus,
emailStatus,
autoSendStatus,
autoSendDayOfMonth,
autoSendTimeOfDay,
autoSendCycleType
} = request;
return (
<WeaSearchGroup title="基础信息" items={[]} needTigger showGroup col={1}>
<WeaFormItem
label="薪资账套"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
{
this.state.inited &&
<WeaSelect
viewAttr={3}
options={options}
value={salarySob ? salarySob : ""}
style={{ width: 200 }}
onChange={value => this.hanldeChange({ salarySob: value })}/>
}
</WeaFormItem>
<WeaFormItem
label="工资单模板名称"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput
value={name}
viewAttr={3}
onChange={value => this.hanldeChange({ name: value })}
/>
</WeaFormItem>
<WeaFormItem
label="补发工资单模板名称"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput
value={replenishName}
viewAttr={3}
onChange={value => this.hanldeChange({ replenishName: value })}
/>
</WeaFormItem>
<WeaFormItem
label="补发工资单名单生成规则"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaSelect
options={[{ key: "0", showname: "全部" }, { key: "1", showname: "按规则" }]}
value={reissueRule}
detailtype={3}
viewAttr={3}
onChange={value => this.hanldeChange({ reissueRule: value })}
/>
</WeaFormItem>
{
reissueRule !== "0" &&
<React.Fragment>
<WeaSearchGroup title="基础信息" items={[]} needTigger showGroup col={1} className="payrollBaseInfoWrapper">
<WeaFormItem
label="规则设置"
label="薪资账套"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
{
this.state.inited &&
<WeaSelect
viewAttr={3}
options={options}
value={salarySob ? salarySob : ""}
style={{ width: 200 }}
onChange={value => this.handleChange({ salarySob: value })}/>
}
</WeaFormItem>
<WeaFormItem
label="工资单模板名称"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput
value={name}
viewAttr={3}
onChange={value => this.handleChange({ name: value })}
/>
</WeaFormItem>
<WeaFormItem
label="补发工资单模板名称"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput
value={replenishName}
viewAttr={3}
onChange={value => this.handleChange({ replenishName: value })}
/>
</WeaFormItem>
<WeaFormItem
label="补发工资单名单生成规则"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaSelect
options={replenishRuleOptions}
value={replenishRule}
options={[{ key: "0", showname: "全部" }, { key: "1", showname: "按规则" }]}
value={reissueRule}
detailtype={3}
viewAttr={3}
onChange={value => this.hanldeChange({ replenishRule: value })}
onChange={value => this.handleChange({ reissueRule: value })}
/>
</WeaFormItem>
}
<WeaFormItem
label="备注"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput
value={description}
onChange={value => this.hanldeChange({ description: value })}
/>
</WeaFormItem>
</WeaSearchGroup>
{
reissueRule !== "0" &&
<WeaFormItem
label="规则设置"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaSelect
options={replenishRuleOptions}
value={replenishRule}
viewAttr={3}
onChange={value => this.handleChange({ replenishRule: value })}
/>
</WeaFormItem>
}
<WeaFormItem
label="备注"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput
value={description}
onChange={value => this.handleChange({ description: value })}
/>
</WeaFormItem>
</WeaSearchGroup>
<WeaSearchGroup title={getLabel(111, "发送设置")} items={[]} needTigger showGroup col={1}
className="payrollBaseInfoWrapper">
<WeaFormItem label={getLabel(111, "系统消息")} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
<WeaCheckbox value={msgStatus ? "1" : "0"} display="switch"
onChange={value => this.handleChange({ msgStatus: value === "1" })}/>
</WeaFormItem>
<WeaFormItem label={getLabel(111, "邮件")} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
<WeaCheckbox value={emailStatus ? "1" : "0"} display="switch"
onChange={value => this.handleChange({ emailStatus: value === "1" })}/>
</WeaFormItem>
<WeaFormItem label={getLabel(111, "定时发送")} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
<WeaCheckbox value={autoSendStatus ? "1" : "0"} display="switch"
onChange={value => {
this.handleChange({
autoSendStatus: value === "1",
autoSendDayOfMonth: value === "1" ? "1" : null,
autoSendTimeOfDay: value === "1" ? "09:00" : null,
autoSendCycleType: value === "1" ? 1 : null,
});
}}/>
</WeaFormItem>
{
autoSendStatus &&
<WeaFormItem label={getLabel(111, "发送时间")} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
<SendTimeComp
salaryMonthOptions={salaryMonthOptions}
value={{
autoSendDayOfMonth,
autoSendTimeOfDay,
autoSendCycleType
}}
onChange={this.handleChange}
/>
</WeaFormItem>
}
</WeaSearchGroup>
</React.Fragment>
);
}
}
const SendTimeComp = (props) => {
const { value, onChange, salaryMonthOptions } = props;
const { autoSendDayOfMonth, autoSendTimeOfDay, autoSendCycleType } = value;
const handleChangeSendtime = (key, val) => {
onChange({ autoSendDayOfMonth, autoSendTimeOfDay, autoSendCycleType, [key]: val });
};
return <div className="customTimeCompWrapper">
<div>
<span>{getLabel(542604, "薪资所属月")}</span>
<WeaSelect
value={autoSendCycleType.toString()}
options={salaryMonthOptions}
onChange={v => handleChangeSendtime("autoSendCycleType", Number(v))}
/>
<WeaSelect
value={!_.isNil(autoSendDayOfMonth) ? autoSendDayOfMonth : "1"}
options={_.map(getDay(autoSendCycleType), item => ({ key: item, showname: item }))}
onChange={v => handleChangeSendtime("autoSendDayOfMonth", v)}
/>
<span>{getLabel(16992, "号")}</span>
</div>
<WeaTimePicker value={!_.isNil(autoSendTimeOfDay) ? autoSendTimeOfDay : "09:00"} size="small"
onChange={v => handleChangeSendtime("autoSendTimeOfDay", v)}/>
</div>;
};
const getDay = (num = 1) => {
let days = [];
let day = getDaysInMonth(moment().year(), moment().month() + num);
for (let i = 1; i <= day; i++) {
days.push(i);
}
return days;
};
const getDaysInMonth = (year, month) => {
month = parseInt(month, 10);
let d = new Date(year, month, 0);
return d.getDate();
};

View File

@ -223,3 +223,31 @@
padding: 16px;
}
}
.payrollBaseInfoWrapper {
.wea-form-cell-wrapper {
border: 1px solid #e5e5e5;
border-bottom: none;
.wea-form-item {
padding: 5px 16px;
border-bottom: 1px solid #e5e5e5;
}
}
.customTimeCompWrapper {
display: flex;
justify-content: flex-start;
& > div {
margin-right: 10px;
display: flex;
align-items: center;
.wea-select {
width: 80px;
margin: 0 10px;
}
}
}
}

View File

@ -0,0 +1,104 @@
/*
* Author: 黎永顺
* name: 工资单模板基础设置
* Description:
* Date: 2023/6/12
*/
import React, { Component } from "react";
import { WeaCheckbox, WeaFormItem, WeaLocaleProvider, WeaSearchGroup, WeaSelect } from "ecCom";
import { message } from "antd";
import { getSalaryBillBaseSetForm, salaryBillBaseSetSave } from "../../apis/payroll";
import WaterMarkSetModal from "./components/waterMarkSetModal";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
class TemplateBaseSettings extends Component {
constructor(props) {
super(props);
this.state = {
watermarkStatus: "0",
watermark: "DEFAULT",
wmSetting: null,
watermarkSet: {
visible: false, watermarkSetting: null
}
};
}
componentDidMount() {
this.getSalaryBillBaseSetForm();
}
getSalaryBillBaseSetForm = () => {
const { watermarkSet } = this.state;
getSalaryBillBaseSetForm().then(({ status, data }) => {
if (status) {
const { watermarkStatus, watermark = "DEFAULT", watermarkSetting } = data;
this.setState({
watermark, watermarkStatus: watermarkStatus ? "1" : "0",
watermarkSet: {
...watermarkSet,
watermarkSetting
}
}, () => window.localStorage.setItem("wmSetting", JSON.stringify({ wmSetting: watermarkSetting })));
}
});
};
salaryBillBaseSetSave = () => {
const { watermark, watermarkStatus, wmSetting } = this.state;
let payload = { watermarkStatus: watermarkStatus === "1" };
if (watermarkStatus === "1") payload = { ...payload, watermark };
if (!_.isNil(wmSetting)) payload = { ...payload, watermark, ...wmSetting };
this.props.onChangeLoading(true);
salaryBillBaseSetSave(payload).then(({ status, errormsg }) => {
this.props.onChangeLoading(false);
if (status) {
message.success(getLabel(111, "保存成功"));
this.getSalaryBillBaseSetForm();
} else {
message.error(errormsg || getLabel(111, "保存失败"));
}
}).catch(() => this.props.onChangeLoading(false));
};
render() {
const { watermarkStatus, watermark, watermarkSet } = this.state;
return (
<WeaSearchGroup title={getLabel(111, "水印设置")} showGroup needTigger className="waterMarkWrapper">
<WeaFormItem label={getLabel(111, "启用水印")} labelCol={{ span: 2 }} wrapperCol={{ span: 4 }}>
<WeaCheckbox value={watermarkStatus} display="switch"
onChange={watermarkStatus => this.setState({ watermarkStatus, watermark: "DEFAULT" })}/>
</WeaFormItem>
{
watermarkStatus === "1" &&
<WeaFormItem label={getLabel(111, "水印类型")} labelCol={{ span: 2 }} wrapperCol={{ span: 4 }}>
<WeaSelect
value={watermark}
options={[
{ key: "DEFAULT", showname: getLabel(111, "系统默认水印") },
{ key: "CUSTOM", showname: getLabel(111, "自定义水印") }
]}
onChange={watermark => this.setState({ watermark })}
/>
{
watermark === "CUSTOM" &&
<span className="waterMarkTitle" onClick={() => this.setState({
watermarkSet: {
...watermarkSet,
visible: true
}
})}>{getLabel(111, "水印设置")}</span>
}
<WaterMarkSetModal {...watermarkSet}
onClose={() => this.setState({ watermarkSet: { ...watermarkSet, visible: false } })}
onChange={wmSetting => this.setState({ wmSetting })}
/>
</WeaFormItem>
}
</WeaSearchGroup>
);
}
}
export default TemplateBaseSettings;

View File

@ -31,7 +31,7 @@ export default class ComputerTemplate extends React.Component {
}
componentDidMount() {
if(this.props.isMsgPreview && this.props.salaryItemSet){
if (this.props.isMsgPreview && this.props.salaryItemSet) {
this.setState({
salaryItemSet: JSON.parse(this.props.salaryItemSet),
salaryTemplateShowSet: JSON.parse(this.props.salaryTemplateShowSet)
@ -55,7 +55,7 @@ export default class ComputerTemplate extends React.Component {
const rowNum = 3;
const sumRows = len % rowNum;
const sumRowMod = len / rowNum;
const rows = (sumRows == 0 ? sumRowMod : sumRowMod + 1);
const rows = (sumRows == 0 ? sumRowMod : parseInt(sumRowMod.toString()) + 1);
for (let j = 0; j < rows; j++) {
let iLen = (j + 1) * rowNum;
iLen = iLen > len ? len : iLen;
@ -86,7 +86,7 @@ export default class ComputerTemplate extends React.Component {
<div className="sobItemDiv" style={{ margin: "20px 10px" }}>
{
salaryTemplateShowSet.textContentPosition === "1" && salaryTemplateShowSet.textContent
salaryTemplateShowSet.textContentPosition == 1 && salaryTemplateShowSet.textContent
}
</div>
@ -106,7 +106,7 @@ export default class ComputerTemplate extends React.Component {
</div>
<div style={{ margin: "20px 10px" }}>
{
salaryTemplateShowSet.textContentPosition === "2" && salaryTemplateShowSet.textContent
salaryTemplateShowSet.textContentPosition == 2 && salaryTemplateShowSet.textContent
}
</div>
</div>

View File

@ -13,17 +13,17 @@ export default class PhoneTemplate extends React.Component {
this.state = {
salaryItemSet: [],
salaryTemplateShowSet: {
theme:'',
background:'',
textContentPosition: '',
textContent: ''
theme: "",
background: "",
textContentPosition: "",
textContent: ""
}
};
}
componentWillMount() {
if(this.props.isPreview) return;
if (this.props.isPreview) return;
let salaryTemplateShowSetStr = window.localStorage.getItem("salary-showset");
let salaryItemSetStr = window.localStorage.getItem("salaryItemSet");
this.setState({
@ -31,18 +31,29 @@ export default class PhoneTemplate extends React.Component {
salaryTemplateShowSet: JSON.parse(salaryTemplateShowSetStr)
});
}
componentDidMount() {
// && window.em
if (this.props.isMsgPreview && this.props.salaryItemSet) {
this.setState({
salaryItemSet: JSON.parse(this.props.salaryItemSet),
salaryTemplateShowSet: JSON.parse(this.props.salaryTemplateShowSet)
});
}
}
componentWillReceiveProps(nextProps) {
if(nextProps.salaryTemplateShowSet !== this.props.salaryTemplateShowSet){
if (nextProps.salaryTemplateShowSet !== this.props.salaryTemplateShowSet) {
this.setState({
salaryItemSet: JSON.parse(nextProps.salaryItemSet),
salaryTemplateShowSet: JSON.parse(nextProps.salaryTemplateShowSet),
salaryTemplateShowSet: JSON.parse(nextProps.salaryTemplateShowSet)
});
}
}
render() {
const { salaryTemplateShowSet, salaryItemSet }= this.state;
const { salaryTemplateShowSet, salaryItemSet } = this.state;
return (
<div className="computerTemplate phoneTemplate">
<div className="titleWrapper">
@ -57,7 +68,7 @@ export default class PhoneTemplate extends React.Component {
<div className="sobItemDiv" style={{ margin: "20px 10px" }}>
{
salaryTemplateShowSet.textContentPosition == 1 && salaryTemplateShowSet.textContent
salaryTemplateShowSet.textContentPosition == 1 && salaryTemplateShowSet.textContent
}
</div>
@ -73,7 +84,7 @@ export default class PhoneTemplate extends React.Component {
_.map(group.items, item => {
return <tr className="descriptions-row">
<th className="descriptions-item-label">{item.name}</th>
<td className="descriptions-item-content">{item.salaryItemValue || '-'}</td>
<td className="descriptions-item-content">{item.salaryItemValue || "-"}</td>
</tr>;
})
}

View File

@ -1,10 +1,10 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { Radio, Spin } from "antd";
import { WeaTableNew } from "comsMobx";
const WeaTable = WeaTableNew.WeaTable;
import { WeaLocaleProvider, WeaTable } from "ecCom";
import { toJS } from "mobx";
import { Dropdown, Menu, Radio, Spin } from "antd";
const getLabel = WeaLocaleProvider.getLabel;
@inject("payrollStore")
@observer
export default class TemplateSettingList extends React.Component {
@ -15,23 +15,23 @@ export default class TemplateSettingList extends React.Component {
}
// 编辑操作按钮
onEdit(record) {
onEdit = (record) => {
this.props.onEdit && this.props.onEdit(record);
}
};
// 复制操作按钮
onCopy(record) {
onCopy = (record) => {
this.props.onCopy && this.props.onCopy(record);
}
};
// 删除操作按钮
onDelete(record) {
onDelete = (record) => {
this.props.onDelete && this.props.onDelete(record);
}
};
// 操作按钮
onOperatesClick = (record, index, operate, flag) => {
switch (operate.index.toString()) {
onOperatesClick = (record, operate) => {
switch (operate) {
case "0": // 编辑
this.onEdit(record);
break;
@ -45,21 +45,22 @@ export default class TemplateSettingList extends React.Component {
};
// 默认使用配置
recordItemChange(record) {
recordItemChange = (record) => {
const { payrollStore } = this.props;
const { changePayrollDefaultUse, getPayrollTemplateList } = payrollStore;
changePayrollDefaultUse(record.id).then(() => {
getPayrollTemplateList();
});
}
};
// 增加编辑功能重写columns绑定事件
getColumns = columns => {
const { showOperateBtn } = this.props;
let newColumns = "";
newColumns = columns.map(column => {
getColumns = () => {
const { showOperateBtn, payrollStore } = this.props;
const { templateTableColumns: columns } = payrollStore;
let newColumns = [];
newColumns = _.filter(toJS(columns), item => item.dataIndex !== "id").map(column => {
let newColumn = column;
newColumn.render = (text, record, index) => {
newColumn.render = (text, record) => {
//前端元素转义
let valueSpan =
record[newColumn.dataIndex + "span"] !== undefined
@ -70,10 +71,8 @@ export default class TemplateSettingList extends React.Component {
return (
<Radio
disabled={!showOperateBtn}
checked={record.useType == "1"}
onChange={value => {
this.recordItemChange(record);
}}
checked={record.useType === "1"}
onChange={() => this.recordItemChange(record)}
/>
);
default:
@ -82,25 +81,79 @@ export default class TemplateSettingList extends React.Component {
};
return newColumn;
});
return newColumns;
return [
...newColumns,
{
dataIndex: "operate",
title: getLabel(30585, "操作"),
width: 150,
render: (_, record) => {
return <React.Fragment>
<a href="javascript:void(0);" style={{ marginRight: 10 }}
onClick={() => this.onOperatesClick(record, "0")}>{getLabel(501169, "编辑")}</a>
<a href="javascript:void(0);" style={{ marginRight: 10 }}
onClick={() => this.onOperatesClick(record, "1")}>{getLabel(77, "复制")}</a>
<Dropdown
overlay={
<Menu onClick={() => this.onOperatesClick(record, "2")}>
<Menu.Item key="delete">{getLabel(535052, "删除")}</Menu.Item>
</Menu>
}>
<i className="icon-coms-more more"/>
</Dropdown>
</React.Fragment>;
}
}
];
};
render() {
const { payrollStore } = this.props;
const { templateStore, loading } = payrollStore;
const {
templateTableDataSource,
loading,
templateTablePageInfo,
setTemplateTablePageInfo,
getPayrollTemplateList,
templateTableSelectedRowKeys,
setTemplateTableSelectedRowKeys
} = payrollStore;
const pagination = {
...templateTablePageInfo,
showTotal: total => `${getLabel(18609, "共")} ${total} ${getLabel(18256, "条")}`,
showQuickJumper: true,
showSizeChanger: true,
pageSizeOptions: ["10", "20", "50", "100"],
onShowSizeChange: (current, pageSize) => {
setTemplateTablePageInfo({ ...templateTablePageInfo, current, pageSize }, () => {
getPayrollTemplateList();
});
},
onChange: current => {
setTemplateTablePageInfo({ ...templateTablePageInfo, current }, () => {
getPayrollTemplateList();
});
}
};
const rowSelection = {
selectedRowKeys: toJS(templateTableSelectedRowKeys),
onChange: selectedRowKeys => setTemplateTableSelectedRowKeys(selectedRowKeys)
};
return (
<div>
{loading
? <div style={{ width: "100%", textAlign: "center" }}>
<Spin/>
</div>
: <WeaTable // table内部做了loading加载处理页面就不需要再加了
comsWeaTableStore={templateStore} // table store
hasOrder={true} // 是否启用排序
needScroll={true} // 是否启用table内部列表滚动将自适应到父级高度
getColumns={this.getColumns}
onOperatesClick={this.onOperatesClick.bind(this)}
/>}
{
loading
? <div style={{ width: "100%", textAlign: "center" }}>
<Spin/>
</div>
: <WeaTable
rowKey="id"
rowSelection={rowSelection}
columns={this.getColumns()}
dataSource={toJS(templateTableDataSource)}
pagination={pagination}
/>
}
</div>
);
}

View File

@ -0,0 +1,58 @@
/*
* Author: 黎永顺
* name: 水印预览
* Description:
* Date: 2023/6/15
*/
import React, { Component } from "react";
import { salaryBillBaseSetPreviewWaterMark } from "../../apis/payroll";
import { WeaTools } from "ecCom";
const { watermark } = WeaTools;
class WatermarkPreview extends Component {
componentDidMount() {
const wmSetting = window.localStorage.getItem("wmSetting");
wmSetting && this.salaryBillBaseSetPreviewWaterMark(JSON.parse(wmSetting));
}
salaryBillBaseSetPreviewWaterMark = (payload) => {
salaryBillBaseSetPreviewWaterMark(payload).then(({ status, data }) => {
if (status) {
const { wmSetting: { wmHeight: height, wmWidth: width, wmNoTransparent, wmRotate } } = payload;
watermark({
text: data,
src: "",
width, height,
rotate: `-${wmRotate || 15}`,
alpha: wmNoTransparent / 100 || 0.15,
interval: 2000,
intervalCheck: true,
clickCheck: true
});
}
});
};
render() {
return (
<div style={{ display: "flex", alignItems: "center", flexDirection: "column" }}>
<h1 style={{ textAlign: "center" }}>水印预览效果</h1>
<p
style={{ fontSize: 14 }}>水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果</p>
<p
style={{ fontSize: 14 }}>水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果</p>
<p
style={{ fontSize: 14 }}>水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果</p>
<p
style={{ fontSize: 14 }}>水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果</p>
<p
style={{ fontSize: 14 }}>水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果</p>
<p
style={{ fontSize: 14 }}>水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果水印预览效果</p>
</div>
);
}
}
export default WatermarkPreview;

View File

@ -17,11 +17,11 @@ class ExportMenu extends Component {
case "fixed":
runStatusList = "FIXED,SUSPEND";
break;
case "SUSPEND":
case "suspend":
runStatusList = _.upperCase(selectedKey);
break;
case "stop":
runStatusList = 'STOP_FROM_PENDING,STOP_FROM_SUSPEND';
runStatusList = "STOP_FROM_PENDING,STOP_FROM_SUSPEND";
break;
default:
break;

View File

@ -14,7 +14,7 @@ import {
WeaFormItem,
WeaHelpfulTip,
WeaInput,
WeaNewScroll,
WeaLocaleProvider,
WeaPopoverHrm,
WeaSearchGroup,
WeaSelect,
@ -23,7 +23,7 @@ import {
WeaTop
} from "ecCom";
import { WeaTableNew } from "comsMobx";
import { Button, Dropdown, Menu, message, Modal, Popover } from "antd";
import { Button, Dropdown, Menu, message, Modal, Spin } from "antd";
import ImportMenu from "./components/importMenu";
import ExportMenu from "./components/exportMenu";
import AllWithoutPay from "./components/allWithoutPay";
@ -32,8 +32,8 @@ import SlideModalTitle from "../../components/slideModalTitle";
import SalaryFileViewSlide from "../salaryFile/saralyFileViewSlide";
import ChangeSalaryModal from "../salaryFile/changeSalaryModal";
import "./index.less";
import UnifiedTable from "../../components/UnifiedTable";
const getLabel = WeaLocaleProvider.getLabel;
const WeaTableComx = WeaTableNew.WeaTable;
@inject("payrollFilesStore", "taxAgentStore", "salaryFileStore")
@ -67,9 +67,10 @@ class Index extends Component {
},
searchItemsValue: {
username: "",
workcode: "",
departmentIds: "",
positionIds: "",
userstatus: "",
statuses: "",
// archiveStatus: "EFFICIENT",
taxAgentId: "",
subcompanyIds: ""
@ -84,24 +85,26 @@ class Index extends Component {
paysetParams: {
payStartDate: "",
payEndDate: ""
}
},
salaryArchiveDelete: "" //待定薪、停薪员工 是否允许删除薪资档案 0 否, 1
};
}
Input = (value, key) => {
const { username } = this.state.searchItemsValue;
const { username, workcode } = this.state.searchItemsValue;
return (
<WeaFormItem
label={value}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<WeaInput value={username} onChange={(val) => this.setState({
searchItemsValue: {
...this.state.searchItemsValue,
[key]: val
}
})}/>
<WeaInput value={key === "username" ? username : workcode}
onChange={(val) => this.setState({
searchItemsValue: {
...this.state.searchItemsValue,
[key]: val
}
})}/>
</WeaFormItem>
);
};
@ -125,7 +128,7 @@ class Index extends Component {
};
Select = (value, key) => {
const { taxAgentStore } = this.props;
const { userstatus, archiveStatus, taxAgentId } = this.state.searchItemsValue;
const { statuses, archiveStatus, taxAgentId } = this.state.searchItemsValue;
const { archiveStatusList, userStatusList } = this.state;
const { taxAgentAdminOption } = taxAgentStore;
return (
@ -135,8 +138,9 @@ class Index extends Component {
wrapperCol={{ span: 18 }}
>
<WeaSelect
value={key === "userstatus" ? userstatus : key === "taxAgentId" ? taxAgentId : archiveStatus}
options={key === "userstatus" ? userStatusList : key === "taxAgentId" ? [{
multiple={key === "statuses"}
value={key === "statuses" ? statuses : key === "taxAgentId" ? taxAgentId : archiveStatus}
options={key === "statuses" ? userStatusList : key === "taxAgentId" ? [{
key: "",
showname: ""
}, ...taxAgentAdminOption] : archiveStatusList}
@ -152,11 +156,61 @@ class Index extends Component {
this.queryTabTotal();
this.queryList("/api/bs/hrmsalary/salaryArchive/pendingList");
const init = this.init();
window.addEventListener("message", this.handleReceive, false);
}
componentWillUnmount() {
window.removeEventListener("message", this.handleReceive, false);
}
handleReceive = ({ data }) => {
const { payrollFilesStore: { tableStore }, taxAgentStore: { showOperateBtn } } = this.props;
const columns = _.map(_.filter(toJS(tableStore.columns), (item) => item.display === "true"), (it, idx) => ({
dataIndex: it.dataIndex,
width: (it.dataIndex === "username" || it.dataIndex === "operate") ? 150 : it.dataIndex === "taxAgentName" ? 176 : 150,
title: it.title, align: "left",
fixed: (idx === 0 || idx === 1 || idx === 2) ? "left" : it.dataIndex === "operate" ? "right" : "",
ellipsis: true
}));
const { type, payload: { id, params } = {} } = data;
const { dataSource, pageInfo, selectedKey, selectedRowKeys } = this.state;
if (type === "init") {
this.postMessageToChild({
columns, dataSource, showOperateBtn, selectedKey,
showSum: false, pageInfo, selectedRowKeys
});
} else if (type === "turn") {
if (id === "PAGEINFO") {
const { pageNum: current, size: pageSize } = params;
this.setState({ pageInfo: { ...pageInfo, current, pageSize } }, () => this.query());
} else if (id === "EDIT") {
const { record } = params;
this.handleEdit(record);
} else if (id === "MOREOPT") {
const { id, event: e } = params;
this.handleMenuClick(e, id);
} else if (id === "CANCELSTOP") {
const { id } = params;
this.cancelStop(id);
} else if (id === "ROWSELECTION") {
const { selectedRowKeys } = params;
this.setState({ selectedRowKeys });
}
}
};
postMessageToChild = (payload) => {
const childFrameObj = document.getElementById("atdTable");
const { dataSource, columns, showSum, pageInfo, showOperateBtn, selectedKey, selectedRowKeys } = payload;
const { salaryArchiveDelete } = this.state;
childFrameObj && childFrameObj.contentWindow.postMessage(JSON.stringify({
dataSource, columns, showSum, pageInfo, showOperateBtn, selectedKey, selectedRowKeys, salaryArchiveDelete
}), "*");
};
init = async () => {
const { data: archiveStatusList } = await this.commonEnumList({ enumClass: "com.engine.salary.enums.salaryarchive.ArchiveStatusEnum" });
const { data: userStatusList } = await this.commonEnumList({ enumClass: "com.engine.salary.enums.UserStatusEnum" });
const { data: salaryArchiveDelete } = await this.salaryArchiveDelete();
this.setState({
archiveStatusList: [{
key: "",
@ -165,13 +219,11 @@ class Index extends Component {
key: String(it.value),
showname: it.defaultLabel
}))],
userStatusList: [{
key: "",
showname: ""
}, ..._.map(userStatusList, it => ({
userStatusList: [..._.map(userStatusList, it => ({
key: String(it.value),
showname: it.defaultLabel
}))]
}))],
salaryArchiveDelete
}, () =>
this.getImportTypes());
};
@ -191,15 +243,15 @@ class Index extends Component {
});
};
queryList = (url) => {
const { loading, pageInfo, searchItemsValue } = this.state;
const { payrollFilesStore: { tableStore, queryList } } = this.props;
const { loading, pageInfo, searchItemsValue, selectedKey } = this.state;
const { payrollFilesStore: { tableStore, queryList }, taxAgentStore: { showOperateBtn } } = this.props;
const payload = { ...pageInfo };
this.setState({
loading: { ...loading, query: true }
});
queryList(payload, searchItemsValue, url).then(({ data, status }) => {
this.setState({ loading: { ...loading, query: false } });
if (status) {
if (status && selectedKey === _.lowerCase(data.listType)) {
const { pageInfo: paganition } = data;
const { list: dataSource, total, pageNum: current, pageSize } = paganition;
this.setState({
@ -209,7 +261,8 @@ class Index extends Component {
total,
current,
pageSize
}
},
tabCount: { ...this.state.tabCount, [tabCountKey[selectedKey]]: total }
});
}
});
@ -241,6 +294,9 @@ class Index extends Component {
commonEnumList = (params) => {
return API.commonEnumList(params);
};
salaryArchiveDelete = () => {
return API.salaryArchiveDelete();
};
getImportTypes = () => {
API.getImportTypes().then(({ data, status }) => {
if (status) {
@ -467,85 +523,18 @@ class Index extends Component {
return [];
};
getColumns = () => {
const { selectedKey } = this.state;
const { payrollFilesStore: { tableStore }, taxAgentStore: { showOperateBtn } } = this.props;
let columns = _.filter(toJS(tableStore.columns), (item) => item.display === "true");
return _.map([
...columns], item => {
if (item.dataIndex === "username") {
return {
...item,
render: (text, record) => {
return <a
href={`javaScript:openhrm(${record.employeeId});`}
onClick={e => window.pointerXY(e)}
className="ellipsis"
title={text}
>
{text}
</a>;
}
};
} else if (item.dataIndex === "operate") {
return {
...item,
render: (text, record) => {
if (!showOperateBtn) {
return <div className="optWrapper">
<a href="javascript:void(0);" onClick={() => this.handleEdit(record)}>查看</a>
</div>;
} else {
if (selectedKey === "pending") {
return <div className="optWrapper">
<a href="javascript:void(0);" className="mr10" onClick={() => this.handleEdit(record)}>编辑</a>
<Popover
overlayClassName="moreIconWrapper"
placement="bottomRight"
content={<Menu onClick={(e) => this.handleMenuClick(e, record.id)}>
<Menu.Item key="payroll">设为发薪人员</Menu.Item>
<Menu.Item key="deletePendingTodo">删除待办</Menu.Item>
</Menu>} title="">
<i className="icon-coms-more"/>
</Popover>
</div>;
} else if (selectedKey === "fixed" || selectedKey === "ext") {
return <a onClick={() => this.handleEdit(record)}>调薪</a>;
} else if (selectedKey === "suspend") {
return <div className="optWrapper">
<a href="javascript:void(0);" className="mr10" onClick={() => this.handleEdit(record)}>编辑</a>
<Popover
overlayClassName="moreIconWrapper"
placement="bottomRight"
content={<Menu onClick={(e) => this.handleMenuClick(e, record.id)}>
<Menu.Item key="stopSalary">停薪</Menu.Item>
<Menu.Item key="deleteSuspendTodo">删除待办</Menu.Item>
</Menu>} title="">
<i className="icon-coms-more"/>
</Popover>
</div>;
} else {
return <div className="optWrapper">
<a href="javascript:void(0);" className="mr10" onClick={() => this.cancelStop(record.id)}>取消停薪</a>
<Popover
overlayClassName="moreIconWrapper"
placement="bottomRight"
content={<Menu onClick={(e) => this.handleMenuClick(e, record)}>
<Menu.Item key="view">查看</Menu.Item>
</Menu>} title="">
<i className="icon-coms-more"/>
</Popover>
</div>;
}
}
}
};
}
return {
...item,
render: (text) => {
return <span className="ellipsis" title={text}>{text}</span>;
}
};
const columns = _.map(_.filter(toJS(tableStore.columns), (item) => item.display === "true"), (it, idx) => ({
dataIndex: it.dataIndex,
width: (it.dataIndex === "username" || it.dataIndex === "operate") ? 150 : it.dataIndex === "taxAgentName" ? 176 : 150,
title: it.title, align: "left",
fixed: (idx === 0 || idx === 1 || idx === 2) ? "left" : it.dataIndex === "operate" ? "right" : "",
ellipsis: true
}));
this.postMessageToChild({
columns, showOperateBtn, selectedKey: this.state.selectedKey,
dataSource: this.state.dataSource, selectedRowKeys: this.state.selectedRowKeys,
showSum: false, pageInfo: this.state.pageInfo
});
};
handleEdit = (record) => {
@ -587,6 +576,21 @@ class Index extends Component {
this.deleteSuspendTodo([id]);
} else if (key === "view") {
this.handleEdit(id);
} else if (key === "deleteAchives") {
Modal.confirm({
title: getLabel(131329, "信息确认"),
content: getLabel(388758, "确认要删除吗?"),
onOk: () => {
API.deleteSalaryArchive([id]).then(({ status, errormsg }) => {
if (status) {
message.success(getLabel(30700, "操作成功"));
this.query();
} else {
message.error(errormsg || getLabel(30651, "操作失败"));
}
});
}
});
}
};
// 查看 Slide 头部操作按钮
@ -621,13 +625,14 @@ class Index extends Component {
current: 1,
pageSize: 10
}
}, () => {
if (!this.handleChangeDebounce) {
this.handleChangeDebounce = _.debounce(() => {
this.query();
}, 500);
}
this.handleChangeDebounce();
});
if (!this.handleChangeDebounce) {
this.handleChangeDebounce = _.debounce(() => {
this.query();
}, 500);
}
this.handleChangeDebounce();
};
//编辑保存
handleSave = () => {
@ -694,43 +699,23 @@ class Index extends Component {
tabCount,
selectedKey,
loading,
dataSource,
pageInfo,
showSearchAd,
selectedRowKeys,
slideParams,
changeSalaryVisible,
paysetParams
} = this.state;
const { payrollFilesStore: { tableStore } } = this.props;
const pagination = {
current: pageInfo.current,
pageSize: pageInfo.pageSize,
total: pageInfo.total,
showTotal: total => `${total}`,
showQuickJumper: true,
showSizeChanger: true,
pageSizeOptions: ["10", "20", "50", "100"],
onShowSizeChange: (current, pageSize) => {
this.setState({ pageInfo: { ...pageInfo, current, pageSize } }, () => {
this.query();
});
},
onChange: current => {
this.setState({ pageInfo: { ...pageInfo, current } }, () => {
this.query();
});
}
};
const renderSearch = () => {
const searchItems = [
{ com: this.Input("姓名", "username") },
{ com: this.Browser("分部", "subcompanyIds") },
{ com: this.Browser("部门", "departmentIds") },
{ com: this.Browser("岗位", "positionIds") },
{ com: this.Select("人员状态", "userstatus") },
{ com: this.Select("人员状态", "statuses") },
// { com: this.Select("档案状态", "archiveStatus") },
{ com: this.Select("个税扣缴义务人", "taxAgentId") }
{ com: this.Select("个税扣缴义务人", "taxAgentId") },
{ com: this.Input("工号", "workcode") }
];
return <WeaSearchGroup title={"基本信息"} items={searchItems} showGroup/>;
};
@ -749,18 +734,15 @@ class Index extends Component {
<Button type="ghost" onClick={() => this.setState({
searchItemsValue: {
username: "",
workcode: "",
departmentIds: "",
positionIds: "",
userstatus: "",
statuses: "",
archiveStatus: ""
}
})}> 重置 </Button>,
<Button type="ghost" onClick={() => this.setState({ showSearchAd: false })}> 取消 </Button>
];
const rowSelection = {
selectedRowKeys,
onChange: (selectedRowKeys) => this.setState({ selectedRowKeys })
};
const rightMenu = [
{
key: "BTN_COLUMN",
@ -815,24 +797,22 @@ class Index extends Component {
searchsBaseValue={this.state.searchItemsValue.username}
/>
<div className="tableWrapper">
<WeaNewScroll height="100%">
<UnifiedTable
rowKey="id"
loading={loading.query}
columns={this.getColumns()}
dataSource={dataSource}
pagination={pagination}
rowSelection={rowSelection}
xWidth={this.getColumns().length * 120}
<Spin spinning={loading.query}>
<iframe
style={{ border: 0, width: "100%", height: "100%" }}
// src="http://localhost:7607/#/payrollFilesTable"
src="/spa/hrmSalary/hrmSalaryCalculateDetail/index.html#/payrollFilesTable"
id="atdTable"
/>
{/*人员卡片*/}
<WeaPopoverHrm/>
<WeaTableComx
style={{ display: "none" }}
comsWeaTableStore={tableStore}
needScroll={true}
/>
</WeaNewScroll>
</Spin>
{/*人员卡片*/}
<WeaPopoverHrm/>
<WeaTableComx
style={{ display: "none" }}
comsWeaTableStore={tableStore}
needScroll={true}
columns={this.getColumns()}
/>
</div>
</WeaTop>
<div style={{ display: "none" }}>
@ -914,3 +894,11 @@ const HelpfulDiv = () => {
<span>3.调整个税扣缴义务人档案中已存在的人员批量调整个税扣缴义务人包括返聘人员的情况</span>
</div>;
};
export const tabCountKey = {
suspend: "SUSPEND",
stop: "STOP",
fixed: "FIXED",
pending: "PENDING"
};

View File

@ -7,6 +7,11 @@
.tableWrapper {
flex: 1;
overflow: hidden;
padding: 16px 16px 0 16px;
.ant-spin-nested-loading, .ant-spin-container {
height: 100%;
}
}
}

Some files were not shown because too many files have changed in this diff Show More