123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- import React,{Component} from 'react';
- import classNames from 'classnames';
- import config from '@config/index.js';
- import style from './index.less';
- import {deepClone,filterArr,handleEnter,isIE,getPageCoordinate,windowEventHandler,filterDataArr} from '@utils/tools.js';
- import {Notify} from '@commonComp';
- import ReactDom from "react-dom";
- import {getIds} from '@common/js/func.js';
- import $ from 'jquery';
- /****
- * 标签组合下拉,选中的项目展开
- * author:zn@2018-11-21
- * 接收参数:
- * keepSelf:展开标签后是否保留原标签
- * data:下拉内容
- * placeholder:灰显文字
- *
- * ***/
- class SpreadDrop extends Component{
- constructor(props){
- super(props);
- const {nones,noneOn,noneIds,withOn,exists,nowOn,withs,exclusion,excluName} = deepClone(props.selecteds||[]);
- this.state = {
- nones:nones||'', //无,字符串拼接
- exists:exists||[], //主症状id
- excluName:excluName||'',
- withs:withs||[], //伴随 id
- noneIds:noneIds||[],
- noneOn:noneOn||false, //无是否选中
- withOn:withOn||false, //伴是否选中
- nowOn:nowOn||'', //最近选中“无”还是“伴”
- exclusion:exclusion||'', //选中互斥项id
- timer:null, //延时,区分单击双击
- ban:{}, //放'伴'字段
- editable:false, //双击编辑
- labelVal:'', //存放标签原有的值--主诉字数限制用
- boxLeft:0,
- boxTop:0,
- tmpScroll:0,
- tmpTop:0,
- };
- this.$div = React.createRef();
- this.handleSelect = this.handleSelect.bind(this);
- this.clearState = this.clearState.bind(this);
- this.handleClear = this.handleClear.bind(this);
- this.handleShow = this.handleShow.bind(this);
- this.handleConfirm = this.handleConfirm.bind(this);
- this.changeToEdit = this.changeToEdit.bind(this);
- this.handleBlur = this.handleBlur.bind(this);
- this.onChange = this.onChange.bind(this);
- /*是否点击确定按钮标记,处理点击其他等同于确定操作bug,
- 如不区分确定按钮提交和点击其他提交,确定按钮提交后会多更新一次状态导致数据重复*/
- this.btnClickFlag = false;
- }
- handleShow(e){//单击
- e&&e.stopPropagation();
- // let boxLeft = e.pageX -175 + 'px';
- // let offsetTop = e.target.offsetTop;
- // const ht = e.target.offsetHeight; //如杂音选中文字有多行时,写死会遮挡
- // let boxTop = offsetTop + ht +2 + 'px';
- // this.setState({
- // boxLeft:boxLeft,
- // boxTop:boxTop
- // })
- this.setState({
- boxLeft:getPageCoordinate(e).boxLeft,
- boxTop:getPageCoordinate(e).boxTop,
- tmpScroll: $("#addScrollEvent")[0].scrollTop,
- tmpTop:getPageCoordinate(e).boxTop
- });
- windowEventHandler('scroll',()=>{ //弹窗跟随滚动条滚动或者关闭弹窗
- let scrollYs = $("#addScrollEvent")[0].scrollTop;
- this.setState({
- boxTop:this.state.tmpTop - scrollYs + this.state.tmpScroll
- })
- },$("#addScrollEvent")[0])
- // window.event? window.event.cancelBubble = true : e.stopPropagation();
- this.setStateInit(); //恢复初始选中状态
- const {ikey,handleShow,placeholder,flag,id,value,tagType,type} = this.props;
- const that = this;
- this.btnClickFlag = false;
- clearTimeout(this.state.timer);
- this.state.timer = setTimeout(function(){
- if (that.state.editable) {//如果处于编辑状态点击不显示下拉框
- return
- }else{
- handleShow&&handleShow({ikey,placeholder,flag,id,value,tagType,type});
- }
- },300)
- }
- changeToEdit(e){//双击
- const {value,id,placeholder,handleDbclick,handleHide} = this.props;
- let text = e.target.innerText;
- handleHide&&handleHide(); //展开情况下双击收起
- // clearTimeout(this.state.timer);//取消延时的单击事件
- e.stopPropagation();
- // e.preventDefault();
- if(value&&value.trim()){//有选中值的标签才能双击编辑
- this.setState({
- labelVal:text,
- editable:true
- });
- e.target.focus();
- handleDbclick && handleDbclick({value,id,placeholder});
- }
- }
- onChange(e){
- const {mainSaveText,ikey,type,handleLabelChange} = this.props;
- const {labelVal,editable} = this.state;
- let mainText = filterDataArr(mainSaveText);//主诉字数
- if(editable){//避免IE中点击标签也会触发
- let val = e.target.innerText;
- if(+type==1){// 主诉字数达到上限时不允许输入
- if(mainText.length >= config.limited){
- if(val.length > labelVal.length){
- e.target.innerText = labelVal;
- Notify.info(config.limitText);
- return
- }else if(val.length == labelVal.length){
- this.setState({
- labelVal:val
- });
- }else{
- handleLabelChange && handleLabelChange({ikey,changeVal:val,type});
- }
- }
- }
- }
- }
- handleBlur(e){
- e.stopPropagation();
- const {ikey,type,handleLabelChange} = this.props;
- const {editable} = this.state;
- const ev = e || window.event;
- if(editable){
- // 更改标签的value值
- let changeVal = ev.target.innerText;
- if(!isIE()){
- e.target.innerText = ''; //避免出现重复输入值
- }
- handleLabelChange && handleLabelChange({ikey,changeVal,type});
- }
- this.setState({
- editable:false
- });
- }
- setStateInit(){
- const {nones,noneOn,noneIds,withOn,exists,nowOn,withs,exclusion,excluName} = deepClone(this.props.selecteds||[]);
- this.setState({
- nones:nones||'',
- exists:exists||[],
- excluName:excluName||'',
- withs:withs||[],
- noneIds:noneIds||[],
- noneOn:noneOn||false,
- withOn:withOn||false,
- nowOn:nowOn||'',
- exclusion:exclusion||'',
- ban:{},
- });
- }
- clearState(){
- this.setState({
- nones:'',
- exists:[],
- //existsName:{},
- //withsName:{},
- withs:[],
- noneIds:[],
- noneOn:false,
- withOn:false,
- nowOn:'',
- exclusion:'',
- excluName:'',
- ban:{}
- });
- this.btnClickFlag = false;
- }
- handleClear(e){
- e.stopPropagation();
- this.clearState();
- }
- handleConfirm(e){
- e.stopPropagation();
- const {handleConfirm,ikey,type,tagType,order,mainSaveText,copyType,value} = this.props;
- const params = Object.assign({},this.state,{ikey,type,tagType,order,mainSaveText,copyType,value});
- handleConfirm&&handleConfirm(params);
- this.btnClickFlag = true;
- //点确定后隐藏弹窗
- this.props.handleHide();
- }
- handleSelect(item,isExclu,joint,listIndex,selected){
- let {withOn,withs,noneOn,exclusion,exists,nowOn,nones,noneIds,ban} = this.state;
- /*if(this.props.selecteds)
- console.log(exists,this.props.selecteds.exists,exists===this.props.selecteds.exists)*/
- const id = item.id;
- const linkStr = joint||'';
- const name = item.name+linkStr;
- if(isExclu){ //操作“互斥项”
- if([...noneIds,...exists,...withs].length>0){ //已选非互斥项,互斥项不可操作
- return;
- }
- let temp = '';
- if(exclusion==''){
- temp = id;
- }else if(exclusion!=''&&exclusion!==id){
- temp = exclusion;
- }
- this.setState({
- exclusion:temp,
- excluName:temp ===''?'':name
- });
- return;
- }
- //操作单选项
- if(selected){
- const tIndex= exists.findIndex((it)=>it.id===selected.id);
- if(tIndex!=-1){
- exists.splice(tIndex,1,{id,name,listIndex});
- this.setState({
- exists,
- })
- }
- return;
- }
- if(exclusion!==''){ //互斥项被选中,其他不可操作
- return;
- }
- if(+item.code===1){ //操作“伴”类型
- this.setState({
- withOn:!withOn,
- // withs:withOn?[]:[...withs,id], //取消“伴”选中,伴随症状全部取消选中
- // withs:withOn?[]:[...withs,{id:item.id,name:name}],
- withs:withOn?[]:withs,
- ban:withOn?{}:{id:id,name:name},
- //withsName:withOn?"":withsName+name, //取消“伴”选中,伴随症状全部取消选中
- nowOn:withOn?(noneOn?'none':''):'with'
- });
- return;
- }
- if(+item.code===2){ //操作“无”类型
- this.setState({
- noneOn:!noneOn,
- noneIds:noneOn?[]:[...noneIds,id],
- nones:noneOn?'':name,
- nowOn:noneOn?(withOn?'with':''):'none'
- });
- return;
- }
- //操作普通项
- let existsIds = exists.length>0? getIds(exists):[];
- let withsIds = withs.length>0? getIds(withs):[];
- if(existsIds.includes(id)){
- let existsData = exists;
- exists.forEach((it,i)=>{
- if(it.id==id){
- existsData.splice(i,1);
- }
- })
- exists = existsData;
- }else if(noneIds.includes(id)){
- nones = nones.replace(name+'、','');
- noneIds.splice(noneIds.indexOf(id),1);
- }else if(withsIds.includes(id)){
- let withsData = withs;
- withs.forEach((it,i)=>{
- if(it.id==id){
- withsData.splice(i,1);
- }
- })
- withs = withsData;
- }else{ //选中普通项
- if(nowOn=='none'){
- nones += name+'、';
- noneIds.push(id);
- }else if(nowOn=='with'){
- withs.push({id:id,name:name});
- }else{
- exists.push({id:id,name:name,listIndex});
- }
- }
- this.setState({
- nones,
- noneIds,
- exists,
- withs,
- ban
- //existsName,
- //withsName,
- });
- }
- getClass(){
- const blueBorder = this.state.editable?style['blue-border']:'';
- if(this.props.show){
- $(this.$div.current).addClass(style['borderd']);
- }else{
- $(this.$div.current).removeClass(style['borderd']);
- }
- if(this.props.value){
- return classNames(style['selected-tag'],blueBorder);
- }
- return style['tag'];
- }
- componentDidMount(){
- if(isIE()){
- $(this.$div.current).onIe8Input(function(e){
- this.onChange(e)
- },this);
- }
- }
- render(){
- const {placeholder,value,show,data} = this.props;
- const {editable,boxLeft,boxTop} = this.state;
- return <div className={style['container']}
- onFocus={(e)=>e.stopPropagation()}
- onBlur={(e)=>e.stopPropagation()}
- onInput={(e)=>e.stopPropagation()}>
- <div
- ref={this.$div}
- onClick={this.handleShow}
- className={this.getClass()}
- contentEditable={editable}
- onDoubleClick={this.changeToEdit}
- onBlur={this.handleBlur}
- onInput={this.onChange}
- onkeydown={handleEnter}
- >{value||placeholder}</div>
- <ListItems data={data} left={boxLeft}
- top={boxTop} show={show} handleSelect={this.handleSelect} handleConfirm={this.handleConfirm} handleClear={this.handleClear} {...this.state}></ListItems>
- </div>
- }
- }
- class ListItems extends Component{
- constructor(props){
- super(props);
- }
- getLabels(){
- const {data,handleSelect} = this.props;
- let detail = [];
- let isSpecialPos = false; //是否特殊位置(单行在上面,如无殊)
- let isExclu = false; //是否与其他互斥
- let isRadio; //是否为单选列,默认多选列
- const list = data&&data.map((it,i)=>{
- isSpecialPos = (+it.formPosition === 1);
- isExclu = (+it.exclusionType===1);
- isRadio = (+it.tagType ===1&&+it.controlType === 1);
- if(+it.controlType===0){
- detail = it.questionMapping;
- }else{
- detail = it.questionDetailList;
- }
- return <ListItem datas={detail}
- isRadio={isRadio}
- joint={it.joint}
- listIndex={i}
- isSpecialPos={isSpecialPos}
- isExclu={isExclu}
- handleClick={handleSelect}
- {...this.props}></ListItem>;
- });
- return list;
- }
- getStyle(){
- const {left,top,show} = this.props;
- return {
- left:left?left+'px':'',
- top:top?top+'px':'',
- display:show?'block':'none'
- }
- }
- render (){
- const {handleClear,handleConfirm} = this.props;
- const domNode = document.getElementById('root');
- return ReactDom.createPortal(
- <div className={style["drop-list"]} style={this.getStyle()} contentEditable="false" onClick={(e)=>{e.stopPropagation();}}>
- {this.getLabels()}
- <div className="oper">
- <span className={style['clear']} onClick={handleClear}>清空选项</span>
- <span className={style['confirm']} onClick={handleConfirm}>确定</span>
- </div>
- </div>
- ,domNode)
- }
- }
- class ListItem extends Component{
- constructor(props){
- super(props);
- }
- handleClick(e,item,i){
- e.stopPropagation();
- // window.event? window.event.cancelBubble = true : e.stopPropagation();
- const {handleClick,isExclu,isRadio,data,exists,noneIds,withs,joint,listIndex} = this.props;
- const index=listIndex+''+i;
- //列单选处理
- if(isRadio){
- const selected = data.find((it)=>{
- return exists.findIndex((i)=>i.id===it.id)!==-1||noneIds.includes(it.id)||withs.findIndex((i)=>i.id===it.id)!==-1;
- });
- if(selected&&selected.id!=item.id){ //该列已有选中项,传回已选中的id,name取消选中
- handleClick&&handleClick(item,isExclu,joint,index,{id:selected.id,name:selected.name});
- }else{
- handleClick&&handleClick(item,isExclu,joint,index);
- }
- return;
- }
- handleClick&&handleClick(item,isExclu,joint,index);
- }
- getClass(id){ //无之后显示黑色,之前显示蓝色
- const {exclusion,nones,noneIds,exists,withs,isExclu,ban} = this.props;
- if(exclusion!=''){
- if(+id===+exclusion){
- return style['selected'];
- }else{
- return style['exclusion'];
- }
- }else{
- if(isExclu&&[...noneIds,...exists,...withs].length>0){
- return style['exclusion'];
- }
- if(noneIds.includes(id)){
- return style['none-selected'];
- }
- let existsIds = getIds(exists);
- let withsIds = getIds(withs);
- // if(existsIds.includes(id)||withsIds.includes(id)){
- if(existsIds.includes(id)||withsIds.includes(id)||ban.id && ban.id==id){
- return style['selected'];
- }
- return '';
- }
- }
- render(){
- const {datas,isSpecialPos} = this.props;
- const pos = isSpecialPos?style['independent']:'';
- return <ul className={classNames(style['row'],pos)} onBlur={(e)=>e.stopPropagation()}>
- {datas&&datas.map((it,i)=>{
- /*return <li onClick={(e)=>this.handleClick(e,it,i)}
- className={this.getClass(it.id)}>{it.labelPrefix}{it.name}{it.labelSuffix}</li>*/
- return <li onClick={(e)=>this.handleClick(e,it,i)} className={this.getClass(it.id)} title={it.name.length>8?it.name:''}>{it.name&&it.name.length>8?it.name.slice(0,8)+'...':it.name}</li>
- })}
- </ul>;
- }
- }
- export default SpreadDrop;
|