custom/领悦

This commit is contained in:
黎永顺 2024-09-03 16:19:42 +08:00
parent 4385b8c6b2
commit 64c56fc280
12 changed files with 501 additions and 14 deletions

View File

@ -0,0 +1,130 @@
/*
* 自定义浏览框组件
*
* @Author: 黎永顺
* @Date: 2024/8/29
* @Wechat:
* @Email: 971387674@qq.com
* @description:
*/
import React, { Component } from "react";
import { WeaLocaleProvider } from "ecCom";
import { Button, Icon, Select } from "antd";
import classNames from "classnames";
import { postFetch } from "../../../util/request";
const getLabel = WeaLocaleProvider.getLabel;
const Option = Select.Option;
class AssociativeSearchMult extends Component {
constructor(props) {
super(props);
this.state = {
loading: false, data: [], activeKey: "", dropdownWidth: 200
};
this.selectedData = {};
}
componentDidMount() {
const { dropdownWidth } = this.state;
const w = $(this.refs.searchWrapperMui).outerWidth();
if (dropdownWidth < w) {
this.setState({ dropdownWidth: w });
}
}
handleSearch = (value) => {
this.setState({ loading: true });
this.getData(value);
};
getData = (name = "") => {
const { completeURL = "/api/bs/hrmsalary/salarysob/listByTaxAgent" } = this.props;
if (_.trim(name)) {
postFetch(completeURL, { taxAgentId: "19", name }).then(({ status, data }) => {
this.setState({ loading: false });
if (status) {
this.setState({ data: _.map(data, o => ({ ...o, id: String(o.id) })), activeKey: this.getActiveKey(data) });
}
});
} else {
this.setState({ data: [], loading: false, activeKey: "" });
}
};
getActiveKey = (data) => {
const { selectedValues = [] } = this.props;
let v = "";
if (data && data.length > 0) {
let target = data.filter((d) => selectedValues.indexOf(d.id) === -1);
if (!_.isEmpty(target)) v = String(target[0].id);
}
return v;
};
getItemById = (id) => {
const { data } = this.state, { datas } = this.props;
if (datas[id]) return datas[id];
if (!_.isEmpty(data)) {
for (let i = 0; i < data.length; i++) {
if (id === data[i].id) return data[i];
}
}
};
handleChange = (values) => {
this.selectedData = {};
values.forEach((v) => {
let item = this.getItemById(v);
if (item) this.selectedData[v] = item;
});
this.props.onChange && this.props.onChange(values, this.selectedData);
this.setState({ activeKey: "" });
};
handleBlur = () => this.setState({ data: [], activeKey: "" });
handleClick = (e) => {
e && e.preventDefault();
const { datas, selectedValues } = this.props;
if (this.props.clickCallback) this.props.clickCallback(selectedValues, datas);
};
render() {
const { data, dropdownWidth } = this.state;
const { viewAttr, selectedValues, datas } = this.props;
const clsname = classNames({
"required": (viewAttr === 3 || viewAttr === "3") && _.isEmpty(selectedValues),
"mr12": viewAttr === "3" && _.isEmpty(selectedValues)
});
let options = data.map(d => <Option key={d.id} title={d.name}>{d.name}</Option>);
selectedValues && selectedValues.map((v) => {
v && options.unshift(<Option key={v} title={datas[v].name}>{datas[v].name}</Option>);
});
const select = <Select
{...this.props}
hasScroll={false}
hideSelected={true}
transitionName=""
animation=""
multiple={true}
notFoundContent=""
defaultActiveFirstOption={true}
showArrow={false}
filterOption={false}
defaultValue={selectedValues}
value={selectedValues}
dropdownStyle={{ minWidth: dropdownWidth }}
onSearch={_.debounce(this.handleSearch, 400)}
onChange={this.handleChange}
onBlur={this.handleBlur}
>
{options}
</Select>;
return (
<div className={`wea-associative-search wea-associative-search-mult ${clsname}`} ref="searchWrapperMui">
{select}
<Icon type="loading" style={{ display: this.state.loading ? "block" : "none" }}/>
<div className="ant-input-group-wrap">
<Button type="ghost" icon="search" onClick={this.handleClick}/>
</div>
</div>
);
}
}
export default AssociativeSearchMult;

