diff --git a/pc4mobx/hrmSalary/apis/item.js b/pc4mobx/hrmSalary/apis/item.js index 128cd24f..ccf93af9 100644 --- a/pc4mobx/hrmSalary/apis/item.js +++ b/pc4mobx/hrmSalary/apis/item.js @@ -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 *** // 获取公式变量类型 diff --git a/pc4mobx/hrmSalary/apis/mySalaryBenefits.js b/pc4mobx/hrmSalary/apis/mySalaryBenefits.js index 7a29d7db..a2f5be7a 100644 --- a/pc4mobx/hrmSalary/apis/mySalaryBenefits.js +++ b/pc4mobx/hrmSalary/apis/mySalaryBenefits.js @@ -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); -}; \ No newline at end of file + 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); +}; diff --git a/pc4mobx/hrmSalary/apis/ruleconfig.js b/pc4mobx/hrmSalary/apis/ruleconfig.js index 2e5967fc..b0639647 100644 --- a/pc4mobx/hrmSalary/apis/ruleconfig.js +++ b/pc4mobx/hrmSalary/apis/ruleconfig.js @@ -43,3 +43,11 @@ export const getEncryptProgress = params => { export const operateTaxDeclarationFunction = (params) => { return postFetch('/api/bs/hrmsalary/sys/operateTaxDeclarationFunction', 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); +} diff --git a/pc4mobx/hrmSalary/apis/statistics.js b/pc4mobx/hrmSalary/apis/statistics.js new file mode 100644 index 00000000..197339b5 --- /dev/null +++ b/pc4mobx/hrmSalary/apis/statistics.js @@ -0,0 +1,68 @@ +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); +}; diff --git a/pc4mobx/hrmSalary/common/Icon-empty-file.svg b/pc4mobx/hrmSalary/common/Icon-empty-file.svg new file mode 100644 index 00000000..cfab82a9 --- /dev/null +++ b/pc4mobx/hrmSalary/common/Icon-empty-file.svg @@ -0,0 +1,38 @@ + + + Icon-empty-file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pc4mobx/hrmSalary/common/leftTree-hide.png b/pc4mobx/hrmSalary/common/leftTree-hide.png new file mode 100644 index 00000000..0a1cadfc Binary files /dev/null and b/pc4mobx/hrmSalary/common/leftTree-hide.png differ diff --git a/pc4mobx/hrmSalary/common/leftTree-show.png b/pc4mobx/hrmSalary/common/leftTree-show.png new file mode 100644 index 00000000..cc791aad Binary files /dev/null and b/pc4mobx/hrmSalary/common/leftTree-show.png differ diff --git a/pc4mobx/hrmSalary/components/excelEditor/components/codeAction.js b/pc4mobx/hrmSalary/components/excelEditor/components/codeAction.js new file mode 100644 index 00000000..1ab26b1f --- /dev/null +++ b/pc4mobx/hrmSalary/components/excelEditor/components/codeAction.js @@ -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(funcText) !== -1) + })); + return ( +
+
+
+
{getLabel(111, "变量")}
+
+
+ this.setState({ variableText })}/> + + { + _.map(variableDatalist, item => { + const { key, value, children = [] } = item; + const itemChildren = _.filter(children.slice(1), it => it.name.indexOf(variItemText) !== -1); + return + { + _.map([...children.slice(0, 1), ...itemChildren], (child, childIndex) => { + const { name, fieldId } = child; + return ( + fieldId === "searchInput" ? + this.setState({ variItemText })} + /> + } + key={fieldId + "_" + childIndex}/> : + + ); + }) + } + ; + }) + } + +
+
+ { + referenceType !== "sql" && + +
+
+
{getLabel(111, "函数")}
+
+
+ this.setState({ funcText })}/> + this.setState({ funcExpandedKeys })} + > + { + _.map(funcDatalist, item => { + const { name, dataType, children = [] } = item; + return + { + _.map(children, (child, childIndex) => { + const { name: childName, chineseName } = child; + return ( + this.props.onFuncSelect(childName)} + onMouseEnter={() => this.setState({ funcHoverItem: child })}> + {childName} + {chineseName} +
+ } + key={childIndex} + /> + ); + }) + } + ; + }) + } + +
+
+
+
+
+ {!_.isEmpty(funcHoverItem) ? funcHoverItem.name : getLabel(111, "提示")} +
+
+
+
+ + } + + ); + } +} + +export default CodeAction; + +const TipList = (props) => { + const { tips } = props; + const { paramDescs = [], formatString, description, example, result } = tips; + return _.isEmpty(tips) ?
+
+ {/*
{getLabel(111, "{C:选项} 用来选择特定选项字段下的备选项")}
*/} + {/*
{getLabel(111, "{U:姓名} 用来选择工作区成员")}
*/} + {/*
{getLabel(111, "{D:数据} 用来选择一个部门")}
*/} +
+
:
+
+
{getLabel(111, "语法")}
+
+
{formatString}
+
{description}
+
+
{getLabel(111, "参数")}
+ { + _.map(paramDescs, it => { + return
+ . + {it} +
; + }) + } +
{getLabel(111, "示例")}
+ {example} +
{getLabel(111, "结果")}
+ {result} +
+
; +}; diff --git a/pc4mobx/hrmSalary/components/excelEditor/constants.js b/pc4mobx/hrmSalary/components/excelEditor/constants.js new file mode 100644 index 00000000..2bb11e58 --- /dev/null +++ b/pc4mobx/hrmSalary/components/excelEditor/constants.js @@ -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" }, +] diff --git a/pc4mobx/hrmSalary/components/excelEditor/extendCodeMirror.js b/pc4mobx/hrmSalary/components/excelEditor/extendCodeMirror.js new file mode 100644 index 00000000..e70c6967 --- /dev/null +++ b/pc4mobx/hrmSalary/components/excelEditor/extendCodeMirror.js @@ -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: "", + newlineAfterToken: function (type, content, textAfter) { + return type == "tag" && />$/.test(content) || /^ -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 }; diff --git a/pc4mobx/hrmSalary/components/excelEditor/index.js b/pc4mobx/hrmSalary/components/excelEditor/index.js new file mode 100644 index 00000000..1d1cd89f --- /dev/null +++ b/pc4mobx/hrmSalary/components/excelEditor/index.js @@ -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 ( + +
+
+ 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()} + /> +
+ { + referenceType !== "sql" && +
+
+
+ { + _.map(keyboardBaseBtns, item => { + const { key, label } = item; + return ; + }) + } +
+
+ + +
+
+ +
+ } +
+ {/*公式参数列表*/} + +
+ ); + } +} + +export default ExcelEditor; diff --git a/pc4mobx/hrmSalary/components/excelEditor/index.less b/pc4mobx/hrmSalary/components/excelEditor/index.less new file mode 100644 index 00000000..0ea0081a --- /dev/null +++ b/pc4mobx/hrmSalary/components/excelEditor/index.less @@ -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 + } + } + } + } +} diff --git a/pc4mobx/hrmSalary/index.js b/pc4mobx/hrmSalary/index.js index b59a534a..3037a01b 100644 --- a/pc4mobx/hrmSalary/index.js +++ b/pc4mobx/hrmSalary/index.js @@ -32,6 +32,8 @@ 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 ReportView from "./pages/reportView"; import stores from "./stores"; import "./style/index"; @@ -78,6 +80,8 @@ const DataAcquisition = (props) => props.children; // sysconfig-1 规则配置 // appconfig 应用配置 // fieldManagement 字段管理 +// analysisOfSalaryStatistics 薪酬统计分析 +// reportView 薪酬报表查看 const Routes = ( + + ); diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/conditions.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/conditions.js new file mode 100644 index 00000000..a622aefb --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/conditions.js @@ -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 + } +]; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/dimensionSlide.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/dimensionSlide.js new file mode 100644 index 00000000..b7bd9c2e --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/dimensionSlide.js @@ -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 ( + + {formId ? getLabel(111, "编辑统计维度") : getLabel(111, "新建统计维度")} + + + } + > + {getSearchs(form, condition, 1, false, this.formItemChange)} + { + dimType !== "QUALITATIVE" && + + { + dimType === "RATION_GROUP_SPACING" && + + } + { + dimType === "RATION_GROUP_INDIVIDUAL" && + + } + + } + + ); + } +} + +export default DimensionSlide; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/dimensionTable.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/dimensionTable.js new file mode 100644 index 00000000..fb5a4cb1 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/dimensionTable.js @@ -0,0 +1,115 @@ +/* + * 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 ( + + onEdit(record.id)}>{getLabel(111, "编辑")} + this.dimensionDelete([record.id])}>{getLabel(111, "删除")} + + ); + } + } + ]; + return ( + + ); + } +} + +export default DimensionTable; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/groupIndividualEditTable.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/groupIndividualEditTable.js new file mode 100644 index 00000000..1d709bc6 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/groupIndividualEditTable.js @@ -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 ( + + ); + } +} + +export default GroupIndividualEditTable; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/groupSpacingEditTable.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/groupSpacingEditTable.js new file mode 100644 index 00000000..c976cd93 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/groupSpacingEditTable.js @@ -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 ( + ({ ...item, to: getLabel(111, "至") }))} + showCopy={false} onChange={this.handleChangeTableData} + /> + ); + } +} + +export default GroupSpacingEditTable; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/reportForm.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/reportForm.js new file mode 100644 index 00000000..0308e2ed --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/reportForm.js @@ -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 ( + {getSearchs(form, condition, 1, false)} + ); + } +} + +export default ReportForm; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/reportList.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/reportList.js new file mode 100644 index 00000000..6510d5b1 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/reportList.js @@ -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 ( + + { + _.isEmpty(dataSource) ?
{getLabel(111, "暂无数据")}
: + _.map(dataSource, it => { + const { reportName, dimension, id, dimensionId } = it; + return this.handleGoReportView(id)}> +
+
+
+ {reportName} +
+
{getLabel(111, "统计维度")}:
+
{dimension}
+
+
+
+ this.handleOptsClick(e, id, dimensionId)}> + {getLabel(111, "编辑")} + {getLabel(111, "删除")} + + }> + + +
+
+ ; + }) + } +
+ ); + } +} + +export default ReportList; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/statisticsModal.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/statisticsModal.js new file mode 100644 index 00000000..c8920887 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/components/statisticsModal.js @@ -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" ? [ + + ] : []; + return ( + + {this.props.children} + + ); + } +} + +export default StatisticsModal; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/index.js b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/index.js new file mode 100644 index 00000000..fe08d250 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/index.js @@ -0,0 +1,297 @@ +/* + * Author: 黎永顺 + * name: 薪酬统计分析 + * Description: + * Date: 2023/4/10 + */ +import React, { Component } from "react"; +import { inject, observer } from "mobx-react"; +import { 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 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 "./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: "", + 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" ? +
+ {getLabel(111, "统计维度管理")} + +
+ : 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 } = this.state; + const buttons = [ + , + , + this.setState({ reportName })} + onSearch={() => this.handleReqBtnsClick("search")}/> + ]; + const tabs = [ + { key: "statistics", title: getLabel(111, "统计表") } + // { key: "detail", title: getLabel(111, "员工明细") } + ]; + return ( + } + iconBgcolor="#F14A2D" buttons={!statisticsReportBtn ? buttons.slice(-1) : buttons} buttonSpace={10} + showDropIcon={false} tabDatas={tabs} className="xc_tj_fx_wrapper" + selectedKey={selectedKey} + onChange={selectedKey => this.setState({ selectedKey }, () => this.state.selectedKey === "statistics" && this.initReportFormCondition())} + > + { + this.state.selectedKey === "statistics" && + this.reportListRef = dom} + reportName={reportName} + onEdit={this.handleReqBtnsClick} + /> + } + + { + modalReq.typeKey === "dimension" && + this.dimensionTableRef = dom} + onEdit={id => this.handleAddDimension(id)} + /> + } + { + modalReq.typeKey === "addReport" && + + } + + + + ); + } +} + +export default Index; diff --git a/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/index.less b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/index.less new file mode 100644 index 00000000..97860916 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/analysisOfSalaryStatistics/index.less @@ -0,0 +1,141 @@ +.xc_tj_fx_wrapper { + .search { + top: -3px; + margin-right: 10px; + width: 220px; + } + + .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%; + } + } +} diff --git a/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/acctResultImportModal.js b/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/acctResultImportModal.js index cd2c9c44..766594f7 100644 --- a/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/acctResultImportModal.js +++ b/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/acctResultImportModal.js @@ -2,8 +2,8 @@ import React from "react"; import ImportModal from "../../../../components/importModal"; 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"; @inject("calculateStore", "standingBookStore") @observer @@ -16,7 +16,10 @@ export default class AcctResultImportModal extends React.Component { salaryItemIds: "" }, step: 0, - selectFieldVisible: false + selectFieldVisible: false, + addHeadFields: { + visible: false, itemsByGroup: [] + } }; } @@ -24,11 +27,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 +34,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,58 +109,22 @@ export default class AcctResultImportModal extends React.Component { } // 渲染第一步表单 - renderFormComponent() { + renderFormComponent = () => { return - + ; - } + }; // 选择表单字段 - handleSelectedField() { + handleSelectedField = () => { this.setState({ - selectFieldVisible: true + addHeadFields: { + ...this.state.addHeadFields, + visible: true + } }); - } - - // 添加表头字段 - handleAdd(fieldDate) { - let salaryItemIdsList = []; - if (!_.isEmpty(fieldDate.formulaItems)) { - fieldDate.formulaItems.map(item => { - if (item.checked) { - salaryItemIdsList.push(item.salaryItemId); - } - }); - } - if (!_.isEmpty(fieldDate.inputItems)) { - fieldDate.inputItems.map(item => { - if (item.checked) { - salaryItemIdsList.push(item.salaryItemId); - } - }); - } - if (!_.isEmpty(fieldDate.sqlItems)) { - fieldDate.sqlItems.map(item => { - if (item.checked) { - salaryItemIdsList.push(item.salaryItemId); - } - }); - } - let salaryItemIds = ""; - if (salaryItemIdsList.length > 0) { - salaryItemIds = salaryItemIdsList.join(","); - } - - let modalParam = { ...this.state.modalParam }; - modalParam.salaryItemIds = salaryItemIds; - this.setState({ - modalParam - }); - this.props.onAdd(fieldDate); - } + }; // 初始化Import数据 handleImportModalInit() { @@ -197,7 +172,7 @@ export default class AcctResultImportModal extends React.Component { importInsuranceAcctDetail, importBalanceInsuranceDetail } = standingBookStore; - const { step, selectFieldVisible, modalParam } = this.state; + const { step, modalParam, addHeadFields } = this.state; return (
{ @@ -223,7 +198,7 @@ export default class AcctResultImportModal extends React.Component { !isStandingBook ? fetchImportAcctResult(params) : standingBookType === "difference" ? - importBalanceInsuranceDetail({...params, billMonth}) : + importBalanceInsuranceDetail({ ...params, billMonth }) : importInsuranceAcctDetail(params); }} templateLink={() => { @@ -236,23 +211,19 @@ export default class AcctResultImportModal extends React.Component { }} /> } - { - selectFieldVisible && { - this.handleAdd(fieldDate); - }} - onCancel={() => { - this.setState({ - selectFieldVisible: false - }); - }} - /> - } + this.setState({ addHeadFields: { ...addHeadFields, visible: false } })} + onAdd={(salaryItemIds) => this.setState({ + addHeadFields: { + ...addHeadFields, + visible: false + }, + modalParam: { + ...modalParam, + salaryItemIds: salaryItemIds.join(",") + } + })} + />
); } diff --git a/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/addHeaderFieldsModal.js b/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/addHeaderFieldsModal.js new file mode 100644 index 00000000..66b00e4c --- /dev/null +++ b/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/addHeaderFieldsModal.js @@ -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 ( + this.props.onAdd(itemsCheckeds)}>{getLabel(111, "添加")}, + + ]} + bottomLeft={} + > + { + _.map(dataSource, item => { + const { salarySobItemGroupName, salaryItems, salarySobItemGroupId } = item; + const value = _.every(salaryItems, it => !!it.checked) ? "1" : "0"; + return this.handleSelectGroupAll(salarySobItemGroupId, val)}/>}> + + { + !_.isEmpty(salaryItems) ? + _.map(salaryItems, it => { + const { salaryItemId, salaryItemName, checked } = it; + return + this.setState({ itemsCheckeds: _.xorWith(itemsCheckeds, [salaryItemId], _.isEqual) })}/> + ; + }) : 暂无数据 + } + + ; + }) + } + + ); + } +} + +export default AddHeaderFieldsModal; diff --git a/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/index.less b/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/index.less new file mode 100644 index 00000000..1de6458c --- /dev/null +++ b/pc4mobx/hrmSalary/pages/calculateDetail/acctResult/importModal/index.less @@ -0,0 +1,11 @@ +.addHeaderFieldsWrapper { + .wea-search-group { + .wea-title { + padding-left: 0 !important; + } + + .wea-content { + padding: 8px 16px 0; + } + } +} diff --git a/pc4mobx/hrmSalary/pages/calculateDetail/editSalaryDetail.js b/pc4mobx/hrmSalary/pages/calculateDetail/editSalaryDetail.js index 075c55a1..2051451d 100644 --- a/pc4mobx/hrmSalary/pages/calculateDetail/editSalaryDetail.js +++ b/pc4mobx/hrmSalary/pages/calculateDetail/editSalaryDetail.js @@ -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 {
基本信息 - +
-
{ !_.isEmpty(acctresultDetailForm.employeeInfos) && @@ -123,69 +113,9 @@ export default class EditSalaryDetail extends React.Component { /> } { - selectedKey === "0" && -
-
- 输入项 -
- - { - acctresultDetailForm.inputItems && acctresultDetailForm.inputItems.map((item, index) => { - const len = acctresultDetailForm.inputItems.length; - return ( - - - {item.salaryItemName} - { - this.handleItemValueChange(item.salaryItemName, value, "inputItems"); - }}/> - - - ); - }) - } - -
-
-
- - 公式项 - - -
- - { - acctresultDetailForm.formulaItems && acctresultDetailForm.formulaItems.map((item, index) => { - const len = acctresultDetailForm.formulaItems.length; - return ( - - - {item.salaryItemName} - { - this.handleItemValueChange(item.salaryItemName, value, "formulaItems"); - }}/> - - - ); - }) - } - -
-
-
+ selectedKey === "0" && _.map(itemsByGroup, item => { + return ; + }) } { selectedKey === "1" && diff --git a/pc4mobx/hrmSalary/pages/calculateDetail/index.less b/pc4mobx/hrmSalary/pages/calculateDetail/index.less index 7cbb9b42..f821272b 100644 --- a/pc4mobx/hrmSalary/pages/calculateDetail/index.less +++ b/pc4mobx/hrmSalary/pages/calculateDetail/index.less @@ -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) { diff --git a/pc4mobx/hrmSalary/pages/calculateDetail/issuedAndReissueTable.js b/pc4mobx/hrmSalary/pages/calculateDetail/issuedAndReissueTable.js index f18e620f..666c774a 100644 --- a/pc4mobx/hrmSalary/pages/calculateDetail/issuedAndReissueTable.js +++ b/pc4mobx/hrmSalary/pages/calculateDetail/issuedAndReissueTable.js @@ -40,7 +40,7 @@ class IssuedAndReissueTable extends Component { } }, { - dataIndex: "salaryBackItemFormula", + dataIndex: "itemFormulaContent", title: 核算公式 { + return {text}; + } + }, + { + dataIndex: "resultValue", + title: + {getLabel(111, "项目值")} + + , + width: "20%", + render: (text, record) => { + const { canEdit, dataType } = record; + return dataType === "number" ? onChangeIssueReissueValue(record.salaryItemId, value, "itemsByGroup", salarySobItemGroupId)} + /> : onChangeIssueReissueValue(record.salaryItemId, value, "itemsByGroup", salarySobItemGroupId)} + />; + } + }, + { + dataIndex: "itemFormulaContent", + title: + {getLabel(111, "核算公式")} + + , + width: "65%", + render: (text, record) => { + return {_.isNil(text) ? "输入" : text}; + } + } + ]; + return ( + + + + ); + } +} + +export default PayrollItemsTable; diff --git a/pc4mobx/hrmSalary/pages/equationEditor/index.js b/pc4mobx/hrmSalary/pages/equationEditor/index.js new file mode 100644 index 00000000..ffcc361c --- /dev/null +++ b/pc4mobx/hrmSalary/pages/equationEditor/index.js @@ -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 ( +
+ {}}/> + + this.setState({ visible: false })} + > + {}}/> + +
+ ); + } +} + +export default Index; diff --git a/pc4mobx/hrmSalary/pages/mobilePayroll/index.js b/pc4mobx/hrmSalary/pages/mobilePayroll/index.js index 4d08a972..1978860a 100644 --- a/pc4mobx/hrmSalary/pages/mobilePayroll/index.js +++ b/pc4mobx/hrmSalary/pages/mobilePayroll/index.js @@ -1,10 +1,14 @@ 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 "./index.less"; @inject("mySalaryStore") @observer @@ -12,6 +16,8 @@ export default class MobilePayroll extends React.Component { constructor(props) { super(props); this.state = { + visible: false, + authCode: "", mySalaryBillData: { employeeInformation: {}, salaryTemplate: [] @@ -24,11 +30,43 @@ export default class MobilePayroll extends React.Component { const type = getQueryString("type"); this.id = getQueryString("id"); const { mySalaryStore: { init } } = this.props; - // type !== "phone" && init(false); - init(false); + type !== "phone" && init(false); + type === "phone" && this.initMobile(); this.getMySalaryBill(this.id); } + 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 { + 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 }); + } else { + message.error(checkMsg); + } + }); + }; getMySalaryBill = (salaryInfoId) => { const { mySalaryStore: { getMySalaryBill } } = this.props; const params = this.getUrlkey(); @@ -57,7 +95,8 @@ export default class MobilePayroll extends React.Component { }; render() { - const { mySalaryBillData } = this.state; + const { mySalaryStore: { clearLoading } } = this.props; + const { mySalaryBillData, visible } = this.state; const type = getQueryString("type"); const employeeInformation = mySalaryBillData.employeeInformation ? mySalaryBillData.employeeInformation : {}; const salaryGroups = mySalaryBillData.salaryGroups ? mySalaryBillData.salaryGroups : []; @@ -67,18 +106,33 @@ export default class MobilePayroll extends React.Component { overflowY: "hidden", paddingBottom: "20px" }}> + this.setState({ visible: false }, () => clearLoading())} + title="请输入二次验证密码" visible={visible} initLoadCss + className="verifyWrapper" + hasScroll buttons={[ + + ]} + > + + this.setState({ authCode })}/> + + { type === "phone" ? -
-
- + +
+
+ +
-
+ : diff --git a/pc4mobx/hrmSalary/pages/mobilePayroll/index.less b/pc4mobx/hrmSalary/pages/mobilePayroll/index.less new file mode 100644 index 00000000..c51890f3 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/mobilePayroll/index.less @@ -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%; + } + } + } + } +} diff --git a/pc4mobx/hrmSalary/pages/payroll/templatePreview/phoneTemplate/index.js b/pc4mobx/hrmSalary/pages/payroll/templatePreview/phoneTemplate/index.js index 4d8fb5f4..607d2d42 100644 --- a/pc4mobx/hrmSalary/pages/payroll/templatePreview/phoneTemplate/index.js +++ b/pc4mobx/hrmSalary/pages/payroll/templatePreview/phoneTemplate/index.js @@ -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,28 @@ export default class PhoneTemplate extends React.Component { salaryTemplateShowSet: JSON.parse(salaryTemplateShowSetStr) }); } + + componentDidMount() { + if (this.props.isMsgPreview && this.props.salaryItemSet && window.em) { + 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 (
@@ -57,7 +67,7 @@ export default class PhoneTemplate extends React.Component {
{ - salaryTemplateShowSet.textContentPosition == 1 && salaryTemplateShowSet.textContent + salaryTemplateShowSet.textContentPosition == 1 && salaryTemplateShowSet.textContent }
@@ -73,7 +83,7 @@ export default class PhoneTemplate extends React.Component { _.map(group.items, item => { return {item.name} - {item.salaryItemValue || '-'} + {item.salaryItemValue || "-"} ; }) } diff --git a/pc4mobx/hrmSalary/pages/reportView/components/chartsRangeSettingsModal.js b/pc4mobx/hrmSalary/pages/reportView/components/chartsRangeSettingsModal.js new file mode 100644 index 00000000..143f16a7 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/reportView/components/chartsRangeSettingsModal.js @@ -0,0 +1,405 @@ +/* + * Author: 黎永顺 + * name: 分析图标范围数据设置弹框 + * Description: + * Date: 2023/5/11 + */ +import React, { Component } from "react"; +import { Button, Col, message, Row } from "antd"; +import { + WeaDialog, + WeaError, + WeaFormItem, + WeaHelpfulTip, + WeaInputNumber, + WeaLocaleProvider, + WeaReqTop, + WeaSearchGroup, + WeaSelect +} from "ecCom"; +import { saveRangeSetting } from "../../../apis/statistics"; +import "./index.less"; + +const { getLabel } = WeaLocaleProvider; + +class ChartsRangeSettingsModal extends Component { + constructor(props) { + super(props); + this.state = { + loading: false, + selectedKey: "1", + rangeSetting: { + itemValues: "", + itemColValue: "", + dimensionRange: "0" + }, + rangeSettingExtra: { + itemSortValue: "", + itemColSortValue: "", + sortType: "0", + sortNum: "" + }, + statisticalItemsOptions: [], + statisticalColsOptions: [], + rangeSettingExtraOptions: { + sortStatisticsOptions: [], + sortColumnsOptions: [] + } + }; + } + + componentWillReceiveProps(nextProps, nextContext) { + if (nextProps.visible !== this.props.visible && nextProps.visible) { + const { columns } = nextProps; + this.setState({ + statisticalItemsOptions: _.map(_.filter(columns, item => !_.isEmpty(item.children)), it => ({ + key: it.column, showname: it.text, + children: _.map(it.children, child => ({ key: child.column, showname: child.text })) + })) + }); + } + if (nextProps.rangeVal !== this.props.rangeVal && nextProps.rangeVal) { + const { rangeVal } = nextProps; + const { rangeSetting, rangeSettingExtra } = this.state; + this.setState({ + rangeSetting: { + ...rangeSetting, + ..._.reduce(Object.keys(rangeSetting), (pre, cur) => { + return { + ...pre, + [cur]: Array.isArray(rangeVal[cur]) ? rangeVal[cur].join(",") : + !_.isNil(rangeVal[cur]) ? rangeVal[cur].toString() : cur === "dimensionRange" ? "0" : "" + }; + }, {}) + }, + rangeSettingExtra: { + ...rangeSettingExtra, + ..._.reduce(Object.keys(rangeSettingExtra), (pre, cur) => { + return { + ...pre, + [cur]: !_.isNil(rangeVal[cur]) ? rangeVal[cur].toString() : cur === "sortType" ? "0" : "" + }; + }, {}) + } + }, () => { + const { statisticalItemsOptions } = this.state; + const { itemValues, itemSortValue } = rangeVal; + let statisticalColsOptions = [], sortStatisticsOptions = []; + _.forEach(itemValues, item => { + _.forEach(statisticalItemsOptions, child => { + if (item === child.key) { + statisticalColsOptions = [...statisticalColsOptions, ...child.children]; + sortStatisticsOptions = [...sortStatisticsOptions, child]; + } + }); + }); + this.setState({ + statisticalColsOptions, + rangeSettingExtraOptions: { + sortStatisticsOptions + } + }, () => { + const { rangeSettingExtraOptions } = this.state; + const { sortStatisticsOptions } = rangeSettingExtraOptions; + this.setState({ + rangeSettingExtraOptions: { + ...rangeSettingExtraOptions, + sortColumnsOptions: !_.isEmpty(_.find(sortStatisticsOptions, it => it.key === itemSortValue)) ? _.find(sortStatisticsOptions, it => it.key === itemSortValue).children : [] + } + }); + }); + }); + } + } + + handleSaveChartsRangeSettings = () => { + const { reportId, rangeVal } = this.props; + const { rangeSetting, rangeSettingExtra, selectedKey: chartsType } = this.state; + const { itemValues, itemColValue, dimensionRange } = rangeSetting; + if (!itemColValue && !itemValues) { + this.refs.itemValues.showError(); + this.refs.itemColValue.showError(); + return; + } + if (!itemValues) { + this.refs.itemValues.showError(); + return; + } + if (!itemColValue) { + this.refs.itemColValue.showError(); + return; + } + const payload = { + reportId, chartsType, id: rangeVal.id, + ...rangeSetting, + itemValues: itemValues.split(",") + }; + this.setState({ loading: true }); + saveRangeSetting( + dimensionRange === "0" ? payload : { ...payload, ...rangeSettingExtra } + ).then(({ status, errormsg }) => { + this.setState({ loading: false }); + if (status) { + message.success(getLabel(111, "保存成功")); + this.props.onGetData(); + this.handleCancel(); + } else { + message.error(errormsg || getLabel(111, "保存失败")); + } + }).catch(() => this.setState({ loading: false })); + }; + handleCancel = () => { + this.setState({ + rangeSetting: { + itemValues: "", + itemColValue: "", + dimensionRange: "0" + }, + rangeSettingExtra: { + itemSortValue: "", + itemColSortValue: "", + sortType: "0", + sortNum: "" + }, + selectedKey: "1", + statisticalItemsOptions: [], + statisticalColsOptions: [] + }, () => this.props.onCancel()); + }; + handleResetFormVal = () => { + const { selectedKey: chartsType } = this.state; + const { reportId } = this.props; + this.props.onChange({ reportId, chartsType }); + }; + handleChange = ({ key, val }) => { + const { rangeSetting } = this.state; + this.setState({ + rangeSetting: { + ...rangeSetting, + [key]: val + } + }, () => { + if (key === "itemValues") { + const { statisticalItemsOptions } = this.state; + let statisticalColsOptions = [], sortStatisticsOptions = []; + _.forEach(val.split(","), item => { + _.forEach(statisticalItemsOptions, child => { + if (item === child.key) { + statisticalColsOptions = [...statisticalColsOptions, ...child.children]; + sortStatisticsOptions = [...sortStatisticsOptions, child]; + } + }); + }); + this.setState({ + statisticalColsOptions, + rangeSettingExtra: { + itemSortValue: "", + itemColSortValue: "", + sortType: "0", + sortNum: "" + }, + rangeSettingExtraOptions: { + sortStatisticsOptions + } + }); + } + }); + }; + handleChangeRange = ({ key, val }) => { + const { rangeSettingExtra } = this.state; + this.setState({ + rangeSettingExtra: { + ...rangeSettingExtra, + [key]: val + } + }, () => { + if (key === "itemSortValue") { + const { rangeSettingExtraOptions } = this.state; + const { sortStatisticsOptions } = rangeSettingExtraOptions; + this.setState({ + rangeSettingExtraOptions: { + ...rangeSettingExtraOptions, + sortColumnsOptions: _.find(sortStatisticsOptions, it => it.key === val).children + } + }); + } + }); + }; + + render() { + const { + selectedKey, + rangeSetting, + statisticalItemsOptions, + statisticalColsOptions, + rangeSettingExtra, + rangeSettingExtraOptions, + loading + } = this.state; + const dataShowItems = [ + { + com: RangSelect({ + name: "itemValues", + label: getLabel(111, "统计项"), + onChange: this.handleChange, + value: rangeSetting.itemValues, + options: statisticalItemsOptions, + multiple: selectedKey !== "0" + }) + }, + { + com: RangSelect({ + name: "itemColValue", + label: getLabel(111, "统计列"), + onChange: this.handleChange, + value: rangeSetting.itemColValue, + options: statisticalColsOptions + }) + } + ]; + const rangValItems = [ + { + com: RangSelect({ + name: "dimensionRange", + label: getLabel(111, "统计维度查看范围"), + onChange: this.handleChange, + value: rangeSetting.dimensionRange, + options: [ + { key: "0", showname: getLabel(111, "全部") }, + { key: "1", showname: getLabel(111, "设置范围") } + ], + detailtype: 3, + helpfulTip: getLabel(111, "通过某个统计项统计值的排序,确定统计维度的查看范围。 例:查看统计项【薪资成本】的统计值降序为前10的部门的分析图情况") + }) + } + ]; + const rangValExtraItems = [ + { + com: RangMultiItem({ + label: getLabel(111, "设置范围"), + onChange: this.handleChangeRange, + value: rangeSettingExtra, + options: rangeSettingExtraOptions + }) + } + ]; + const { dimensionRange } = rangeSetting; + return ( + this.setState({ selectedKey }, () => this.handleResetFormVal())} + onSaveChartsRangeSettings={this.handleSaveChartsRangeSettings} + />} + > + + {getLabel(111, "统计项数据展示范围设置")} + +
+ } + showGroup items={dataShowItems} needTigger col={1} + /> + + + ); + } +} + +export default ChartsRangeSettingsModal; + +const RangSetingTitle = (props) => { + const { selectedKey, onChange, onSaveChartsRangeSettings, loading } = props; + const btns = []; + return } + iconBgcolor="#F14A2D" buttons={btns} showDropIcon={false} + tabDatas={[ + { key: "1", title: "柱状图" }, + { key: "2", title: "折线图" }, + { key: "0", title: "饼图" } + ]} selectedKey={selectedKey} onChange={onChange} + />; +}; +const RangSelect = payload => { + const { + label, onChange, value, options = [], + viewAttr = 3, multiple = false, name, + detailtype = 1, helpfulTip + } = payload; + return ( + + {label} + { + helpfulTip && + + } + + } labelCol={{ span: 8 }} wrapperCol={{ span: 12 }}> + + onChange({ key: name, val })}/> + + + ); +}; +const RangMultiItem = payload => { + const { label, onChange, value, options } = payload; + const { itemSortValue, itemColSortValue, sortType, sortNum } = value; + const { sortStatisticsOptions, sortColumnsOptions } = options; + return ( + + + {getLabel(111, "排序统计项:")} + onChange({ key: "itemSortValue", val })}/> + + + {getLabel(111, "排序列:")} + onChange({ key: "itemColSortValue", val })}/> + + + + onChange({ key: "sortType", val })} + /> + + + {getLabel(111, "前")} + onChange({ key: "sortNum", val })}/> + + + + ); +}; diff --git a/pc4mobx/hrmSalary/pages/reportView/components/condition.js b/pc4mobx/hrmSalary/pages/reportView/components/condition.js new file mode 100644 index 00000000..c8422666 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/reportView/components/condition.js @@ -0,0 +1,422 @@ +import { WeaLocaleProvider } from "ecCom"; +import { format_with_regex } from "../../../util"; + +const { getLabel } = WeaLocaleProvider; +export const condition = [ + { + items: [ + { + colSpan: 2, + checkbox: false, + checkboxValue: false, + conditionType: "SELECT", + domkey: ["taxAgent"], + fieldcol: 18, + label: getLabel(111, "个税扣缴义务人"), + labelcol: 6, + options: [], + multiple: true, + viewAttr: 2 + }, + { + browserConditionParam: { + completeParams: {}, + conditionDataParams: {}, + dataParams: {}, + destDataParams: {}, + hasAddBtn: false, + hasAdvanceSerach: true, + idSeparator: ",", + isAutoComplete: 1, + isDetail: 0, + isMultCheckbox: false, + isSingle: false, + linkUrl: "", + pageSize: 10, + quickSearchName: "", + replaceDatas: [], + title: getLabel(111, "分部"), + type: "164", + viewAttr: 2 + }, + colSpan: 2, + conditionType: "BROWSER", + domkey: ["subCompany"], + fieldcol: 18, + isQuickSearch: false, + label: getLabel(111, "分部"), + labelcol: 6, + viewAttr: 2 + }, + { + browserConditionParam: { + completeParams: {}, + conditionDataParams: {}, + dataParams: {}, + destDataParams: {}, + hasAddBtn: false, + hasAdvanceSerach: true, + idSeparator: ",", + isAutoComplete: 1, + isDetail: 0, + isMultCheckbox: false, + isSingle: false, + linkUrl: "", + pageSize: 10, + quickSearchName: "", + replaceDatas: [], + title: getLabel(111, "部门"), + type: "57", + viewAttr: 2 + }, + colSpan: 2, + conditionType: "BROWSER", + domkey: ["department"], + fieldcol: 18, + isQuickSearch: false, + label: getLabel(111, "部门"), + labelcol: 6, + viewAttr: 2 + }, + // { + // browserConditionParam: { + // completeParams: {}, + // conditionDataParams: {}, + // dataParams: {}, + // destDataParams: {}, + // hasAddBtn: false, + // hasAdvanceSerach: true, + // idSeparator: ",", + // isAutoComplete: 1, + // isDetail: 0, + // isMultCheckbox: false, + // isSingle: false, + // linkUrl: "", + // pageSize: 10, + // quickSearchName: "", + // replaceDatas: [], + // title: getLabel(111, "岗位"), + // type: "278", + // viewAttr: 2 + // }, + // colSpan: 2, + // conditionType: "BROWSER", + // domkey: ["position"], + // fieldcol: 18, + // isQuickSearch: false, + // label: getLabel(111, "岗位"), + // labelcol: 6, + // viewAttr: 2 + // }, + { + browserConditionParam: { + completeParams: {}, + conditionDataParams: {}, + dataParams: {}, + destDataParams: {}, + hasAddBtn: false, + hasAdvanceSerach: true, + idSeparator: ",", + isAutoComplete: 1, + isDetail: 0, + isMultCheckbox: false, + isSingle: false, + linkUrl: "", + pageSize: 10, + quickSearchName: "", + replaceDatas: [], + title: getLabel(111, "人员"), + type: "17", + viewAttr: 2 + }, + colSpan: 2, + conditionType: "BROWSER", + domkey: ["employee"], + fieldcol: 18, + isQuickSearch: false, + label: getLabel(111, "人员"), + labelcol: 6, + viewAttr: 2 + }, + { + colSpan: 2, + conditionType: "RANGEPICKER", + domkey: ["hiredate1", "hiredate2"], + fieldcol: 18, + label: getLabel(111, "入职日期"), + labelcol: 6, + viewAttr: 2 + } + ], + title: "", + defaultshow: true + } +]; + +const colorList = ["#709DF7", "#73DEB3", "#7585A2", "#F7C739", "#5FC3E3", "#AEE279", "#FF7F81"]; +export const mapBarOptions = (params) => ({ + tooltip: { + trigger: "axis", + axisPointer: { + type: "shadow" + }, + backgroundColor: "#FFF", + borderColor: "#FFF", + borderWidth: "1", + borderRadius: "5", + textStyle: { + color: "#333" + }, + formatter: function (params) { + let str = params[0].axisValue + "
"; + for (let item of params) { + str += `
${item.marker}${item.seriesName}${format_with_regex(item.value)}
`; + } + return str; + } + }, + legend: { + icon: "rect", + top: "0%", + right: "center", + itemGap: 10, + textStyle: { + fontSize: 12,//字体大小 + color: "#B8B8B8"//字体颜色 + } + }, + grid: { + top: "10%", + right: "0%", + left: "2%", + bottom: "0%", + containLabel: true + }, + xAxis: { + type: "category", + axisTick: { + alignWithLabel: true, + show: false + }, + data: params.xAxis, + axisLabel: { + interval: 0, + margin: 10, + textStyle: { + fontSize: 11 + } + } + }, + yAxis: { + name: params.name, + axisLabel: { + padding: [3, 0, 0, 0], + formatter: "{value}", + color: "#666", + textStyle: { + fontSize: 11 + } + }, + nameTextStyle: { + color: "#787E95", + fontSize: 12 + }, + axisLine: { + show: true, + lineStyle: { + color: "transparent" + } + }, + axisTick: { + show: false // 不显示坐标轴刻度线 + }, + splitLine: { + show: false, + lineStyle: { + color: "rgba(66, 192, 255, 0.1)" + } + } + }, + series: _.map(params.data, (item, index) => { + return { + name: item.name, + barWidth: "32", + data: _.map(item.data, (it) => it.replace(/,/g, "")), + type: "bar", + itemStyle: { + normal: { + color: function (params) { + return colorList[params.seriesIndex] || colorList[Math.floor((Math.random() * colorList.length))]; + } + } + }, + label: { + show: true, + position: "insideBottom", + distance: 15, + align: "left", + verticalAlign: "middle", + rotate: "90", + formatter: function (params) { + if (parseInt(params.value) === 0) { + return ``; + } else { + return [ + `{a|${format_with_regex(params.value)}} {b|${params.seriesName}}` + ]; + } + }, + rich: { + a: { + fontWeight: "bold", + fontSize: 14, + color: "#333", + marginRight: 10 + }, + b: { + fontSize: 12, + color: "#333" + } + } + } + }; + }) +}); +export const mapLineOptions = (params) => ({ + tooltip: { + // 坐标轴指示器,坐标轴触发有效 + trigger: "axis", + axisPointer: { + // 默认为直线,可选为:'line' | 'shadow' + type: "line" + } + }, + legend: { + icon: "circle", + top: "0%", + right: "center", + itemGap: 20, + textStyle: { + fontSize: 12,//字体大小 + color: "#787E95"//字体颜色 + } + }, + grid: { + top: "10%", + left: "3%", + right: "2%", + bottom: "3%", + containLabel: true + }, + xAxis: [ + { + type: "category", + boundaryGap: false, + data: params.xAxis, + axisTick: { + alignWithLabel: true, + show: false + }, + // 修改坐标值样式 + axisLabel: { + color: "#B8B8B8", + fontSize: 12, + show: true + }, + axisLine: { + show: false + } + } + ], + yAxis: [ + { + type: "value", + // 修改坐标值样式 + axisLabel: { + color: "#787E95", + fontSize: 14 + }, + nameTextStyle: { + color: "#787E95", + fontSize: 16 + }, + // 修改坐标轴线样式 + axisLine: { + show: true, + lineStyle: { + color: "transparent" + } + }, + axisTick: { + show: false // 不显示坐标轴刻度线 + }, + splitLine: { + lineStyle: { + color: "rgba(93,126,158,1)" + } + } + } + ], + series: _.map(params.data, (item, index) => { + return { + name: item.name, + data: _.map(item.data, (it) => it.replace(/,/g, "")), + type: "line", + itemStyle: { + normal: { + color: function (params) { + return colorList[params.seriesIndex] || colorList[Math.floor((Math.random() * colorList.length))]; + }, + lineStyle: { + color: colorList[index] || colorList[Math.floor((Math.random() * colorList.length))] + } + } + } + }; + }) +}); +export const mapPieOptions = (params) => ({ + tooltip: { + show: true, + formatter: function (params) { + let str = params.seriesName + "
"; + str += params.marker + params.name + ":" + format_with_regex(params.value) + "(" + params.percent + "%" + ")" + "
"; + return str; + } + }, + legend: { + icon: "rect", + top: "0%", + left: "2%", + orient: "vertical", + itemGap: 10, + textStyle: { + fontSize: 12,//字体大小 + color: "#787E95"//字体颜色 + } + }, + series: _.map(params.data, item => { + return { + name: item.name, + data: _.map(item.data, (it) => ({ ...it, value: it.value.replace(/,/g, "") })), + type: "pie", + radius: "60%", + avoidLabelOverlap: true, + animation: false, + labelLine: { + show: true, + normal: { + length: 5, + align: "center" + } + }, + itemStyle: { + normal: { + color: function (colors) { + return colorList[colors.dataIndex] || colorList[Math.floor((Math.random() * colorList.length))]; + } + } + } + }; + }) +}); diff --git a/pc4mobx/hrmSalary/pages/reportView/components/customStatisticsItemsModal.js b/pc4mobx/hrmSalary/pages/reportView/components/customStatisticsItemsModal.js new file mode 100644 index 00000000..f87d7912 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/reportView/components/customStatisticsItemsModal.js @@ -0,0 +1,416 @@ +/* + * Author: 黎永顺 + * name: 新建自定义统计项目弹框 + * Description: + * Date: 2023/4/10 + */ +import React, { Component } from "react"; +import { Button, message, Modal } from "antd"; +import { + WeaBrowser, + WeaCheckbox, + WeaDialog, + WeaError, + WeaFormItem, + WeaHelpfulTip, + WeaInput, + WeaInputNumber, + WeaLocaleProvider, + WeaTable +} from "ecCom"; +import { reportStatisticsItemSave, statisticsItemGetform } from "../../../apis/statistics"; +import "../index.less"; + +const { getLabel } = WeaLocaleProvider; + +class CustomStatisticsItemsModal extends Component { + constructor(props) { + super(props); + this.state = { + loading: false, + columns: [], + dataSource: [], + formData: { + itemValue: "", itemValueSpan: "", + itemName: "" + } + }; + } + + componentWillReceiveProps(nextProps, nextContext) { + if (nextProps.visible !== this.props.visible && nextProps.visible) { + this.statisticsItemGetform({ id: nextProps.statisticsItemId }); + } else { + this.setState({ + columns: [], + dataSource: [], + formData: { + itemValue: "", itemValueSpan: "", + itemName: "" + } + }); + } + } + + handleSaveStatisticalItems = () => { + const { dataSource, formData } = this.state; + const { id: statReportId, statisticsItemId } = this.props; + const { itemValue, itemName } = formData; + const isNoRules = _.some(dataSource, it => !!it.m2mValue || !!it.ratioValue || !!it.totalValue || !!it.y2yValue); + const isChainRequired = _.some(dataSource, it => !!it.m2mValue && (!it.m2mLowerLimit || !it.m2mUpperLimit)); + const isChainValRight = _.some(dataSource, it => !!it.m2mValue && it.m2mLowerLimit !== 0 && it.m2mUpperLimit !== 0 && (Number(it.m2mLowerLimit) > Number(it.m2mUpperLimit))); + const isYoyRequired = _.some(dataSource, it => !!it.y2yValue && (!it.y2yLowerLimit || !it.y2yUpperLimit)); + const isYoyValRight = _.some(dataSource, it => !!it.y2yValue && it.y2yLowerLimit !== 0 && it.y2yUpperLimit !== 0 && (Number(it.y2yLowerLimit) > Number(it.y2yUpperLimit))); + if (!itemValue && !itemName) { + this.refs.proError.showError(); + this.refs.nameError.showError(); + return; + } + if (!itemValue) { + this.refs.proError.showError(); + return; + } + if (!itemName) { + this.refs.nameError.showError(); + return; + } + if (!isNoRules) { + message.warning(getLabel(111, "请至少设置一个统计规则")); + return; + } + if (isChainRequired) { + message.warning(getLabel(111, "请完善环比增幅正常区间设置上下限")); + return; + } + if (isChainValRight) { + message.warning(getLabel(111, "环比增幅上下限设置错误")); + return; + } + if (isYoyRequired) { + message.warning(getLabel(111, "请完善同比增幅正常区间设置上下限")); + return; + } + if (isYoyValRight) { + message.warning(getLabel(111, "同比增幅上下限设置错误")); + return; + } + let payload = { statReportId, itemValue: itemValue.split(","), itemName }; + payload = { + id: statisticsItemId, + ...payload, + ..._.reduce(dataSource, (pre, cur) => { + if (!!cur.m2mValue || !!cur.ratioValue || !!cur.totalValue || !!cur.y2yValue) { + const { y2yLowerLimit, y2yUpperLimit, m2mLowerLimit, m2mUpperLimit } = cur; + if (!!cur.m2mValue) { + return { + ...pre, + [`${cur["id"]}Rule`]: { + m2mValue: cur.m2mValue.toString(), + ratioValue: cur.ratioValue.toString(), + totalValue: cur.totalValue.toString(), + y2yValue: cur.y2yValue.toString(), + m2mLowerLimit: m2mLowerLimit.toString(), + m2mUpperLimit: m2mUpperLimit.toString() + } + }; + } + if (!!cur.m2mValue) { + return { + ...pre, + [`${cur["id"]}Rule`]: { + m2mValue: cur.m2mValue.toString(), + ratioValue: cur.ratioValue.toString(), + totalValue: cur.totalValue.toString(), + y2yValue: cur.y2yValue.toString(), + y2yLowerLimit: y2yLowerLimit.toString(), + y2yUpperLimit: y2yUpperLimit.toString() + } + }; + } + if (!!cur.y2yValue && !!cur.y2yValue) { + return { + ...pre, + [`${cur["id"]}Rule`]: { + m2mValue: cur.m2mValue.toString(), + ratioValue: cur.ratioValue.toString(), + totalValue: cur.totalValue.toString(), + y2yValue: cur.y2yValue.toString(), + m2mLowerLimit: m2mLowerLimit.toString(), + m2mUpperLimit: m2mUpperLimit.toString(), + y2yLowerLimit: y2yLowerLimit.toString(), + y2yUpperLimit: y2yUpperLimit.toString() + } + }; + } + return { + ...pre, + [`${cur["id"]}Rule`]: { + m2mValue: cur.m2mValue.toString(), + ratioValue: cur.ratioValue.toString(), + totalValue: cur.totalValue.toString(), + y2yValue: cur.y2yValue.toString() + } + }; + } + return { ...pre }; + }, {}) + }; + if (statisticsItemId) { + Modal.confirm({ + title: getLabel(111, "信息确认"), + content: getLabel(111, `确定要编辑统计项吗?编辑后,可能需要重新设置分析图设置。`), + onOk: () => this.reportStatisticsItemSave(payload) + }); + } else { + this.reportStatisticsItemSave(payload); + } + }; + reportStatisticsItemSave = (payload) => { + this.setState({ loading: true }); + reportStatisticsItemSave(payload).then(({ status, errormsg }) => { + this.setState({ loading: false }); + if (status) { + this.setState({ + formData: { + itemValue: "", itemName: "" + } + }, () => this.props.onCancel(true)); + } else { + message.error(errormsg); + } + }).catch(() => this.setState({ loading: false })); + }; + + + statisticsItemGetform = (payload) => { + statisticsItemGetform(payload).then(({ status, data }) => { + if (status) { + const { formData } = this.state; + const { ruleData, baseForm } = data; + const { data: dataDetail } = baseForm; + const { columns, data: dataSource } = ruleData; + this.setState({ + columns, dataSource, + formData: { + ...formData, + itemName: dataDetail ? dataDetail.itemName : "", + itemValue: dataDetail ? _.map(dataDetail.itemValue, it => it.id).join() : "", + itemValueSpan: dataDetail ? _.map(dataDetail.itemValue, it => it.name).join() : "" + } + }); + } + }); + }; + handleChangeColumnCheckBox = (key, value, id) => { + const { dataSource } = this.state; + this.setState({ + dataSource: _.map(dataSource, it => { + if (it.id === id) { + if (key !== "totalValue" && !!value && value !== "0") { + return { + ...it, + totalValue: Number(value), + [key]: Number(value) + }; + } + return { + ...it, + [key]: Number(value) + }; + } + return { ...it }; + }) + }); + }; + handleChangeColumnAllChecked = (key, val) => { + const { dataSource } = this.state; + this.setState({ + dataSource: _.map(dataSource, it => { + if (key !== "totalValue" && !!val && val !== "0") { + return { + ...it, + totalValue: Number(val), + [key]: Number(val) + }; + } + return { + ...it, + [key]: Number(val) + }; + }) + }); + }; + handleChangeColumnM2MValue = (key, value, id) => { + const { dataSource } = this.state; + this.setState({ + dataSource: _.map(dataSource, it => { + if (it.id === id) { + return { + ...it, + [key]: value + }; + } + return { ...it }; + }) + }); + }; + handleChangeStatisticalItems = (itemValue, _names, datas) => { + const { formData } = this.state; + this.setState({ + formData: { + ...formData, + itemValue, + itemValueSpan: _.map(datas, it => it.name).join(","), + itemName: datas.length === 1 ? _.map(datas, it => it.names).join(",") : "" + } + }); + }; + + render() { + const { loading, columns, dataSource, formData } = this.state; + const { itemName, itemValue, itemValueSpan } = formData; + const { statisticsItemId } = this.props; + const cols = _.map(columns, it => { + const { text, column } = it; + if (column === "ruleName" || column === "ratio" || column === "m2m" || column === "y2y") { + const key = column === "ruleName" ? "total" : column; + return { + ...it, + title: + !!child[`${key}Value`])} + onChange={val => this.handleChangeColumnAllChecked(`${key}Value`, val)} + /> + {text} + , + render: (txt, record) => { + return + this.handleChangeColumnCheckBox(`${key}Value`, val, record.id)} + /> + + {column === "ruleName" ? record["ruleName"] : text} + + ; + } + }; + } else if (column === "m2mLimit") { + return { + ...it, + title: + {text} + 10%,差值和增幅标记为红色,增幅<-10%标记为绿色")} + placement="top" width={200}/> + , + render: (txt, record) => { + return !!record["m2mValue"] && this.handleChangeColumnM2MValue(`${column.replace("Limit", "")}${type === "min" ? "LowerLimit" : "UpperLimit"}`, val, record.id)} + />; + } + }; + } else if (column === "y2yLimit") { + return { + ...it, + title: + {text} + 10%,差值和增幅标记为红色,增幅<-10%标记为绿色")} + placement="top" width={200}/> + , + render: (txt, record) => { + return !!record["y2yValue"] && this.handleChangeColumnM2MValue(`${column.replace("Limit", "")}${type === "min" ? "LowerLimit" : "UpperLimit"}`, val, record.id)} + />; + } + }; + } + }); + return ( + + {statisticsItemId ? getLabel(111, "编辑自定义统计项目") : getLabel(111, "新建自定义统计项目")} + +
+ } + style={{ width: 900, height: 450 }} + className="statisticItemsWrapper" + > +
+ + + ({ + id: it, + name: itemValueSpan.split(",")[idx] + })) : []} + completeParams={{ + type: 162, + fielddbtype: "browser.salaryItemBrowser", + f_weaver_belongto_usertype: "0" + }} + conditionDataParams={{ + type: "browser.salaryItemBrowser", + fielddbtype: "browser.salaryItemBrowser", + f_weaver_belongto_usertype: "0" + }} + dataParams={{ + type: "browser.salaryItemBrowser", + f_weaver_belongto_usertype: "0" + }} + destDataParams={{ + type: "browser.salaryItemBrowser", + f_weaver_belongto_usertype: "0" + }} + isMultCheckbox + inputStyle={{ width: "100%" }} + onChange={this.handleChangeStatisticalItems} + /> + + + + + this.setState({ formData: { ...formData, itemName } })}/> + + +
+ +
+
+ + ); + } +} + +export default CustomStatisticsItemsModal; +/* + * Author: 黎永顺 + * Description: 区间设置 + * Params: + * Date: 2023/4/23 + */ +const IntervalSettingsComp = (props) => { + const { LowerLimit, UpperLimit, onChange } = props; + return
+ onChange("min", val)}/> + {`% <${getLabel(111, "增幅")}<`} + onChange("max", val)}/> + % +
; +}; diff --git a/pc4mobx/hrmSalary/pages/reportView/components/index.less b/pc4mobx/hrmSalary/pages/reportView/components/index.less new file mode 100644 index 00000000..33c5aed0 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/reportView/components/index.less @@ -0,0 +1,50 @@ +.rangSettingWrapper { + .wea-search-group { + .wea-error, .wea-select, .ant-select, .ant-select-selection { + width: 100%; + } + } + + .ant-modal-content { + .wea-browser-single-icon-circle { + display: none; + } + + .wea-new-top-req-main { + border-radius: 10px; + background: transparent; + } + + .wea-new-top-req, .wea-new-top-req-title > div:last-child { + background: transparent; + } + + .wea-new-top-req-title { + & > div:first-child { + width: 216px !important; + + & > div:first-child { + max-width: 415px !important; + } + } + } + + .ant-col-22, .text-elli { + padding-left: 0 !important; + } + } + + .rangSettingItemTitle { + display: flex; + align-items: center; + + & > span { + margin-right: 8px; + } + } + + .extraCol { + display: flex; + align-items: center; + } +} diff --git a/pc4mobx/hrmSalary/pages/reportView/components/leftTab.js b/pc4mobx/hrmSalary/pages/reportView/components/leftTab.js new file mode 100644 index 00000000..c4c1494f --- /dev/null +++ b/pc4mobx/hrmSalary/pages/reportView/components/leftTab.js @@ -0,0 +1,83 @@ +/* + * Author: 黎永顺 + * name: 报表查看-左侧tab标题 + * Description: + * Date: 2023/4/20 + */ +import React, { Component } from "react"; +import { WeaInputSearch, WeaLocaleProvider } from "ecCom"; +import { reportStatisticsReportList } from "../../../apis/statistics"; +import { Menu } from "antd"; +import { getQueryString } from "../../../util/url"; +import "../index.less"; + + +const { getLabel } = WeaLocaleProvider; + +class LeftTab extends Component { + constructor(props) { + super(props); + this.state = { + reportName: "", + selectedKeys: getQueryString("id").split(","), + reportList: [] + }; + } + + componentDidMount() { + this.reportStatisticsReportList(); + } + + reportStatisticsReportList = () => { + const { reportName, selectedKeys } = this.state; + const { onChangeTab } = this.props; + reportStatisticsReportList({ reportName }).then(({ status, data: reportList }) => { + if (status) this.setState({ reportList }, () => { + onChangeTab(_.find(this.state.reportList, it => it.id === selectedKeys[0])); + }); + }); + }; + updateReportList = (report) => { + const { reportList } = this.state; + this.setState({ + reportList: _.reduce(reportList, (pre, cur) => { + if (report.id === cur.id) { + return [...pre, report]; + } + return [...pre, cur]; + }, []) + }); + }; + + render() { + const { reportName, selectedKeys, reportList } = this.state; + const { onChangeTab } = this.props; + return ( +
+
+ this.setState({ reportName })} + placeholder={getLabel(111, "请输入报表名称")} onSearch={this.reportStatisticsReportList} + /> +
+ { + this.setState({ selectedKeys: key.split(",") }, () => { + onChangeTab(_.find(reportList, it => it.id === key)); + }); + }} + > + { + _.map(reportList, item => { + const { reportName, id } = item; + return {reportName}; + }) + } + +
+ ); + } +} + +export default LeftTab; diff --git a/pc4mobx/hrmSalary/pages/reportView/components/reportContent.js b/pc4mobx/hrmSalary/pages/reportView/components/reportContent.js new file mode 100644 index 00000000..3e0747f2 --- /dev/null +++ b/pc4mobx/hrmSalary/pages/reportView/components/reportContent.js @@ -0,0 +1,256 @@ +/* + * Author: 黎永顺 + * name: 报表内容区 + * Description: + * Date: 2023/4/21 + */ +import React, { Component } from "react"; +import { Spin } from "antd"; +import { WeaEchart } from "ecCom"; +import RightOptions from "./rightOptions"; +import ChartsRangeSettingsModal from "./chartsRangeSettingsModal"; +import { mapBarOptions, mapLineOptions, mapPieOptions } from "./condition"; +import { queryRangeSetting, reportStatisticsReportGetData } from "../../../apis/statistics"; +import "../index.less"; + +class ReportContent extends Component { + constructor(props) { + super(props); + this.state = { + columns: [], + dataSource: [], + countResult: {}, + loading: false, + viewType: "dataView", + chartsType: "0", + chartsInfo: {}, + rangSet: { + visible: false, reportId: "", + rangeVal: {} + } + }; + } + + componentDidMount() { + window.addEventListener("message", this.handleReceive, false); + if (this.refs.chart) this.refs.chart.paint(); + } + + componentWillReceiveProps(nextProps, nextContext) { + if (nextProps.report !== this.props.report && nextProps.report.dimensionId) { + this.reportStatisticsReportGetData(nextProps.report.id, nextProps.report.dimensionId); + this.setState({ viewType: "dataView", chartsInfo: {} }); + } + } + + componentWillUnmount() { + window.removeEventListener("message", this.handleReceive, false); + } + + handleReceive = ({ data }) => { + const { type } = data; + if (type === "init") { + const { columns, countResult, dataSource } = this.state; + this.postMessageToChild({ + columns, countResult, dataSource, + showSum: !_.isEmpty(countResult) + }); + } else if (type === "turn") { + } + }; + postMessageToChild = (payload) => { + const childFrameObj = document.getElementById("atdTable"); + const { dataSource, columns, showSum, countResult } = payload; + childFrameObj && childFrameObj.contentWindow.postMessage(JSON.stringify({ + dataSource, columns, showSum, countResult + }), "*"); + }; + reportStatisticsReportGetData = (id, dimensionId) => { + const payload = { id, dimensionId }; + this.setState({ loading: true }); + reportStatisticsReportGetData(payload).then(({ status, data }) => { + this.setState({ loading: false }); + if (status) { + const { countResult, columns, pageInfo: { list } } = data; + this.setState({ + countResult, + columns: _.map(columns, it => ({ + ...it, + dataIndex: it.column, width: 150, + title: it.text, align: "center", + children: !_.isNil(it.children) ? _.map(it.children, child => ({ + ...child, + dataIndex: child.column, width: 150, + title: child.text, align: "center" + })) : [] + })), + dataSource: list || [] + }, () => { + this.postMessageToChild({ + columns: this.state.columns, countResult: this.state.countResult, + dataSource: this.state.dataSource, + showSum: !_.isEmpty(this.state.countResult) + }); + }); + } + }).catch(() => this.setState({ loading: false })); + }; + queryRangeSetting = (payload, isTab) => { + const { dataSource, columns } = this.state; + this.setState({ loading: true }); + queryRangeSetting(payload).then(({ status, data }) => { + this.setState({ loading: false }); + if (status) { + const { rangSet, viewType } = this.state; + const { itemValues, itemColValue, id } = data; + this.setState({ + rangSet: { + ...rangSet, + rangeVal: data + } + }); + if (id) { + if (!isTab) return; + switch (viewType) { + case "bar": + this.setState({ + chartsInfo: { + name: _.find(_.reduce(_.filter(columns, col => !_.isNil(col.children)), (pre, cur) => ([...pre, ...cur.children]), []), it => it.column === itemColValue).text, + xAxis: _.reduce(itemValues, (pre, cur) => ([...pre, _.find(columns, item => item.column === cur).text]), []), + data: _.map(dataSource, item => { + return { + name: item.dimension, + data: _.map(itemValues, child => { + const key = child + itemColValue.slice(_.indexOf(itemColValue, "_")); + return item[key] || "0"; + }) + }; + }) + } + }); + break; + case "line": + this.setState({ + chartsInfo: { + xAxis: _.map(dataSource, it => it.dimension), + data: _.map(itemValues, item => { + return { + name: `${_.find(_.reduce(_.filter(columns, col => !_.isNil(col.children)), (pre, cur) => ([...pre, ...cur.children]), []), it => it.column === itemColValue).text}(${_.find(columns, it => it.column === item).text})`, + data: _.map(dataSource, child => { + const key = item + itemColValue.slice(_.indexOf(itemColValue, "_")); + return child[key] || "0"; + }) + }; + }) + } + }); + break; + case "pie": + this.setState({ + chartsInfo: { + data: _.map(itemValues, item => { + return { + name: _.find(_.reduce(_.filter(columns, col => !_.isNil(col.children)), (pre, cur) => ([...pre, ...cur.children]), []), it => it.column === itemColValue).text, + data: _.map(dataSource, child => { + return { + name: child["dimension"], + value: child[itemColValue] + }; + }) + }; + }) + } + }); + break; + default: + break; + } + if (this.refs.chart) this.refs.chart.paint(); + } else { + this.setState({ chartsInfo: {} }); + } + } + }).catch(() => this.setState({ loading: false })); + }; + handleChangeChartOpts = (chartsType, viewType) => { + this.setState({ chartsInfo: {} }); + if (this.refs.chart && viewType !== "setting" && viewType !== "dataView" && !this.state.rangSet.visible) this.refs.chart.clear(); + const { report: { id: reportId, dimensionId } } = this.props; + const { rangSet } = this.state; + viewType !== "setting" && this.setState({ chartsType, viewType }, () => { + const { viewType, chartsType } = this.state; + viewType !== "dataView" ? + this.queryRangeSetting({ reportId, chartsType }, true) : + this.reportStatisticsReportGetData(reportId, dimensionId); + }); + viewType === "setting" && this.setState({ rangSet: { ...rangSet, visible: true, reportId } }, () => { + this.queryRangeSetting({ reportId, chartsType }); + }); + }; + handleCancel = () => { + this.setState({ + rangSet: { + visible: false, reportId: "", + rangeVal: {} + } + }); + }; + handleGetData = () => { + const { report } = this.props; + const { id, dimensionId } = report; + this.setState({ viewType: "dataView" }, () => this.reportStatisticsReportGetData(id, dimensionId)); + }; + renderCharts = () => { + const { chartsInfo, viewType } = this.state; + return _.isEmpty(chartsInfo) ? + : (viewType === "bar" || viewType === "line" || viewType === "pie") ? + : +
123
; + }; + + render() { + const { loading, viewType, rangSet, columns } = this.state; + return ( +
+
+ + { + viewType === "dataView" ? +