Skip to content

Instantly share code, notes, and snippets.

@daniilgrigoryev
Created August 1, 2019 10:18
Show Gist options
  • Select an option

  • Save daniilgrigoryev/e11bc9302a20507d612c04548a08e7ac to your computer and use it in GitHub Desktop.

Select an option

Save daniilgrigoryev/e11bc9302a20507d612c04548a08e7ac to your computer and use it in GitHub Desktop.
Из ребенка в родитель
import React, {Component} from 'react';
import {compose} from 'redux'
import {FieldArray, reduxForm} from 'redux-form/immutable'
import AppealTable from './table.js'
import {getSessionId} from '../../selectors/common.js'
import {connect} from 'react-redux'
import {Button, Input, Card, Layout} from 'element-react'
import {post} from '../../services/ajax.js'
import {appealLoad} from '../../actions/common.js'
import Immutable from 'immutable'
import {relocate} from '../app/app.js'
import {EInput} from '../components/finput.js'
import {ESelect} from '../components/select.js'
import {EAutocomplete} from '../components/fautocomplete.js'
import {EPicker} from '../components/picker.js'
import {SearchRoot} from '../components/searchRoot.js'
import map from '../../markup/appeal/mapping.js'
import {baseUrl} from '../../services/api.js'
import * as _ from 'lodash'
import {messageSet} from '../../actions/common.js'
import { timingSafeEqual } from 'crypto';
const MS = map.status;
const MB = map.basicData;
const MC = map.claimantData;
const timeOfs = new Date().getTimezoneOffset() * 60 * 1000;
const im = (obj) => Immutable.fromJS(obj)
const desc = {
info_alias: 'i_obr',
alias: null // 'APPEAL_LIST' or 'APPEAL_LIST_MY'
}
const style = {textAlign: 'center', width: '8em'};
const mapping = {
REG_NUM: 'Регистрационный номер',
DATE_REG: 'Дата регистрации',
//DATE_CONTROL:'Дата контроля',
NAME: 'Заявитель',
FP_NAME: 'Физ. лицо',
JP_NAME: 'ЮЛ наименование',
STAGE: 'Статус',
ISP_NAME: 'Исполнитель',
ISP_OTD: 'Отдел'
}
const templating = {};
const condKey = 'i_obr'
class AppealExplorer extends React.Component {
constructor(props) {
super(props);
const fields = []
this.state = {fields};
this.where = {};
this.key = 0;
this.registerGetSelected = this.registerGetSelected.bind(this);
this.conditionGetter = null;
this.dataFromChild = null;
this.conditionRemover = null;
this.search = this.search.bind(this);
this.searchMy = this.searchMy.bind(this);
this.getXFile = this.getXFile.bind(this);
this.remove = this.remove.bind(this);
this.checkRemoteCommands = this.checkRemoteCommands.bind(this);
}
componentDidMount(){
this.checkRemoteCommands();
}
async checkRemoteCommands(){
const alias='TABLE_INFO';
const table_alias= 'i_obr';
const orphan = true;
const CS = sessionStorage.getItem('claim_show');
sessionStorage.removeItem('claim_show');
if (CS){ // есть внешний запрос на показ Обращения
const {claim_id,theme_id} = JSON.parse(CS);
if (claim_id){
sessionStorage.setItem('show_theme',theme_id);
this.openRow({ID:claim_id},true)();
} else if (theme_id) {
const alias = 'GET_CLAIM_ID_BY_THEME';
const x = await post('db/select', {alias, theme_id,orphan})
const claim_id = parseInt(x.data);
if (!isNaN(claim_id)){
sessionStorage.setItem('show_theme',theme_id);
this.openRow({ID:claim_id},true)();
}
}
} else { // внешнего запроса нет - показ таблицы
const x = await post('db/select',{alias,table_alias,orphan});
const {data,error} = x;
if (_.size(data)){
this.setState({fields:data});
}
}
}
openRow(rowData, holdTab) {
const {dispatch, change, initialize, sid} = this.props;
const alias = 'CLAIM_GET';
const orphan = true;
return async () => {
const claim_id = rowData.ID;
const x = await post('db/select', {alias, claim_id,orphan});
dispatch(initialize(im(x.data)));
if (holdTab){
relocate('appeal_incoming');
} else {
const key = window.stateSave();
const href = window.location.href.replace('/explore',`/appeal_incoming&storageKey=${key}`);
window.open(href,'_blank');
}
}
}
search() {
const s = this.conditionGetter();
const w = _.chain(s).filter(x=>x.value || x.oper=='NOT NULL' || x.oper=='NULL').value();
if (!_.size(w)){
this.key=0;
window.claimMessageAdd('E','Условие для поиска не задано');
this.forceUpdate();
return;
}
desc.alias = 'APPEAL_LIST';
this.where = w;
this.key = 'k' + new Date().getTime();
this.forceUpdate();
}
searchMy(){
const s = this.conditionGetter();
const w = _.chain(s).filter(x=>x.value || x.oper=='NOT NULL' || x.oper=='NULL').value();
desc.alias = 'APPEAL_LIST_MY';
this.where = w;
this.key = 'k' + new Date().getTime();
this.forceUpdate();
}
remove() {
const rlyRem = window.confirm('Вы уверены, что хотите очистить условия?');
if (!rlyRem) {
return;
}
this.conditionRemover();
}
getXFile() {
const alias = 'I_CLAIM_EXCEL_LIST';
const {sid} = this.props;
const selected = this.getSelected();
if (_.isEmpty(selected)) {
const msg = 'Ни одна запись не выбрана';
messageSet(msg, 'error');
console.error(msg);
return;
}
const doc_ids = '{'+(selected||[]).map(x=>x.ID).join(',')+'}';
const params = new URLSearchParams();
params.append('sessionId',sid);
params.append('doc_ids', doc_ids);
params.append('alias', alias);
const path = 'xls/fill?';
const tempLink = document.createElement('a');
var event = document.createEvent('MouseEvents');
event.initMouseEvent(
'click', true, false, window, 0, 0, 0, 0, 0
, false, false, false, false, 0, null
);
tempLink.href = baseUrl() + path + params.toString();
tempLink.setAttribute('download', 'test.xls');
tempLink.dispatchEvent(event);
setTimeout(()=>(tempLink && (tempLink.remove())),5000);
}
registerGetSelected(outerGetSelected) {
this.getSelected = outerGetSelected;
this.forceUpdate();
}
render() {
const {key,where,state,registerGetSelected, remove} = this;
const {fields} = state;
const noTable = this.key == 0;
const {sid} = this.props;
templating['REG_NUM'] = (rowData, column) => (<a onClick={this.openRow(rowData)}>{rowData.REG_NUM}</a>); //
const actionCol = null && {style, body};
const setGetter = (getter) => this.conditionGetter = getter;
const setRemover = (remover) => this.conditionRemover = remover;
const myCallback = (dataFromChild) => this.dataFromChild = dataFromChild;
return (<React.Fragment>
<Card className="box-card sectionCard" header={
<div className="headline">
<h3>Поиск обращений</h3>
</div>
}>
<SearchRoot {...{fields,setGetter,setRemover,condKey}} callbackFromParent={this.myCallback}/>
<div className='btns align-t mt18'>
<Button className="txt-middle mx6" type="primary" icon="search" onClick={this.search}>Поиск</Button>
<Button className="txt-middle mx6" type="primary" icon="search" onClick={this.searchMy}>Поиск среди своих</Button>
{!noTable && (<Button className="txt-middle mx6" type="primary" onClick={this.getXFile}>xls</Button>)}
<Button size="small" className="txt-middle color-darken75 opacity50 opacity100-on-hover" type="text" onClick={remove}>
<i className="ico load align-t mr12"/>
<span>Очистить</span>
</Button>
</div>
</Card>
{ noTable ? <div className='mt60'><h3 className='txt-h3 align-center color-darken10'>Нет результатов поиска</h3></div>
: <Card className="box-card" bodyStyle={{ padding: '0' }}>
<AppealTable {...{key,sid,desc,actionCol,mapping,templating,where, registerGetSelected}} hdelta={'420'} selectable={true} />
</Card>}
</React.Fragment>);
} //
}
const state2props = (state) =>({sid: getSessionId(state)})
export default compose(
connect(state2props),
reduxForm({
form: 'appeal', // <------ same form name
destroyOnUnmount: false, // <------ preserve form data
forceUnregisterOnUnmount: true, // <------ unregister fields on unmount
enableReinitialize: true
//validate
})
)(AppealExplorer)
import React, {Component} from 'react';
import {EInput} from './finput.js'
import {ESelect} from './select.js'
import {EPicker} from './picker.js'
import {ECheckbox} from './checkbox.js'
import {Button} from 'element-react'
import {Field, reduxForm} from 'redux-form/immutable'
import {messageSet} from '../../actions/common.js'
import positions from 'positions'
// import '../../../scss/searchRoot.scss'
import '../../../scss/index.scss';
const SearchRow = (props)=>{
const {im,change,remove,label,typ,dict,root,link,oper,i} = props;
let {value} = props;
const nullable =(oper=='NULL' || oper=='NOT NULL');
let Row = <EInput {...{value}} onChange={(e)=>change(i,'value',e)}/>;
if (nullable){
Row = <span />;
} else if (!!dict){
Row= <ESelect {...{value}} onChange={(e)=>change(i,'value',e)} dataKey={dict} />;
} else if (typ=='N'){
Row = <EInput {...{value}} onChange={(e)=>change(i,'value',e)} type="number"/>;
} else if (typ=='D'){
Row = <EPicker className="w60" {...{value}} onChange={(e)=>change(i,'value',e)} datepicker='+'/>;
} else if (typ=='B'){
Row = <ECheckbox {...{value}} onChange={(e)=>change(i,'value',e)} />
} //
return (
<div className="row">
<div className="column">
<div className="value">
<EInput value={label} className="readOnly" readOnly/>
</div>
</div>
<div className="column">
<div className="value">
<div className="select-container">
{oper && <select className="select bg-white"
value={oper}
onChange={(evt)=>change(i,'oper',evt.target.value)}>
<option value="=">=</option>
<option value=">=">&gt;=</option>
<option value=">">&gt;</option>
<option value="<=">&lt;=</option>
<option value="<">&lt;</option>
<option value="<>">&lt;&gt;</option>
<option value="NULL">NULL</option>
<option value="NOT NULL">NOT NULL</option>
<option value="LIKE">Контекст</option>
</select>}
<div className='select-arrow'></div>
</div>
</div>
</div>
<div className="column">
<div className="value fixedDropDown">
{Row}
</div>
</div>
<div className="column column--end">
<div className="value mt0">
<Button className="py0" size="small" type="text" onClick={()=>remove(i)}>
<i className="ico round minus"/>
</Button>
{/* {disabled ? null :
<Button className="py0" size="small" type="text" onClick={add}>
<i className="ico round plus"/>
</Button>
} */}
</div>
</div>
</div>);
} //
class SearchRoot extends React.Component {
constructor(props){
super(props);
this.scrollElement = null;
this.state = {
root :[],
defCondName : '',
conditionName : '',
conditionsLables : [],
showSavePort : false,
showLoadPort : false
};
this.change = this.change.bind(this);
this.remove = this.remove.bind(this);
this.add = this.add.bind(this);
this.saveCondition = this.saveCondition.bind(this)
this.loadCondition = this.loadCondition.bind(this)
this.setName = this.setName.bind(this);
this.retPort = this.retPort.bind(this);
this.changeSavePort = this.changeSavePort.bind(this);
this.changeLoadPort = this.changeLoadPort.bind(this);
this.setDefaultCondition = this.setDefaultCondition.bind(this);
this.deleteCondition = this.deleteCondition.bind(this);
this.removeAll = this.removeAll.bind(this);
}
componentDidMount(){
const {setGetter, setRemover} = this.props;
if (typeof setGetter == 'function'){
setGetter(()=>(this.state.root));
}
if (typeof setRemover == 'function') {
setRemover(this.removeAll);
}
const conditions = this.getConditions();
const defaultConditionKey = this.getDefaultConditionKey();
const defaultCondition = conditions[defaultConditionKey];
this.setState ({
conditionsLables :_.keys(conditions),
root : defaultCondition ? defaultCondition : [],
conditionName : defaultConditionKey,
defCondName : defaultConditionKey
});
}
change(key,field,evt){
const {root} = this.state;
root[key][field]=evt
this.setState({root});
}
remove(key){
const root = this.state.root.filter((x,i)=>i!=key);
let {showSavePort, showLoadPort, conditionName} = this.state;
if (_.isEmpty(root)) {
showSavePort = false;
showLoadPort = false;
conditionName = '';
}
this.setState({showSavePort, showLoadPort, conditionName, root});
}
removeAll() {
this.setState({
showSavePort : false,
showLoadPort : false,
conditionName : '',
root : []
});
}
add(fieldLabel){
const {fields} = this.props;
let {root} = this.state;
const field = fields.filter(x=>x.label==fieldLabel)[0];
let oper = field.typ=='S'? 'LIKE' : '=';
if (oper=='ARRAY_LONG' || oper=='ARRAY_STR'){
oper = null;
}
const row = Object.assign({oper,value:''},field);
root = [...root,row];
this.setState({root},()=>{
setTimeout((this.scrollElement.scrollTop=this.scrollElement.scrollHeight), 0);
});
this.props.callbackFromParent();
}
getConditions() {
const {condKey} = this.props
try {
const serializedState = localStorage.getItem(condKey);
if (serializedState) {
return JSON.parse(serializedState);
}
} catch (err) {
}
return {};
}
getDefaultConditionKey() {
const {condKey} = this.props
try {
const cKey = localStorage.getItem(condKey+'_key');
if (cKey) {
return cKey;
}
} catch (err) {
}
return '';
}
saveCondition() {
if (this.hasErrors()) {
return;
}
const {root, conditionName} = this.state;
const {condKey} = this.props
const conditions = this.getConditions();
if (conditions[conditionName]){
messageSet('Условие перезаписано', 'info');
}
conditions[conditionName] = root;
const serializedCond = JSON.stringify(conditions);
localStorage.setItem(condKey, serializedCond);
this.setState({
showSavePort : false,
conditionsLables : _.keys(conditions),
conditionName : conditionName
})
}
loadCondition(condName) {
const conditionName = !condName ? '' : condName;
let {root} = this.state
const {condKey} = this.props
const conditions = this.getConditions();
if (conditions && !_.isEmpty(conditions[conditionName])) {
root = conditions[conditionName];
}
this.setState({conditionName, root});
}
deleteCondition() {
const rlyDel = window.confirm('Вы уверены, что хотите удалить условие?');
if (this.hasErrors() || !rlyDel) {
return;
}
const {root, conditionName, defCondName} = this.state;
const {condKey} = this.props
const conditions = this.getConditions();
let defCond = defCondName;
if (conditionName == defCondName) {
localStorage.removeItem(condKey+'_key')
defCond = '';
}
delete conditions[conditionName];
const serializedCond = JSON.stringify(conditions);
localStorage.setItem(condKey, serializedCond);
this.setState({
root : [],
conditionsLables : _.keys(conditions),
conditionName : '',
defCondName : defCond
});
}
hasErrors() {
const {root, conditionName} = this.state;
let msg = null;
if (_.isEmpty((conditionName||'').trim())) {
msg = 'Необходимо указать название';
} else if (!root || _.isEmpty(root)) {
msg = 'Необходимо указать условие'
}
if (!msg) {
return false;
}
messageSet(msg, 'error');
console.error(msg);
return true;
}
setDefaultCondition() {
const {conditionName, defCondName, conditionsLables} = this.state;
const {condKey} = this.props
if (this.hasErrors() || conditionName == defCondName) {
return;
}
const conditions = _.without(conditionsLables, conditionName);
conditions.unshift(conditionName);
this.setState({defCondName : conditionName, conditionsLables : conditions});
localStorage.setItem(condKey+'_key', conditionName);
messageSet('Установлено по умолчанию', 'info');
}
setName(conditionName) {
this.setState({conditionName});
}
changeLoadPort() {
this.setState({
showLoadPort: !this.state.showLoadPort,
showSavePort: false
});
}
changeSavePort() {
this.setState({
showSavePort: !this.state.showSavePort,
showLoadPort: false
});
}
retPort() {
const {loadCondition, changeLoadPort, saveCondition, changeSavePort, setDefaultCondition, deleteCondition, setName} = this;
const {conditionName, conditionsLables, showLoadPort, showSavePort, defCondName} = this.state;
const notDefaultCondition = !defCondName || conditionName != defCondName
if (showLoadPort || showSavePort) {
const INNER = showLoadPort
?(<React.Fragment>
<ESelect key={conditionName} value={conditionName} onChange={(v) => loadCondition(v)} data={conditionsLables}/>
<Button size="small" className="mx6" type="danger" onClick={deleteCondition}>Удалить</Button>
</React.Fragment>)
:(<React.Fragment>
<EInput value={conditionName} onChange={(v)=>setName(v)} />
<Button size="small" className="mx6" type="primary" onClick={saveCondition}>Сохранить</Button>
</React.Fragment>); //
return(
<div className="flex-table ml0">
<div className="row">
<div className="column">
<div className="label">
Сохраненные настройки поиска
</div>
<div className="value">
<div className="flex-parent flex-parent--center-cross">
{INNER}
<Button size="small" className="mx6" type="text" onClick={showLoadPort?changeLoadPort:changeSavePort}>отмена</Button>
</div>
<a className={`link txt-petite ml3 ${notDefaultCondition ? 'default' : 'txt-underline txt-bold'}`} onClick={setDefaultCondition}>
{notDefaultCondition ? "Установить по умолчанию" : "Установлено по умолчанию"}
</a>
</div>
</div>
</div>
</div>);
}
return null;//
}
render() {
const {change, remove, add, changeSavePort, changeLoadPort} = this;
const {root} = this.state;
const {fields,condKey} = this.props;
const showSaveBtn = root && !_.isEmpty(root);
let ADD = fields.map(x=><option key={x.label} value={x.label}>{x.label}</option>);
ADD = [<option key='000' value='000'>Добавить поле</option>,...ADD]; //
const showPort = this.retPort();
return (
<React.Fragment>
<div className="searchRoot">
<div className="panel">
<div>
<div className="searchRoot-item searchRoot__add">
<div className="wrap">
<div className="item item--full mb6">
<small className="label">Добавить поле для поиска</small>
<div className="value">
<div className="select-container bg-white">
<select className="select" value='000' onChange={(evt)=>add(evt.target.value)}>{ADD}</select>
<div className='select-arrow'></div>
</div>
</div>
</div>
</div>
</div>
<div className="searchRoot-item searchRoot__control" ref={el => (this.scrollElement = el) }>
<div className="flex-table ml0">
{root.map((x,i)=><SearchRow {...x} {...{change,remove,i}} />)}
</div>
</div>
</div>
<div className="searchRoot-item searchRoot__saver">
{!condKey ? null: <div className="flex-parent flex-parent--center-cross">
<Button size="small" onClick={changeLoadPort}>Загрузить условие</Button>
{showSaveBtn && <Button size="small" onClick={changeSavePort}>Сохранить условие</Button>}
</div>}
{showPort}
</div>
</div>
</div>
</React.Fragment>
);//
}
}
export {SearchRoot}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment