diff --git a/pc4mobx/hrmSalary/apis/payroll.js b/pc4mobx/hrmSalary/apis/payroll.js index e0d5460d..7e654721 100644 --- a/pc4mobx/hrmSalary/apis/payroll.js +++ b/pc4mobx/hrmSalary/apis/payroll.js @@ -46,7 +46,14 @@ export const exportPayroll = params => { //工资单-工资单模板列表 export const getPayrollTemplateList = params => { - return WeaTools.callApi('/api/bs/hrmsalary/salaryBill/template/list', 'POST', params); + return fetch('/api/bs/hrmsalary/salaryBill/template/list', { + method: 'POST', + mode: 'cors', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(params) + }).then(res => res.json()) } //工资单-获取薪资账套下拉列表 @@ -77,7 +84,14 @@ export const changePayrollDefaultUse = params => { //工资单-新建工资单 export const savePayroll = params => { - return WeaTools.callApi('/api/bs/hrmsalary/salaryBill/template/save', 'POST', params); + return fetch('/api/bs/hrmsalary/salaryBill/template/save', { + method: 'POST', + mode: 'cors', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(params) + }).then(res => res.json()) } //工资单-编辑工资单 diff --git a/pc4mobx/hrmSalary/components/importModal/modalStep1.js b/pc4mobx/hrmSalary/components/importModal/modalStep1.js index 16bf8b7b..3c810b47 100644 --- a/pc4mobx/hrmSalary/components/importModal/modalStep1.js +++ b/pc4mobx/hrmSalary/components/importModal/modalStep1.js @@ -28,7 +28,7 @@ export default class ModalStep1 extends React.Component { const dragger = { name: 'file', multiple: false, - action: "/api/doc/upload/uploadFile", //上传地址 + action: "handleCancel", //上传地址 onChange: (info) => { const { status } = info.file; if (status !== 'uploading') { diff --git a/pc4mobx/hrmSalary/pages/payroll/components/backgroundUpload.js b/pc4mobx/hrmSalary/pages/payroll/components/backgroundUpload.js new file mode 100644 index 00000000..ee6c83a8 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/payroll/components/backgroundUpload.js @@ -0,0 +1,91 @@ +import React from 'react' +import { Upload, Icon, Modal } from 'antd'; +import "./index.less" + +function getBase64(img, callback) { + const reader = new FileReader(); + reader.addEventListener('load', () => callback(reader.result)); + reader.readAsDataURL(img); +} + +function beforeUpload(file) { + const isJPG = file.type === 'image/jpeg' || file.type==="image/png"; + if (!isJPG) { + message.error('只允许上传jpg、png类型的图片!'); + } + const isLt2M = file.size / 1024 / 1024 < 2; + if (!isLt2M) { + message.error('图片大小限制2MB!'); + } + return isJPG && isLt2M; +} + + export default class BackgroundUpload extends React.Component { + constructor(props) { + super(props) + this.state = { + showOperate: false, + visible: false + } + } + + // 上传完成监听 + handleChange = (info) => { + if (info.file.status === 'done') { + this.props.onChange && this.props.onChange(info.file.response.data.acclink) + getBase64(info.file.originFileObj, imageUrl => this.setState({ imageUrl })); + } + } + + // 删除 + handleDelete = () => { + this.setState({ + imageUrl: null, + }) + this.props.onChange && this.props.onChagne(""); + } + + // 预览 + handlePreview = () => { + this.setState({visible: true}) + } + + render() { + const props = { + action: '/api/doc/upload/uploadFile', + multiple: false, + listType: "picture-card", + showUploadList: false, + onChange: this.handleChange.bind(this) + }; + const imageUrl = this.state.imageUrl; + return ( +
+ { + imageUrl ? +
{this.setState({showOperate: true})}} onMouseLeave={() => {this.setState({showOperate: false})}}> + + { + this.state.showOperate &&
+ {this.handlePreview()}}/> + {this.handleDelete()}}/> +
+ } +
+ : + + + + } + {this.setState({visible: false})}} > +
+ +
+
+
+ + + + ); + } + } \ No newline at end of file diff --git a/pc4mobx/hrmSalary/pages/payroll/components/index.less b/pc4mobx/hrmSalary/pages/payroll/components/index.less new file mode 100644 index 00000000..aec5737a --- /dev/null +++ b/pc4mobx/hrmSalary/pages/payroll/components/index.less @@ -0,0 +1,31 @@ +.uploadPictureWrapper { + .previewWrapper { + position: relative; + width: 96px; + height: 96px; + border: 1px dashed #d9d9d9; + .previewImg { + width: 100%; + height: 100%; + } + .operateWrapper { + position: absolute; + width: 96px; + height: 90px; + top: 0; + left: 0; + line-height: 96px; + z-index: 100; + color: #fff; + background-color: rgba(0, 0, 0, 0.3); + text-align: center; + .operateIcon { + margin-right: 20px; + cursor: pointer; + } + .operateIcon:last-child { + margin-right: 0px; + } + } + } +} \ No newline at end of file diff --git a/pc4mobx/hrmSalary/pages/payroll/index.js b/pc4mobx/hrmSalary/pages/payroll/index.js index e788e292..9f43798b 100644 --- a/pc4mobx/hrmSalary/pages/payroll/index.js +++ b/pc4mobx/hrmSalary/pages/payroll/index.js @@ -2,7 +2,7 @@ import React from 'react'; import { inject, observer } from 'mobx-react'; import { toJS } from 'mobx'; -import { Button, Table, DatePicker } from 'antd'; +import { Button, Table, DatePicker, message } from 'antd'; import moment from 'moment' import { WeaTop, WeaTab, WeaRightMenu, WeaRangePicker, WeaTable,WeaDatePicker, WeaHelpfulTip, WeaSelect, WeaInputSearch, WeaSlideModal } from 'ecCom'; @@ -17,10 +17,12 @@ import ItemMangeFormModal from '../dataAcquisition/attendance/itemMangeFormModal import BaseInformForm from './stepForm/baseInformForm' import ShowSettingForm from './stepForm/showSettingForm' import SlideModalTitle from "../../components/slideModalTitle" +import TemplateSettingList from './templateSettingList' +import { notNull } from '../../util/validate'; const { MonthPicker } = DatePicker; -@inject('baseTableStore') +@inject('payrollStore') @observer export default class Payroll extends React.Component { constructor(props) { @@ -73,10 +75,25 @@ export default class Payroll extends React.Component { }) } + // 工资单模板-新建表单变化监听 + handleBaseInfoChange(request) { + const { payrollStore: {setTemplateBaseData}} = this.props; + setTemplateBaseData(request); + } + + // 新建保存 + handleSave() { + const { payrollStore } = this.props; + const { fetchSavePayroll } = payrollStore + fetchSavePayroll().then(() => { + this.setState({currentStep: 0, stepSlideVisible: false}) + }) + } render() { - const { baseTableStore } = this.props; - const { loading, hasRight, form, condition, tableStore, showSearchAd, getTableDatas, doSearch, setShowSearchAd } = baseTableStore; + const { payrollStore } = this.props; + const { loading, hasRight, form, condition, tableStore, showSearchAd, getTableDatas, doSearch, setShowSearchAd } = payrollStore; + const { currentStep, selectedTab } = this.state if (!hasRight && !loading) { // 无权限处理 return renderNoright(); @@ -152,7 +169,24 @@ export default class Payroll extends React.Component { "显示设置" ] + + const validateStep1 = () => { + const { payrollStore: {templateBaseData}} = this.props; + if(!notNull(templateBaseData.name)) { + message.warning("工资单模板名称不能为空") + return false + } + + if(!notNull(templateBaseData.salarySob)) { + message.warning("薪资账套不能为空") + return false; + } + return true; + } const nextStep = () => { + if(!validateStep1()) { + return + } this.setState({ currentStep: this.state.currentStep + 1 }) @@ -186,7 +220,8 @@ export default class Payroll extends React.Component { } { - this.state.selectedKey == 1 && + this.state.selectedKey == 1 && + } @@ -206,7 +241,7 @@ export default class Payroll extends React.Component { { currentStep == 1 &&
- +
} @@ -216,7 +251,7 @@ export default class Payroll extends React.Component { content={
{ - currentStep == 0 && + currentStep == 0 && {this.handleBaseInfoChange(request)}}/> } { currentStep == 1 && diff --git a/pc4mobx/hrmSalary/pages/payroll/stepForm/baseInformForm.js b/pc4mobx/hrmSalary/pages/payroll/stepForm/baseInformForm.js index cc65ba48..85d6bebe 100644 --- a/pc4mobx/hrmSalary/pages/payroll/stepForm/baseInformForm.js +++ b/pc4mobx/hrmSalary/pages/payroll/stepForm/baseInformForm.js @@ -1,31 +1,69 @@ import React from 'react' import { Row, Col, Switch } from 'antd' import { WeaInput, WeaSelect } from 'ecCom' +import { inject, observer } from 'mobx-react'; +import RequiredLabelTip from '../../../components/requiredLabelTip'; import "./index.less" +@inject('payrollStore') +@observer export default class BaseInformForm extends React.Component { + constructor(props) { + super(props) + this.state = { + inited: false, + options: [], + request: {} + } + } + componentWillMount() { + const { payrollStore} = this.props; + const { getPayrollBaseForm} = payrollStore + getPayrollBaseForm(this.props.id).then(data => { + this.setState({ + inited: true, + options: data.salarySobOptions, + request: data.templateBaseData + }) + }) + } + + hanldeChange(params) { + let request = {...this.state.request, ...params}; + this.setState({ + request + }) + this.props.onChange && this.props.onChange(request) + } + render() { + const { request } = this.state; + const { salarySob, salarySobOption, name, + description, emailStatus, sendEmail, + sendEmailOptions, msgStatus } = request; return (
基础信息
- 薪资账套 + 薪资账套 - + { + this.state.inited && {this.hanldeChange({salarySob: value})}}/> + } - 工资单模板名称 + 工资单模板名称 - + this.hanldeChange({name: value})}/> 备注 - + this.hanldeChange({description: value})}/>
@@ -38,7 +76,7 @@ export default class BaseInformForm extends React.Component { 邮件 - + {this.hanldeChange({emailStatus: value})}}/> @@ -46,7 +84,7 @@ export default class BaseInformForm extends React.Component { 发送地址 - + {this.hanldeChange({sendEmail: value})}}/> @@ -56,7 +94,7 @@ export default class BaseInformForm extends React.Component { 消息中心 - + {this.hanldeChange({msgStatus: value})}}/> diff --git a/pc4mobx/hrmSalary/pages/payroll/stepForm/index.less b/pc4mobx/hrmSalary/pages/payroll/stepForm/index.less index 8ad0c6dc..afc1e5c4 100644 --- a/pc4mobx/hrmSalary/pages/payroll/stepForm/index.less +++ b/pc4mobx/hrmSalary/pages/payroll/stepForm/index.less @@ -32,6 +32,9 @@ line-height: 40px; } } + .themeFormalStr { + margin-right: 10px; + } .settingItemWrapper { margin-top: 10px; .itemTitle { diff --git a/pc4mobx/hrmSalary/pages/payroll/stepForm/showSettingForm.js b/pc4mobx/hrmSalary/pages/payroll/stepForm/showSettingForm.js index 10b5e13d..ccf72587 100644 --- a/pc4mobx/hrmSalary/pages/payroll/stepForm/showSettingForm.js +++ b/pc4mobx/hrmSalary/pages/payroll/stepForm/showSettingForm.js @@ -1,15 +1,65 @@ import React from 'react' import { Row, Col, Upload, Icon, Radio, Switch } from 'antd' import { WeaInput } from 'ecCom' +import { inject, observer } from 'mobx-react'; +import BackgroundUpload from '../components/backgroundUpload' const Dragger = Upload.Dragger; - +@inject('payrollStore') +@observer export default class ShowSettingForm extends React.Component { + + componentWillMount() { + const { payrollStore } = this.props; + const { initShowSettingForm } = payrollStore + initShowSettingForm(this.props.id) + } + // form 字段变化时的回调 + handleChange(params) { + const { payrollStore: {salaryTemplateShowSet, setSalaryTemplateShowSet}} = this.props; + let request= {...salaryTemplateShowSet, ...params}; + setSalaryTemplateShowSet(request); + // this.props.onChange && this.props.onChange(request); + } + + // 工资单主题 插入变量 + handleThemeNameCllck(param) { + const { payrollStore } = this.props; + const { salaryTemplateShowSet, setSalaryTemplateShowSet } = payrollStore; + let request= {...salaryTemplateShowSet}; + request.theme = (request.theme ? request.theme : "") + param; + setSalaryTemplateShowSet(request); + } + render() { + const { payrollStore } = this.props; + const { salaryTemplateShowSet } = payrollStore; + const { salaryItemSet } = payrollStore + const { theme, + background, + textContent, + textContentPosition, + salaryItemNullStatus, + salaryItemZeroStatus + } = salaryTemplateShowSet const dropProps = { name: 'file', - action: 'http://www.mocky.io/v2/5e0085b82f0000780013b4c7', + action: '/api/doc/upload/uploadFile', + onChange(info) { + const { status } = info.file; + if (status !== 'uploading') { + console.log(info.file, info.fileList); + } + if (status === 'done') { + message.success(`${info.file.name} file uploaded successfully.`); + } else if (status === 'error') { + message.error(`${info.file.name} file upload failed.`); + } + }, + onDrop(e) { + console.log('Dropped files', e.dataTransfer.files); + }, }; return (
@@ -21,51 +71,56 @@ export default class ShowSettingForm extends React.Component { 工资单主题 - + {this.handleChange({theme:value})}}/> 插入变量: - 公司名称 - 薪资所属月 + {this.handleThemeNameCllck("${companyName}")}} className="themeFormalStr">公司名称 + {this.handleThemeNameCllck("${salaryMonth}")}} className="themeFormalStr">薪资所属月 - 工资单主题 - + {this.handleChange({textContentPosition: value})}}/> + {/*
-
+
*/}
文本内容 - - - 薪资项目前 - 薪资项目后 + {this.handleChange({textContent: value})}}/> + + + + + 文本内容位置 + + {this.handleChange({textContentPosition: e.target.value})}}> + 薪资项目前 + 薪资项目后 - 薪资项为空时不显示 - + {this.handleChange({salaryItemNullStatus: value})}}/> 薪资项为0时不显示 - + {this.handleChange({salaryItemZeroStatus: value})}}/>
@@ -74,16 +129,18 @@ export default class ShowSettingForm extends React.Component {
薪资项目设置
-
-
员工信息
-
个税扣缴义务人 姓名 部门
-
- -
-
月度固定薪酬
-
基本工资 岗位工资 工资薪金合计
-
- + { + salaryItemSet.map(group => ( +
+
{group.groupName}
+
+ {group.items.map(item => ( + {item.name} + ))} +
+
+ )) + }
diff --git a/pc4mobx/hrmSalary/pages/payroll/templateSettingList.js b/pc4mobx/hrmSalary/pages/payroll/templateSettingList.js new file mode 100644 index 00000000..4f723ea7 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/payroll/templateSettingList.js @@ -0,0 +1,29 @@ +import React from 'react' +import { inject, observer } from 'mobx-react'; +import { WeaTableNew } from 'comsMobx'; +const WeaTable = WeaTableNew.WeaTable; + +@inject('payrollStore') +@observer +export default class TemplateSettingList extends React.Component { + componentWillMount() { + const { payrollStore } = this.props; + const { getPayrollTemplateList } = payrollStore; + getPayrollTemplateList(); + } + render() { + const { payrollStore } = this.props; + const { templateStore } = payrollStore; + return ( +
+ +
+ ) + } +} \ No newline at end of file diff --git a/pc4mobx/hrmSalary/stores/index.js b/pc4mobx/hrmSalary/stores/index.js index e26a2be8..594052fd 100644 --- a/pc4mobx/hrmSalary/stores/index.js +++ b/pc4mobx/hrmSalary/stores/index.js @@ -13,6 +13,7 @@ import { SalaryItemStore } from './salaryItem' import { LedgerStore } from './ledger' import { ArchivesStore } from './archives' import { salaryFileStore } from './salaryFile'; +import { payrollStore } from './payroll'; module.exports = { baseFormStore: new BaseFormStore(), @@ -28,6 +29,7 @@ module.exports = { salaryItemStore: new SalaryItemStore(), ledgerStore: new LedgerStore(), archivesStore: new ArchivesStore(), - salaryFileStore: new salaryFileStore() + salaryFileStore: new salaryFileStore(), + payrollStore: new payrollStore() }; diff --git a/pc4mobx/hrmSalary/stores/payroll.js b/pc4mobx/hrmSalary/stores/payroll.js new file mode 100644 index 00000000..0839cdff --- /dev/null +++ b/pc4mobx/hrmSalary/stores/payroll.js @@ -0,0 +1,211 @@ +import { observable, action, toJS } from 'mobx'; +import { message } from 'antd'; +import { WeaForm, WeaTableNew } from 'comsMobx'; + +import * as API from '../apis/payroll'; // 引入API接口文件 +import { notNull } from '../util/validate'; + +const { TableStore } = WeaTableNew; + +export class payrollStore { + @observable tableStore = new TableStore(); // new table + @observable form = new WeaForm(); // nrew 一个form + @observable condition = []; // 存储后台得到的form数据 + @observable hasRight = true; // 判断用户是有权限查看当前页面: 没有权限渲染无权限页面,有权限渲染数据 + @observable showSearchAd = false; // 高级搜索面板显示 + @observable loading = true; // 数据加载状态 + + // **** 模板页面 **** + @observable templateStore = new TableStore(); // 模板设置列表 + // 基础设置表单 + @observable templateBaseData = {} // 基础信息表单数据 + @observable salarySobOptions = [] // 账套列表 + // 显示设置表单 + @observable salaryTemplateShowSet = {} // 显示设置基础表单 + @observable salaryItemSet = [] // 显示设置薪资项 + + // 基础信息表单数据 + @action + setTemplateBaseData = (templateBaseData) => this.templateBaseData = templateBaseData + + // 显示设置基础表单 + @action + setSalaryTemplateShowSet = (salaryTemplateShowSet) => this.salaryTemplateShowSet = salaryTemplateShowSet + + // 初始化操作 + @action + doInit = () => { + // this.getCondition(); + // this.getTableDatas(); + } + + // 获得高级搜索表单数据 + @action + getCondition = () => { + API.getCondition().then(action(res => { + if (res.api_status) { // 接口请求成功/失败处理 + this.condition = res.condition; + this.form.initFormFields(res.condition); // 渲染高级搜索form表单 + } else { + message.error(res.msg || '接口调用失败!') + } + })); + } + + // 渲染table数据 + @action + getTableDatas = (params) => { + this.loading = true; + const formParams = this.form.getFormParams() || {}; + params = params || formParams; + API.getTableDatas(params).then(action(res => { + if (res.api_status) { // 接口请求成功/失败处理 + this.tableStore.getDatas(res.datas); // table 请求数据 + this.hasRight = res.hasRight; + } else { + message.error(res.msg || '接口调用失败!') + } + this.loading = false; + })); + } + + @action + setShowSearchAd = bool => this.showSearchAd = bool; + + // 高级搜索 - 搜索 + @action doSearch = () => { + this.getTableDatas(); + this.showSearchAd = false; + } + + // 工资单模板-工资单模板列表 + @action + getPayrollTemplateList = () => { + let params = {} + API.getPayrollTemplateList(params).then(res => { + if(res.status) { + this.templateStore.getDatas(res.data.datas); + } else { + message.error(res.errormsg || "获取失败"); + } + }) + } + + // 工资单模板-获取工资单模板基础设置表单 + @action + getPayrollBaseForm = (id = "") => { + let params = { + id + } + return new Promise((resolve, reject) => { + API.getPayrollBaseForm(params).then(res => { + if(res.status) { + let response = res.data.salaryTemplateBaseSet + let templateBaseData = response.data + templateBaseData.salarySob = templateBaseData.salarySob !== undefined ? templateBaseData.salarySob : null; + this.templateBaseData = templateBaseData // 基础信息表单数据 + + this.salarySobOptions = response.salarySobOptions ? + response.salarySobOptions.map(item => { + let result = {} + result.showname = item.name; + result.key = item.id + ""; + result.selected = false; + return result; + }) : [] + resolve({ + templateBaseData: this.templateBaseData, + salarySobOptions: this.salarySobOptions + }); + } else { + message.errro(res.errormsg || "获取失败"); + reject() + } + }) + }) + } + + + // 工资单模板-获取工资单模板显示设置表单 + @action + getPayrollShowForm = (id = "") => { + let params = { + id + } + API.getPayrollShowForm(params).then(res => { + if(res.status) { + this.salaryTemplateShowSet = res.data.salaryTemplateShowSet.data + } else { + message.error(res.errormsg || "获取失败") + } + }) + } + + // 工资单模板-获取薪资项目设置 + @action + getPayrollItemList = (salarySobId = "") => { + let params = { + salarySobId + } + API.getPayrollItemList(params).then(res => { + if(res.status) { + this.salaryItemSet = res.data + } else { + message.error(res.errormsg || "获取失败") + } + }) + } + + // 初始化显示设置表单 + @action + initShowSettingForm = (id = "") => { + this.getPayrollShowForm(id); + if(id == "") { + this.getPayrollItemList(this.templateBaseData.salarySob) + } + } + + // 校验显示设置表单 + validateSalaryTemplateShowSet = () => { + if(!notNull(this.salaryTemplateShowSet.theme)) { + message.warning("工资单主题不能为空"); + return false; + } + return true; + } + + // 拼装保存参数 + convertParams = () => { + let params = {...this.templateBaseData, ...this.salaryTemplateShowSet} + params.salarySobId = params.salarySob + params.emailStatus = params.emailStatus ? params.emailStatus : false; + params.msgStatus = params.msgStatus ? params.msgStatus : false + params.salaryItemNullStatus = params.salaryItemNullStatus ? params.salaryItemNullStatus : false; + params.salaryItemZeroStatus = params.salaryItemZeroStatus ? params.salaryItemZeroStatus : false; + params.salaryItemSetting = this.salaryItemSet + return params + } + + + // 工资单模板-新建工资单模板 + @action + fetchSavePayroll = () => { + if(!(this.validateSalaryTemplateShowSet())) { + return false + } + let params = this.convertParams() + return new Promise((resolve, reject) => { + API.savePayroll(params).then(res => { + if(res.status) { + message.success("保存成功"); + this.getPayrollTemplateList(); + resolve(); + } else { + message.error(res.errormsg || "保存失败") + reject() + } + }) + }) + } + +} \ No newline at end of file diff --git a/pc4mobx/hrmSalary/util/validate.js b/pc4mobx/hrmSalary/util/validate.js index 5c0391fc..0d1ac881 100644 --- a/pc4mobx/hrmSalary/util/validate.js +++ b/pc4mobx/hrmSalary/util/validate.js @@ -1,12 +1,18 @@ +/** + * 判断是否为空 + * @param {*} name + * @returns false 为空 , true 不为空 + */ export const notNull = (name) => { if(typeof(name) == "string") { name = name.trim() } - if(name !== undefined) { - name = name.toString() - } - if(!name || name == "") { - return false + if(typeof(name) == "string") { + if(name == "") { + return false; + } + } else if(name === null || name === undefined) { + return false; } return true } \ No newline at end of file