View File

@ -0,0 +1,83 @@
/*
* 自定义浏览框组件
* 弹框选择
* @Author: 黎永顺
* @Date: 2024/8/30
* @Wechat:
* @Email: 971387674@qq.com
* @description:
*/
import React, { Component } from "react";
import { WeaDialog, WeaInputSearch, WeaLocaleProvider, WeaNewScroll } from "ecCom";
import { Button, Col, Row, Spin } from "antd";
import CustomBrowserMutiLeft from "./customBrowserMutiLeft";
import CustomBrowserMutiRight from "./customBrowserMutiRight";
import CustomBrowserOperation from "./customBrowserOperation";
import { postFetch } from "../../../util/request";
const getLabel = WeaLocaleProvider.getLabel;
class CustomBrowserDialog extends Component {
constructor(props) {
super(props);
this.state = {
loading: false, listDatas: []
};
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.visible !== this.props.visible) this.getData();
}
getData = (query = {}) => {
const { completeURL = "/api/bs/hrmsalary/salarysob/listByTaxAgent" } = this.props;
this.setState({ loading: true });
postFetch(completeURL, { taxAgentId: "19", ...query }).then(({ status, data }) => {
this.setState({ loading: false });
if (status) {
this.setState({ listDatas: _.map(data, o => ({ ...o, id: String(o.id) })) });
}
});
};
render() {
const { loading, listDatas } = this.state;
const sheight = this.dialog ? this.dialog.state.height - 55 : 260;
return (
<WeaDialog
{...this.props} initLoadCss ref={dom => this.dialog = dom} title={getLabel(111, "数据选择")}
className="custom_browser_dialog" style={{
width: 784, height: 460, minHeight: 200, minWidth: 380,
maxHeight: "90%", maxWidth: "90%", overflow: "hidden", transform: "translate(0px, 0px)"
}} buttons={[
<Button type="primary">{getLabel(111, "确 定")}</Button>,
<Button type="ghost">{getLabel(111, "清 除")}</Button>,
<Button type="ghost" onClick={this.props.onCancel}>{getLabel(111, "取 消")}</Button>]}>
<Spin spinning={loading}>
<div style={{ padding: 10, height: "100%" }}>
<div className="wea-hr-muti-input-left">
<Row style={{ height: 35 }}>
<Col span="24"> <WeaInputSearch/> </Col>
</Row>
<div>
<WeaNewScroll height={sheight}>
<CustomBrowserMutiLeft
datas={listDatas}
/>
</WeaNewScroll>
</div>
</div>
<div className="wea-transfer-opration">
<CustomBrowserOperation/>
</div>
<div className="wea-hr-muti-input-right">
<CustomBrowserMutiRight height={sheight}/>
</div>
</div>
</Spin>
</WeaDialog>
);
}
}
export default CustomBrowserDialog;

View File

@ -0,0 +1,41 @@
/*
* 自定义浏览框组件
* 选择框左边
* @Author: 黎永顺
* @Date: 2024/8/30
* @Wechat:
* @Email: 971387674@qq.com
* @description:
*/
import React, { Component } from "react";
import { WeaLocaleProvider } from "ecCom";
const getLabel = WeaLocaleProvider.getLabel;
class CustomBrowserMutiLeft extends Component {
render() {
const { datas } = this.props;
const list = datas.map(item => {
return <li>
<div className="item-wrap" style={{ fontSize: 12 }}> {item.name} </div>
<div className="icon-wrap"/>
<i className="icon-coms-Selected"/>
</li>;
});
return (
<div className="wea-crm-list">
<ul className="wea-crm-list-wrapper">
{list}
</ul>
{
list.length === 0 &&
<div className="empty-tip" style={{ color: "#2f2929", paddingTop: 30, textAlign: "center" }}>
{getLabel(111, "没有可显示的数据")}
</div>
}
</div>
);
}
}
export default CustomBrowserMutiLeft;

View File

