index.jsx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. import React from 'react';
  2. import style from './index.less';
  3. import chronicPic from "../../common/images/chronic.png";
  4. import level1 from "../../common/images/级别1.png";
  5. import tableIcon from '@common/images/table.png';
  6. import allTableIcon from '@common/images/all-table.png';
  7. import checkIcon from '@common/images/check.png';
  8. import up from '@common/images/slide-up.png';
  9. import down from '@common/images/slide-down.png';
  10. import {ComplexModal,ConfirmModal,MiniToast, Radio,CheckBtn,Footer,Notify} from '@commonComp';
  11. import infoShow from '@common/images/info-show.png';
  12. import infoMove from '@common/images/info-move.png';
  13. import ScaleTable from '@containers/ScaleTable';
  14. import {deepClone} from '@utils/tools';
  15. import $ from 'jquery';
  16. import config from '@config/index';
  17. /***
  18. 慢病右侧推送模块规则:
  19. 慢病--显示慢病名称以及管理和评估
  20. 普通病--不显示管理和评估和量表按钮
  21. 明细--量表-计算公式-核心指标
  22. controlType:0-radio 1-checkbox 2-text 3-dropdownlist
  23. **/
  24. class ChronicInfo extends React.Component{
  25. constructor(props){
  26. super(props);
  27. this.state = {
  28. show:true,
  29. showInfo:false,
  30. showOption:false,
  31. showAssess:false, //评估弹窗
  32. infoId:null, //静态知识
  33. formulaId:null, //计算公式
  34. optionId:null, //可能结果,
  35. isAssessConfirm:false, //是否点击评估弹窗确定按钮
  36. radioVal:{}, //可能结果选择内容
  37. possible:{}, //可能结果
  38. formulaParam: {}, //量表计算公式计算入参
  39. isCalculated:false, //是否刚计算过,关闭时值与结果对应
  40. calcuValues:deepClone(props.calcuValues), //计算公式填的值
  41. hasEnterImg: false, //是否移入info
  42. currentIndex: -1, //当前index
  43. comfirnFlag:false,
  44. flag:true,
  45. ff:false,
  46. timer:null,
  47. scaleParam:{}, //加入病例需要的参数
  48. };
  49. this.$result = React.createRef();
  50. this.$content = React.createRef();
  51. this.showInfo = this.showInfo.bind(this);
  52. this.closeInfo = this.closeInfo.bind(this);
  53. this.showOption = this.showOption.bind(this);
  54. this.closeOption = this.closeOption.bind(this);
  55. this.showTable = this.showTable.bind(this);//显示量表弹窗
  56. this.closeTable = this.closeTable.bind(this);//关闭量表弹窗
  57. this.showFormula = this.showFormula.bind(this); //打开计算公式
  58. this.handleAddAssessItem = this.handleAddAssessItem.bind(this); //加入病例记录
  59. this.onPrint = this.onPrint.bind(this);
  60. this.handleForRadio = this.handleForRadio.bind(this);
  61. this.handleSaveCalcu = this.handleSaveCalcu.bind(this); //保存评估修改的计算和可能结果
  62. this.slideToggle = this.slideToggle.bind(this);
  63. this.resetComfirnFlag = this.resetComfirnFlag.bind(this);
  64. this.slideToggle = this.slideToggle.bind(this);
  65. this.comfirnTable = this.comfirnTable.bind(this);
  66. this.unscroeClose = this.unscroeClose.bind(this);
  67. }
  68. onPrint() {
  69. const {showHide} = this.props;
  70. let dom = showHide&&showHide.showTable?$("#printcontent"):$("#AssistResult");
  71. dom.jqprint({
  72. debug: false,
  73. importCSS: true,
  74. printContainer: true,
  75. operaSupport: false,
  76. });
  77. }
  78. showInfo(item){
  79. // 静态知识显示在提示信息里(4-18)
  80. const {getInfomation} = this.props;
  81. const param = {
  82. id:item.id,
  83. name: item.name,
  84. // id:40738, //目前只有“肾功能不全”有数据
  85. type:22,
  86. position: 1
  87. }
  88. getInfomation&&getInfomation(param);
  89. }
  90. closeInfo(){//关闭静态知识
  91. this.setState({
  92. infoId:null
  93. })
  94. }
  95. showOption(id){
  96. this.setState({
  97. optionId:id,
  98. formulaId:null //关闭计算公式
  99. });
  100. const {patDom} = this.props;
  101. const ht = $(patDom.current).height();
  102. setTimeout(function(){
  103. $(patDom.current).scrollTop(ht+200);
  104. })
  105. }
  106. closeOption(){
  107. // 关闭-有可能结果则保持与结果一致,没有就保持最新选择的内容
  108. let {possible,radioVal} = this.state;
  109. if(JSON.stringify(possible)=='{}'){
  110. this.setState({
  111. optionId:null
  112. })
  113. }else{
  114. this.setState({
  115. radioVal:Object.assign({},radioVal,possible),
  116. optionId:null,
  117. });
  118. }
  119. }
  120. showTable(it,v,i,j){
  121. const {scaleInfo} = this.props;
  122. // 密西根糖尿病周围神经病评分(MDNS), id:40744
  123. const item = {
  124. conceptId:it.conceptId,
  125. name:it.name
  126. };
  127. // 判断:store里已经有该量表就无需重新调接口
  128. if(scaleInfo&&scaleInfo[it.conceptId]){
  129. this.props.hideList({name:'showTable',value:true},it);
  130. }else{
  131. this.props.getScaleInfo(item);
  132. }
  133. this.setState({
  134. formulaId:null, //关闭计算公式和可能结果弹窗
  135. optionId:null,
  136. scaleParam:{
  137. v,i,j
  138. }
  139. })
  140. }
  141. // 量表明细-关闭,isClose是否是点击关闭按钮
  142. closeTable(isClose){
  143. const {scaleParam} = this.state;
  144. const {showHide} = this.props;
  145. if(!showHide.isPop){
  146. //量表结果,判断需要计算并且dom中有值才能加入病例记录
  147. const res = this.$result.current&&this.$result.current.innerText;
  148. if(!isClose&&(this.$result.current&&!res)){
  149. Notify.info("请先计算量表结果!");
  150. return ;
  151. }
  152. !isClose&&this.handleAddAssessItem(scaleParam.v,scaleParam.i,scaleParam.j);
  153. this.setState({
  154. scaleParam:{}
  155. });
  156. }
  157. this.props.hideList({name:'showTable',value:false});
  158. }
  159. // 非计分量表确定-延时关闭->量表存值
  160. unscroeClose(){
  161. let {timer} = this.state;
  162. this.setState({
  163. ff:true
  164. })
  165. clearTimeout(timer)
  166. let _timer = setTimeout(()=>{
  167. this.closeTable();
  168. },200)
  169. this.setState({
  170. timer:_timer
  171. })
  172. }
  173. // 量表明细-确定
  174. comfirnTable(){
  175. const {flag} = this.state;
  176. this.setState({
  177. comfirnFlag:true,
  178. flag:!flag //触发更新
  179. })
  180. }
  181. resetComfirnFlag(){
  182. this.setState({
  183. comfirnFlag:false,
  184. ff:false
  185. })
  186. }
  187. showFormula(id){//计算公式
  188. this.setState({
  189. formulaId:id,
  190. optionId:null //关闭可能结果
  191. });
  192. const {patDom} = this.props;
  193. const ht = $(patDom.current).height();
  194. setTimeout(function(){
  195. $(patDom.current).scrollTop(ht+200);
  196. })
  197. }
  198. closeFormula(it){
  199. const {formulaId,isCalculated} =this.state;
  200. if(!isCalculated){
  201. //没有计算结果时,保存输入的值
  202. const {calcuResult,calcuValues} = this.props;
  203. const cres = calcuResult&&calcuResult[formulaId]||it.content.result;
  204. const result = cres&&cres[1]&&cres[1].text;
  205. if(result){
  206. this.setState({
  207. calcuValues:deepClone(calcuValues)
  208. });
  209. }
  210. }
  211. this.setState({
  212. formulaId:null,
  213. });
  214. }
  215. handleAddAssessItem(v,pIndex,i){
  216. const {addAssessItem,showHide,addScaleItems,scaleInfo} = this.props;
  217. if(!v){
  218. addScaleItems(scaleInfo[showHide.conceptId],showHide.conceptId);
  219. return ;
  220. }
  221. addAssessItem(v,pIndex,i);
  222. }
  223. addFormula(it,v,pIndex,i){
  224. const {chronicMagItem} = this.props;
  225. this.closeFormula(it);
  226. chronicMagItem&&this.handleAddAssessItem(v,pIndex,i);
  227. }
  228. handleReg(e){ //只能输入数字和特殊符号
  229. //const hasDot = e.target.value.indexOf('.')!=-1;
  230. const key = e.key;
  231. if(key!='Backspace'&&((/[^\d|.\/%*~]/.test(key)))){
  232. e.preventDefault();
  233. }
  234. }
  235. handleInputformula(id,calcuContent,i,e) {
  236. const {calcuValues} = this.state;
  237. let obj = deepClone(calcuValues);
  238. let values = (obj&&obj[id])||deepClone(calcuContent);
  239. const txt = e.target.value;
  240. values[i].value = txt.replace(/[\u4e00-\u9fa5]|[^\d|.\/%*~]/g,''); //处理中文输入法的情况
  241. obj[id] = values;
  242. if(/[\u4e00-\u9fa5]|[^\d|.\/%*~]/g.test(txt)){
  243. e.target.value = txt.replace(/[\u4e00-\u9fa5]|[^\d|.\/%*~]/g,'');
  244. }
  245. this.setState({
  246. isCalculated:false,
  247. calcuValues:obj
  248. });
  249. }
  250. handleForRadio(id,calcuContent,i,fidx){//计算公式
  251. const { calcuValues } = this.state;
  252. let obj = deepClone(calcuValues);
  253. let values = (obj&&obj[id])||deepClone(calcuContent);
  254. let details = values[i].details;
  255. for(let x=0;x<details.length;x++){
  256. if(x!=fidx){
  257. details[x].state=0;
  258. }else{
  259. details[x].state=1;
  260. }
  261. }
  262. obj[id] = values;
  263. this.setState({
  264. isCalculated:false,
  265. calcuValues:obj
  266. });
  267. }
  268. handleRadio(item,parent){//可能结果
  269. let {radioVal} = this.props;
  270. this.setState({
  271. radioVal:Object.assign({},radioVal,{[parent.conceptId]:item.detailName})
  272. })
  273. }
  274. confirmOption(parent,pIndex,i){//可能结果确定
  275. const {radioVal,possible} = this.state;
  276. const {savePossibleResult,chronicMagItem} = this.props;
  277. this.setState({
  278. possible:Object.assign({},possible,radioVal),
  279. radioVal:Object.assign({},possible,radioVal),//不设置radioVal只有最近一次选中的值
  280. optionId:null,
  281. });
  282. savePossibleResult&&savePossibleResult({possible:Object.assign({},possible,radioVal),radioVal:Object.assign({},possible,radioVal)})
  283. chronicMagItem&&this.handleAddAssessItem(parent,pIndex,i);
  284. }
  285. handleSaveCalcu(obj){
  286. this.setState({
  287. possible:Object.assign({},obj.possible),
  288. radioVal:Object.assign({},obj.radioVal),//不设置radioVal只有最近一次选中的值
  289. })
  290. }
  291. calcuFormula(id,it) { //计算公式计算
  292. const { calcuFormula } = this.props;
  293. let item = deepClone(it);
  294. const values = this.state.calcuValues;
  295. const calcuValues = Object.keys(values).length&&values[id]?values[id]:item.content.details;
  296. let allHasInfo = true;
  297. for (let i = 0; i < calcuValues.length; i++) {
  298. if(calcuValues[i].controlType == 2) { //输入框类型的有没有填值
  299. if(!calcuValues[i].value) {
  300. allHasInfo = false;
  301. }
  302. } else if(calcuValues[i].controlType == 0) {
  303. let hasSelect = false;
  304. for( let z = 0; z <calcuValues[i].details.length; z++) {
  305. if(calcuValues[i].details[z].state == 1) {
  306. hasSelect= true;
  307. }
  308. }
  309. if(!hasSelect) {
  310. allHasInfo = false;
  311. }
  312. }
  313. }
  314. item.content.details = calcuValues;
  315. if(allHasInfo) { //所有都有值,则计算
  316. let param = {
  317. type: 2,
  318. data: item,
  319. disId: id
  320. };
  321. calcuFormula(param);
  322. this.setState({
  323. isCalculated:true
  324. });
  325. } else { //不是所有值都填过了
  326. Notify.info('请填写计算公式内容')
  327. }
  328. }
  329. handleMouseEnterDrug(index) {
  330. this.setState({
  331. currentIndex: index,
  332. })
  333. }
  334. handleMouseLeaveDrug() {
  335. this.setState({
  336. currentIndex: -1,
  337. })
  338. }
  339. handleMouseEnterImg() {
  340. this.setState({
  341. hasEnterImg: true
  342. })
  343. }
  344. handleMouseLeaveImg() {
  345. this.setState({
  346. hasEnterImg: false
  347. })
  348. }
  349. getDetail(){
  350. const {data,formulaResult,calcuResult,chronicMagItem} = this.props;
  351. const {formulaId,optionId,possible,radioVal,calcuValues,currentIndex,hasEnterImg} = this.state;
  352. let list = data&&data.map((v,i)=>{
  353. return <div className={style["list"]}>
  354. {v.name?<p>
  355. <span>患者可能有</span>
  356. <span
  357. className={style['dis-name']}
  358. onMouseEnter={this.handleMouseEnterDrug.bind(this, i)}
  359. onMouseLeave = {this.handleMouseLeaveDrug.bind(this)}
  360. >
  361. {v.name}
  362. {<img className={style['info-img']}
  363. style ={currentIndex === i ? {display: "inline-block"} : {display: "none"}}
  364. src={currentIndex === i ?(hasEnterImg ? infoMove : infoShow ): infoShow}
  365. onMouseEnter={this.handleMouseEnterImg.bind(this)}
  366. onMouseLeave = {this.handleMouseLeaveImg.bind(this)}
  367. onClick={this.showInfo.bind(this,v)}/>}
  368. </span>
  369. {/* <img src={infoShow} className={style["infoPic"]} onClick={this.showInfo.bind(this,v.id)}/> */}
  370. </p>:''}
  371. {v.details&&v.details.map((it,j)=>{
  372. if(it.type==1){
  373. return <p>
  374. <span className={style["listName"]}>
  375. <i onClick={this.showTable.bind(this,it.content,v,i,j)}>{'【'+it.content.name+'】'}</i>
  376. {formulaResult&&formulaResult[it.content.conceptId]?<i>{'结果:'}{formulaResult[it.content.conceptId].calcalculate&&formulaResult[it.content.conceptId].calcalculate.result.value +' '+ formulaResult[it.content.conceptId].calcalculate.result.text}</i>:''}
  377. </span>
  378. </p>
  379. }else if(it.type==2){
  380. const cres = calcuResult&&calcuResult[v.conceptId]||it.content.result;
  381. const result = cres&&cres[1]&&cres[1].text;
  382. const details = calcuValues&&calcuValues[v.conceptId]||it.content.details;
  383. return <div className={style["marTop"]}>
  384. <span className={style["limit"]}>
  385. 计算公式结果:
  386. <i className={style["blue"]} onClick={this.showFormula.bind(this,v.conceptId)}>{result?result:'请选择'}</i>
  387. <img src={level1} />
  388. </span>
  389. {formulaId&&formulaId==v.conceptId&&<MiniToast title={it.content.name}
  390. icon={allTableIcon}
  391. confirmText={chronicMagItem?'加入病历记录':'确定'}
  392. show={formulaId&&formulaId==v.conceptId?true:false}
  393. close={this.closeFormula.bind(this,it)}
  394. confirm={this.addFormula.bind(this,it,v,i,j)}
  395. footer={result?true:false}>
  396. <table>
  397. {details.map((item,idd)=>{
  398. if(item.controlType==0){//单选
  399. return <tr>
  400. <td>
  401. <span>{'请选择'+item.name+':'}</span>
  402. </td>
  403. <td>
  404. {Array.isArray(item.details)&&item.details.map((ii,ind)=>{
  405. return <div className={style["chooseItem"]}>
  406. <Radio label={ii.detailName}
  407. isSelect={ii.state == 1}
  408. handleClick={item.isShow == '0' ? '' : this.handleForRadio.bind(this,v.conceptId,details,idd,ind)}>
  409. </Radio>
  410. </div>
  411. })}
  412. </td>
  413. </tr>
  414. }else if(item.controlType==2){//输入框
  415. return <tr>
  416. <td>
  417. <span>{'请输入'+item.name+':'}</span>
  418. </td>
  419. <td>
  420. <input type="text" placeholder="请输入" readonly={item.isShow == '0'} value={item.value} onKeyDown={this.handleReg.bind(this)} onInput={this.handleInputformula.bind(this,v.conceptId,details,idd)}/>
  421. </td>
  422. <td>
  423. <span>{item.uint}</span>
  424. </td>
  425. </tr>
  426. }
  427. })}
  428. </table>
  429. <div className={style["forMulBtn"]} onClick={this.calcuFormula.bind(this,v.conceptId,it)}>计算</div>
  430. <table>
  431. {cres && Array.isArray(cres) &&cres.map((itemResult, resultIndex) => {
  432. return <tr>
  433. <td>
  434. <span>{itemResult.name+':'}</span>
  435. </td>
  436. <td>
  437. <span>{itemResult.text}</span>
  438. </td>
  439. </tr>
  440. })}
  441. </table>
  442. </MiniToast>}
  443. </div>
  444. }else if(it.type==3){
  445. return <div className={style["marTop"]}>
  446. <span className={style["limit"]}>
  447. 可能结果:
  448. <i onClick={this.showOption.bind(this,v.conceptId)} className={style["blue"]}>{possible[v.conceptId]?possible[v.conceptId]:'请选择'}</i>
  449. <img src={level1} />
  450. </span>
  451. <MiniToast title='结果选择'
  452. icon={checkIcon}
  453. confirmText={chronicMagItem?'加入病历记录':'确定'}
  454. show={optionId&&optionId==v.conceptId?true:false}
  455. close={this.closeOption}
  456. confirm={this.confirmOption.bind(this,v,i,j)}
  457. footer={radioVal[v.conceptId]?true:false}>
  458. <div className={style["infoOption"]}>
  459. <span>{it.content.name?it.content.name+':':''}</span>
  460. {it.content.details&&it.content.details.map((lis,ind)=>{
  461. return <div className={style["chooseItem"]}>
  462. <Radio label={lis.detailName}
  463. isSelect={radioVal[v.conceptId]==lis.detailName}
  464. handleClick={this.handleRadio.bind(this,lis,v)}>
  465. </Radio>
  466. {lis.state==1?<span className={style['recomand']}>(智能推荐)</span>:''}
  467. </div>
  468. })}
  469. </div>
  470. </MiniToast>
  471. </div>
  472. }
  473. })}
  474. </div>
  475. })
  476. return list;
  477. }
  478. componentWillReceiveProps(next){
  479. if(JSON.stringify(next.calcuValues)!=JSON.stringify(this.props.calcuValues)){
  480. this.setState({
  481. calcuValues:next.calcuValues
  482. })
  483. }
  484. if (JSON.stringify(next.wholeResults.possible) != JSON.stringify(this.props.possible)) {
  485. this.setState({
  486. radioVal: next.wholeResults.radioVal,
  487. possible: next.wholeResults.possible
  488. })
  489. }
  490. if(next.slideUp!=this.props.slideUp){
  491. if(next.slideUp){
  492. $(this.$content.current).slideUp(config.slideTime);
  493. }else{
  494. $(this.$content.current).slideDown(config.slideTime);
  495. }
  496. }
  497. }
  498. slideToggle(){
  499. const {toggleSlide,slideUp} = this.props;
  500. toggleSlide&&toggleSlide(!slideUp);
  501. }
  502. render(){
  503. const {comfirnFlag,flag,ff} = this.state;
  504. const {chronicMagItem,chronicDesease,data,showHide,slideUp} = this.props;
  505. const scaleFooter = <Footer print={true}
  506. footText={showHide.isPop||!chronicMagItem?"确定":"加入病历记录"}
  507. handlePrint={this.onPrint}
  508. handleConfirm={this.comfirnTable}/>;
  509. if(data&&data.length>0){
  510. return <div className={style["tips"]} style={{marginBottom:'15px'}}>
  511. <div className={`${style["tips-title"]} ${style["chronic"]}`} onClick={this.slideToggle}>
  512. <div className={style["tips-name"]}>
  513. <img src={chronicPic} />
  514. <h2>{chronicMagItem&&chronicMagItem.name||chronicDesease&&chronicDesease.name||'病情提示'}<span className={style["redTips"]}>(页面信息有更新可能影响评估结果)</span></h2>
  515. </div>
  516. <div className={style['toggle-btn']}>
  517. <img src={slideUp?down:up} alt="展开/收起"/>
  518. </div>
  519. </div>
  520. <div className={style["content"]} ref={this.$content}>
  521. {this.getDetail()}
  522. </div>
  523. {showHide&&showHide.showTable?<ComplexModal onclose={()=>this.closeTable(true)} footer={scaleFooter}
  524. title={showHide.name}
  525. icon={tableIcon}
  526. top={20}
  527. bottom={20}
  528. width={820}>
  529. <ScaleTable title={showHide.name}
  530. tableId={showHide.conceptId}
  531. comfirnFlag={comfirnFlag}
  532. flag={flag}
  533. flagT={ff}
  534. resetFlag={this.resetComfirnFlag}
  535. unscroeClose={this.unscroeClose}
  536. closeTable={this.closeTable}
  537. resRef={this.$result}
  538. ></ScaleTable>
  539. </ComplexModal>:''}
  540. </div>
  541. }
  542. //量表弹窗-无指标推送时量表弹窗要单独加载
  543. if(showHide&&showHide.showTable){
  544. return <ComplexModal onclose={()=>this.closeTable(true)} footer={scaleFooter}
  545. title={showHide.name}
  546. icon={tableIcon}
  547. top={20}
  548. bottom={20}
  549. width={820}>
  550. <ScaleTable title={showHide.name}
  551. tableId={showHide.conceptId}
  552. comfirnFlag={comfirnFlag}
  553. flag={flag}
  554. flagT={ff}
  555. resetFlag={this.resetComfirnFlag}
  556. unscroeClose={this.unscroeClose}
  557. closeTable={this.closeTable}
  558. resRef={this.$result}
  559. ></ScaleTable>
  560. </ComplexModal>;
  561. }
  562. }
  563. }
  564. export default ChronicInfo;