@ -0,0 +1,43 @@
/*
* 自定义浏览框组件
* 选择框右边
* @Author: 黎永顺
* @Date: 2024/8/30
* @Wechat:
* @Email: 971387674@qq.com
* @description:
*/
import React, { Component } from "react";
import { WeaInputSearch, WeaLocaleProvider, WeaNewScroll } from "ecCom";
import { Tree } from "antd";
const getLabel = WeaLocaleProvider.getLabel;
const TreeNode = Tree.TreeNode;
class CustomBrowserMutiRight extends Component {
generateTreeNodes = () => {
};
render() {
const { height } = this.props;
return (
<div className="wea-transfer-right">
<WeaInputSearch/>
<div>
<WeaNewScroll height={height || 400}>
{/*<Tree className="transfer-tree"*/}
{/* draggable*/}
{/* multiple={true}*/}
{/* async={true}*/}
{/* selectable={true}>*/}
{/* {this.generateTreeNodes()}*/}
{/*</Tree>*/}
</WeaNewScroll>
</div>
</div>
);
}
}
export default CustomBrowserMutiRight;

View File

@ -0,0 +1,64 @@
/*
* 自定义浏览框组件
* 弹框操作栏
* @Author: 黎永顺
* @Date: 2024/8/30
* @Wechat:
* @Email: 971387674@qq.com
* @description:
*/
import React, { Component } from "react";
import { WeaLocaleProvider } from "ecCom";
import { Button } from "antd";
const getLabel = WeaLocaleProvider.getLabel;
class CustomBrowserOperation extends Component {
render() {
const {
moveToLeft,
moveToRight,
leftArrowText,
rightArrowText,
leftActive,
rightActive,
className,
leftAllActive,
moveAllToLeft,
rightAllActive,
moveAllToRight
} = this.props;
const moveToLeftButton = (
<Button type="primary" size="small" disabled={!rightActive} onClick={moveToRight}>
{<span><i className="icon-coms-Browse-box-Add-to"/></span>}
</Button>
);
const moveToRightButton = (
<Button type="primary" size="small" disabled={!leftActive} onClick={moveToLeft}>
{<span><i className="icon-coms-Browse-box-delete"/></span>}
</Button>
);
const moveAllToLeftButton = (
<Button type="primary" size="small" disabled={!leftAllActive} onClick={moveAllToRight}>
{<span><i className="icon-coms-Browse-box-add-all"/></span>}
</Button>
);
const moveAllToRightButton = (
<Button type="primary" size="small" disabled={!rightAllActive} onClick={moveAllToLeft}>
{<span><i className="icon-coms-Browse-box-Delete-all"/></span>}
</Button>
);
return (
<div className={className}>
{moveToLeftButton}
{moveToRightButton}
{moveAllToLeftButton}
{moveAllToRightButton}
</div>
);
}
}
export default CustomBrowserOperation;

View File

@ -0,0 +1,86 @@
/*
* 自定义浏览框组件
*
* @Author: 黎永顺
* @Date: 2024/8/29
* @Wechat:
* @Email: 971387674@qq.com
* @description:
*/
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTools } from "ecCom";
import AssociativeSearchMult from "./components/associativeSearchMult";
import CustomBrowserDialog from "./components/customBrowserDialog";
import classNames from "classnames";
import "./index.less";
const getLabel = WeaLocaleProvider.getLabel;
const getKey = WeaTools.getKey;
class Index extends Component {
constructor(props) {
super(props);
this.state = {
browserDialog: { visible: false },
selectedData: {}, searchKeys: [], // 搜索按钮选择的数据和keys
rightDatas: [] // 右侧展示的数据
};
}
renderSingle = () => {
return null;
};
renderMult = () => {
const { fieldConfig } = this.props;
const { selectedData, searchKeys } = this.state;
return (<div>
<AssociativeSearchMult
{...fieldConfig}
{...this.props}
datas={selectedData}
selectedValues={searchKeys}
onChange={this.onBrowerChangeHandler}
clickCallback={this.onBrowerClick}
/>
</div>);
};
onBrowerChangeHandler = (values, datas) => {
const { form, fieldConfig } = this.props;
this.setState({ searchKeys: values, selectedData: datas }, () => {
this.props.onChange && this.props.onChange(values.join(","));
if (form) {
form.updateFields({
[getKey(fieldConfig)]: { value: values.join(",") }
});
}
});
};
onBrowerClick = (keys, selectedObj) => {
if (_.isEmpty(keys)) {
this.setState({ searchKeys: [], selectedData: {}, rightDatas: [] });
}
this.setState({ browserDialog: { visible: true } });
};
render() {
const { browserDialog } = this.state;
const { isSingle, viewAttr, fieldConfig = {} } = this.props;
const { browserConditionParam = {} } = fieldConfig || {};
const className = classNames({
"wea-browser": true,
"wea-field-readonly": viewAttr === "1" || fieldConfig.viewAttr === "1"
});
const browser = (isSingle || browserConditionParam.isSingle) ? this.renderSingle() : this.renderMult();
const style = {};
if (this.props.resize) style.visibility = "hidden";
return (<React.Fragment>
<div className={`${className} ${this.props.className || ""}`} style={style}>{browser}</div>
<CustomBrowserDialog
{...browserDialog} {...browserConditionParam} {...this.props}
onCancel={() => this.setState({ browserDialog: { visible: false } })}/>
</React.Fragment>
);
}
}
export default Index;

View File

@ -0,0 +1,14 @@
.custom_browser_dialog {
.ant-spin-nested-loading, .ant-spin-container {
height: 100%;
}
.wea-input-focus {
height: 35px !important;
width: 100% !important;
input {
height: 100% !important;
}
}
}

View File

@ -1,7 +1,7 @@
import React, { Component } from "react";
import { inject, observer } from "mobx-react";
import { WeaDialog, WeaLocaleProvider } from "ecCom";
import { Button } from "antd";
import { Button, message } from "antd";
import { vouchersConditions } from "./conditions";
import { commonEnumList } from "../../../../apis/ruleconfig";
import { getSearchs } from "../../../../util";
@ -44,8 +44,16 @@ class GenerateVouchersDialog extends Component {
});
};
save = () => {
const { LYStore: { form }, ffgsqc, salaryMonth } = this.props;
const payload = { ...form.getFormParams(), ffgsqc, salaryMonth };
const { LYStore: { form }, ffgsqc, salaryMonth, ffgsqcLabel } = this.props;
const payload = { ...form.getFormParams(), salaryMonth, ffgsqc };
if (!salaryMonth) {
message.warning(getLabel(111, "薪资所属月参数不能为空"));
return;
}
if (!ffgsqc) {
message.warning(getLabel(111, `${ffgsqcLabel}参数不能为空`));
return;
}
form.validateForm().then(f => {
if (f.isValid) {
window.open(`/spa/hrmSalary/static/index.html#/main/hrmSalary/customPage_vouchers_lingyue?${convertToUrlString(payload)}`, "_blank");

View File

@ -36,7 +36,7 @@ class List extends Component {
this.state = {
dataSource: [], columns: [], pageInfo: { current: 1, pageSize: 10, total: 0 }, loading: false,
selectedRowKeys: [], sumDataSource: {}, payload: {}, visible: false,
voucherDialog: { visible: false }
voucherDialog: { visible: false, ffgsqcLabel: props.ffgsqcLabel }
};
this.handleDebounce = null;
}
@ -87,7 +87,7 @@ class List extends Component {
const { query, type, onInit } = this.props, { pageInfo, selectedRowKeys } = this.state;
const payload = { ...pageInfo, ...query };
this.setState({ loading: true });
interfaceType[type]["list"](payload).then(async ({ status, data }) => {
interfaceType[type]["list"](payload).then(async ({ status, data, errormsg }) => {
this.setState({ loading: false });
if (status) {
const { data: { sumRow: sumDataSource } } = isSum ?
@ -106,6 +106,8 @@ class List extends Component {
sumDataSource: this.state.sumDataSource, scrollHeight: !_.isEmpty(dataSource) ? 195 : 0
});
});
} else {
message.warning(errormsg);
}
});
};

View File

@ -38,7 +38,7 @@ class Index extends Component {
<Layout title={getLabel(111, "薪资汇总表")} query={query} onChange={this.handleLayoutChange}
listRef={this.listRef} isQuery={isQuery} lyAuth={lyAuth} ffgsqcLabel={getLabel(111, "发放公司全称")}>
<List query={query} isQuery={isQuery} type="salarySum" ref={dom => this.listRef = dom}
onInit={() => this.forceUpdate()}/>
onInit={() => this.forceUpdate()} ffgsqcLabel={getLabel(111, "发放公司全称")}/>
</Layout>
);
}

View File

@ -32,7 +32,7 @@ class Index extends Component {
<Layout title={getLabel(111, "社保公积金汇总表")} query={query} onChange={this.handleLayoutChange}
listRef={this.listRef} isQuery={isQuery} ffgsqcLabel={getLabel(111, "购买公司全称")}>
<List query={query} isQuery={isQuery} type="socialFundSum" ref={dom => this.listRef = dom}
onInit={() => this.forceUpdate()}/>
onInit={() => this.forceUpdate()} ffgsqcLabel={getLabel(111, "购买公司全称")}/>
</Layout>
);
}

View File

@ -10,9 +10,11 @@
import React, { Component } from "react";
import { WeaLocaleProvider, WeaTableEdit, WeaTop } from "ecCom";
import * as API from "../../../../apis/custom-apis/lingyue";
import { getURLParameters } from "../../../../util/url";
import { getQueryString, getURLParameters } from "../../../../util/url";
import CustomBrowser from "../../../../components/CustomBrowser";
const getLabel = WeaLocaleProvider.getLabel;
const pzlxEnum = ["0", "1", "2"];
class Index extends Component {
constructor(props) {
@ -27,19 +29,30 @@ class Index extends Component {
}
genAndPreveiw = () => {
const pzlx = getQueryString("pzlx");
this.setState({ loading: true });
const payload = { ...getURLParameters(window.location.hash) };
const payload = {
...getURLParameters(window.location.hash),
ffgsqc: decodeURI(getURLParameters(window.location.hash).ffgsqc)
};
API.genAndPreveiw(payload).then(({ status, data }) => {
this.setState({ loading: false });
if (status) {
const { columns, data: datas } = data;
this.setState({
datas, columns: columns.map(col => ({
title: col.text, dataIndex: col.column, key: col.column, width: col.width,
title: col.text, dataIndex: col.column, key: col.column, width: (100 / columns.length) + "%",
com: [
{ label: "", type: "INPUT", viewAttr: 1, key: col.column }
],
colSpan: 1
{
key: col.column, otherParams: { precision: 2 },
type: (col.column === "zy" || col.column === "kjkm") ? "INPUT" :
(col.column === "jfValue" || col.column === "dfValue") ? "INPUTNUMBER" : "custom",
viewAttr: !pzlxEnum.includes(pzlx) ? 2 : 1,
render: (text, record, index, onEdit) => {
return <CustomBrowser viewAttr={!pzlxEnum.includes(pzlx) ? 2 : 1}/>;
}
}
]
}))
});
}
@ -48,6 +61,7 @@ class Index extends Component {
render() {
const { datas, columns } = this.state;
const pzlx = getQueryString("pzlx");
return (
<WeaTop
title={getLabel(111, "凭证汇总表")} icon={<i className="icon-coms-fa"/>} buttons={[]} showDropIcon={false}
@ -55,8 +69,10 @@ class Index extends Component {
<div className="vouchers-body">
<WeaTableEdit
ref={el => this.tableEdit = el} showCopy={false} deleteConfirm
showAdd={!pzlxEnum.includes(pzlx)} showDelete={!pzlxEnum.includes(pzlx)}
columns={columns} datas={datas} onChange={datas => this.setState({ datas })}
getRowSelection={() => false} tableProps={{ scroll: { y: `calc(100vh - 174.58px)` } }}
getRowSelection={rowSelection => !pzlxEnum.includes(pzlx) ? rowSelection : false}
tableProps={{ scroll: { y: `calc(100vh - 174.58px)` } }}
/>
</div>
</WeaTop>