Browse Source

uas手机版
将U审批整合到项目中

RaoMeng 5 years ago
parent
commit
2a5d06b62f
48 changed files with 5829 additions and 7 deletions
  1. 1 1
      uas-office-web/uas-mobile/public/index.html
  2. 1 1
      uas-office-web/uas-mobile/src/components/common/bizgoblin/CommonCharts.jsx
  3. 4 0
      uas-office-web/uas-mobile/src/components/common/currencyDetail/currency-detail.less
  4. 1 0
      uas-office-web/uas-mobile/src/components/common/currencyList/currency-list.less
  5. 2 3
      uas-office-web/uas-mobile/src/components/common/mainHeader/MainHeader.jsx
  6. 15 1
      uas-office-web/uas-mobile/src/configs/antd.config.less
  7. 1 1
      uas-office-web/uas-mobile/src/configs/iconfont.conig.js
  8. 13 0
      uas-office-web/uas-mobile/src/configs/router.config.js
  9. 28 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/LoadingMore.jsx
  10. 35 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/PageLoading.jsx
  11. 72 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/RefreshLayout.jsx
  12. 116 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/approvalItem/ApprovalItem.jsx
  13. 74 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/approvalItem/approvalItem.css
  14. 50 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/approvalNode/ApprovalNode.jsx
  15. 78 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/approvalNode/approvalNode.css
  16. 49 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/employeeItem/EmployeeItem.jsx
  17. 30 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/employeeItem/employee.css
  18. 39 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/enclosureItem/EnclosureItem.jsx
  19. 15 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/enclosureItem/enclosureItem.css
  20. 250 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/pointsItem/PointsItem.jsx
  21. 70 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/pointsItem/pointsItem.css
  22. 265 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/tableItem/TableItem.jsx
  23. 45 0
      uas-office-web/uas-mobile/src/pages/private/approval/components/tableItem/tableItem.css
  24. 92 0
      uas-office-web/uas-mobile/src/pages/private/approval/index.css
  25. 145 0
      uas-office-web/uas-mobile/src/pages/private/approval/model/ApprovalBean.js
  26. 21 0
      uas-office-web/uas-mobile/src/pages/private/approval/model/ApprovalRecordBean.js
  27. 63 0
      uas-office-web/uas-mobile/src/pages/private/approval/model/BillGroupModel.js
  28. 79 0
      uas-office-web/uas-mobile/src/pages/private/approval/model/BillModel.js
  29. 20 0
      uas-office-web/uas-mobile/src/pages/private/approval/model/EmployeeModel.js
  30. 8 0
      uas-office-web/uas-mobile/src/pages/private/approval/model/LocalData.js
  31. 2673 0
      uas-office-web/uas-mobile/src/pages/private/approval/pages/Approval.jsx
  32. 857 0
      uas-office-web/uas-mobile/src/pages/private/approval/pages/ApprovalHome.jsx
  33. 363 0
      uas-office-web/uas-mobile/src/pages/private/approval/pages/approval.css
  34. 2 0
      uas-office-web/uas-mobile/src/pages/private/homePage/HomePage.jsx
  35. 8 0
      uas-office-web/uas-mobile/src/pages/private/homePage/home-page.less
  36. 4 0
      uas-office-web/uas-mobile/src/pages/private/report/report.less
  37. 79 0
      uas-office-web/uas-mobile/src/redux/actions/approvalState.js
  38. 10 0
      uas-office-web/uas-mobile/src/redux/constants/actionTypes.js
  39. 2 0
      uas-office-web/uas-mobile/src/redux/reducers/index.js
  40. 122 0
      uas-office-web/uas-mobile/src/redux/reducers/redApprovalState.js
  41. 2 0
      uas-office-web/uas-mobile/src/redux/utils/redux.utils.js
  42. BIN
      uas-office-web/uas-mobile/src/res/img/approved.png
  43. BIN
      uas-office-web/uas-mobile/src/res/img/bg_bind_phone.png
  44. BIN
      uas-office-web/uas-mobile/src/res/img/default_header.png
  45. BIN
      uas-office-web/uas-mobile/src/res/img/endapproved.png
  46. BIN
      uas-office-web/uas-mobile/src/res/img/ic_uas_icon.png
  47. BIN
      uas-office-web/uas-mobile/src/res/img/unapproved.png
  48. 25 0
      uas-office-web/uas-mobile/src/utils/common/common.util.js

+ 1 - 1
uas-office-web/uas-mobile/public/index.html

@@ -28,7 +28,7 @@
 </head>
 <body>
 <noscript>You need to enable JavaScript to run this app.</noscript>
-<div id="root"></div>
+<div id="root" style="width: 100%;height: 100%;"></div>
 <!--
   This HTML file is a template.
   If you open it directly in the browser, you will see an empty page.

+ 1 - 1
uas-office-web/uas-mobile/src/components/common/bizgoblin/CommonCharts.jsx

@@ -64,7 +64,7 @@ export default class CommonCharts extends Component {
       <div className='common-charts' style={{ marginBottom: '8px' }}>
         <LazyLoad
           once
-          height={400}
+          height={150}
           resize={true}
           overflow={setOverflow}
         >

+ 4 - 0
uas-office-web/uas-mobile/src/components/common/currencyDetail/currency-detail.less

@@ -10,5 +10,9 @@
     flex: 1;
     overflow: auto;
     -webkit-overflow-scrolling: touch;
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
   }
 }

+ 1 - 0
uas-office-web/uas-mobile/src/components/common/currencyList/currency-list.less

@@ -3,6 +3,7 @@
   width: 100%;
   height: 100vh;
 
+
   .currency-list-search-root {
     .com-row-flex;
     align-items: center;

+ 2 - 3
uas-office-web/uas-mobile/src/components/common/mainHeader/MainHeader.jsx

@@ -82,9 +82,8 @@ class MainHeader extends Component {
     } else if (funcObj.name === '我的订阅') {
       this.props.history.push('/subscribeList')
     } else if (funcObj.name === '待审批') {
-      window.open(
-        _baseURL + '/uas/#/uasApproval/' + this.props.userState.accountCode,
-        '_self')
+      this.props.history.push(
+        '/approvalHome/' + this.props.userState.accountCode)
     }
   }
 

+ 15 - 1
uas-office-web/uas-mobile/src/configs/antd.config.less

@@ -22,7 +22,11 @@
   //padding-top: @tab-bar-padding-top !important;
 }
 
-/********************itemList的样式***********************/
+.am-tabs-pane-wrap::-webkit-scrollbar {
+  display: none;
+}
+
+/********************List的样式***********************/
 .am-list-item {
   margin-bottom: 10px;
 }
@@ -46,6 +50,10 @@
   white-space: normal !important;
 }
 
+.am-list-view-scrollview::-webkit-scrollbar {
+  display: none;
+}
+
 /********************Button按钮的样式***********************/
 .am-button {
   height: @com-button-height !important;
@@ -133,3 +141,9 @@
 .ant-btn-icon-only.ant-btn-sm > * {
   font-size: 18px !important;
 }
+
+/*************************弹框**************************/
+
+.am-modal-wrap-popup::-webkit-scrollbar {
+  display: none;
+}

+ 1 - 1
uas-office-web/uas-mobile/src/configs/iconfont.conig.js

@@ -5,7 +5,7 @@ import { createFromIconfontCN } from '@ant-design/icons'
  * Desc: iconfont图标库
  */
 const UasIcon = createFromIconfontCN({
-  scriptUrl: '//at.alicdn.com/t/font_2183203_lsazaw409qi.js',
+  scriptUrl: '//at.alicdn.com/t/font_2183203_zg2y7uh7dy.js',
 })
 
 export default UasIcon

+ 13 - 0
uas-office-web/uas-mobile/src/configs/router.config.js

@@ -26,6 +26,12 @@ const UasEntry = PageLoadable(
 const HomePage = PageLoadable(
   import(/* webpackChunkName:'home' */'@/pages/private/homePage/HomePage'))
 
+/**************************************************审批**************************************************/
+const ApprovalHomePage = PageLoadable(
+  import(/* webpackChunkName:'approval' */'@/pages/private/approval/pages/ApprovalHome'))
+const ApprovalPage = PageLoadable(
+  import(/* webpackChunkName:'approval' */'@/pages/private/approval/pages/Approval'))
+
 /**************************************************日程**************************************************/
 const SchedulePage = PageLoadable(
   import(/* webpackChunkName:'schedule' */'@/pages/private/schedulePage/SchedulePage'))
@@ -118,6 +124,13 @@ class Routes extends React.Component {
           {/*主页*/}
           <Route path='/homePage' component={HomePage}/>
 
+          {/***************************************审批*******************************************/}
+          {/*U审批首页*/}
+          <Route path='/approvalHome/:master/:type?'
+                 component={ApprovalHomePage}/>
+          {/*U审批详情页*/}
+          <Route path='/approval/:paramsStr?' component={ApprovalPage}/>
+
           {/***************************************日程*******************************************/}
           <Route path='/schedulePage' component={SchedulePage}/>
           {/* 会议详情 */}

+ 28 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/LoadingMore.jsx

@@ -0,0 +1,28 @@
+/**
+ * Created by RaoMeng on 2018/11/14
+ * Desc: 加载更多
+ */
+
+import React, { Component } from 'react'
+import { Icon } from 'antd'
+
+export default class LoadingMore extends Component {
+
+  constructor () {
+    super()
+
+    this.state = {}
+  }
+
+  componentDidMount () {
+  }
+
+  render () {
+    return (
+      <div className='common-load-more'>
+        <Icon type="loading" theme="outlined"/>
+        <span style={{ marginLeft: '10px' }}>正在加载</span>
+      </div>
+    )
+  }
+}

+ 35 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/PageLoading.jsx

@@ -0,0 +1,35 @@
+/**
+ * Created by RaoMeng on 2020/3/4
+ * Desc: 页面加载组件
+ */
+
+import React, { Component } from 'react'
+import { ActivityIndicator } from 'antd-mobile'
+
+export default class PageLoading extends Component {
+
+  constructor () {
+    super()
+
+    this.state = {}
+  }
+
+  componentDidMount () {
+  }
+
+  render () {
+    return (
+      <div style={{
+        width: '100%',
+        height: '100%',
+        display: 'flex',
+        flexDirection: 'column',
+        alignItems: 'center',
+        justifyContent: 'center',
+      }}>
+        <ActivityIndicator size="large"/>
+        <span style={{ marginTop: 8 }}>页面加载中</span>
+      </div>
+    )
+  }
+}

+ 72 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/RefreshLayout.jsx

@@ -0,0 +1,72 @@
+/**
+ * Created by RaoMeng on 2018/12/1
+ * Desc: antd刷新组件二次封装
+ */
+
+import React, {Component} from 'react'
+import {PullToRefresh} from "antd-mobile";
+import PropTypes from 'prop-types'
+
+export default class RefreshLayout extends Component {
+
+    static propTypes = {
+        direction: PropTypes.string,//刷新方向:up或down,默认up
+        refreshing: PropTypes.bool.isRequired,//是否正在刷新
+        style: PropTypes.object,//样式,有默认样式一般可以不传
+        onRefresh: PropTypes.func.isRequired,//加载方法,必传
+        damping: PropTypes.number,//加载距离,不用传
+        distanceToRefresh: PropTypes.number,//可拉动距离,不用传
+        height:PropTypes.number,//组件高度,一般不用传
+    }
+
+    static defaultProps = {
+        direction: 'up',
+        damping: 120,
+        distanceToRefresh: 30
+    }
+
+    constructor() {
+        super()
+
+        this.state = {
+            height: document.documentElement.clientHeight
+        }
+    }
+
+    componentDidMount() {
+        setTimeout(() => {
+            if (this.props.height) {
+                this.setState({
+                    height: this.props.height,
+                })
+            } else {
+                // const hei = this.state.height - ReactDOM.findDOMNode(this.ptr).offsetTop;
+                // this.setState({
+                //     height: hei
+                // })
+            }
+        }, 0);
+    }
+
+    render() {
+        const {height} = this.state
+        const {direction, refreshing,style, onRefresh, damping, distanceToRefresh} = this.props
+
+        return (
+            <PullToRefresh
+                direction={direction}
+                refreshing={refreshing}
+                ref={el => this.ptr = el}
+                style={{
+                    height: height,
+                    overflow: 'auto',
+                    ...style
+                }}
+                damping={damping}
+                distanceToRefresh={distanceToRefresh}
+                onRefresh={onRefresh}>
+                {this.props.children}
+            </PullToRefresh>
+        )
+    }
+}

+ 116 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/approvalItem/ApprovalItem.jsx

@@ -0,0 +1,116 @@
+/**
+ * Created by RaoMeng on 2020/2/18
+ * Desc: 审批列表item
+ */
+
+import React, { Component } from 'react'
+import './approvalItem.css'
+import moment from 'moment'
+import { isObjEmpty } from '../../../../../utils/common/common.util'
+
+export default class ApprovalItem extends Component {
+
+  constructor () {
+    super()
+
+    this.state = {}
+  }
+
+  componentDidMount () {
+
+  }
+
+  componentWillUnmount () {
+
+  }
+
+  render () {
+    const { approval, type } = this.props
+    let approvalStatus = '等待我审批'
+    let statusColor = '#33A3F4'
+    if (type === 2) {
+      approvalStatus = approval.JN_DEALRESULT
+      if (!isObjEmpty(approvalStatus)) {
+        if (approvalStatus.startWith('不同意') || approvalStatus.startWith('结束流程')
+          || approvalStatus.startWith('未通过')) {
+          approvalStatus = '未通过'
+          statusColor = '#db3a34'
+        } else if (approvalStatus.startWith('变更处理人')) {
+          statusColor = '#999999'
+          if (!isObjEmpty(approval.JN_OPERATEDDESCRIPTION)) {
+            approvalStatus = '变更处理人(' + approval.JN_OPERATEDDESCRIPTION + ')'
+          } else {
+            approvalStatus = '变更处理人'
+          }
+        } else {
+          approvalStatus = '已审批'
+          statusColor = '#999999'
+        }
+      }
+    } else if (type === 3) {
+      approvalStatus = approval.JP_STATUS
+      if (!isObjEmpty(approvalStatus)) {
+        if (approvalStatus === '待审批') {
+          statusColor = '#33A3F4'
+          approvalStatus = '等待' + approval.JP_NODEDEALMANNAME + '审批'
+        } else if (approvalStatus === '未通过') {
+          statusColor = '#db3a34'
+        } else {
+          statusColor = '#999999'
+        }
+      }
+    }
+
+    return (
+      <div style={{ padding: '0 10px' }} onClick={this.onItemClick}>
+        <div className='recharge-item-root'>
+          <div className='homework-item-title-layout'>
+            {approval.JP_LAUNCHERNAME +
+            '的' + approval.JP_NAME}
+          </div>
+          <div className='gray-line'
+               style={{ height: '1px', marginBottom: '4px' }}></div>
+          <div className='recharge-item-line'>
+            <div className='recharge-item-caption'>单号:</div>
+            <div className='recharge-item-value'>
+              {approval.JP_CODEVALUE}
+            </div>
+          </div>
+          <div className='recharge-item-line'>
+            <div className='recharge-item-caption'>{approval.JN_DEALTIME ===
+            undefined ? '发起时间:' : '处理时间:'}</div>
+            <div
+              className='recharge-item-value'>{!isObjEmpty(
+              approval.JP_LAUNCHTIME)
+              ? moment(approval.JP_LAUNCHTIME).format('YYYY-MM-DD HH:mm:ss')
+              : !isObjEmpty(approval.JN_DEALTIME) ? moment(
+                approval.JN_DEALTIME).format('YYYY-MM-DD HH:mm:ss') : ''
+            }</div>
+          </div>
+          <div className='recharge-item-line' style={{ paddingBottom: '6px' }}>
+            <div className='recharge-item-caption'>{
+              /*approval.JP_STATUS
+                ? '单据状态:'
+                : approval.JN_DEALRESULT ? '审批结果:' :*/
+              '状态:'}</div>
+            <div
+              // className='recharge-item-value'
+              style={{
+                background: statusColor,
+                borderRadius: '8px',
+                color: 'white',
+                padding: '1px 6px',
+                fontSize: '12px',
+              }}>{approvalStatus}</div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+
+  onItemClick = () => {
+    if (this.props.onItemClick) {
+      this.props.onItemClick(this.props.index, this.props.approval)
+    }
+  }
+}

+ 74 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/approvalItem/approvalItem.css

@@ -0,0 +1,74 @@
+.recharge-item-root {
+    width: 100%;
+    background: white;
+    border-radius: 5px;
+    display: flex;
+    flex-direction: column;
+    box-sizing: border-box;
+    margin: 10px 0;
+}
+
+.recharge-item-line {
+    width: 100%;
+    display: flex;
+    padding: 2px 2px 2px 10px;
+    font-family: PingFangSC-Regular;
+    font-size: 13px;
+    align-items: center;
+    letter-spacing: 0;
+    flex-direction: row;
+}
+
+.recharge-item-caption {
+    width: 85px;
+    color: #999999;
+}
+
+.recharge-item-value {
+    flex: 1;
+    color: #666666;
+    overflow: hidden;
+    word-wrap: break-word;
+    padding-right: 10px;
+}
+
+.top_Time {
+    text-align: center;
+    height: 25px;
+    width: 100%;
+    background-color: #F2F2F2;
+    margin-bottom: 10px;
+}
+
+.top_time_span {
+    background-color: #FFFFFF;
+    width: 160px;
+    border-radius: 20px;
+    padding: 5px 20px;
+    color: #6C6C6C;
+    font-size: 12px;
+}
+
+.homework-item-title-layout {
+    padding: 8px 10px 4px;
+    /*font-family: PingFangSC-Regular;*/
+    font-size: 13px;
+    color: #000;
+    letter-spacing: 0;
+    flex: 1;
+    font-weight: bold;
+}
+
+.homework-item-todo, .homework-item-done {
+    font-family: PingFangSC-Regular;
+    font-size: 12px;
+    letter-spacing: 1.5px;
+}
+
+.homework-item-todo {
+    color: #F30000;
+}
+
+.homework-item-done {
+    color: #383838;
+}

+ 50 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/approvalNode/ApprovalNode.jsx

@@ -0,0 +1,50 @@
+import React, {Component} from 'react'
+import './approvalNode.css'
+import {Icon} from 'semantic-ui-react'
+import {Avatar} from 'antd'
+import {isObjEmpty, getParenthesesStr} from "../../../../../utils/common/common.util";
+
+
+export default class ApprovalNode extends Component {
+
+    render() {
+        let approval = this.props.approval
+        let idKey = approval.idKey
+        let iconColor = 'blue'
+        let stateColor = '#999999'
+        let status = ''
+        if (!isObjEmpty(idKey)) {
+            if (idKey.startWith('待审批')) {
+                stateColor = '#3BAE7E'
+                iconColor = 'blue'
+                status = '等待审批'
+            } else if (idKey.startWith('未通过') || idKey.startWith('结束') || idKey.startWith('不同意')) {
+                stateColor = '#999999'
+                iconColor = 'grey'
+                status = '不同意'
+            } else if (idKey.startWith('已审批') || idKey.startWith('变更') || idKey.startWith('同意')) {
+                stateColor = '#999999'
+                iconColor = 'grey'
+                status = '已审批'
+            }
+        }
+
+        return <div className='parent'>
+            <div className='dateLayout'>
+                <div className='dateItem'>{isObjEmpty(approval.values) ? '' : approval.values}</div>
+                <div className='dateItem'>{isObjEmpty(approval.dbFind) ? '' : approval.dbFind}</div>
+            </div>
+            <div className='arrowLayout'>
+                <div className={this.props.isFirst ? 'noLine' : 'arrowLine'}></div>
+                <Icon color={iconColor} name='chevron circle up' style={{margin: '0px', padding: '0px'}}/>
+                <div className={this.props.isLast ? 'noLine' : 'arrowLine'}></div>
+            </div>
+            <Avatar shape="square" src={require('../../../../../res/img/default_header.png')} className='headerImg'/>
+            <div className='contentLayout'>
+                <div className='nameItem'>{approval.caption}</div>
+                <div className='opinionItem'>{isObjEmpty(idKey) ? '' : getParenthesesStr(idKey)}</div>
+            </div>
+            <div className='stateItem' style={{color: stateColor}}>{status}</div>
+        </div>
+    }
+}

+ 78 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/approvalNode/approvalNode.css

@@ -0,0 +1,78 @@
+
+.parent {
+    width: 100%;
+    height: 72px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    padding-right: 10px;
+}
+
+.dateLayout {
+    width: 56px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    padding-top: 10px;
+}
+
+.dateItem, .timeItem {
+    text-align: center;
+    font-size: 13px;
+}
+
+.arrowLayout {
+    display: flex;
+    height: 100%;
+    flex-direction: column;
+    align-items: center;
+}
+
+.arrowLine {
+    flex: 1;
+    width: 1px;
+    background: #cccccc;
+}
+
+.noLine {
+    flex: 1;
+    width: 1px;
+    background: transparent;
+}
+
+.headerImg {
+    width: 35px;
+    height: 35px;
+    margin-left: 10px;
+}
+
+.contentLayout {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    flex: 1;
+    height: 100%;
+    margin-left: 10px;
+}
+
+.nameItem {
+    color: #999999;
+    font-size: 13px;
+}
+
+.opinionItem {
+    color: #999999;
+    font-size: 12px;
+    overflow-y: scroll;
+}
+
+.opinionItem::-webkit-scrollbar {
+    display: none;
+}
+
+.stateItem {
+    color: #999999;
+    margin-bottom: 20px;
+    font-size: 12px;
+}

+ 49 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/employeeItem/EmployeeItem.jsx

@@ -0,0 +1,49 @@
+/**
+ * Created by RaoMeng on 2020/2/27
+ * Desc: 人员组织架构
+ */
+
+import React, { Component } from 'react'
+import './employee.css'
+
+export default class EmployeeItem extends Component {
+
+  constructor () {
+    super()
+
+    this.state = {}
+  }
+
+  componentDidMount () {
+  }
+
+  componentWillUnmount () {
+
+  }
+
+  render () {
+    const { employee } = this.props
+    return (
+      <div className='employee-item-root'>
+        <div className='employee-item-line'>
+          <div className='employee-item-caption'>姓名:</div>
+          <div className='employee-item-value'>
+            {employee.EM_NAME}
+          </div>
+        </div>
+        <div className='employee-item-line'>
+          <div className='employee-item-caption'>岗位:</div>
+          <div className='employee-item-value'>
+            {employee.EM_POSITION}
+          </div>
+        </div>
+        <div className='employee-item-line'>
+          <div className='employee-item-caption'>组织:</div>
+          <div className='employee-item-value'>
+            {employee.EM_DEFAULTORNAME}
+          </div>
+        </div>
+      </div>
+    )
+  }
+}

+ 30 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/employeeItem/employee.css

@@ -0,0 +1,30 @@
+.employee-item-root {
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    box-sizing: border-box;
+}
+
+.employee-item-line {
+    width: 100%;
+    display: flex;
+    padding: 2px 2px 2px 6x;
+    font-family: PingFangSC-Regular;
+    font-size: 12px;
+    align-items: center;
+    letter-spacing: 0;
+    flex-direction: row;
+}
+
+.employee-item-caption {
+    width: 60px;
+    color: #999999;
+}
+
+.employee-item-value {
+    flex: 1;
+    color: #666666;
+    overflow: hidden;
+    word-wrap: break-word;
+    padding-right: 10px;
+}

+ 39 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/enclosureItem/EnclosureItem.jsx

@@ -0,0 +1,39 @@
+/**
+ * Created by RaoMeng on 2020/2/13
+ * Desc: 附件列表
+ */
+
+import React, { Component } from 'react'
+import './enclosureItem.css'
+
+export default class EnclosureItem extends Component {
+
+  constructor () {
+    super()
+
+    this.state = {}
+  }
+
+  componentDidMount () {
+
+  }
+
+  componentWillUnmount () {
+
+  }
+
+  render () {
+    const { approval } = this.props
+
+    return (
+      <div className='enclosure-parent'>
+        <div className='enclosure-value'
+             onClick={this.onEnclosureSelect}>{approval.caption}</div>
+      </div>
+    )
+  }
+
+  onEnclosureSelect = () => {
+    this.props.onEnclosureSelect(this.props.index)
+  }
+}

+ 15 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/enclosureItem/enclosureItem.css

@@ -0,0 +1,15 @@
+.enclosure-parent {
+    width: 100%;
+    background: white;
+    padding: 4px 10px;
+    font-size: 14px;
+}
+
+.enclosure-value {
+    width: 100%;
+    background: #E4F0F9;
+    color: #333333;
+    padding: 0 6px;
+    min-height: 28px;
+    line-height: 28px;
+}

+ 250 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/pointsItem/PointsItem.jsx

@@ -0,0 +1,250 @@
+import React, { Component } from 'react'
+import './pointsItem.css'
+import { Icon, Modal } from 'semantic-ui-react'
+import { DatePicker } from 'antd'
+import locale from 'antd/lib/date-picker/locale/zh_CN'
+import { isObjEmpty } from '../../../../../utils/common/common.util'
+import ApprovalBean from '../../model/ApprovalBean'
+import moment from 'moment'
+
+export default class PointsItem extends Component {
+
+  componentDidMount () {
+    let { mApproval } = this.state
+
+    this.setState({
+      mApproval: this.props.approval,
+      approvalAble: this.props.approvalAble,
+    })
+    let options = []
+    let datas = mApproval.datas
+    if (!isObjEmpty(datas)) {
+      for (let i = 0; i < datas.length; i++) {
+        options.push(datas[i].display)
+      }
+    }
+    this.setState({
+      selectList: options,
+      inputValue: mApproval.values,
+    })
+  }
+
+  componentWillReceiveProps () {
+    this.componentDidMount()
+  }
+
+  constructor () {
+    super()
+
+    this.state = {
+      modalOpen: false,
+      selectList: [],
+      inputValue: '',
+      mApproval: new ApprovalBean(),
+      approvalAble: true,
+    }
+  }
+
+  render () {
+    let valueItem = ''
+    const dateFormat = 'YYYY-MM-DD'
+    const { inputValue, selectList, mApproval, approvalAble } = this.state
+
+    if (approvalAble == false) {
+      valueItem = <div className='value-input'>{mApproval.values}</div>
+    } else if (mApproval.isSelect()) {
+      let placeHolder = ''
+      if (mApproval.mustInput) {
+        placeHolder = '请选择(必选)'
+      } else {
+        placeHolder = '请选择(非必选)'
+      }
+      if (mApproval.inputType() == 2) {
+        //日期选择框
+        let defaultDate = inputValue
+        if (!isObjEmpty(inputValue)) {
+          defaultDate = ''
+        } else {
+          defaultDate = moment(defaultDate, 'YYYY-MM-DD')
+          if (!defaultDate._isValid) {
+            defaultDate = ''
+          }
+        }
+        valueItem = <div style={{ display: 'flex' }}>
+          <DatePicker locale={locale} className='date-input'
+                      defaultValue={defaultDate}
+                      format={dateFormat} size='small'
+                      placeholder={placeHolder}
+                      onChange={this.onDatePicker}
+                      suffixIcon=' '/>
+          <Icon name='angle right' style={{ margin: '0px', padding: '0px' }}/>
+        </div>
+      } else {
+        //弹框选择
+        const { modalOpen } = this.state
+        let modalItems = []
+        for (let i = 0; i < selectList.length; i++) {
+          modalItems.push(<div className='selectItem' onClick={
+            this.modalSelect.bind(this, i)
+          }>{selectList[i]}</div>)
+        }
+        valueItem = <Modal trigger={<div style={{ display: 'flex' }}
+                                         onClick={this.onSelectClick}>
+          <input placeholder={placeHolder} readOnly unselectable='on'
+                 className='value-input'
+                 value={inputValue}/>
+          <Icon name='angle right' style={{ margin: '0px', padding: '0px' }}/>
+        </div>}
+                           open={modalOpen}
+                           onClose={this.modalClose}
+                           size='small'>
+          <Modal.Content image>
+            <Modal.Description>
+              {modalItems}
+            </Modal.Description>
+          </Modal.Content>
+        </Modal>
+
+      }
+    } else {
+      let placeHolder = ''
+      if (mApproval.mustInput) {
+        placeHolder = '请输入(必填)'
+      } else {
+        placeHolder = '请输入(非必填)'
+      }
+      if (mApproval.dfType == 'N') {
+        //数字输入框
+        valueItem = <div style={{ display: 'flex' }}>
+          <input type='number' onKeyPress={this.numKeyPress}
+                 placeholder={placeHolder} className='value-input'
+                 value={inputValue} onChange={this.inputChange}/>
+          <Icon name='angle right' style={{
+            margin: '0px',
+            padding: '0px',
+            visibility: 'hidden',
+          }}/>
+        </div>
+      } else {
+        //文本输入框
+        valueItem = <div style={{ display: 'flex' }}>
+          <input placeholder={placeHolder} className='value-input'
+                 value={inputValue} onChange={this.inputChange}/>
+          <Icon name='angle right' style={{
+            margin: '0px',
+            padding: '0px',
+            visibility: 'hidden',
+          }}/>
+        </div>
+      }
+    }
+    /*switch (this.props.type) {
+        case '1':
+            //输入框
+            valueItem = <div style={{display: 'flex'}}>
+                <input placeholder='请输入' className='value-input'
+                       value={inputValue} onChange={this.inputChange}/>
+                <Icon name='angle right' style={{margin: '0px', padding: '0px', visibility: 'hidden'}}/>
+            </div>
+            break
+        case '2':
+            //日期选择框
+            valueItem = <div style={{display: 'flex'}}>
+                <DatePicker locale={locale} className='date-input'
+                            defaultValue={inputValue}
+                            format={dateFormat} size='small'
+                            onChange={this.onDatePicker}
+                            suffixIcon=' '/>
+                <Icon name='angle right' style={{margin: '0px', padding: '0px'}}/>
+            </div>
+            break
+        case '3':
+            //弹框选择
+            const {modalOpen, selectList} = this.state
+            let modalItems = []
+            for (let i = 0; i < selectList.length; i++) {
+                modalItems.push(<div className='selectItem' onClick={
+                    this.modalSelect.bind(this, i)
+                }>{selectList[i]}</div>)
+            }
+            valueItem = <Modal trigger={<div style={{display: 'flex'}} onClick={this.onSelectClick}>
+                <input placeholder='请选择' readOnly unselectable='on'
+                       className='value-input'
+                       value={inputValue}/>
+                <Icon name='angle right' style={{margin: '0px', padding: '0px'}}/>
+            </div>}
+                               open={modalOpen}
+                               onClose={this.modalClose}
+                               size='small'>
+                <Modal.Content image>
+                    <Modal.Description>
+                        {modalItems}
+                    </Modal.Description>
+                </Modal.Content>
+            </Modal>
+
+            break
+        default:
+            valueItem = <div></div>
+            break
+    }*/
+
+    return <div style={{ padding: '4px' }}>
+      <div className='points-parent'>
+        <div className='points-caption'>{mApproval.caption}</div>
+        <div className='points-value'>
+          {valueItem}
+        </div>
+      </div>
+    </div>
+
+  }
+
+  numKeyPress = (event) => {
+    const invalidChars = ['-', '+', 'e', '.', 'E']
+    if (invalidChars.indexOf(event.key) !== -1) {
+      event.preventDefault()
+    }
+  }
+
+  modalClose = () => {
+    this.setState({
+      modalOpen: false,
+    })
+  }
+
+  modalSelect = (index) => {
+    const { selectList } = this.state
+    this.setState({
+      inputValue: selectList[index],
+      modalOpen: false,
+    }, () => {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        this.state.inputValue, false)
+    })
+  }
+
+  inputChange = (e) => {
+    this.setState({
+      inputValue: e.target.value,
+    }, () => {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        this.state.inputValue, false)
+    })
+  }
+
+  onDatePicker = (e, dateString) => {
+    this.setState({
+      inputValue: dateString,
+    }, () => {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        this.state.inputValue, false)
+    })
+  }
+
+  onSelectClick = () => {
+    this.setState({
+      modalOpen: true,
+    })
+  }
+}

+ 70 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/pointsItem/pointsItem.css

@@ -0,0 +1,70 @@
+div {
+    margin: 0px;
+    padding: 0px;
+}
+
+.points-parent {
+    width: 100%;
+    display: flex;
+    box-sizing: border-box;
+    flex-direction: row;
+    align-items: center;
+    background: white;
+    border-bottom: 1px solid #ccc;
+    padding: 3px 0px;
+}
+
+.points-caption {
+    width: 100px;
+    color: #999999;
+    font-size: 12px;
+    margin-left: 6px;
+}
+
+.points-value {
+    flex: 1;
+    height: 26px;
+    text-align: right;
+    line-height: 26px;
+    margin-left: 6px;
+    color: #333333;
+    font-size: 13px;
+}
+
+.value-input, .date-input {
+    width: 100%;
+    background: none;
+    border: none;
+    text-align: right;
+}
+
+.ui.input input{
+    padding-left: 6px;
+}
+
+.value-input .ant-calendar-picker-input {
+    width: 100%;
+    color: #333333;
+    font-size: 13px;
+    padding-left: 6px;
+}
+
+.date-input .ant-calendar-picker-input {
+    width: 100%;
+    background: none;
+    border: none;
+    text-align: right;
+    color: #333333;
+    font-size: 13px;
+}
+
+.date-input .anticon {
+    display: none;
+}
+
+.selectItem {
+    height: 38px;
+    text-align: center;
+    line-height: 35px;
+    border-bottom: 1px solid #ccc;
+}

+ 265 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/tableItem/TableItem.jsx

@@ -0,0 +1,265 @@
+import React, { Component } from 'react'
+import './tableItem.css'
+import { Input, Modal } from 'semantic-ui-react'
+import { DatePicker, Radio } from 'antd'
+import locale from 'antd/lib/date-picker/locale/zh_CN'
+import { isObjEmpty, numFormat, strContain } from '../../../../../utils/common/common.util'
+import ApprovalBean from '../../model/ApprovalBean'
+import moment from 'moment'
+
+const RadioGroup = Radio.Group
+
+export default class TableItem extends Component {
+
+  componentDidMount () {
+    let { mApproval } = this.state
+
+    this.setState({
+      mApproval: this.props.approval,
+      approvalAble: this.props.approvalAble,
+    })
+    let options = []
+    let datas = mApproval.datas
+    if (!isObjEmpty(datas)) {
+      for (let i = 0; i < datas.length; i++) {
+        options.push(datas[i].display)
+      }
+    }
+    this.setState({
+      selectList: options,
+      inputValue: mApproval.values,
+    })
+    let values = mApproval.values
+    if (values == ApprovalBean.VALUES_YES
+      || values == '0') {
+      this.setState({
+        radioValue: 1,
+      })
+    } else if (values == ApprovalBean.VALUES_NO) {
+      this.setState({
+        radioValue: 2,
+      })
+    }
+  }
+
+  componentWillReceiveProps () {
+    this.componentDidMount()
+  }
+
+  constructor () {
+    super()
+
+    this.state = {
+      modalOpen: false,
+      selectList: [],
+      inputValue: '',
+      radioValue: 1,
+      mApproval: new ApprovalBean(),
+      approvalAble: true,//审批状态
+    }
+  }
+
+  render () {
+    let valueItem = ''
+    const dateFormat = 'YYYY-MM-DD'
+    const { inputValue, radioValue, selectList, mApproval, approvalAble } = this.state
+
+    if (approvalAble == false) {
+      if (mApproval.dfType == 'N'
+        || mApproval.dfType == 'floatcolumn8'
+        || mApproval.dfType == 'SN'
+        || strContain(mApproval.dfType, 'floatcolumn')) {
+        valueItem =
+          <div>{numFormat(mApproval.values)}</div>
+      } else {
+        valueItem =
+          <div dangerouslySetInnerHTML={{ __html: mApproval.values }}></div>
+      }
+    } else if (mApproval.neerInput) {
+      let placeHolder = ''
+      if (mApproval.mustInput) {
+        if (mApproval.inputType() == 2 || mApproval.inputType() == 3 ||
+          mApproval.inputType() == 4) {
+          placeHolder = '请选择(必选)'
+        } else {
+          placeHolder = '请输入(必填)'
+        }
+      } else {
+        if (mApproval.inputType() == 2 || mApproval.inputType() == 3 ||
+          mApproval.inputType() == 4) {
+          placeHolder = '请选择(非必选)'
+        } else {
+          placeHolder = '请输入(非必填)'
+        }
+      }
+      switch (mApproval.inputType()) {
+        case 0:
+          //字符输入
+          valueItem = <Input className='value-input' placeholder={placeHolder}
+                             value={inputValue} onChange={this.inputChange}/>
+          break
+        case 1:
+          //数字输入
+          valueItem = <Input type='number' onKeyPress={this.numKeyPress}
+                             className='value-input' placeholder={placeHolder}
+                             value={inputValue} onChange={this.inputChange}/>
+          break
+        case 2:
+          //日期选择框
+          let defaultDate = inputValue
+          if (!isObjEmpty(inputValue)) {
+            defaultDate = ''
+          } else {
+            defaultDate = moment(defaultDate, 'YYYY-MM-DD')
+            if (!defaultDate._isValid) {
+              defaultDate = ''
+            }
+          }
+          valueItem = <DatePicker locale={locale} className='value-input'
+                                  defaultValue={defaultDate}
+                                  placeholder={placeHolder}
+                                  format={dateFormat} size='small'
+                                  onChange={this.onDatePicker}/>
+          break
+        case 3:
+          //弹框选择
+          const { modalOpen } = this.state
+          let modalItems = []
+          for (let i = 0; i < selectList.length; i++) {
+            modalItems.push(<div className='selectItem' onClick={
+              this.modalSelect.bind(this, i)
+            }>{selectList[i]}</div>)
+          }
+          valueItem = <Modal trigger={<Input className='value-input'
+                                             readOnly unselectable='on'
+                                             placeholder={placeHolder}
+                                             onClick={this.onSelectClick}
+                                             value={inputValue}/>}
+                             open={modalOpen}
+                             onClose={this.modalClose}
+                             size='small'>
+            <Modal.Content image>
+              <Modal.Description>
+                {modalItems}
+              </Modal.Description>
+            </Modal.Content>
+          </Modal>
+
+          break
+        case 4:
+          //dbfind
+          valueItem = <Input className='value-input'
+                             readOnly unselectable='on'
+                             placeholder={placeHolder}
+                             onClick={this.onDbfindClick}
+                             value={inputValue}/>
+          break
+        case 5:
+          valueItem =
+            <RadioGroup onChange={this.onRadioChange} value={radioValue}>
+              <Radio value={1}>是</Radio>
+              <Radio value={2}>否</Radio>
+            </RadioGroup>
+          break
+        default:
+          valueItem = <div></div>
+          break
+      }
+    } else {
+      let oldValues = mApproval.oldValues
+      if (!isObjEmpty(oldValues)) {
+        valueItem = <div className='oldNewLayout'>
+          <span style={{ textDecoration: 'line-through' }}>{oldValues}</span>
+          <span style={{ color: '#f10813' }}>{mApproval.values}</span>
+        </div>
+      } else {
+        if (mApproval.dfType == 'N'
+          || mApproval.dfType == 'floatcolumn8'
+          || mApproval.dfType == 'SN'
+          || strContain(mApproval.dfType, 'floatcolumn')) {
+          valueItem =
+            <div>{numFormat(mApproval.values)}</div>
+        } else {
+          valueItem =
+            <div dangerouslySetInnerHTML={{ __html: mApproval.values }}></div>
+        }
+      }
+    }
+
+    return <div className='table-parent'>
+      <div className='table-caption'>{mApproval.caption}</div>
+      <div className='table-value'>
+        {valueItem}
+      </div>
+    </div>
+  }
+
+  onRadioChange = (e) => {
+    let value = e.target.value
+    this.setState({
+      radioValue: value,
+    })
+    if (value == 1) {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        ApprovalBean.VALUES_YES, false)
+    } else {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        ApprovalBean.VALUES_NO, false)
+    }
+  }
+
+  numKeyPress = (event) => {
+    const invalidChars = ['-', '+', 'e', '.', 'E']
+    if (invalidChars.indexOf(event.key) !== -1) {
+      event.preventDefault()
+    }
+  }
+
+  modalClose = () => {
+    this.setState({
+      modalOpen: false,
+    })
+  }
+
+  modalSelect = (index) => {
+    const { selectList } = this.state
+    this.setState({
+      inputValue: selectList[index],
+      modalOpen: false,
+    }, () => {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        this.state.inputValue, false)
+    })
+  }
+
+  inputChange = (e) => {
+    this.setState({
+      inputValue: e.target.value,
+    }, () => {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        this.state.inputValue, false)
+    })
+
+  }
+
+  onDatePicker = (e, dateString) => {
+    this.setState({
+      inputValue: dateString,
+    }, () => {
+      this.props.valueListener(this.props.approval.type, this.props.index,
+        this.state.inputValue, false)
+    })
+  }
+
+  onSelectClick = () => {
+    this.setState({
+      modalOpen: true,
+    })
+  }
+
+  onDbfindClick = () => {
+    if (this.props.onDbfindClick) {
+      this.props.onDbfindClick(this.props.approval.type, this.props.index)
+    }
+  }
+}

+ 45 - 0
uas-office-web/uas-mobile/src/pages/private/approval/components/tableItem/tableItem.css

@@ -0,0 +1,45 @@
+.table-parent {
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    /*align-items: center;*/
+    background: white;
+    padding: 4px 10px;
+    font-size: 13px;
+}
+
+.table-caption {
+    width: 100px;
+    color: #777777;
+}
+
+.table-value {
+    flex: 1;
+    color: #333333;
+    overflow: hidden;
+}
+
+.value-input {
+    height: 24px;
+    line-height: 24px;
+    color: #333333;
+    width: 100%;
+    margin-right: 10px;
+}
+
+DatePicker {
+    margin: 0px;
+    padding: 0px;
+}
+
+.selectItem {
+    height: 38px;
+    text-align: center;
+    line-height: 35px;
+    border-bottom: 1px solid #ccc;
+}
+
+.oldNewLayout {
+    display: flex;
+    flex-direction: column;
+}

+ 92 - 0
uas-office-web/uas-mobile/src/pages/private/approval/index.css

@@ -0,0 +1,92 @@
+@import "~antd/dist/antd.css";
+@import "~semantic-ui-css/semantic.min.css";
+
+.gray-line {
+    width: 100%;
+    background: #dedede;
+}
+
+.displayNone {
+    display: none;
+}
+
+.visibleHidden {
+    visibility: hidden;
+}
+
+.common-flex-row {
+    display: flex;
+    flex-direction: row;
+}
+
+.common-flex-row-10 {
+    display: flex;
+    flex-direction: row;
+    padding: 10px;
+    align-items: center;
+}
+
+.common-flex-row-12 {
+    display: flex;
+    flex-direction: row;
+    padding: 12px;
+    align-items: center;
+}
+
+.common-flex-row-16 {
+    display: flex;
+    flex-direction: row;
+    padding: 16px;
+    align-items: center;
+}
+
+.am-tabs-pane-wrap.am-tabs-pane-wrap-active::-webkit-scrollbar {
+    display: none;
+}
+
+.am-pull-to-refresh.am-pull-to-refresh-up::-webkit-scrollbar {
+    display: none;
+}
+
+input {
+    outline: none;
+    border: none;
+}
+
+textarea {
+    resize: none
+}
+
+textarea::-webkit-scrollbar {
+    display: none;
+}
+
+.common-load-more {
+    width: 100%;
+    height: 54px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+.search-bar-root {
+    width: 100%;
+    height: 40px;
+    padding: 6px;
+    background: #F6F6F6;
+}
+
+.search-bar-layout {
+    width: 100%;
+    height: 100%;
+    background: white;
+    font-family: PingFangSC-Regular;
+    font-size: 14px;
+    color: #8C8C8C;
+    display: flex;
+    align-items: center;
+    padding-left: 14px;
+    border-radius: 6px;
+}
+
+

+ 145 - 0
uas-office-web/uas-mobile/src/pages/private/approval/model/ApprovalBean.js

@@ -0,0 +1,145 @@
+import { isObjEmpty, isObjNull, strContain } from '../../../../utils/common/common.util'
+import moment from 'moment'
+
+export default function ApprovalBean (type) {
+  this.neerInput = false//是否需要输入
+  this.mustInput = false//是否是必填字段
+  this.id = -1
+  this.type = type
+  this.idKey = ''
+  this.caller = ''
+  this.gCaller = ''
+  this.coreKey = ''
+  this.dfType = ''//返回的字段类型
+  this.dbFind = ''//是否dbfind的判断
+  this.caption = ''//字幕,表示备注
+  this.values = ''//字幕对应的值显示
+  this.oldValues = ''//变更前的值
+  this.valuesKey = ''//字幕对应的值显示的key值
+  this.datas = []
+
+  this.data2Values = function () {
+    switch (this.dfType) {
+      case 'D':
+        this.data2DType()
+        break
+      case 'B':
+        if (this.values == 1) {
+          this.values = ApprovalBean.VALUES_YES
+        } else {
+          this.values = ApprovalBean.VALUES_NO
+        }
+        this.setOldSelectValues()
+        break
+      case 'YN':
+        if (this.values == '-1') {
+          this.values = ApprovalBean.VALUES_YES
+        } else if (this.values == 1 && this.type == ApprovalBean.DETAIL &&
+          this.neerInput) {
+          this.values = ApprovalBean.VALUES_UNKNOWN
+        } else {
+          this.values = ApprovalBean.VALUES_NO
+        }
+        this.setOldSelectValues()
+        break
+      case 'C':
+        if (this.values == '-1') {
+          this.values = ApprovalBean.VALUES_YES
+        } else if (this.values == '1' && this.type == ApprovalBean.DETAIL &&
+          this.neerInput) {
+          this.values = ApprovalBean.VALUES_UNKNOWN
+        } else if (this.values == '0') {
+          this.values = ApprovalBean.VALUES_NO
+        }
+        this.setOldSelectValues()
+        break
+    }
+  }
+
+  this.isDBFind = function () {
+    return (this.dbFind == 'T' || this.dbFind == 'AT' || this.dbFind == 'M' ||
+      this.dbFind == 'DF')
+  }
+
+  this.setOldSelectValues = function () {
+    if (!isObjNull(this.oldValues)) {
+      if (this.oldValues == '0') {
+        this.oldValues = ApprovalBean.VALUES_NO
+      } else if (this.oldValues == '-1' || this.oldValues == '1') {
+        this.oldValues = ApprovalBean.VALUES_YES
+      }
+    }
+  }
+
+  this.data2DType = function () {
+    // let time = Date.parse(new Date(this.values.replace(/\-/g, '/')))
+    // if (time > 0) {
+    //   let newDate = new Date()
+    //   newDate.setTime(time)
+    //   this.values = moment(newDate).format('YYYY-MM-DD')
+    // }
+    if (!isObjEmpty(this.values)) {
+      let newDate = new Date(this.values.replace(/\-/g, '/'))
+      if (!isObjEmpty(newDate) && newDate !== 'Invalid date') {
+        this.values = moment(newDate).format('YYYY-MM-DD')
+      }
+    }
+
+    if (!isObjEmpty(this.oldValues)) {
+      let oldDate = new Date(this.oldValues.replace(/\-/g, '/'))
+      if (!isObjEmpty(oldDate) && oldDate !== 'Invalid date') {
+        this.oldValues = moment(oldDate).format('YYYY-MM-DD')
+      }
+    }
+  }
+
+  this.isNumber = function () {
+    return this.dfType == 'N'
+      || this.dfType == 'floatcolumn8'
+      || this.dfType == 'SN'
+      || strContain(this.dfType, 'floatcolumn')
+  }
+
+  this.isSelect = function () {
+    return this.dfType == 'C' || this.dfType == 'D' || this.dfType == 'DT'
+      || this.dfType == 'C' || this.dfType == 'YN' || this.dfType == 'B'
+  }
+
+  /**
+   * 输入类型:0字符输入  1.数字输入  2.日期输入选择  3.下拉选择  4.dbfind
+   */
+  this.inputType = function () {
+    if (this.isNumber()) {
+      return 1
+    } else if (this.dfType == 'DT' || this.dfType == 'D') {
+      return 2
+    } else if (this.dfType == 'C') {
+      return 3
+    } else if (this.isDBFind()) {
+      return 4
+    } else if (this.dfType == 'B' || this.dfType == 'YN') {
+      return 5
+    }
+    return 0
+  }
+
+}
+
+ApprovalBean.Data = function (value, display) {
+  this.value = value
+  this.display = display
+}
+
+ApprovalBean.VALUES_YES = '是'
+ApprovalBean.VALUES_NO = '否'
+ApprovalBean.VALUES_UNKNOWN = '未选择'
+
+ApprovalBean.TITLE = 11//标题
+ApprovalBean.MAIN = 12  //主表
+ApprovalBean.DETAIL = 13//从表
+ApprovalBean.SETUPTASK = 14//历史审批要点
+ApprovalBean.ENCLOSURE = 16//附件
+ApprovalBean.POINTS = 17//要点
+ApprovalBean.NODES_TAG = 18//审批节点标记
+ApprovalBean.NODES = 19//审批节点
+ApprovalBean.TAG = 20//标题

+ 21 - 0
uas-office-web/uas-mobile/src/pages/private/approval/model/ApprovalRecordBean.js

@@ -0,0 +1,21 @@
+export default function ApprovalRecordBean() {
+    this.isForknode = false;
+    this.id = 0;
+    this.nodeId = 0;
+    this.title = "";
+    this.chcheNode = "";
+    this.imid = "";
+    this.status = "";
+    this.currentNodeMan = "";//当前节点的人员编号
+    this.nodeName = "";
+    this.needInputKeys = "";
+    this.showNeedMessage = "";//保存必填字段时候,,没有填写时候提示信息
+    this.processInstanceId = "";
+    this.caller = "";
+    this.callerName = "";
+
+
+    this.getCallerName = function () {
+        return this.callerName.replace('流程', '')
+    }
+}

+ 63 - 0
uas-office-web/uas-mobile/src/pages/private/approval/model/BillGroupModel.js

@@ -0,0 +1,63 @@
+/**
+ * 单据分组Model
+ * @constructor
+ */
+import { isObjEmpty, isObjNull } from '../../../../utils/common/common.util'
+
+export default function BillGroupModel () {
+  this.isDeleteAble = false//是否可以删除
+  this.isForm = false//是否是主表
+  this.lastInType = false//是否当前单据明细的最后一个
+  this.groupIndex = 0//当前组所在的整个显示集合里面的索引
+  this.gridIndex = 0//当前组在明细表内的索引
+  this.minDetno = 10000000//最小的序号
+  this.group = ''//组名
+  this.keyField = ''//提交时候主表或明细表id字段名称
+  this.mTagMap = {}//附带信息
+  this.billCaller = ''//表caller
+
+  this.hideBillFields = []//当前组隐藏的字段列表
+  this.showBillFields = []//当前组显示的字段列表
+  this.updateBillFields = []//当前组可更新的字段列表
+  this.dex = 0//当前组所在的整个显示集合里面的索引
+
+  this.updateTagMap = function (key, value) {
+    if (isObjEmpty(key)) {
+      return
+    }
+    if (isObjNull(this.mTagMap)) {
+      this.mTagMap = {}
+    }
+    this.mTagMap.key = value
+  }
+
+  this.addHide = function (billModel) {
+    if (isObjNull(billModel)) {
+      return
+    }
+    if (isObjNull(this.hideBillFields)) {
+      this.hideBillFields = []
+    }
+    this.hideBillFields.push(billModel)
+  }
+
+  this.addShow = function (billModel) {
+    if (isObjNull(billModel)) {
+      return
+    }
+    if (isObjNull(this.showBillFields)) {
+      this.showBillFields = []
+    }
+    this.showBillFields.push(billModel)
+  }
+
+  this.addUpdate = function (billModel) {
+    if (isObjNull(billModel)) {
+      return
+    }
+    if (isObjNull(this.updateBillFields)) {
+      this.updateBillFields = []
+    }
+    this.updateBillFields.push(billModel)
+  }
+}

+ 79 - 0
uas-office-web/uas-mobile/src/pages/private/approval/model/BillModel.js

@@ -0,0 +1,79 @@
+import { isObjEmpty, isObjNull } from '../../../../utils/common/common.util'
+
+export default function BillModel (billModel) {
+  if (isObjNull(billModel)) {
+    this.id = 0//id
+    this.groupIndex = 0//所在组索引
+    this.detno = 1000000//序号
+    this.length = 0//字符长度
+    this.appwidth = 0//宽度
+    this.isdefault = 0//是否显示
+    this.dbfind = ''//是否是dbfind字段判定
+    this.caption = ''//字段名称
+    this.type = ''//类型(标题类型为Constants.TYPE_TITLE,不触发点击事件等 )
+    this.logicType = ''//logic类型
+    this.readOnly = ''//字段是否只读  T/F
+    this.field = ''//字段
+    this.value = ''//值
+    this.display = ''//上传值
+    this.defValue = ''//默认值
+    this.findFunctionName = ''//默认值
+    this.allowBlank = ''//是否允许为空(注:当作为标题的时候T:表示可以删除 F:表示不可删除)
+    this.renderer = ''
+    this.enclusureId = ''
+    this.localDatas = []//获取到的本地选择数据
+    this.mBillJump = ''//判断是否需要要跳转字段
+    this.mTabList = []//是否
+    this.updatable = ''//是否可更新
+    this.editable = ''//是否可编辑(临时属性,对某些字段的特殊处理,和字段本身属性无关,在添加明细时,要重置这个值)
+  } else {
+    this.id = billModel.id
+    this.groupIndex = billModel.groupIndex + 1
+    this.length = billModel.length
+    this.detno = billModel.detno
+    this.appwidth = billModel.appwidth
+    this.isdefault = billModel.isdefault
+    this.dbfind = billModel.dbfind
+    this.caption = billModel.caption
+    this.type = billModel.type
+    this.logicType = billModel.logicType
+    this.readOnly = billModel.readOnly
+    this.field = billModel.field
+    this.defValue = billModel.defValue
+    this.renderer = billModel.renderer
+    this.enclusureId = billModel.enclusureId
+    this.allowBlank = billModel.allowBlank
+    this.findFunctionName = billModel.findFunctionName
+    this.mBillJump = billModel.mBillJump
+    this.localDatas = billModel.localDatas
+    this.mTabList = billModel.mTabList
+    this.updatable = billModel.updatable
+    this.editable = ''//复制字段时要重置
+
+    this.isShow = billModel => (
+      billModel.isdefault === -1 && billModel.type === 'H'
+    )
+    if (this.isShow(billModel) == false
+      && !isObjEmpty(billModel.renderer)
+      && billModel.renderer.indexOf('defaultValue') != -1) {
+      //隐藏字段,renderer里包含defaultValue,则复制value
+      this.value = billModel.value
+      this.display = billModel.display
+    } else {
+      this.value = ''
+      this.display = ''
+    }
+  }
+
+  this.getValue = () => (
+    this.value || this.defValue || ''
+  )
+
+  this.getDisplay = () => (
+    this.display || this.getValue()
+  )
+}
+
+export const TYPE_TITLE = 'LOCAL_TITLE'
+export const TYPE_ADD = 'LOCAL_ADD'
+export const TYPE_TAB = 'LOCAL_TAB'

+ 20 - 0
uas-office-web/uas-mobile/src/pages/private/approval/model/EmployeeModel.js

@@ -0,0 +1,20 @@
+/**
+ * Created by RaoMeng on 2020/2/27
+ * Desc: 组织架构
+ */
+
+export default function EmployeeModel () {
+  this.EM_ID = 0
+  this.Em_IMID = ''
+  this.EM_CODE = ''
+  this.EM_NAME = ''
+  this.EM_POSITION = ''
+  this.EM_DEFAULTORNAME = ''
+  this.EM_DEPART = ''
+  this.EM_MOBILE = ''
+  this.EM_EMAIL = ''
+  this.EM_UU = ''
+  this.COMPANY = ''
+  this.WHICHSYS = ''
+  this.Em_defaultorid = ''
+}

+ 8 - 0
uas-office-web/uas-mobile/src/pages/private/approval/model/LocalData.js

@@ -0,0 +1,8 @@
+export default function LocalData () {
+  this.value = ''//显示的值  ||附件时候表示 路径,文件名
+  this.display = ''//上传的值 ||附件时候表示上传的附件id
+
+  this.name = ''
+  this.obj = {}//选项对象
+  this.isSelected = false//是否被选中,用于多选
+}

+ 2673 - 0
uas-office-web/uas-mobile/src/pages/private/approval/pages/Approval.jsx

@@ -0,0 +1,2673 @@
+import React, { Component } from 'react'
+import './approval.css'
+import '../index.css'
+import { Icon, TextArea } from 'semantic-ui-react'
+import PointsItem from '../components/pointsItem/PointsItem'
+import TableItem from '../components/tableItem/TableItem'
+import ApprovalNode from '../components/approvalNode/ApprovalNode'
+import { Avatar, message, Popover, Spin } from 'antd'
+import ApprovalBean from '../model/ApprovalBean'
+import ApprovalRecordBean from '../model/ApprovalRecordBean'
+import { ListView, Modal, SearchBar, Toast, List } from 'antd-mobile'
+import {
+  fetchGet,
+  fetchPostForm,
+} from '../../../../utils/common/fetchRequest'
+import { connect } from 'react-redux'
+import {
+  getArrayValue,
+  getBracketStr,
+  getIntValue,
+  getObjValue,
+  getParenthesesStr,
+  getStrValue,
+  getTimeValue,
+  isEmptyObject,
+  isObjEmpty,
+  isObjNull,
+  MapToJson,
+  strMapToObj,
+  strContain,
+} from '../../../../utils/common/common.util'
+import EnclosureItem from '../components/enclosureItem/EnclosureItem'
+import {
+  clearSendState,
+  saveReceiveState,
+} from '../../../../redux/actions/approvalState'
+import EmployeeItem from '../components/employeeItem/EmployeeItem'
+import LocalData from '../model/LocalData'
+import { _baseURL } from '../../../../configs/api.config'
+
+const operation = Modal.operation
+const alert = Modal.alert
+//==============================================================================================
+let mType//0或undefined:待审批; 1:已审批; 2:我发起的;
+let mMaster, mSessionId, mEmcode, mNodeId, mCachePoints
+let mApprovalRecord = new ApprovalRecordBean()
+let mTitleApproval = new ApprovalBean()
+let mParams = []
+let mFormStore = new Map()
+
+let mHineApprovals = []//隐藏字段
+let mShowApprovals = []//显示字段
+let mHistoryNodes = []//历史审批
+let mMainList = []//主表
+let mDetailList = []//从表
+let mSetuptasList = []//历史审批要点
+let mEnclosureList = []//附件
+let mNodeList = []//审批节点
+let mPointsList = []//要点
+
+let mModalList = []//组织架构、放大镜
+
+let mBaseUrl
+const SELECT_APPROVAL = 'select_approval'
+
+const defaultApprovalState = {
+  approvalContent: '',
+  fastList: [
+    '赞',
+    'OK',
+    '加油',
+    '好的',
+    '请及时完成',
+  ],
+  fastModalOpen: false,
+  approvalIndex: 0,
+  loading: true,
+  finished: false,
+  finishSuccess: true,
+  finishMsg: '审批流程结束',
+
+  disagreeAble: true,//不同意按钮是否显示
+  agreeAble: true,//同意按钮是否显示
+  takeoverAble: false,//接管按钮是否显示
+  changeAble: false,//变更处理人按钮是否显示
+  optionAble: false,//底部审批操作布局是否显示
+  nodesTagAble: false,//审批节点切换是否显示
+  revokeAble: false,//撤回按钮是否显示
+
+  approvalStatus: 0,//审批状态 0:待审批;1:审批通过;2:审批不通过:3:异常结束
+  approvalAble: false,
+
+  titleApproval: {
+    caption: '',
+  },
+  historyNodes: [],//历史审批
+  mainList: [],//主表
+  detailList: [],//从表
+  setuptasList: [],//历史审批要点
+  enclosureList: [],//附件
+  nodeList: [],//审批节点
+  pointsList: [],//要点
+
+  changeModalOpen: false,//变更处理人弹框是否显示
+  changeDataSource: new ListView.DataSource({
+    rowHasChanged: (row1, row2) => row1 !== row2,
+  }),//变更处理人列表
+  selectModel: {},//被选中的item
+}
+
+class Approval extends Component {
+
+  constructor () {
+    super()
+
+    this.state = defaultApprovalState
+  }
+
+  componentDidMount () {
+    document.title = '审批单据'
+    this.initData()
+    let paramsStr = this.props.match.params.paramsStr
+    if (isObjEmpty(paramsStr)) {
+      let storage = window.localStorage
+      paramsStr = storage.getItem('paramJson')
+    }
+    console.log('paramsStr', paramsStr)
+    if (!isObjEmpty(paramsStr)) {
+      try {
+        let paramsJson = JSON.parse(decodeURIComponent(paramsStr))
+
+        paramsJson.baseUrl
+          ? (mBaseUrl = decodeURIComponent(paramsJson.baseUrl))
+          : (mBaseUrl = _baseURL)
+        mMaster = paramsJson.master
+        mNodeId = paramsJson.nodeId
+        mType = paramsJson.type
+
+        this.getCurrentNode()
+        // this.loginErp()
+      } catch (e) {
+        this.setState({
+          loading: false,
+        })
+        message.error('参数获取失败')
+      }
+    } else {
+      this.setState({
+        loading: false,
+      })
+      message.error('参数获取失败')
+    }
+  }
+
+  componentWillUnmount () {
+    Toast.hide()
+    this.moreOperation && this.moreOperation.close()
+    this.revokeAlert && this.revokeAlert.close()
+  }
+
+  initData = () => {
+    mCachePoints = ''
+    mApprovalRecord = new ApprovalRecordBean()
+    mTitleApproval = new ApprovalBean()
+    mParams = []
+    mFormStore = new Map()
+    mHineApprovals = []//隐藏字段
+    mShowApprovals = []//显示字段
+    mHistoryNodes = []//历史审批
+    mMainList = []//主表
+    mDetailList = []//从表
+    mSetuptasList = []//历史审批要点
+    mEnclosureList = []//附件
+    mNodeList = []//审批节点
+    mPointsList = []//要点
+    mModalList = []
+  }
+
+  getSessionId () {
+    const c_name = 'JSESSIONID'
+    if (document.cookie.length > 0) {
+      let c_start = document.cookie.indexOf(c_name + '=')
+      if (c_start != -1) {
+        c_start = c_start + c_name.length + 1
+        let c_end = document.cookie.indexOf(';', c_start)
+        if (c_end == -1) {
+          c_end = document.cookie.length
+        }
+        return unescape(document.cookie.substring(c_start, c_end))
+      }
+    }
+  }
+
+  render () {
+    const {
+      loading,
+      finished,
+      finishMsg,
+      finishSuccess,
+      approvalContent,
+      fastList,
+      fastModalOpen,
+      approvalIndex,
+      disagreeAble,//不同意按钮是否显示
+      agreeAble,//同意按钮是否显示
+      takeoverAble,//接管按钮是否显示
+      changeAble,//变更处理人按钮是否显示
+      revokeAble,//撤回按钮是否显示
+      optionAble,
+      titleApproval,
+      nodesTagAble,
+      historyNodes,//历史审批
+      mainList,//主表
+      detailList,//从表
+      setuptasList,//历史审批要点
+      enclosureList,//附件
+      nodeList,//审批节点
+      pointsList,//要点
+      approvalStatus,//审批状态
+      approvalAble,
+
+      changeModalOpen,//变更处理人弹框是否显示
+      changeDataSource,//变更处理人列表
+      selectModel,
+    } = this.state
+
+    //审批常用语
+    let fastItems = []
+    for (let i = 0; i < fastList.length; i++) {
+      fastItems.push(<div key={'fast' + i} className='fastItem' onClick={
+        this.fastSelect.bind(this, i)
+      }>{fastList[i]}</div>)
+    }
+
+    let tableItems = []
+    //主表字段
+    for (let i = 0; i < mainList.length; i++) {
+      tableItems.push(<TableItem key={'main' + i} approval={mainList[i]}
+                                 index={i}
+                                 approvalAble={approvalAble}
+                                 onDbfindClick={this.onDbfindClick.bind(this)}
+                                 valueListener={this.childStateListener.bind(
+                                   this)}/>)
+    }
+
+    //从表字段
+    if (!isObjEmpty(detailList)) {
+      tableItems.push(<div className='gray-line'
+                           style={{ height: '6px' }}></div>)
+      for (let i = 0; i < detailList.length; i++) {
+        let detailObject = detailList[i]
+        if (detailObject.type == ApprovalBean.TAG) {
+          tableItems.push(<div
+            className='tableTitle'>{detailObject.caption}</div>)
+        } else {
+          tableItems.push(<TableItem key={'detail' + i} approval={detailList[i]}
+                                     index={i}
+                                     approvalAble={approvalAble}
+                                     onDbfindClick={this.onDbfindClick.bind(
+                                       this)}
+                                     valueListener={this.childStateListener.bind(
+                                       this)}/>)
+        }
+      }
+    }
+
+    //历史审批要点
+    if (!isObjEmpty(setuptasList)) {
+      tableItems.push(<div className='gray-line'
+                           style={{ height: '6px' }}></div>)
+      for (let i = 0; i < setuptasList.length; i++) {
+        let detailObject = setuptasList[i]
+        if (detailObject.type == ApprovalBean.TAG) {
+          tableItems.push(<div
+            className='tableTitle'>{detailObject.caption}</div>)
+        } else {
+          tableItems.push(<TableItem key={'setup' + i}
+                                     approval={setuptasList[i]} index={i}
+                                     approvalAble={approvalAble}
+                                     valueListener={this.childStateListener.bind(
+                                       this)}></TableItem>)
+        }
+      }
+    }
+
+    //附件列表
+    let enclosureItems = []
+    if (!isObjEmpty(enclosureList)) {
+      for (let i = 0; i < enclosureList.length; i++) {
+        let enclosureObject = enclosureList[i]
+        if (enclosureObject.type == ApprovalBean.TAG) {
+          enclosureItems.push(<div
+            className='tableTitle'>{enclosureObject.caption}</div>)
+        } else {
+          enclosureItems.push(<EnclosureItem key={'enclosure' + i}
+                                             approval={enclosureObject}
+                                             index={i}
+                                             onEnclosureSelect={
+                                               this.onEnclosureSelect.bind(this)
+                                             }/>)
+        }
+      }
+    }
+
+    //审批要点
+    let pointItems = []
+    for (let i = 0; i < pointsList.length; i++) {
+      let pointsObject = pointsList[i]
+      if (pointsObject.type == ApprovalBean.TAG) {
+        pointItems.push(<div
+          className='tableTitle'>{pointsObject.caption}</div>)
+      } else {
+        pointItems.push(<PointsItem key={'points' + i} approval={pointsList[i]}
+                                    index={i}
+                                    approvalAble={approvalAble}
+                                    valueListener={this.childStateListener.bind(
+                                      this)}></PointsItem>)
+      }
+    }
+
+    //审批节点
+    let approvalPoint = []
+
+    approvalPoint.push(<div key='node_tag' className={nodesTagAble
+      ? 'approval_tab_parent'
+      : 'displayNone'}>
+      <div className={approvalIndex == 0 ?
+        'approval_tab_selected' : 'approval_tab_normal'}
+           onClick={this.approvalTabSelect1}>审批节点
+      </div>
+      <div
+        style={{ background: '#cccccc', width: '1px', height: '20px' }}></div>
+      <div className={approvalIndex == 1 ?
+        'approval_tab_selected' : 'approval_tab_normal'}
+           onClick={this.approvalTabSelect2}>审批历史
+      </div>
+    </div>)
+
+    if (nodesTagAble) {
+      for (let i = 0; i < nodeList.length; i++) {
+        approvalPoint.push(<div
+          className={approvalIndex == 0 ? '' : 'displayNone'}>
+          <ApprovalNode key={'nodes' + i} isFirst={i == 0}
+                        isLast={i == nodeList.length - 1}
+                        approval={nodeList[i]}></ApprovalNode>
+        </div>)
+      }
+      for (let i = 0; i < historyNodes.length; i++) {
+        approvalPoint.push(<div
+          className={approvalIndex == 1 ? '' : 'displayNone'}>
+          <ApprovalNode key={'history' + i} isFirst={i == 0}
+                        isLast={i == historyNodes.length - 1}
+                        approval={historyNodes[i]}></ApprovalNode>
+        </div>)
+      }
+    } else {
+      for (let i = 0; i < nodeList.length; i++) {
+        approvalPoint.push(<ApprovalNode key={'nodes' + i} isFirst={i == 0}
+                                         isLast={i == nodeList.length - 1}
+                                         approval={nodeList[i]}></ApprovalNode>)
+      }
+    }
+
+    return <div style={{ width: '100%', height: '100%' }}>
+      <div className='finishedLayout'
+           style={{ display: finished ? 'flex' : 'none' }}>
+        <Icon name={finishSuccess ? 'check circle' : 'warning circle'}
+              size='huge'
+              color={finishSuccess ? 'green' : 'red'}/>
+        <span style={{
+          marginTop: '10px',
+          color: finishSuccess ? 'green' : 'red',
+        }}>{finishMsg}</span>
+      </div>
+
+      <Spin size="large"
+            style={{ display: finished ? 'none' : (loading ? 'flex' : 'none') }}
+            tip='数据请求中...'>
+      </Spin>
+
+      <div className='approval-detail-root'
+           style={{ display: finished ? 'none' : (loading ? 'none' : 'flex') }}>
+        <div className='content'>
+          <div className='headerLayout'>
+            <Avatar size={42} src={require('../../../../res/img/default_header.png')}/>
+            <div className='headerText'>
+              <div>{titleApproval.caption}</div>
+              <div style={{
+                fontSize: '12px',
+                color: '#333333',
+                marginTop: '4px',
+              }}>{titleApproval.masterName}</div>
+            </div>
+            {
+              approvalStatus === 0 ? null
+                : approvalStatus == 1 ?
+                <Avatar
+                  size={54} style={{ marginRight: 10 }}
+                  src={require('../../../../res/img/approved.png')}/>
+                : approvalStatus == 2 ?
+                  <Avatar
+                    size={54} style={{ marginRight: 10 }}
+                    src={require('../../../../res/img/unapproved.png')}/>
+                  : approvalStatus == 3 ?
+                    <Avatar
+                      size={54} style={{ marginRight: 10 }}
+                      src={require('../../../../res/img/endapproved.png')}/> : null
+            }
+          </div>
+          <div className='gray-line' style={{ height: '1px' }}></div>
+          {tableItems}
+          {enclosureItems.length > 0
+            ? <div className='gray-line'
+                   style={{ height: '6px' }}></div>
+            : ''}
+          {enclosureItems}
+          {pointItems.length > 0 ? <div className='gray-line'
+                                        style={{ height: '6px' }}></div> : ''}
+          {pointItems}
+          <div className='gray-line' style={{ height: '6px' }}></div>
+          {approvalPoint}
+        </div>
+        {
+          (approvalAble == true) ? (
+              //待审批,且可操作
+              <div className={optionAble ? 'bottomMenu' : 'displayNone'}>
+                <div className='gray-line' style={{ height: '2px' }}></div>
+                <div className='editLayout'>
+                  <Icon disabled name='edit'/>
+                  <TextArea className='editInput'
+                            value={approvalContent}
+                            placeholder='请输入审批意见...'
+                            onChange={this.approvalEdit}/>
+                  <Popover title='常用语' trigger='click'
+                           content={fastItems}
+                           visible={fastModalOpen}
+                           onVisibleChange={this.handleFastVisiable}>
+                    <div className='fastWords' onClick={this.fastClick}>常</div>
+                  </Popover>
+                </div>
+                <div className='gray-line' style={{ height: '6px' }}></div>
+                <div className='menuParent'>
+                  <div className={takeoverAble ? 'menuItem' : 'displayNone'}
+                       onClick={this.approvalTakeover}>接管
+                  </div>
+                  <div className={takeoverAble ? '' : 'displayNone'}
+                       style={{
+                         background: '#cccccc',
+                         width: '1px',
+                         height: '24px',
+                       }}></div>
+
+                  <div className={agreeAble ? 'menuItem' : 'displayNone'}
+                       onClick={this.approvalAgree}>同意
+                  </div>
+                  <div className={agreeAble ? '' : 'displayNone'}
+                       style={{
+                         background: '#cccccc',
+                         width: '1px',
+                         height: '24px',
+                       }}></div>
+
+                  <div className={disagreeAble ? 'menuItem' : 'displayNone'}
+                       onClick={this.approvalDisagree}>不同意
+                  </div>
+                  <div className={disagreeAble ? '' : 'displayNone'}
+                       style={{
+                         background: '#cccccc',
+                         width: '1px',
+                         height: '24px',
+                       }}></div>
+
+                  <div
+                    className={approvalStatus === 0 ? 'menuItem' : 'displayNone'}
+                    onClick={this.moreMenu}>更多
+                  </div>
+                </div>
+              </div>)
+            : ((mType == 2) ? (
+                //mType=2 我发起的单据 操作菜单
+                <div className={optionAble ? 'bottomMenu' : 'displayNone'}>
+                  <div className='gray-line' style={{ height: '2px' }}></div>
+                  <div className='menuParent'>
+                    <div className={approvalStatus === 0
+                      ? 'menuItem'
+                      : 'displayNone'}
+                         onClick={this.urgeToApproval}>催办
+                    </div>
+                    <div className={approvalStatus === 0 ? '' : 'displayNone'}
+                         style={{
+                           background: '#cccccc',
+                           width: '1px',
+                           height: '24px',
+                         }}></div>
+
+                    <div className={revokeAble ? 'menuItem' : 'displayNone'}
+                         onClick={this.revokeApproval}>撤回
+                    </div>
+                    <div className={revokeAble ? '' : 'displayNone'}
+                         style={{
+                           background: '#cccccc',
+                           width: '1px',
+                           height: '24px',
+                         }}></div>
+
+                    <div
+                      className={'menuItem'}
+                      onClick={this.loadNextMine}>下一条
+                    </div>
+                  </div>
+                </div>
+              ) : (
+                (mType == 1) ? (
+                  //【我的审批】-【已审批】
+                  <div className={optionAble ? 'bottomMenu' : 'displayNone'}>
+                    <div className='gray-line' style={{ height: '2px' }}></div>
+                    <div className='menuParent'>
+                      <div
+                        className={'menuItem'}
+                        onClick={this.loadNextMine}>下一条
+                      </div>
+                    </div>
+                  </div>
+                ) : ''
+              )
+            )
+        }
+        {/*变更处理人、放大镜弹出框*/}
+        {this.getChangeModal()}
+      </div>
+    </div>
+  }
+
+  /**
+   * 弹出【更多】操作弹框
+   */
+  moreMenu = () => {
+    const { takeoverAble } = this.state
+    let actions = []
+
+    if (!takeoverAble) {
+      actions.push({ text: '变更处理人', onPress: this.approvalChange })
+    }
+    actions.push({ text: '下一条', onPress: this.loadNextProcess })
+    this.moreOperation = operation(actions)
+  }
+
+  /*变更处理人、放大镜弹框*/
+  getChangeModal () {
+    const {
+      changeModalOpen,//变更处理人弹框是否显示
+      changeDataSource,//变更处理人列表
+      selectModel,//选中的item
+    } = this.state
+    return <Modal visible={changeModalOpen}
+                  animationType={'slide-up'}
+                  onClose={() => {
+                    this.setState({
+                      changeModalOpen: false,
+                      selectModel: {},
+                    })
+                    if (selectModel.type == SELECT_APPROVAL
+                      && this.state.approvalStatus == 1) {
+                      this.loadNextProcess()
+                    }
+                  }}
+                  title={selectModel.caption}
+                  popup
+    >
+      <SearchBar
+        placeholder={'搜索人员'}
+        maxLength={12}
+        onChange={value => {
+          if (isObjEmpty(value)) {
+            this.setState({
+              changeDataSource: changeDataSource.cloneWithRows(
+                mModalList),
+            })
+          } else {
+            let searchList = []
+            if (!isObjEmpty(mModalList)) {
+              mModalList.forEach(item => {
+                if (!isObjNull(item)
+                  && (
+                    strContain(item.values, value)
+                    || strContain(item.value, value)
+                    || strContain(item.display, value)
+                    || strContain(item.name, value)
+                    || strContain(item.EM_CODE, value)
+                    || strContain(item.EM_NAME, value)
+                    || strContain(item.EM_POSITION, value)
+                    || strContain(item.EM_DEFAULTORNAME, value)
+                    || strContain(item.EM_DEPART, value)
+                    || strContain(item.EM_MOBILE, value)
+                    || strContain(item.EM_EMAIL, value)
+                    || strContain(item.COMPANY, value)
+                  )) {
+                  searchList.push(item)
+                }
+              })
+            }
+            this.setState({
+              changeDataSource: changeDataSource.cloneWithRows(
+                searchList),
+            })
+          }
+        }}
+        onClear={value => {
+          this.setState({
+            changeDataSource: changeDataSource.cloneWithRows(
+              mModalList),
+          })
+        }}
+        /*onCancel={value => {
+          this.setState({
+            changeDataSource: changeDataSource.cloneWithRows(
+              mModalList),
+          })
+        }}*/
+      />
+      <ListView
+        dataSource={this.state.changeDataSource}
+        initialListSize={30}
+        renderRow={(rowData, sectionID, rowID) => {
+          switch (selectModel.type) {
+            case SELECT_APPROVAL:
+              return <List.Item
+                key={rowID}
+                wrap
+                onClick={this.onChangeSelect.bind(this,
+                  rowData)}>
+                <EmployeeItem employee={rowData}/>
+              </List.Item>
+            default:
+              return <List.Item
+                key={rowID}
+                wrap
+                onClick={this.onDbfindSelect.bind(this,
+                  selectModel,
+                  rowData)}>{rowData.value}</List.Item>
+          }
+        }}
+        style={{
+          height: '72vh',
+          overflow: 'auto',
+        }}
+        pageSize={20}
+        // onScroll={() => {}}
+        // scrollRenderAheadDistance={500}
+        // onEndReachedThreshold={10}
+      />
+    </Modal>
+  }
+
+  initPageState = () => {
+    this.initData()
+    this.setState(defaultApprovalState)
+  }
+
+  /**
+   * 放大镜选项选中
+   */
+  onDbfindSelect = (selectModel, rowData) => {
+    const {
+      mainList,//主表
+      detailList,//从表
+    } = this.state
+    let selectData = rowData
+    let dataObj = selectData.obj
+    let isForm = (selectModel.type === ApprovalBean.MAIN)
+    if (isForm == true) {
+      mainList.forEach((showModel, index) => {
+        if (showModel.valuesKey in dataObj) {
+          showModel.values = dataObj[showModel.valuesKey]
+        }
+      })
+    } else {
+      detailList.forEach((showModel, index) => {
+        if (showModel.valuesKey in dataObj) {
+          showModel.values = dataObj[showModel.valuesKey]
+        }
+      })
+    }
+    this.setState({
+      mainList,
+      detailList,
+      changeModalOpen: false,
+      selectModel: {},
+    })
+  }
+
+  onDbfindClick = (type, index) => {
+    let {
+      mainList,//主表
+      detailList,//从表
+    } = this.state
+    let selectModel = {}
+    switch (type) {
+      case ApprovalBean.MAIN:
+        selectModel = mainList[index]
+        break
+      case ApprovalBean.DETAIL:
+        selectModel = detailList[index]
+        break
+    }
+    selectModel.type = type
+    selectModel.index = index
+    this.setState({ selectModel })
+    //DBFind选择
+    this.getDbfindList(selectModel)
+  }
+
+  /**
+   * 放大镜类型
+   * @param billModel
+   * @param billGroup
+   */
+  getDbfindList (selectModel) {
+    let fieldKey = selectModel.valuesKey
+    let isForm = (selectModel.type === ApprovalBean.MAIN)
+    // let corekey = selectModel.corekey
+    let gridCaller = selectModel.gCaller
+
+    let condition = '1=1'
+
+    let params = {
+      which: isForm == true ? 'form' : 'grid',
+      caller: isForm == true
+        ? (selectModel.caller)
+        : gridCaller,
+      field: fieldKey,
+      condition: condition,
+      page: 1,
+      pageSize: 1000,
+    }
+    if (isForm == false) {
+      params.gridField = fieldKey
+      params.gridCaller = (selectModel.caller)
+    }
+    fetchGet(mBaseUrl + '/uapproval/common/dbfind.action',
+      params).then(response => {
+      Toast.hide()
+      let dbfinds = response.dbfinds || response.gridDbfinds
+      if (isObjEmpty(dbfinds)) {
+        message.warn('选项数据为空')
+        return
+      }
+      let dataStr = response.data
+      let dataList = JSON.parse(dataStr)
+      if (isObjEmpty(dataList)) {
+        message.warn('选项数据为空')
+        return
+      }
+      let fieldKeyLike = ''
+      let configMap = {}
+      dbfinds.forEach((config, index) => {
+        //显示值对应字段名
+        let dbGridField = config.dbGridField || config.ds_dbfindfield
+        //实际字段名
+        let field = config.field || config.ds_gridfield
+        if (!isObjEmpty(dbGridField) && !isObjEmpty(field)) {
+          if (field == fieldKey) {
+            fieldKeyLike = dbGridField
+          }
+          configMap[dbGridField] = field
+        }
+      })
+      let dbList = []
+      dataList.forEach((item, index) => {
+        let localData = new LocalData()
+        localData.name = item[fieldKeyLike]
+        let jsonMap = {}
+        for (let key in configMap) {
+          jsonMap[configMap[key]] = item[key]
+        }
+        localData.value = this.getShowValue(jsonMap)
+        localData.obj = jsonMap
+        dbList.push(localData)
+      })
+      mModalList = dbList
+      if (dbList.length === 0) {
+        message.error('选项数据为空')
+      } else {
+        this.setState({
+          changeDataSource: this.state.changeDataSource.cloneWithRows(
+            mModalList),
+          changeModalOpen: true,
+        })
+      }
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('选项获取失败')
+      }
+    })
+  }
+
+  getShowValue = (jsonMap) => {
+    let showValue = ''
+    for (let key in jsonMap) {
+      if (!isObjEmpty(jsonMap[key])) {
+        showValue += jsonMap[key] + ','
+      }
+    }
+    showValue = showValue.substr(0, showValue.length - 1)
+    return showValue
+  }
+
+  childStateListener = (type, index, value, isDbfind) => {
+    let {
+      mainList,//主表
+      detailList,//从表
+      pointsList,//要点
+    } = this.state
+    console.log(type + '-' + index + '-' + value + '-' + isDbfind)
+    switch (type) {
+      case ApprovalBean.MAIN:
+        mainList[index].values = value
+        this.setState({
+          mainList: mainList,
+        })
+        break
+      case ApprovalBean.DETAIL:
+        detailList[index].values = value
+        this.setState({
+          detailList: detailList,
+        })
+        break
+      case ApprovalBean.POINTS:
+        pointsList[index].values = value
+        this.setState({
+          pointsList: pointsList,
+        })
+        break
+    }
+  }
+
+  /**
+   * 获取下一条我发起的/已审批单据
+   */
+  loadNextMine = () => {
+    Toast.loading('正在获取下一条单据', 0)
+    let type = 'alreadyDo'
+    if (mType == 1) {
+      type = 'alreadyDo'
+    } else if (mType == 2) {
+      type = 'alreadyLaunch'
+    }
+    fetchPostForm(mBaseUrl + '/uapproval/common/getNextApprovalProcess.action',
+      {
+        taskId: mNodeId,
+        master: mMaster,
+        type: type,
+        _noc: 1,
+      }).then(response => {
+      Toast.hide()
+      let nextNode = getIntValue(response, 'nodeId')
+      if (nextNode > 0) {
+        mNodeId = nextNode
+        this.toNextNode()
+      } else {
+        message.warn('没有下一条单据')
+      }
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('单据获取失败')
+      }
+    })
+  }
+
+  /**
+   * 催办
+   */
+  urgeToApproval = () => {
+    Toast.loading('正在催办', 0)
+    fetchPostForm(mBaseUrl + '/uapproval/common/urgeDeal.action', {
+      caller: mApprovalRecord.caller,
+      id: mApprovalRecord.id,
+    }).then(response => {
+      Toast.hide()
+      message.success('催办成功')
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('催办失败')
+      }
+    })
+  }
+
+  /**
+   * 撤回单据
+   */
+  revokeApproval = () => {
+    this.revokeAlert = alert('提示', '单据将反提交,确认撤回?', [
+      { text: '取消', onPress: () => {} },
+      {
+        text: '确定', onPress: () => {
+          Toast.loading('正在撤回单据', 0)
+          fetchPostForm(mBaseUrl + '/uapproval/common/cancelAprroval.action', {
+            caller: mApprovalRecord.caller,
+            id: mApprovalRecord.id,
+          }).then(response => {
+            Toast.hide()
+            message.success('单据撤回成功')
+            this.props.history.replace('/approvalAdd/'
+              + mApprovalRecord.caller
+              + '/' + mMaster
+              + '/' + mApprovalRecord.id)
+            clearSendState({
+              searchKey: this.props.homeState.sendState
+                ? ''
+                : this.props.homeState.sendState.searchKey,
+            })()
+          }).catch(error => {
+            Toast.hide()
+            if (typeof error === 'string') {
+              message.error(error)
+            } else {
+              message.error('单据撤回失败')
+            }
+          })
+        },
+      },
+    ])
+
+  }
+
+  /**
+   * 附件被选择
+   * @param index
+   */
+  onEnclosureSelect = (index) => {
+    const { enclosureList } = this.state
+    if (!isObjEmpty(enclosureList) && enclosureList.length > index) {
+      let enclosure = enclosureList[index]
+      console.log('path', enclosure.idKey)
+      Toast.loading('附件加载中...', 0)
+      fetch(enclosure.idKey, {
+        method: 'GET',
+        mode: 'cors',
+        credentials: 'include',
+        headers: new Headers({
+          'Accept': 'application/json',
+          'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
+        }),
+      }).then(response => {
+        if (response.status == 200) {
+          Toast.hide()
+          const link = document.createElement('a')
+          link.style.display = 'none'
+          link.href = enclosure.idKey
+          document.body.appendChild(link)
+          link.click()
+
+          // 释放的 URL 对象以及移除 a 标签
+          window.URL.revokeObjectURL(link.href)
+          document.body.removeChild(link)
+        } else {
+          throw '附件加载失败'
+        }
+      }).catch(error => {
+        Toast.hide()
+        message.error('附件加载失败')
+      })
+    }
+  }
+
+  /*loginErp = () => {
+    fetchPostForm(
+      mBaseUrl + 'mobile/login.action'
+      , {
+        'username': mPhone,
+        'password': mPassword,
+        'master': mMaster,
+      }).then((response) => {
+      console.log('login', response)
+      if (response.success) {
+        mSessionId = response.sessionId
+        document.cookie = 'JSESSIONID=' + mSessionId
+        mEmcode = response.erpaccount
+
+        this.getCurrentNode()
+      } else {
+        message.error(response.reason)
+        this.setState({
+          loading: false,
+        })
+      }
+    }).catch((error) => {
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      this.setState({
+        loading: false,
+      })
+    })
+  }*/
+
+  //获取当前节点
+  getCurrentNode = () => {
+    fetchGet(mBaseUrl + '/common/getCurrentNode.action', {
+      'jp_nodeId': mNodeId,
+      'master': mMaster,
+      '_noc': 1,
+      // 'sessionId': mSessionId,
+      // 'sessionUser': mEmcode,
+    }).then((response) => {
+      try {
+        let result = response
+        let infoObject = result.info
+
+        if (isEmptyObject(infoObject)) {
+          this.setState({
+            loading: false,
+          })
+          return
+        }
+        mEmcode = infoObject.currentemcode//当前登录人
+        mApprovalRecord.masterName = infoObject.masterName
+        mApprovalRecord.processInstanceId = infoObject.InstanceId
+        mApprovalRecord.isForknode = (getIntValue(infoObject, 'forknode') ===
+          0)
+        let currentnode = getObjValue(infoObject, 'currentnode')
+        if (!isObjNull(currentnode)) {
+          let recordName = getStrValue(currentnode, 'jp_launcherName')
+          let jp_nodeDealMan = getStrValue(currentnode, 'jp_nodeDealMan')
+          mApprovalRecord.currentNodeMan = jp_nodeDealMan
+          if (isObjEmpty(jp_nodeDealMan)) {
+            this.setState({
+              disagreeAble: false,
+              agreeAble: false,
+              takeoverAble: true,
+            })
+          } else {
+            this.setState({
+              agreeAble: true,
+              takeoverAble: false,
+            })
+          }
+          let launcherCode = getStrValue(currentnode, 'jp_launcherId')
+          let nodeName = getStrValue(currentnode, 'jp_nodeName')
+          let keyValue = getStrValue(currentnode, 'jp_keyValue')
+          let jp_name = getStrValue(currentnode, 'jp_name')
+          mApprovalRecord.title = jp_name
+          mApprovalRecord.callerName = jp_name
+
+          let statusStr = getStrValue(currentnode, 'jp_status')
+          mApprovalRecord.status = statusStr
+          if (!isObjEmpty(statusStr)) {
+            if (statusStr.indexOf('已审批') != -1) {
+              this.setState({
+                approvalStatus: 1,
+              })
+            } else if (statusStr.indexOf('未通过') != -1) {
+              this.setState({
+                approvalStatus: 2,
+              })
+            } else if (statusStr.indexOf('已结束') != -1) {
+              this.setState({
+                approvalStatus: 3,
+              })
+            } else {
+              this.setState({
+                approvalStatus: 0,
+                approvalAble: ((mType === undefined || mType == 0) &&
+                  ((isObjEmpty(mApprovalRecord.currentNodeMan)
+                    || mEmcode == mApprovalRecord.currentNodeMan)))
+                  ? true
+                  : false,
+              })
+            }
+          }
+
+          let caller = getStrValue(currentnode, 'jp_caller')
+
+          if (!isObjNull(keyValue)) {
+            mApprovalRecord.id = keyValue
+          }
+
+          if (!isObjNull(mApprovalRecord.title)) {
+            if (!isObjNull(recordName)) {
+              mApprovalRecord.title = recordName + '  ' +
+                mApprovalRecord.title
+            }
+          }
+
+          if (!isObjNull(caller)) {
+            mApprovalRecord.caller = caller
+          }
+
+          if (!isObjNull(nodeName)) {
+            mApprovalRecord.nodeName = nodeName
+          }
+
+          if (isObjNull(mApprovalRecord.imid)) {
+            mApprovalRecord.imid = ''
+          }
+        }
+
+        let button = infoObject.button
+        if (!isObjNull(currentnode)) {
+          mApprovalRecord.needInputKeys = getStrValue(button,
+            'jt_neccessaryfield')
+        }
+        this.handerTitle(0)
+        //获取明细表
+        this.getformandgriddata()
+      } catch (e) {
+
+      }
+    }).catch((error) => {
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      // console.log('current', error)
+      this.setState({
+        loading: false,
+      })
+    })
+  }
+
+  getformandgriddata = () => {
+    fetchPostForm(mBaseUrl + '/uapproval/common/getformandgriddata.action',
+      {
+        'caller': mApprovalRecord.caller,
+        'master': mMaster,
+        'id': mApprovalRecord.id,
+        'isprocess': 1,
+        'config': 1,
+      }, {
+        // 'Cookie': 'JSESSIONID=' + mSessionId
+      }).then((response) => {
+      let result = response
+      let datas = result.datas
+      if (!isObjNull(datas)) {
+        //单据是否允许【撤回】
+        this.setState({
+          revokeAble: datas.allowcancel,
+        })
+        //主表数据
+        let formdatas = datas.formdata
+        let formconfigs = datas.formconfigs
+
+        if (!isObjNull(formconfigs)) {
+          let formdata = isObjNull(formdatas) ? '' : formdatas[0]
+          let changeData = formdatas.length <= 1 ? '' : formdatas[1]
+
+          let mainApproval = this.analysisFormdata(changeData['change-new'],
+            formdata,
+            formconfigs, mApprovalRecord.caller, true, true)
+
+          mMainList = mMainList.concat(mainApproval)
+        }
+
+        //从表数据
+        let griddatas = datas.griddata
+        let gridconfigs = datas.gridconfigs
+        if (!isObjNull(gridconfigs) && gridconfigs.length > 0) {
+          if (isObjNull(griddatas) || griddatas.length == 0) {
+            this.analysisFormdata(null, null, gridconfigs,
+              mApprovalRecord.caller, false, true)
+          } else {
+            for (let i = 0; i < griddatas.length; i++) {
+              let detailedApproval = this.analysisFormdata(null, griddatas[i],
+                gridconfigs, mApprovalRecord.caller, false, i == 0)
+              if (!isObjNull(detailedApproval) && detailedApproval.length >
+                0) {
+                let approval = new ApprovalBean(ApprovalBean.TAG)
+                if (!isObjEmpty(mApprovalRecord.currentNodeMan)
+                  && mApprovalRecord.caller.toUpperCase() == 'INQUIRY'
+                  && mEmcode == mApprovalRecord.currentNodeMan) {
+                  approval.values = '初始化'
+                }
+                approval.caption = (i == 0
+                  ? (mApprovalRecord.getCallerName() +
+                    '  明细')
+                  : '')
+                detailedApproval.splice(0, 0, approval)
+                mDetailList = mDetailList.concat(detailedApproval)
+              }
+            }
+          }
+        }
+
+        //多从表
+        let othergrids = datas.othergrids
+        if (!isObjEmpty(othergrids)) {
+          let o = null
+          let caller = null
+          let otherGriddata = null
+          let otherGridconfigs = null
+          let name = null
+          for (let i = 0; i < othergrids.length; i++) {
+            o = othergrids[i]
+            name = getStrValue(o, 'name')
+            caller = getStrValue(o, 'caller')
+            otherGriddata = getArrayValue(o, 'griddata')
+            otherGridconfigs = getArrayValue(o, 'gridconfigs')
+
+            if (!isObjEmpty(otherGriddata) && !isObjEmpty(otherGridconfigs)) {
+              for (let j = 0; j < otherGriddata.length; j++) {
+                //获取到单个明细表单
+                let detailedApproval = this.analysisFormdata(null,
+                  otherGriddata[j],
+                  otherGridconfigs, caller, false, false)
+                if (!isObjEmpty(detailedApproval)) {
+                  let approval = new ApprovalBean(ApprovalBean.TAG)
+                  approval.caption = (j == 0 ? (name + '  明细') : '')
+                  detailedApproval.splice(0, 0, approval)
+
+                  mDetailList = mDetailList.concat(detailedApproval)
+                }
+              }
+            }
+          }
+        }
+
+        this.setState({
+          mainList: mMainList,
+          detailList: mDetailList,
+        })
+        this.getCustomSetupOfTask()
+      } else {
+        message.error('未获取到明细表数据')
+      }
+    }).catch((error) => {
+        if (typeof error === 'string') {
+          message.error(error)
+        } else {
+          message.error('请求异常')
+        }
+        this.setState({
+          loading: false,
+        })
+      },
+    )
+  }
+
+  //获取审批要点
+  getCustomSetupOfTask = () => {
+    fetchGet(mBaseUrl + '/common/getCustomSetupOfTask.action',
+      {
+        '_noc': 1,
+        'master': mMaster,
+        'nodeId': mNodeId,
+        // 'sessionId': mSessionId,
+        // 'sessionUser': mEmcode,
+      }, {
+        // 'Cookie': 'JSESSIONID=' + mSessionId
+      }).then((response) => {
+      this.setState({
+        optionAble: true,
+      })
+      let result = response
+      let isApprove = getIntValue(result, 'isApprove')
+      if (isApprove == 1) {
+        this.setState({
+          disagreeAble: false,
+        })
+      }
+
+      let arrayCS = getArrayValue(result, 'cs')
+      if (!isObjEmpty(arrayCS)) {
+        let data = getStrValue(result, 'data')
+        let datas = []
+        if (!isObjEmpty(data)) {
+          datas = data.split(';')
+        }
+        let pointsList = []
+        for (let i = 0; i < arrayCS.length; i++) {
+          let itemData = this.getItemBySetupTask(arrayCS[i], datas)
+          if (!isObjNull(itemData)) {
+            pointsList.push(itemData)
+          }
+        }
+
+        if (!isObjEmpty(pointsList)) {
+          let points = new ApprovalBean(ApprovalBean.TAG)
+          points.caption = '审批要点'
+          pointsList.splice(0, 0, points)
+
+          mPointsList = pointsList
+          this.setState({
+            pointsList: pointsList,
+          })
+        }
+      }
+
+      this.getAllHistoryNodes()
+    }).catch((error) => {
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      this.setState({
+        loading: false,
+      })
+    })
+  }
+
+  //获取历史审批要点
+  getAllHistoryNodes = () => {
+    fetchGet(mBaseUrl + '/common/getAllHistoryNodes.action', {
+      'master': mMaster,
+      'processInstanceId': mApprovalRecord.processInstanceId,
+      '_noc': 1,
+      // 'sessionId': mSessionId,
+      // 'sessionUser': mEmcode,
+    }, {
+      // 'Cookie': 'JSESSIONID=' + mSessionId
+    }).then((response) => {
+      let historyNode = response
+      this.getCurrentJnodes(historyNode)
+    }).catch((error) => {
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      this.setState({
+        loading: false,
+      })
+    })
+  }
+
+  //获取历史节点数据
+  getCurrentJnodes = (historyNodeJson) => {
+    fetchGet(mBaseUrl + '/common/getCurrentJnodes.action',
+      {
+        'caller': mApprovalRecord.caller,
+        'keyValue': mApprovalRecord.id,
+        '_noc': 1,
+        'master': mMaster,
+        // 'sessionId': mSessionId,
+        // 'sessionUser': mEmcode,
+      }, {
+        // 'Cookie': 'JSESSIONID=' + mSessionId
+      }).then((response) => {
+      let result = response
+
+      let showNode = true
+      let nodes = getArrayValue(result, 'nodes')
+      let processs = getArrayValue(result, 'processs')
+      let datas = getArrayValue(result, 'data')
+
+      let approvals = this.getNodDatas(datas)
+      if (!isObjEmpty(historyNodeJson)) {
+        // let historyNode = historyNodeJson.historyNode
+        // if (!isObjEmpty(historyNode)) {
+        mHistoryNodes = this.handlerHistorySetuptask(historyNodeJson)
+        // }
+      }
+
+      if (isObjEmpty(approvals) && !isObjEmpty(mHistoryNodes)) {
+        showNode = false
+        approvals = mHistoryNodes
+      }
+
+      if (showNode && !isObjEmpty(processs)) {
+        approvals = this.mergeNode(1, processs, approvals, false)
+      }
+
+      if (showNode && !isObjEmpty(nodes)) {
+        approvals = this.mergeNode(2, nodes, approvals, true)
+      }
+
+      let hanNotApproval = false
+      /**
+       * 已审批
+       * 未通过
+       * 已结束
+       * 待审批
+       */
+      for (let i = 0; i < approvals.length; i++) {
+        let approval = approvals[i]
+        let idKey = approval.idKey
+        if (!idKey.startWith('已审批') && !idKey.startWith('未通过')
+          && !idKey.startWith('不同意') && !idKey.startWith('已结束')) {
+          hanNotApproval = true
+          if (idKey.startWith('待审批')) {
+            approval.values = ''
+          }
+        } else if (idKey.startWith('未通过') && i == 0) {
+          mApprovalRecord.status = '未通过'
+        }
+        let emcode = null
+        if (strContain(approval.dfType, ',')) {
+          let emcodes = approval.dfType.split(',')
+          if (!isObjEmpty(emcodes[0])) {
+            emcode = emcodes[0]
+          }
+        } else {
+          emcode = approval.dfType
+        }
+        if (!isObjEmpty(emcode)) {
+          let imid = this.getImByCode(emcode)
+          approval.id = imid
+        }
+      }
+      let reId = -1
+      if (showNode) {
+        if (mApprovalRecord.status == '未通过'
+          || mApprovalRecord.status == '已结束'
+          || mApprovalRecord.status == '已审批') {
+          showNode = false
+          approvals = mHistoryNodes
+        }
+      }
+      if (mApprovalRecord.status == '未通过') {
+        reId = '../../images/unapproved.png'
+      } else if (!hanNotApproval && false) {
+        reId = '../../images/approved.png'
+      }
+      this.handerTitle(reId)
+      mNodeList = approvals
+      if (!isObjEmpty(approvals) && !isObjEmpty(mHistoryNodes) && showNode) {
+        // let nodeTag = new ApprovalBean(ApprovalBean.NODES_TAG)
+        // approvals.splice(0, 0, nodeTag)
+        this.setState({
+          nodesTagAble: true,
+        })
+      } else {
+        this.setState({
+          nodesTagAble: false,
+        })
+      }
+      this.setState({
+        nodeList: mNodeList,
+        historyNodes: mHistoryNodes,
+        loading: false,
+      })
+    }).catch((error) => {
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      this.setState({
+        loading: false,
+      })
+    })
+  }
+
+  mergeNode = (type, array, approvals, isLog) => {
+    for (let i = 0; i < array.length; i++) {
+      let o = array[i]
+      let name//节点名称
+      let launchTime//时间
+      let status//状态
+      let nodeDealCode//处理人编号
+      let nodeDealName//执行人
+      let nodeDescription//执行操作
+      if (type == 1) {
+        name = getStrValue(o, 'jp_nodeName')
+        launchTime = getTimeValue(o, 'jp_launchTime')
+        status = getStrValue(o, 'jp_status')
+        nodeDealCode = getStrValue(o, 'jp_nodeDealMan')
+        nodeDealName = getStrValue(o, 'jp_nodeDealManName')
+        nodeDescription = getStrValue(o, 'jn_nodeDescription')
+      } else if (type == 2) {
+        name = getStrValue(o, 'jn_name')
+        launchTime = getTimeValue(o, 'jn_dealTime')
+        status = getStrValue(o, 'jn_dealResult')
+        nodeDealCode = getStrValue(o, 'jn_dealManId')
+        nodeDealName = getStrValue(o, 'jn_dealManName')
+        nodeDescription = getStrValue(o, 'jn_nodeDescription')
+      }
+      let hanEnd = false
+      status = this.setNodeStatus(status)
+      for (let j = approvals.length - 1; j >= 0; j--) {
+        let approval = approvals[j]
+        if (hanEnd && status != '待审批') {
+          continue
+        }
+        if (approval.valuesKey == mApprovalRecord.nodeName) {
+          hanEnd = true
+        }
+        if (name == approval.valuesKey) {
+          //为当前节点
+          if (!isLog) {
+            approval.dfType = nodeDealCode
+            approval.caption = nodeDealName
+            if (status == '待审批') {
+              if (mEmcode == nodeDealCode) {
+                approval.idKey = status
+              } else {
+                approval.idKey = ''
+              }
+            } else {
+              approval.idKey = status
+            }
+          } else {
+            if (launchTime > 0) {
+              let launchDate = new Date()
+              launchDate.setTime(launchTime)
+              approval.values = launchDate.format('MM-dd')
+              approval.dbFind = launchDate.format('hh:mm')
+            }
+
+            if (approval.dfType == nodeDealCode) {
+              if (status == '不同意') {
+                approval.idKey = '未通过'
+              } else if (status == '同意') {
+                approval.idKey = '已审批'
+              }
+              if (!hanEnd && !isObjEmpty(nodeDescription)) {
+                approval.idKey = approval.idKey + '(' + nodeDescription + ')'
+              }
+            }
+
+          }
+          break
+        }
+      }
+    }
+    return approvals
+  }
+
+  handlerHistorySetuptask = (object) => {
+    let nodeApprovals = []
+    if (isObjEmpty(object)) {
+      return nodeApprovals
+    }
+    let nodes = getArrayValue(object, 'nodes')
+    if (!isObjEmpty(nodes)) {
+      let setuptasks = []
+      let node = null
+      let itemSetuptask = null
+      for (let i = nodes.length - 1; i >= 0; i--) {
+        node = nodes[i]
+        itemSetuptask = this.getSetuptask(node)
+        if (!isObjEmpty(itemSetuptask)) {
+          setuptasks = setuptasks.concat(itemSetuptask)
+        }
+        nodeApprovals.push(this.getNodeApproval(node))
+      }
+      if (!isObjEmpty(setuptasks)) {
+        mSetuptasList = setuptasks
+
+        this.setState({
+          setuptasList: mSetuptasList,
+        })
+      }
+    }
+    return nodeApprovals
+  }
+
+  getNodeApproval = (object) => {
+    let nodeName = getStrValue(object, 'jn_name')//当前结点名称
+    let emCode = getStrValue(object, 'jn_dealManId')//节点处理人编号
+    let manName = getStrValue(object, 'jn_dealManName')//处理人名字
+    let dealTime = getStrValue(object, 'jn_dealTime')//审批时间
+    let result = getStrValue(object, 'jn_dealResult')//审批结果
+    let attach = getStrValue(object, 'jn_attach')//选择类型
+    let description = getStrValue(object, 'jn_nodeDescription')//审批意见
+
+    let approval = new ApprovalBean(ApprovalBean.NODES)
+    approval.neerInput = (attach == 'T')
+    approval.mustInput = (result == '同意')
+
+    result = this.setNodeStatus(result)
+    approval.caption = manName
+    approval.dfType = emCode
+    if (!isObjEmpty(dealTime)) {
+      let time = Date.parse(new Date(dealTime))
+      if (time > 0) {
+        let newDate = new Date()
+        newDate.setTime(time)
+        approval.values = newDate.format('MM-dd hh:mm')
+      }
+    }
+    let resultBuilder = ''
+    if (!isObjEmpty(result)) {
+      resultBuilder += result
+    }
+    if (!isObjEmpty(description)) {
+      resultBuilder += ('(' + description.replace('\\n', '\n') + ')')
+    }
+    approval.idKey = resultBuilder
+    approval.valuesKey = nodeName
+    if (!isObjEmpty(emCode)) {
+      let imid = this.getImByCode(emCode)
+      approval.id = imid
+    }
+
+    return approval
+  }
+
+  getImByCode = (emcode) => {
+    return 0
+  }
+
+  setNodeStatus = (status) => {
+    if (status == '同意') {
+      status = '已审批'
+    } else if (status == '不同意' || status == '不通过') {
+      status = '未通过'
+    } else if (status == '结束流程') {
+      status = '已结束'
+    }
+    return status
+  }
+
+  getSetuptask = (node) => {
+    let name = getStrValue(node, 'jn_dealManName')
+    let approval = new ApprovalBean(ApprovalBean.TAG)
+    approval.caption = name + '的审批记录'
+    let jn_operatedDescription = getStrValue(node, 'jn_operatedDescription')
+    let itemSetuptasks = this.getSetuptaskByData(jn_operatedDescription)
+    if (!isObjEmpty(itemSetuptasks)) {
+      itemSetuptasks.splice(0, 0, approval)
+    }
+    return itemSetuptasks
+  }
+
+  getSetuptaskByData = (data) => {
+    let itemSetuptasks = []
+    if (isObjEmpty(data)) {
+      return itemSetuptasks
+    }
+    let datas = data.split(';')
+    if (isObjEmpty(datas)) {
+      return itemSetuptasks
+    }
+    let approval = null
+    for (let i = 0; i < datas.length; i++) {
+      let description = datas[i]
+      if (strContain(description, '(')) {
+        let caption = description.substring(0, description.indexOf('('))
+        let values = getParenthesesStr(description)
+        if (!isObjEmpty(caption) && !isObjEmpty(values)) {
+          approval = new ApprovalBean(ApprovalBean.SETUPTASK)
+          approval.neerInput = false
+          approval.caption = caption
+          approval.values = values
+
+          itemSetuptasks.push(approval)
+        }
+      }
+    }
+
+    return itemSetuptasks
+  }
+
+  getNodDatas = (datas) => {
+    let approvals = []
+    if (isObjEmpty(datas)) {
+      return approvals
+    }
+    for (let i = datas.length - 1; i >= 0; i--) {
+      let object = datas[i]
+      let nodeName = getStrValue(object, 'JP_NODENAME')
+      let emCode = getStrValue(object, 'JP_NODEDEALMAN')
+      let manName = getStrValue(object, 'JP_NODEDEALMANNAME')
+
+      let approval = new ApprovalBean(ApprovalBean.NODES)
+      approval.caption = isObjEmpty(manName) ? nodeName : manName
+      approval.dfType = emCode
+      approval.valuesKey = nodeName
+
+      approvals.push(approval)
+    }
+
+    return approvals
+  }
+
+  getItemBySetupTask = (cs, datas) => {
+    if (!isObjEmpty(cs)) {
+      let approval = new ApprovalBean(ApprovalBean.POINTS)
+      let css = cs.split('\^')
+      if (!isObjEmpty(css[0])) {
+        approval.caption = css[0]
+        let tag = css[1]
+        if (!isObjEmpty(tag)) {
+          let tags = tag.split('\$')
+          approval.dfType = tags[0]
+          let neer = tags[1]
+          let data = getBracketStr(neer)
+          if (isObjEmpty(data)) {
+            data = '是;否'
+          }
+          let combostore = data.split(';')
+          if (!isObjEmpty(combostore)) {
+            combostore.forEach((item) => {
+              if (!isObjEmpty(item)) {
+                approval.datas.push(new ApprovalBean.Data(item, item))
+              }
+            })
+          }
+          if (!isObjEmpty(neer)) {
+            approval.mustInput = neer.startWith('Y')
+            if (strContain(neer, '@A')) {
+              approval.dfType = '@A'
+            } else if (strContain(neer, '@')) {
+              let rets = neer.split('@')
+              if (!isObjEmpty(rets) && rets.length > 1) {
+                approval.dfType = '@' + rets[1]
+              }
+            }
+          }
+        }
+        if (!isObjEmpty(datas)) {
+          datas.forEach((data) => {
+            if (data.startWith(approval.caption)) {
+              let values = getBracketStr(data)
+              if (!isObjEmpty(values)
+                && values !== 'null'
+                && values !== '(null)'
+                && values !== '(null') {
+                approval.values = values
+              }
+            }
+          })
+        }
+
+        approval.neerInput = true
+        if (!approval.neerInput && isObjEmpty(approval.values)) {
+          return null
+        }
+        return approval
+      }
+    } else {
+      return null
+    }
+  }
+
+  analysisFormdata = (changeData, data, configs, caller, isMain, addHint) => {
+    let approvalList = []
+
+    let idTag = ''
+    let id = 0
+    let merged = ''
+    for (let i = 0; i < configs.length; i++) {
+      let config = configs[i]
+      if (isObjNull(config)) {
+        continue
+      }
+      let approval = new ApprovalBean(
+        isMain ? ApprovalBean.MAIN : ApprovalBean.DETAIL)
+
+      let caption, valueKey, combostore, type, dbFind, isdefault, appwidth
+      if (isMain) {
+        caption = config.FD_CAPTION
+        valueKey = config.FD_FIELD
+        combostore = config.COMBOSTORE
+        type = config.FD_TYPE
+        dbFind = config.FD_DBFIND
+        isdefault = config.MFD_ISDEFAULT
+        appwidth = config.FD_APPWIDTH
+      } else {
+        caption = config.DG_CAPTION
+        valueKey = config.DG_FIELD
+        combostore = config.COMBOSTORE
+        type = config.DG_TYPE
+        dbFind = config.DG_TYPE
+        isdefault = config.MDG_ISDEFAULT
+        appwidth = config.DG_APPWIDTH
+      }
+      approval.dbFind = dbFind
+      approval.dfType = type
+      approval.caption = caption
+      approval.valuesKey = valueKey
+
+      let showAble = ((!isObjNull(data)) && data.hasOwnProperty(valueKey))
+      let values = getStrValue(data, valueKey)
+      let newValues = getStrValue(changeData, valueKey)
+
+      if (showAble && !isObjEmpty(newValues) && !(newValues === values)) {
+        approval.oldValues = values
+      } else {
+        newValues = values
+      }
+
+      if (!isMain) {
+        let findTionName = config.DG_FINDFUNCTIONNAME
+        let renderer = config.DG_RENDERER
+        approval.renderer = renderer
+        if ((!isObjNull(findTionName)) && strContain(findTionName, '|')) {
+          let hhitem = findTionName.indexOf('|')
+
+          let gCaller = findTionName.substring(0, hhitem)
+          let coreKey = findTionName.substring(hhitem + 1)
+          approval.gCaller = gCaller
+          approval.coreKey = coreKey
+        }
+
+        if ((!isObjNull(renderer)) && strContain(renderer, 'formula:')) {
+          try {
+            renderer = renderer.substring('formula:'.length)
+            renderer = this.getOperator(renderer, data)
+            if (strContain(renderer, '字段需要设置为app显示')) {
+              newValues = renderer
+            } else {
+              //暂时不做double类型处理
+              newValues = renderer
+              try {
+                let mathResult = eval(renderer)
+                newValues = mathResult.toFixed(2)
+              } catch (e) {
+
+              }
+            }
+
+          } catch (e) {
+            this.setState({
+              loading: false,
+            })
+          }
+        }
+      }
+
+      if (approval.dfType == 'PF') {
+        //附件
+        let enclosure = new ApprovalBean(ApprovalBean.ENCLOSURE)
+        let path = isObjNull(newValues) ? values : newValues
+        enclosure.idKey = this.getImagePathUrl(path)
+        let splits = path.split('\\.')
+        let suffix = 'jpg'
+        if (!isObjEmpty(splits)) {
+          suffix = splits[splits.length - 1]
+        }
+        enclosure.caption = caption + '.' + suffix
+        let enclosures = []
+        enclosures.push(enclosure)
+        this.addEnclosure(enclosures)
+
+        continue
+      }
+
+      if (approval.dfType == 'FF' ||
+        (approval.renderer == 'detailAttach') ||
+        ((mApprovalRecord.title == '公章用印申请流程') && (caption == '附件'))) {
+        //附件
+        if (isMain) {
+          this.loadFilePaths(newValues)
+        } else {
+          let attachs = newValues.split(';')
+          if (!isObjNull(attachs) && attachs.length > 1) {
+            let attachName = attachs[0]
+            let attach = attachs[1]
+            try {
+              let enclosure = new ApprovalBean(ApprovalBean.ENCLOSURE)
+              enclosure.id = attach
+              enclosure.idKey = this.getImageIdUrl(attach)
+              enclosure.caption = attachName
+
+              this.addEnclosure([enclosure])
+            } catch (e) {
+
+            }
+          }
+        }
+        continue
+      }
+
+      if ((!isObjNull(caption)) && (caption == 'ID' || caption == 'id')) {
+        idTag = valueKey
+        id = getIntValue(data, valueKey)
+      }
+
+      if (approval.dfType == 'H'
+        || isdefault != -1
+        || appwidth == 0
+        || (!isMain && getIntValue(config, 'DG_WIDTH') === 0)) {
+        continue
+      }
+
+      if (!isObjEmpty(caption)) {
+        if (showAble) {
+          approval.values = newValues
+          if (addHint) {
+            mShowApprovals.push(approval)
+          }
+        } else if (addHint) {
+          mHineApprovals.push(approval)
+        }
+      }
+
+      if (isObjEmpty(valueKey) || isObjEmpty(caption)
+        || (merged.length > 0 && strContain(merged, ',' + valueKey + ','))) {
+        continue
+      }
+
+      if (!isObjNull(combostore) && combostore.length > 0) {
+        for (let j = 0; j < combostore.length; j++) {
+          let comboObj = combostore[j]
+          let value = getStrValue(comboObj, 'DLC_VALUE')
+          let display = getStrValue(comboObj, 'DLC_DISPLAY')
+
+          if (!isObjEmpty(value) || !isObjEmpty(display)) {
+            approval.datas.push(new ApprovalBean.Data(display, value))
+          }
+        }
+      }
+
+      let mergeAble = (appwidth == 1 || approval.dfType == 'MT')
+      approval.mustInput = true
+      if (!isObjEmpty(mApprovalRecord.needInputKeys)
+        && strContain(',' + mApprovalRecord.needInputKeys + ',',
+          ',' + valueKey + ',')) {
+        approval.neerInput = true
+        if (approval.datas.length <= 0) {
+          if (approval.dfType == 'YN' || approval.dfType == 'C') {
+            approval.datas.push(
+              new ApprovalBean.Data('-1', ApprovalBean.VALUES_YES))
+            approval.datas.push(
+              new ApprovalBean.Data('0', ApprovalBean.VALUES_NO))
+          } else if (approval.dfType == 'B') {
+            approval.datas.push(
+              new ApprovalBean.Data('1', ApprovalBean.VALUES_YES))
+            approval.datas.push(
+              new ApprovalBean.Data('0', ApprovalBean.VALUES_NO))
+          }
+        }
+      }
+
+      approval.data2Values()
+      if ((!approval.neerInput && isObjEmpty(approval.values)) || !showAble
+        || approval.values == 'null' || approval.values == '(null)') {
+        continue
+      }
+      if (mergeAble && !approval.isDBFind() && !approval.neerInput) {
+        let valueTagKey
+        if (isMain) {
+          valueTagKey = getStrValue(config, 'FD_LOGICTYPE')
+        } else {
+          valueTagKey = getStrValue(config, 'DG_LOGICTYPE')
+        }
+
+        if (!isObjEmpty(valueTagKey)) {
+          let valueTag = getStrValue(data, valueTagKey)
+          if (!isObjEmpty(valueTag)) {
+            merged = merged + ',' + valueTagKey + ','
+            approval.values = approval.values + '/' + valueTag
+          }
+        }
+      }
+      approval.caller = caller
+
+      approvalList.push(approval)
+    }
+
+    for (let i = 0; i < approvalList.length; i++) {
+      let approvalItem = approvalList[i]
+      approvalItem.id = id
+      approvalItem.idKey = idTag
+    }
+
+    return approvalList
+  }
+
+  getImagePathUrl = (path) => {
+    return mBaseUrl + '/common/download.action?path=' + path
+      // + '&sessionId=' + '094F0F24379928148A56D37EA83632AE'
+      // + '&sessionUser=' + 'U0757'
+      + '&master=' + mMaster
+  }
+
+  getImageIdUrl = (id) => {
+    return mBaseUrl + '/common/downloadbyId.action?id=' + id
+      // + '&sessionId=' + '094F0F24379928148A56D37EA83632AE'
+      // + '&sessionUser=' + 'U0757'
+      + '&master=' + mMaster
+  }
+
+  addEnclosure = (enclosures) => {
+    if (!isObjNull(enclosures)) {
+      if (mEnclosureList.length <= 0) {
+        let tag = new ApprovalBean(ApprovalBean.TAG)
+        tag.caption = '附件'
+        mEnclosureList.push(tag)
+      }
+
+      mEnclosureList = mEnclosureList.concat(enclosures)
+
+      this.setState({
+        enclosureList: mEnclosureList,
+      })
+    }
+  }
+
+  loadFilePaths = (attachs) => {
+    if (isObjEmpty(attachs) || attachs == 'null') {
+      return
+    }
+    fetchPostForm(mBaseUrl + '/common/getFilePaths.action', {
+      field: 'fb_attach',
+      master: mMaster,
+      id: attachs,
+    }).then(response => {
+      let files = response.files
+      let enclosures = []
+      if (!isObjEmpty(files)) {
+        for (let i = 0; i < files.length; i++) {
+          let enclosureObj = files[i]
+          if (isObjEmpty(enclosureObj)) {
+            continue
+          }
+          let enclosure = new ApprovalBean(ApprovalBean.ENCLOSURE)
+          enclosure.id = enclosureObj.fp_id
+          enclosure.idKey = this.getImageIdUrl(enclosureObj.fp_id)
+          enclosure.caption = enclosureObj.fp_name
+
+          enclosures.push(enclosure)
+        }
+      }
+      if (!isObjEmpty(enclosures)) {
+        this.addEnclosure(enclosures)
+      }
+    }).catch(error => {
+
+    })
+  }
+
+  getOperator = (renderer, data) => {
+    let result = renderer
+    let splitArray = renderer.split(/[^a-z^A-Z^_]/)
+
+    splitArray.forEach((item) => {
+      if (!isObjNull(item)) {
+        let value = data[item]
+        if (isObjNull(value)) {
+          return item + '字段需要设置为app显示'
+        } else {
+          let reg = new RegExp(item, 'g')
+          result = result.replace(reg, value)
+        }
+      }
+    })
+    return result
+  }
+
+  //设置头部内容
+  handerTitle = (reId) => {
+    let approval = new ApprovalBean(ApprovalBean.TITLE)
+    if (!isObjNull(mApprovalRecord.title)) {
+      approval.caption = mApprovalRecord.title
+    }
+    if (!isObjNull(mApprovalRecord.masterName)) {
+      approval.masterName = mApprovalRecord.masterName
+    }
+    if (!isObjEmpty(mApprovalRecord.imid)) {
+      approval.idKey = mApprovalRecord.imid
+    }
+    if (reId > 0) {
+      approval.id = reId
+    }
+    mTitleApproval = approval
+
+    this.setState({
+      titleApproval: mTitleApproval,
+    })
+  }
+
+  handleFastVisiable = (visible) => {
+    this.setState({
+      fastModalOpen: visible,
+    })
+  }
+
+  approvalTabSelect1 = () => {
+    this.setState({
+      approvalIndex: 0,
+    })
+  }
+
+  approvalTabSelect2 = () => {
+    this.setState({
+      approvalIndex: 1,
+    })
+  }
+
+  /**
+   * 变更处理人
+   */
+  approvalChange = () => {
+    Toast.loading('人员资料获取中', 0)
+    fetchGet(mBaseUrl + '/mobile/getAllHrorgEmps.action', {
+      master: mMaster,
+    }).then(response => {
+      Toast.hide()
+      mModalList = response.employees
+      this.setState({
+        changeModalOpen: true,
+        selectModel: {
+          type: SELECT_APPROVAL,
+          caption: '指定处理人',
+        },
+        changeDataSource: this.state.changeDataSource.cloneWithRows(
+          mModalList),
+      })
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('组织架构获取失败')
+      }
+    })
+  }
+
+  //接管单据
+  approvalTakeover = () => {
+    Toast.loading('正在接管单据', 0)
+    fetchPostForm(mBaseUrl + '/common/takeOverTask.action', {
+      em_code: mEmcode,
+      nodeId: mNodeId,
+      master: mMaster,
+      needreturn: true,
+    }, {
+      // 'Cookie': 'JSESSIONID=' + mSessionId
+    }).then(response => {
+      Toast.hide()
+      message.success('接管成功')
+      this.initPageState()
+      this.getCurrentNode()
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+    })
+  }
+
+  //同意点击事件
+  approvalAgree = () => {
+    // this.setState({
+    //   loading: true,
+    // })
+    Toast.loading('正在审批...', 0)
+    this.loadProcessUpdate()
+  }
+
+  //不同意审批
+  approvalDisagree = () => {
+    // this.setState({
+    //   loading: true,
+    // })
+    Toast.loading('正在审批...', 0)
+    fetchPostForm(mBaseUrl + '/common/review.action', {
+      'taskId': mNodeId,
+      'nodeName': mApprovalRecord.nodeName,
+      'nodeLog': this.state.approvalContent,
+      'master': mMaster,
+      'result': false,
+      'backTaskName': 'RECORDER',
+      'attachs': '',
+      '_noc': 1,
+      'holdtime': 4311,
+      // 'sessionId': mSessionId,
+      // 'sessionUser': mEmcode,
+    }, {
+      // 'Cookie': 'JSESSIONID=' + mSessionId
+    }).then(response => {
+      message.success('单据不同意成功')
+      Toast.hide()
+      this.setState({
+        loading: false,
+        // finished: true,
+        // finishMsg: '单据不同意成功',
+        // finishSuccess: true,
+        approvalStatus: 2,
+      })
+      if (mType == 0) {
+        let { homeState: { receiveState: { tabIndex, itemIndex, listData, todoCount } } } = this.props
+        if (tabIndex == 0 && !isObjEmpty(listData) && listData.length >
+          itemIndex) {
+          listData.splice(itemIndex, 1)
+          saveReceiveState({
+            listData,
+            todoCount: todoCount > 0 ? todoCount - 1 : 0,
+          })()
+        }
+      }
+      this.loadNextProcess()
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      this.setState({
+        loading: false,
+        // finished: true,
+        // finishMsg: error.toString(),
+        // finishSuccess: false
+      })
+    })
+  }
+
+  loadProcessUpdate = () => {
+    mCachePoints = ''
+    if (!this.inputAllPoints()) {
+      Toast.hide()
+      this.setState({
+        loading: false,
+      })
+      return
+    }
+
+    mParams = []
+    mFormStore = new Map()
+    if (!this.inputAllInput()) {
+      Toast.hide()
+      this.setState({
+        loading: false,
+      })
+      return
+    }
+
+    if (mFormStore.size <= 1 && isObjEmpty(mParams)) {
+      this.approvalAgreeRequest()
+      return
+    }
+    let formStoreJson = MapToJson(mFormStore)
+    let paramsJson = strMapToObj(mParams)
+    fetchGet(mBaseUrl + '/common/processUpdate.action', {
+      'caller': mApprovalRecord.caller,
+      'master': mMaster,
+      'processInstanceId': mApprovalRecord.processInstanceId,
+      'formStore': formStoreJson,
+      'param': paramsJson,
+    }, {
+      // 'Cookie': 'JSESSIONID=' + mSessionId
+    }).then(response => {
+      this.approvalAgreeRequest()
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      this.setState({
+        loading: false,
+      })
+    })
+  }
+
+  //同意审批
+  approvalAgreeRequest = () => {
+    const { approvalContent } = this.state
+    if (isObjNull(mCachePoints)) {
+      mCachePoints = ''
+    }
+    let points = mCachePoints.replaceAll('@', '')
+      .replaceAll('\\@', '')
+      .replaceAll('\\\\@', '')
+
+    fetchPostForm(mBaseUrl + '/common/review.action', {
+      'taskId': mNodeId,
+      'nodeName': mApprovalRecord.nodeName,
+      'nodeLog': approvalContent,
+      'result': true,
+      'master': mMaster,
+      'attachs': '',
+      '_center': '0',
+      '_noc': 1,
+      'holdtime': 4311,
+      'customDes': points,
+      // 'sessionId': mSessionId,
+      // 'sessionUser': mEmcode,
+    }, {
+      // 'Cookie': 'JSESSIONID=' + mSessionId
+    }).then(response => {
+      Toast.hide()
+      message.success('单据审批成功')
+      this.setState({
+        loading: false,
+        approvalStatus: 1,
+      })
+      if (mType == 0) {
+        let { homeState: { receiveState: { tabIndex, itemIndex, listData, todoCount } } } = this.props
+        if (tabIndex == 0 && !isObjEmpty(listData) && listData.length >
+          itemIndex) {
+          listData.splice(itemIndex, 1)
+          saveReceiveState({
+            listData,
+            todoCount: todoCount > 0 ? todoCount - 1 : 0,
+          })()
+        }
+      }
+      this.judgeApprovers()
+      // this.loadNextProcess()
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('请求异常')
+      }
+      this.setState({
+        loading: false,
+      })
+    })
+  }
+
+  /**
+   * 获取下一节点审批人
+   */
+  judgeApprovers = () => {
+    Toast.loading('正在获取下一节点审批人', 0)
+    fetchPostForm(mBaseUrl + '/uapproval/common/getMultiNodeAssigns.action', {
+      caller: mApprovalRecord.caller,
+      id: mApprovalRecord.id,
+      master: mMaster,
+    }).then(response => {
+      Toast.hide()
+      this.handlerNextStepoInstance(response)
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('下一节点审批人获取异常')
+      }
+      this.loadNextProcess()
+    })
+  }
+
+  /**
+   * 处理下一节点审批人数据
+   */
+  handlerNextStepoInstance = (response) => {
+    if (!isObjEmpty(response.assigns)) {
+      let assignArray = response.assigns
+      let assignObj = assignArray[0]
+      let nodeid = assignObj ? (assignObj.JP_NODEID || '') : ''
+      let candidates = assignObj ? (assignObj.JP_CANDIDATES || []) : []
+      if (!isObjEmpty(nodeid) && !isObjEmpty(candidates)) {
+        let candidateList = []
+        candidates.forEach(item => {
+          let candidate = item
+          candidate.nodeId = nodeid
+
+          candidateList.push(candidate)
+        })
+        mModalList = candidateList
+        this.setState({
+          changeModalOpen: true,
+          selectModel: {
+            type: SELECT_APPROVAL,
+            caption: '指定处理人',
+          },
+          changeDataSource: this.state.changeDataSource.cloneWithRows(
+            mModalList),
+        })
+      } else {
+        this.loadNextProcess()
+      }
+    } else {
+      this.loadNextProcess()
+    }
+  }
+
+  /**
+   * 变更处理人
+   * @param rowData
+   */
+  onChangeSelect = rowData => {
+    if (!isObjNull(rowData)) {
+      let selectChange = rowData
+
+      Toast.loading('处理人指定中', 0)
+      let params, url
+      let isApproval = !isObjNull(selectChange.nodeId)
+      if (isApproval) {
+        url = '/common/takeOverTask.action'
+        let deal = {
+          em_code: selectChange.EM_CODE,
+          nodeId: selectChange.nodeId,
+        }
+        params = {
+          _noc: '1',
+          master: mMaster,
+          params: JSON.stringify(deal),
+        }
+      } else {
+        url = '/common/setAssignee.action'
+        params = {
+          taskId: mNodeId,
+          master: mMaster,
+          assigneeId: selectChange.EM_CODE,
+          processInstanceId: mApprovalRecord.processInstanceId,
+          description: this.state.approvalContent,
+          _center: 0,
+          _noc: 1,
+        }
+      }
+      fetchPostForm(mBaseUrl + url, params).then(response => {
+        Toast.hide()
+        if (isApproval) {
+          this.loadNextProcess()
+        } else if (response.result == true) {
+          let nextnode = response.nextnode
+          if (!isObjEmpty(nextnode)) {
+            mNodeId = nextnode
+            message.success('处理人指定成功')
+            this.toNextNode()
+          } else {
+            message.success('处理人指定成功')
+            this.setState({
+              approvalStatus: 4,
+            })
+            if (mType == 0) {
+              let { homeState: { receiveState: { tabIndex, itemIndex, listData, todoCount } } } = this.props
+              if (tabIndex == 0 && !isObjEmpty(listData) &&
+                listData.length >
+                itemIndex) {
+                listData.splice(itemIndex, 1)
+                saveReceiveState({
+                  listData,
+                  todoCount: todoCount > 0 ? todoCount - 1 : 0,
+                })()
+              }
+              this.props.history.goBack()
+            }
+            message.warn('没有下一条待审批单据')
+          }
+        } else {
+          message.error('指定处理人失败')
+        }
+      }).catch(error => {
+        Toast.hide()
+        if (typeof error === 'string') {
+          message.error(error)
+        } else {
+          message.error('处理人指定异常')
+        }
+      })
+    }
+
+    this.setState({
+      changeDataSource: new ListView.DataSource({
+        rowHasChanged: (row1, row2) => row1 !== row2,
+      }),
+      changeModalOpen: false,
+    })
+  }
+
+  /**
+   * 跳转下一条待审批数据
+   */
+  toNextNode () {
+    message.loading('跳转下一条审批单据', 1)
+    this.props.history.replace('/approval/%7B%22' +
+      'master%22%3A%22' + mMaster
+      + '%22%2C%22nodeId%22%3A' + mNodeId
+      + (mType === undefined ? '' : ('%2C%22type%22%3A' + mType))
+      + '%2C%22baseUrl%22%3A%22' + encodeURIComponent(mBaseUrl)
+      + '%22%7D')
+    this.initPageState()
+    this.getCurrentNode()
+    if (mType == 0) {
+      saveReceiveState({
+        scrollTop: 0,
+        listData: [],
+        hasMore1: true,
+        pageIndex: 1,
+      })()
+    }
+    // else if (mType == 2) {
+    //   clearSendState({
+    //     searchKey: this.props.homeState.sendState
+    //       ? ''
+    //       : this.props.homeState.sendState.searchKey,
+    //   })()
+    // }
+  }
+
+  /**
+   * 获取下一条审批数据
+   */
+  loadNextProcess = () => {
+    Toast.loading('正在获取下一条审批单据', 0)
+    fetchPostForm(mBaseUrl + '/common/getNextProcess.action', {
+      taskId: mNodeId,
+      master: mMaster,
+      _noc: 1,
+    }).then(response => {
+      Toast.hide()
+      let nextNode = getIntValue(response, 'nodeId')
+      if (nextNode > 0) {
+        mNodeId = nextNode
+        this.toNextNode()
+      } else {
+        message.warn('没有下一条待审批单据')
+      }
+    }).catch(error => {
+      Toast.hide()
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('审批单据获取失败')
+      }
+    })
+  }
+
+  inputAllInput = () => {
+    const { mainList, detailList } = this.state
+
+    let mainArray = []
+    let detailsArray = []
+    let details = []
+    for (let i = 0; i < mainList.length; i++) {
+      let approval = mainList[i]
+      if (!isObjNull(approval) && approval.type == ApprovalBean.MAIN) {
+        mainArray.push(approval)
+      }
+    }
+    for (let i = 0; i < detailList.length; i++) {
+      let approval = detailList[i]
+      if (!isObjNull(approval) && approval.type == ApprovalBean.DETAIL) {
+        details.push(approval)
+        if ((detailList.length > i + 1) &&
+          (detailList[i + 1].type != approval.type)) {
+          detailsArray.push(details)
+          details = []
+        }
+        if (i == detailList.length - 1) {
+          detailsArray.push(details)
+          details = []
+        }
+      }
+    }
+    let mainStore = this.putItem2Params(true, mainArray)
+    if (isObjNull(mainStore)) {
+      return false
+    }
+    mFormStore = new Map([...mFormStore, ...mainStore])
+
+    for (let i = 0; i < detailsArray.length; i++) {
+      let detailsObj = detailsArray[i]
+      let param = this.putItem2Params(true, detailsObj)
+      if (isObjNull(param)) {
+        return false
+      } else if (param.size > 1) {
+        mParams.push(param)
+      }
+    }
+    return true
+  }
+
+  putItem2Params = (showTocat, approvals) => {
+    let formstore = new Map()
+    if (isObjEmpty(approvals)) {
+      return formstore
+    }
+    for (let i = 0; i < approvals.length; i++) {
+      let approval = approvals[i]
+      if (!isObjNull(approval)) {
+        if (approval.neerInput) {
+          if (isObjEmpty(approval.values)) {
+            let msg = '必填字段  ' + approval.caption + '为必填项'
+            if (showTocat) {
+              message.error(msg)
+            }
+            return null
+          } else {
+            if (approval.values == ApprovalBean.VALUES_UNKNOWN) {
+              formstore.set(approval.valuesKey, '1')//添加特殊字符判断
+            } else {
+              let isputed = false
+              let datas = approval.datas
+              if (!isObjNull(datas)) {
+                for (let j = 0; j < datas.length; j++) {
+                  let data = datas[j]
+                  isputed = false
+                  if (!isObjNull(data) && data.display == approval.values) {
+                    formstore.set(approval.valuesKey,
+                      isObjEmpty(data.value) ? approval.values : data.value)
+                    isputed = true
+                    break
+                  }
+                }
+              }
+              if (!isputed) {
+                formstore.set(approval.valuesKey, approval.values)
+              }
+            }
+          }
+        }
+        if (!isObjEmpty(approval.idKey) && approval.id > 0) {
+          formstore.set(approval.idKey, approval.id)
+        }
+      }
+    }
+    return formstore
+  }
+
+  inputAllPoints = () => {
+    const { pointsList } = this.state
+    if (!isObjEmpty(pointsList)) {
+      for (let i = 0; i < pointsList.length; i++) {
+        let approval = pointsList[i]
+        if (approval.mustInput && isObjEmpty(approval.values)) {
+          let msg = '审批要点  ' + approval.caption + '  为必填项'
+          message.error(msg)
+          return false
+        }
+        if (!isObjEmpty(approval.caption)
+          && !isObjEmpty(approval.values) && !isObjNull(mCachePoints)) {
+          if (strContain(approval.values, '@')) {
+            let msg = '审批要点  ' + approval.caption + '  带有特殊字符'
+            message.error(msg)
+            return false
+          }
+          if (approval.dfType == '@A') {
+            mCachePoints += (approval.caption + '(' + approval.values + ')' +
+              '@A@;')
+          } else if (!isObjEmpty(approval.dfType) &&
+            strContain(approval.dfType, '@')) {
+            mCachePoints += (approval.caption + '(' + approval.values + ')' +
+              approval.dfType + '@;')
+          } else {
+            mCachePoints += (approval.caption + '(' + approval.values + ');')
+          }
+        }
+      }
+      mCachePoints = mCachePoints.substring(0, mCachePoints.length - 1)
+    }
+    return true
+  }
+
+  approvalEdit = (e) => {
+    this.setState({
+      approvalContent: e.target.value,
+    })
+  }
+
+  fastSelect = (index) => {
+    const { approvalContent, fastList } = this.state
+    this.setState({
+      approvalContent: approvalContent + fastList[index],
+      fastModalOpen: false,
+    })
+  }
+
+  fastClick = () => {
+    this.setState({
+      fastModalOpen: true,
+    })
+  }
+
+  fastModalClose = () => {
+    this.setState({
+      fastModalOpen: false,
+    })
+  }
+}
+
+let mapStateToProps = (state) => ({
+  homeState: { ...state.redHomeState },
+})
+
+let mapDispatchToProps = (dispatch) => ({})
+
+export default connect(mapStateToProps, mapDispatchToProps)(Approval)

+ 857 - 0
uas-office-web/uas-mobile/src/pages/private/approval/pages/ApprovalHome.jsx

@@ -0,0 +1,857 @@
+/**
+ * Created by RaoMeng on 2020/2/17
+ * Desc: 审批功能首页
+ */
+
+import React, { Component } from 'react'
+import ReactDOM from 'react-dom'
+import { TabBar, SearchBar } from 'antd-mobile'
+import { List, Skeleton, message } from 'antd'
+import './approval.css'
+import Swiper from 'swiper/js/swiper.min'
+import 'swiper/css/swiper.min.css'
+import {
+  getIntValue,
+  isObjEmpty,
+  isObjNull,
+} from '../../../../utils/common/common.util'
+import { fetchGet } from '../../../../utils/common/fetchRequest'
+import { connect } from 'react-redux'
+import {
+  clearReceiveState,
+  clearSendState,
+  freshApprovalHomeState,
+  saveReceiveState,
+  saveSendState,
+} from '../../../../redux/actions/approvalState'
+import ApprovalItem from '../components/approvalItem/ApprovalItem'
+import LoadingMore from '../components/LoadingMore'
+import InfiniteScroll from 'react-infinite-scroller'
+import { _baseURL } from '../../../../configs/api.config'
+import UasIcon from '../../../../configs/iconfont.conig'
+
+let mMaster
+const mPageSize = 20
+let mTodoIndex = 0
+let mDoneIndex = 0
+let mSendIndex = 0
+
+class ApprovalHome extends Component {
+
+  constructor () {
+    super()
+
+    this.state = {
+      pageVisible: false,
+      tabHidden: false,
+      isNewMenuLoading: true,
+      isReceiveTodoLoading: true,
+      isReceiveDoneLoading: true,
+      isReceiveTodoRefresh: false,
+      isReceiveDoneRefresh: false,
+      isSendRefresh: false,
+      isSendLoading: true,
+      receiveKey: '',
+      sendKey: '',
+    }
+  }
+
+  componentDidMount () {
+    mMaster = this.props.match.params.master
+    document.title = 'U审批'
+
+    const { homeState } = this.props
+    let { newState, receiveState, sendState, selectedTab } = homeState
+
+    this.initSwiper(receiveState)
+
+    this.setState({
+      receiveKey: receiveState.searchKey,
+      sendKey: sendState.searchKey,
+    })
+
+    let pageType = this.props.match.params.type
+    if (pageType == 'receive') {
+      selectedTab = 1
+      freshApprovalHomeState({
+        selectedTab: 1,
+      })()
+    } else if (pageType == 'send') {
+      selectedTab = 2
+      freshApprovalHomeState({
+        selectedTab: 2,
+      })()
+    }
+    switch (selectedTab) {
+      case 1: {
+        this.initReceive(receiveState)
+        break
+      }
+      case 2: {
+        this.initSend(sendState)
+        break
+      }
+      default:
+        break
+    }
+  }
+
+  initSwiper (receiveState) {
+    let that = this
+    this.mySwiper = new Swiper('.swiper-container', {
+      autoplay: false,
+      loop: false,
+      noSwiping: true,
+      initialSlide: receiveState.tabIndex,
+      on: {
+        slideChangeTransitionEnd: function () {
+          saveReceiveState({
+            tabIndex: this.activeIndex,
+          })()
+          if (this.activeIndex == 0) {
+            that.refreshTodoList()
+          } else {
+            that.refreshDoneList()
+          }
+        },
+      },
+    })
+  }
+
+  initReceive (receiveState) {
+    if (receiveState && receiveState.tabIndex >= 0) {
+      this.mySwiper.slideTo(receiveState.tabIndex, 0, false)
+    }
+
+    if (receiveState && !isObjEmpty(receiveState.listData)) {
+      this.setState({
+        isReceiveTodoLoading: false,
+      }, () => {
+        setTimeout(() => {
+          ReactDOM.findDOMNode(this.todoTab).parentNode.scrollTop =
+            receiveState.scrollTop
+        }, 10)
+      })
+      mTodoIndex = receiveState.pageIndex
+    } else {
+      mTodoIndex = 0
+      this.loadTodoList()
+    }
+
+    if (receiveState && !isObjEmpty(receiveState.listData2)) {
+      this.setState({
+        isReceiveDoneLoading: false,
+      }, () => {
+        setTimeout(() => {
+          ReactDOM.findDOMNode(this.doneTab).parentNode.scrollTop =
+            receiveState.scrollTop2
+        }, 10)
+
+      })
+      mDoneIndex = receiveState.pageIndex2
+    } else {
+      mDoneIndex = 0
+      this.loadDoneList()
+    }
+  }
+
+  initSend (sendState) {
+    if (!isObjEmpty(sendState.sendList)) {
+      this.setState({
+        isSendLoading: false,
+      }, () => {
+        setTimeout(() => {
+          ReactDOM.findDOMNode(this.sendList).parentNode.scrollTop =
+            sendState.scrollTop
+        }, 10)
+      })
+    } else {
+      mSendIndex = 0
+      this.loadSendList()
+    }
+  }
+
+  componentWillUnmount () {
+
+  }
+
+  render () {
+    return (
+      <div className={'home-root'}>
+        <TabBar
+          unselectedTintColor="#949494"
+          tintColor="#33A3F4"
+          barTintColor="white"
+          prerenderingSiblingsNumber={1}
+          hidden={this.state.tabHidden}
+        >
+          {this.getReceiveTab()}
+          {this.getSendTab()}
+        </TabBar>
+      </div>
+    )
+  }
+
+  /**
+   * 【我的审批】
+   * @returns {*}
+   */
+  getReceiveTab = () => {
+    return (
+      <TabBar.Item
+        title="我的审批"
+        key="Receive"
+        icon={<UasIcon type='uas-receive'/>}
+        selectedIcon={<UasIcon type="uas-receive-selected"/>}
+        selected={this.props.homeState.selectedTab === 1}
+        badge={this.props.homeState.receiveState
+          ? this.props.homeState.receiveState.todoCount : 0}
+        onPress={this.onTab2Selected}
+      >
+        {this.renderReceiveTab()}
+      </TabBar.Item>
+    )
+  }
+
+  /**
+   * 【我发起的】
+   * @returns {*}
+   */
+  getSendTab = () => {
+    return (
+      <TabBar.Item
+        title="我发起的"
+        key="Send"
+        icon={<UasIcon type="uas-send"/>}
+        selectedIcon={<UasIcon type="uas-send-selected"/>}
+        selected={this.props.homeState.selectedTab === 2}
+        // badge={''}
+        onPress={this.onTab3Selected}
+      >
+        {this.renderSendTab()}
+      </TabBar.Item>
+    )
+  }
+
+  onTab2Selected = () => {
+    const { isReceiveTodoLoading, isReceiveDoneLoading } = this.state
+    const { homeState: { receiveState, selectedTab } } = this.props
+    if (selectedTab === 1) {
+      // 刷新页面
+      clearReceiveState()()
+      this.setState({
+        receiveKey: '',
+      })
+      this.mySwiper.slideTo(0, 0, false)
+      if (!isReceiveTodoLoading) {
+        this.setState({
+          isReceiveTodoLoading: true,
+        })
+        mTodoIndex = 0
+        this.loadTodoList()
+      }
+      if (!isReceiveDoneLoading) {
+        this.setState({
+          isReceiveDoneLoading: true,
+        })
+        mDoneIndex = 0
+        this.loadDoneList()
+      }
+    } else {
+      if (isObjEmpty(receiveState.listData)) {
+        this.setState({
+          isReceiveTodoLoading: true,
+        })
+        mTodoIndex = 0
+        this.loadTodoList()
+      } else {
+        this.setState({
+          isReceiveTodoLoading: false,
+        }, () => {
+
+        })
+        mTodoIndex = receiveState.pageIndex
+      }
+      if (isObjEmpty(receiveState.listData2)) {
+        this.setState({
+          isReceiveDoneLoading: true,
+        })
+        mDoneIndex = 0
+        this.loadDoneList()
+      } else {
+        this.setState({
+          isReceiveDoneLoading: false,
+        }, () => {
+
+        })
+        mDoneIndex = receiveState.pageIndex2
+      }
+    }
+    freshApprovalHomeState({
+      selectedTab: 1,
+    })()
+  }
+
+  onTab3Selected = () => {
+    const { isSendLoading } = this.state
+    const { homeState: { sendState, selectedTab } } = this.props
+    if (selectedTab === 2) {
+      // 刷新页面
+      clearSendState()()
+      this.setState({
+        sendKey: '',
+      })
+      if (!isSendLoading) {
+        this.setState({
+          isSendLoading: true,
+        })
+        mSendIndex = 0
+        this.loadSendList()
+      }
+    } else {
+      if (isObjEmpty(sendState.sendList)) {
+        this.setState({
+          isSendLoading: true,
+        })
+        mSendIndex = 0
+        this.loadSendList()
+      } else {
+        this.setState({
+          isSendLoading: false,
+        }, () => {
+
+        })
+      }
+    }
+    freshApprovalHomeState({
+      selectedTab: 2,
+    })()
+  }
+
+  renderReceiveTab = () => {
+    const { homeState: { receiveState } } = this.props
+    const { tabIndex } = receiveState
+    const todoItems = this.renderReceiveTodoItems()
+    const doneItems = this.renderReceiveDoneItems()
+    return (
+      <div className='receive-root'>
+        <SearchBar
+          value={this.state.receiveKey}
+          placeholder={'搜索'}
+          maxLength={16}
+          onChange={value => {
+            this.setState({
+              receiveKey: value,
+            })
+          }}
+          onClear={value => {
+            this.setState({
+              receiveKey: value,
+            })
+          }}
+          onCancel={() => {
+            this.setState({
+              receiveKey: '',
+            })
+            if (!isObjEmpty(receiveState.searchKey)) {
+              this.searchSubmit(0, '')
+            }
+          }}
+          onSubmit={this.searchSubmit.bind(this, 0, this.state.receiveKey)}
+        />
+        {/*<div className='line'></div>*/}
+        <div className='identity-select'>
+          <div className={tabIndex === 0 ?
+            'identity-item-select' : 'identity-item-normal'}
+               onClick={() => {
+                 this.refreshTodoList()
+                 if (tabIndex === 0) {
+
+                 } else {
+                   saveReceiveState({
+                     tabIndex: 0,
+                   })()
+                   this.mySwiper.slideTo(0, 300, false)
+                 }
+               }}>待审批{this.props.homeState.receiveState ?
+            (this.props.homeState.receiveState.todoCount > 0
+              ? ('(' + this.props.homeState.receiveState.todoCount + ')')
+              : '') : ''}
+          </div>
+          <div className={tabIndex === 1 ?
+            'identity-item-select' : 'identity-item-normal'}
+               onClick={() => {
+                 this.refreshDoneList()
+                 if (tabIndex === 1) {
+
+                 } else {
+                   saveReceiveState({
+                     tabIndex: 1,
+                   })()
+                   this.mySwiper.slideTo(1, 300, false)
+                 }
+               }}>已审批
+          </div>
+        </div>
+        <div className="swiper-container"
+             ref={el => {
+               this.contain = el
+             }}>
+          <div className="swiper-wrapper">
+            <div className="swiper-slide swiper-no-swiping">
+              {todoItems}
+            </div>
+            <div className="swiper-slide swiper-no-swiping">
+              {doneItems}
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+
+  refreshDoneList () {
+    const { isReceiveDoneLoading } = this.state
+    if (!isReceiveDoneLoading) {
+      this.setState({
+        isReceiveDoneLoading: true,
+      })
+      saveReceiveState({
+        hasMore2: true,
+        scrollTop2: 0,
+      })()
+      mDoneIndex = 0
+      this.loadDoneList()
+    }
+  }
+
+  refreshTodoList () {
+    const { isReceiveTodoLoading } = this.state
+    if (!isReceiveTodoLoading) {
+      this.setState({
+        isReceiveTodoLoading: true,
+      })
+      saveReceiveState({
+        hasMore1: true,
+        scrollTop: 0,
+      })()
+      mTodoIndex = 0
+      this.loadTodoList()
+    }
+  }
+
+  renderSendTab = () => {
+    const { homeState: { sendState } } = this.props
+
+    return (
+      <div className='receive-content-root'>
+        <SearchBar
+          value={this.state.sendKey}
+          placeholder={'搜索'}
+          maxLength={16}
+          onChange={value => {
+            this.setState({
+              sendKey: value,
+            })
+          }}
+          onClear={value => {
+            this.setState({
+              sendKey: value,
+            })
+          }}
+          onCancel={() => {
+            this.setState({
+              sendKey: '',
+            })
+            if (!isObjEmpty(sendState.searchKey)) {
+              this.searchSubmit(1, '')
+            }
+          }}
+          onSubmit={this.searchSubmit.bind(this, 1, this.state.sendKey)}
+        />
+        <div className='receive-content-root'>
+          <InfiniteScroll
+            initialLoad={false}
+            pageStart={0}
+            ref={el => {
+              this.sendList = el
+            }}
+            loadMore={this.loadSendList}
+            hasMore={sendState.sendHasMore}
+            loader={<LoadingMore/>}
+            threshold={1}
+            useWindow={false}>
+            <Skeleton loading={this.state.isSendLoading} active
+                      paragraph={{ rows: 4 }}>
+              <List split={false}
+                    dataSource={sendState.sendList}
+                    renderItem={(item, index) => (
+                      <ApprovalItem approval={item}
+                                    type={3}
+                                    onItemClick={this.onSendItemClick.bind(
+                                      this)}
+                                    index={index}/>
+                    )}/>
+            </Skeleton>
+          </InfiniteScroll>
+        </div>
+
+      </div>
+    )
+  }
+
+  renderReceiveTodoItems = () => (
+    <div className='receive-content-root'>
+      <InfiniteScroll
+        initialLoad={false}
+        pageStart={0}
+        ref={el => {
+          this.todoTab = el
+        }}
+        loadMore={this.loadTodoList.bind(this, undefined)}
+        hasMore={this.props.homeState.receiveState.hasMore1}
+        loader={<LoadingMore/>}
+        threshold={1}
+        useWindow={false}>
+        <Skeleton loading={this.state.isReceiveTodoLoading} active
+                  paragraph={{ rows: 4 }}>
+          <List split={false}
+                dataSource={this.props.homeState.receiveState.listData}
+                renderItem={(item, index) => (
+                  <ApprovalItem approval={item}
+                                type={1}
+                                onItemClick={this.onReceiveItemClick.bind(this)}
+                                index={index}/>
+                )}/>
+        </Skeleton>
+      </InfiniteScroll>
+    </div>
+  )
+
+  renderReceiveDoneItems = () => (
+    <div className='receive-content-root'>
+      <InfiniteScroll
+        initialLoad={false}
+        pageStart={0}
+        ref={el => {
+          this.doneTab = el
+        }}
+        loadMore={this.loadDoneList.bind(this, undefined)}
+        hasMore={this.props.homeState.receiveState.hasMore2}
+        loader={<LoadingMore/>}
+        threshold={1}
+        useWindow={false}>
+        <Skeleton loading={this.state.isReceiveDoneLoading} active
+                  paragraph={{ rows: 4 }}>
+          <List split={false}
+                dataSource={this.props.homeState.receiveState.listData2}
+                renderItem={(item, index) => (
+                  <ApprovalItem approval={item}
+                                type={2}
+                                onItemClick={this.onReceiveItemClick.bind(this)}
+                                index={index}/>
+                )}/>
+        </Skeleton>
+      </InfiniteScroll>
+    </div>
+  )
+
+  searchSubmit = (type, value) => {
+    if (type === 0) {
+      const { isReceiveTodoLoading, isReceiveDoneLoading } = this.state
+      this.setState({
+        receiveKey: value,
+      })
+      clearReceiveState({
+        searchKey: value,
+        tabIndex: this.props.homeState.receiveState.tabIndex,
+      })()
+      // this.mySwiper.slideTo(0, 0, false)
+      if (!isReceiveTodoLoading) {
+        this.setState({
+          isReceiveTodoLoading: true,
+        })
+        mTodoIndex = 0
+        this.loadTodoList(value)
+      }
+      if (!isReceiveDoneLoading) {
+        this.setState({
+          isReceiveDoneLoading: true,
+        })
+        mDoneIndex = 0
+        this.loadDoneList(value)
+      }
+    } else if (type === 1) {
+      const { isSendLoading } = this.state
+      this.setState({
+        sendKey: value,
+      })
+      clearSendState({
+        searchKey: value,
+      })()
+      if (!isSendLoading) {
+        this.setState({
+          isSendLoading: true,
+        })
+        mSendIndex = 0
+        this.loadSendList(value)
+      }
+    }
+  }
+
+  onFuncClick = (obj) => {
+    this.cacheScrollState()
+    this.props.history.push('/approvalAdd/' + obj.sv_caller + '/' + mMaster)
+  }
+
+  onReceiveItemClick = (index, approval) => {
+    this.cacheScrollState()
+    saveReceiveState({
+      itemIndex: index,
+    })()
+    let jp_form = approval.JP_FORM
+    let currentmaster = approval.CURRENTMASTER
+    if (!isObjEmpty(jp_form) && !isObjEmpty(currentmaster) &&
+      (jp_form.indexOf(currentmaster) != -1)) {
+
+    } else {
+      currentmaster = mMaster
+    }
+    let type = 0
+    if (this.props.homeState.receiveState.tabIndex === 1) {
+      type = 1
+    }
+    this.props.history.push('/approval/%7B%22' +
+      'master%22%3A%22' + currentmaster
+      + '%22%2C%22nodeId%22%3A' + approval.JP_NODEID
+      + '%2C%22type%22%3A' + type
+      + '%2C%22baseUrl%22%3A%22' + encodeURIComponent(_baseURL)
+      + '%22%7D')
+  }
+
+  onSendItemClick = (index, approval) => {
+    this.cacheScrollState()
+    let jp_form = approval.JP_FORM
+    let currentmaster = approval.CURRENTMASTER
+    if (!isObjEmpty(jp_form) && !isObjEmpty(currentmaster) &&
+      (jp_form.indexOf(currentmaster) != -1)) {
+
+    } else {
+      currentmaster = mMaster
+    }
+    this.props.history.push('/approval/%7B%22' +
+      'master%22%3A%22' + currentmaster
+      + '%22%2C%22nodeId%22%3A' + approval.JP_NODEID
+      + '%2C%22type%22%3A' + 2
+      + '%2C%22baseUrl%22%3A%22' + encodeURIComponent(_baseURL)
+      + '%22%7D')
+  }
+
+  cacheScrollState () {
+    // saveNewState({
+    //   scrollTop: ReactDOM.findDOMNode(this.newList).parentNode.scrollTop,
+    // })()
+    saveReceiveState({
+      scrollTop: ReactDOM.findDOMNode(this.todoTab).parentNode.scrollTop,
+      scrollTop2: ReactDOM.findDOMNode(this.doneTab).parentNode.scrollTop,
+    })()
+    saveSendState({
+      scrollTop: ReactDOM.findDOMNode(this.sendList).parentNode.scrollTop,
+    })()
+  }
+
+  loadTodoList = (keyword) => {
+    let { homeState: { receiveState } } = this.props
+    let { listData } = receiveState
+    if (isObjEmpty(listData)) {
+      mTodoIndex = 0
+    }
+    mTodoIndex++
+    if (!this.state.isReceiveTodoLoading) {
+      this.setState({
+        isReceiveTodoRefresh: true,
+      })
+    }
+
+    if (mTodoIndex === 1) {
+      listData.length = 0
+    }
+
+    fetchGet(_baseURL + '/common/desktop/process/uapproval/toDo.action', {
+      pageSize: mPageSize,
+      page: mTodoIndex,
+      keyword: !isObjNull(keyword) ? keyword : receiveState.searchKey,
+    }).then(response => {
+      this.setState({
+        isReceiveTodoLoading: false,
+        isReceiveTodoRefresh: false,
+      })
+      if (response && !isObjEmpty(response.data)) {
+        listData = listData.concat(response.data)
+      } else {
+        if (mTodoIndex > 1) {
+          mTodoIndex--
+        }
+      }
+      saveReceiveState({
+        hasMore1: !(isObjNull(response.data)
+          || response.data.length < mPageSize),
+        listData,
+        pageIndex: mTodoIndex,
+        todoCount: getIntValue(response, 'totalCount'),
+      })()
+    }).catch(error => {
+      if (mTodoIndex > 1) {
+        mTodoIndex--
+      }
+      saveReceiveState({
+        hasMore1: false,
+        listData,
+        pageIndex: mTodoIndex,
+      })()
+      this.setState({
+        isReceiveTodoLoading: false,
+        isReceiveTodoRefresh: false,
+      })
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('待审批列表请求异常')
+      }
+    })
+  }
+
+  loadDoneList = (keyword) => {
+    let { homeState: { receiveState } } = this.props
+    let { listData2 } = receiveState
+    if (isObjEmpty(listData2)) {
+      mDoneIndex = 0
+    }
+    mDoneIndex++
+    if (!this.state.isReceiveDoneLoading) {
+      this.setState({
+        isReceiveDoneRefresh: true,
+      })
+    }
+
+    if (mDoneIndex === 1) {
+      listData2.length = 0
+    }
+
+    fetchGet(_baseURL + '/common/desktop/process/uapproval/alreadyDo.action', {
+      pageSize: mPageSize,
+      page: mDoneIndex,
+      keyword: !isObjNull(keyword) ? keyword : receiveState.searchKey,
+      isMobile: 1,
+      _do: 1,
+    }).then(response => {
+      this.setState({
+        isReceiveDoneLoading: false,
+        isReceiveDoneRefresh: false,
+      })
+      if (response && !isObjEmpty(response.data)) {
+        listData2 = listData2.concat(response.data)
+      } else {
+        if (mDoneIndex > 1) {
+          mDoneIndex--
+        }
+      }
+      saveReceiveState({
+        hasMore2: !(isObjNull(response.data)
+          || response.data.length < mPageSize),
+        listData2,
+        pageIndex: mDoneIndex,
+      })()
+    }).catch(error => {
+      if (mDoneIndex > 1) {
+        mDoneIndex--
+      }
+      saveReceiveState({
+        hasMore2: false,
+        listData2,
+        pageIndex: mDoneIndex,
+      })()
+      this.setState({
+        isReceiveDoneLoading: false,
+        isReceiveDoneRefresh: false,
+      })
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('已审批列表请求异常')
+      }
+    })
+  }
+
+  loadSendList = (keyword) => {
+    let { homeState: { sendState } } = this.props
+    let { sendList } = sendState
+    if (isObjEmpty(sendList)) {
+      mSendIndex = 0
+    }
+    mSendIndex++
+    if (!this.state.isSendLoading) {
+      this.setState({
+        isSendRefresh: true,
+      })
+    }
+
+    if (mSendIndex === 1) {
+      sendList.length = 0
+    }
+
+    fetchGet(
+      _baseURL + '/common/desktop/process/uapproval/alreadyLaunch.action',
+      {
+        pageSize: mPageSize,
+        page: mSendIndex,
+        keyword: !isObjNull(keyword) ? keyword : sendState.searchKey,
+        isMobile: 1,
+        _do: 1,
+      }).then(response => {
+      this.setState({
+        isSendLoading: false,
+        isSendRefresh: false,
+      })
+      if (response && !isObjEmpty(response.data)) {
+        sendList = sendList.concat(response.data)
+      } else {
+        if (mSendIndex > 1) {
+          mSendIndex--
+        }
+      }
+      saveSendState({
+        sendHasMore: !(isObjNull(response.data)
+          || response.data.length < mPageSize),
+        sendList,
+        pageIndex: mSendIndex,
+      })()
+    }).catch(error => {
+      if (mSendIndex > 1) {
+        mSendIndex--
+      }
+      saveSendState({
+        sendHasMore: false,
+        sendList,
+        pageIndex: mSendIndex,
+      })()
+      this.setState({
+        isSendLoading: false,
+        isSendRefresh: false,
+      })
+      if (typeof error === 'string') {
+        message.error(error)
+      } else {
+        message.error('列表请求异常')
+      }
+    })
+  }
+}
+
+let mapStateToProps = (state) => ({
+  homeState: { ...state.approvalState },
+})
+
+let mapDispatchToProps = (dispatch) => ({})
+
+export default connect(mapStateToProps, mapDispatchToProps)(ApprovalHome)

+ 363 - 0
uas-office-web/uas-mobile/src/pages/private/approval/pages/approval.css

@@ -0,0 +1,363 @@
+.root {
+    width: 100%;
+    height: 100%;
+    background: white;
+    display: flex;
+    flex-direction: column;
+}
+
+.content {
+    width: 100%;
+    flex: 1;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+
+.content::-webkit-scrollbar {
+    display: none;
+}
+
+.bottomMenu {
+    width: 100%;
+    height: max-content;
+}
+
+.editLayout {
+    width: 100%;
+    height: max-content;
+    display: flex;
+    padding: 8px;
+    font-size: 12px;
+}
+
+.editInput {
+    flex: 1;
+    min-height: 30px;
+    max-height: 50px;
+    margin: 0 10px;
+}
+
+.menuParent {
+    width: 100%;
+    display: flex;
+    padding: 8px;
+    justify-content: center;
+    align-items: center;
+}
+
+.fastWords {
+    width: 24px;
+    height: 24px;
+    text-align: center;
+    line-height: 20px;
+    background: red;
+    border-radius: 20px;
+    padding: 2px;
+    color: white;
+    background: gray;
+    font-size: 12px;
+}
+
+.fastItem {
+    height: 32px;
+    text-align: center;
+    line-height: 32px;
+    font-size: 12px;
+    border-bottom: 1px solid #ccc;
+}
+
+.menuItem {
+    flex: 1;
+    height: 28px;
+    text-align: center;
+    line-height: 30px;
+    color: deepskyblue;
+    background: white;
+}
+
+.menuItem:active {
+    color: white;
+    background: deepskyblue;
+}
+
+.headerLayout {
+    width: 100%;
+    padding: 10px;
+    display: flex;
+    align-items: center;
+}
+
+.headerImage {
+    width: 42px;
+    height: 42px;
+    border-radius: 50%;
+    border: red solid 1px;
+}
+
+.headerText {
+    font-size: 14px;
+    color: black;
+    margin-left: 10px;
+    flex: 1;
+}
+
+.tableTitle {
+    width: 100%;
+    padding: 5px 6px;
+    color: dodgerblue;
+    font-size: 14px;
+    border-top: 1pt solid #dedede;
+}
+
+.approval_tab_parent {
+    width: 100%;
+    display: flex;
+    align-items: center;
+    font-size: 13px;
+}
+
+.approval_tab_normal {
+    flex: 1;
+    height: 40px;
+    color: #000;
+    border-bottom: 1px solid #ccc;
+    text-align: center;
+    line-height: 40px;
+}
+
+.approval_tab_selected {
+    flex: 1;
+    height: 40px;
+    color: deepskyblue;
+    border-bottom: 1px solid deepskyblue;
+    text-align: center;
+    line-height: 40px;
+}
+
+/************************************************************************/
+
+.home-root {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    overflow-y: scroll;
+    -webkit-overflow-scrolling: touch;
+}
+
+.home-root::-webkit-scrollbar {
+    display: none;
+}
+
+#newMenu-root {
+    width: 100%;
+    height: 100%;
+    background-color: #F2F2F2;
+}
+
+#newMenu-root::-webkit-scrollbar {
+    display: none;
+}
+
+.newMenu-group-layout {
+    padding: 8px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+}
+
+.newMenu-group-icon {
+    width: 18px;
+    height: 18px;
+}
+
+.newMenu-group-text {
+    font-family: PingFangSC-Regular;
+    font-size: 14px;
+    color: #000000;
+    letter-spacing: 2px;
+    padding-left: 6px;
+    font-weight: bold;
+}
+
+.newMenu-func-root {
+    width: 25%;
+    display: inline-block;
+    padding: 14px 4px 8px;
+    background: white;
+}
+
+.newMenu-func-layout {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+}
+
+.newMenu-func-icon {
+    width: 30px;
+    height: 30px;
+}
+
+.newMenu-func-text {
+    font-family: PingFangSC-Regular;
+    font-size: 12px;
+    color: #333333;
+    letter-spacing: 1.6px;
+    padding-top: 6px;
+    text-align: center;
+}
+
+.line {
+    width: 100%;
+    background: #F2F2F2;
+    height: 6px;
+}
+
+.receive-root {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+}
+
+.receive-content-root {
+    width: 100%;
+    /*min-height: 100vh;*/
+    height: 100%;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    background-color: #F2F2F2;
+    overflow: auto;
+}
+
+.receive-content-root::-webkit-scrollbar {
+    display: none;
+}
+
+.identity-select {
+    display: flex;
+    flex-direction: row;
+}
+
+.identity-item-normal, .identity-item-select {
+    flex: 1;
+    background: white;
+    font-family: PingFangSC-Regular;
+    font-size: 14px;
+    letter-spacing: 1.88px;
+    text-align: center;
+    height: 38px;
+    line-height: 38px;
+}
+
+.identity-item-normal {
+    color: #666666;
+    border-bottom: 2px solid #F3F3F3;
+}
+
+.identity-item-select {
+    color: #4197FC;
+    border-bottom: 2px solid #4197FC;
+}
+
+.swiper-container {
+    width: 100%;
+    flex: 1;
+    background: white;
+}
+
+/*.swiper-wrapper {*/
+/*!*background: red;*!*/
+/*}*/
+
+.swiper-slide {
+
+}
+
+.swiper-content {
+    overflow-y: scroll;
+    -webkit-overflow-scrolling: touch;
+}
+
+.approval-add-root {
+    width: 100%;
+    height: 100%;
+    overflow-y: scroll;
+    display: flex;
+    flex-direction: column;
+    background: white;
+}
+
+.approval-add-root::-webkit-scrollbar {
+    display: none;
+}
+
+.approval-detail-root {
+    width: 100%;
+    height: 100%;
+    background: white;
+    display: flex;
+    flex-direction: column;
+}
+
+.approval-detail-root .am-modal-body {
+    overflow: hidden !important;
+}
+
+.approval-detail-root .am-modal-body::-webkit-scrollbar {
+    display: none !important;
+}
+
+
+/************************************************************************/
+
+.ant-spin {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    background: rgba(255, 255, 255, 0.25);
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+}
+
+.ant-spin-spinning {
+
+}
+
+.finishedLayout {
+    width: 100%;
+    height: 100%;
+    padding-bottom: 40px;
+    background: white;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+}
+
+.ant-popover-title {
+    min-width: 110px;
+    text-align: center;
+}
+
+.ant-popover-placement-top > .ant-popover-content > .ant-popover-arrow {
+    left: 84%
+}
+
+.ant-popover-inner {
+    margin-right: 10px;
+}
+
+.ant-popover-inner-content {
+    padding: 8px 10px;
+}
+
+.ui.small.modal {
+    width: 60%;
+}
+
+
+

+ 2 - 0
uas-office-web/uas-mobile/src/pages/private/homePage/HomePage.jsx

@@ -15,6 +15,7 @@ import { requestUserInfo } from '../../../utils/private/user.util'
 import { clearFormState } from '../../../redux/actions/formState'
 import { clearScheduleState } from '../../../redux/actions/scheduleState'
 import { forceVisible } from 'react-lazyload'
+import { clearApprovalHomeState } from '../../../redux/actions/approvalState'
 
 /**
  * Created by RaoMeng on 2020/11/9
@@ -36,6 +37,7 @@ class HomePage extends Component {
     clearListState()
     clearFormState()
     clearScheduleState()
+    clearApprovalHomeState()
 
     requestUserInfo()
   }

+ 8 - 0
uas-office-web/uas-mobile/src/pages/private/homePage/home-page.less

@@ -7,6 +7,10 @@
 .doc-root {
   height: 100%;
   overflow: auto;
+
+  &::-webkit-scrollbar {
+    display: none;
+  }
 }
 
 .report-root {
@@ -17,6 +21,10 @@
     flex: 1;
     overflow: auto;
     width: 100%;
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
   }
 }
 

+ 4 - 0
uas-office-web/uas-mobile/src/pages/private/report/report.less

@@ -29,5 +29,9 @@
   .report-detail-content {
     flex: 1;
     overflow-y: scroll;
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
   }
 }

+ 79 - 0
uas-office-web/uas-mobile/src/redux/actions/approvalState.js

@@ -0,0 +1,79 @@
+/**
+ * Created by RaoMeng on 2018/12/10
+ * Desc: 列表数据缓存
+ */
+
+import {
+  CLEAR_APPROVAL_HOME_STATE,
+  CLEAR_RECEIVE_STATE,
+  CLEAR_SEND_STATE,
+  FRESH_APPROVAL_HOME_STATE,
+  RECEIVE_TAB_STATE,
+  SEND_TAB_STATE,
+} from '../constants/actionTypes'
+import store from '../store/store'
+
+/**
+ * 更新【我的审批】页面菜单数据
+ * @param data
+ * @returns {Function}
+ */
+export const saveReceiveState = (data) => {
+  return () => {
+    store.dispatch({
+      type: RECEIVE_TAB_STATE,
+      ...data,
+    })
+  }
+}
+
+/**
+ * 更新【我发起的】页面菜单数据
+ * @param data
+ * @returns {Function}
+ */
+export const saveSendState = (data) => {
+  return () => {
+    store.dispatch({
+      type: SEND_TAB_STATE,
+      ...data,
+    })
+  }
+}
+
+export const clearReceiveState = (data) => {
+  return () => {
+    store.dispatch({
+      type: CLEAR_RECEIVE_STATE,
+      ...data,
+    })
+  }
+}
+
+export const clearSendState = (data) => {
+  return () => {
+    store.dispatch({
+      type: CLEAR_SEND_STATE,
+      ...data,
+    })
+  }
+}
+
+export const freshApprovalHomeState = (data) => {
+  return () => {
+    store.dispatch({
+      type: FRESH_APPROVAL_HOME_STATE,
+      ...data,
+    })
+  }
+}
+
+/**
+ * 清除列表状态
+ * @returns {Function}
+ */
+export const clearApprovalHomeState = () => {
+  return store.dispatch({
+    type: CLEAR_APPROVAL_HOME_STATE,
+  })
+}

+ 10 - 0
uas-office-web/uas-mobile/src/redux/constants/actionTypes.js

@@ -14,6 +14,16 @@ export const CLEAR_USER_STATE = 'CLEAR_USER_STATE'
 export const CLEAR_MAIN_STATE = 'CLEAR_MAIN_STATE'
 export const FRESH_MAIN_STATE = 'FRESH_MAIN_STATE'
 
+/**********************************审批********************************************/
+export const FRESH_APPROVAL_HOME_STATE = 'FRESH_APPROVAL_HOME_STATE'
+export const NEW_TAB_STATE = 'NEW_TAB_STATE'
+export const RECEIVE_TAB_STATE = 'RECEIVE_TAB_STATE'
+export const SEND_TAB_STATE = 'SEND_TAB_STATE'
+export const CLEAR_NEW_STATE = 'CLEAR_NEW_STATE'
+export const CLEAR_RECEIVE_STATE = 'CLEAR_RECEIVE_STATE'
+export const CLEAR_SEND_STATE = 'CLEAR_SEND_STATE'
+export const CLEAR_APPROVAL_HOME_STATE = 'CLEAR_APPROVAL_HOME_STATE'
+
 /**********************************列表********************************************/
 export const SAVE_LIST_STATE = 'SAVE_LIST_STATE'
 export const CLEAR_LIST_STATE = 'CLEAR_LIST_STATE'

+ 2 - 0
uas-office-web/uas-mobile/src/redux/reducers/index.js

@@ -9,6 +9,7 @@ import redUserState from './redUserState'
 import redFormState from './redFormState'
 import redChartState from './redChartState'
 import redScheduleState from './redScheduleState'
+import redApprovalState from './redApprovalState'
 
 /**
  * Created by RaoMeng on 2020/11/9
@@ -25,4 +26,5 @@ export const appReducer = combineReducers({
   formState: redFormState,
   chartState: redChartState,
   scheduleState: redScheduleState,
+  approvalState: redApprovalState,
 })

+ 122 - 0
uas-office-web/uas-mobile/src/redux/reducers/redApprovalState.js

@@ -0,0 +1,122 @@
+import {
+  CLEAR_NEW_STATE,
+  CLEAR_RECEIVE_STATE,
+  CLEAR_SEND_STATE,
+  NEW_TAB_STATE,
+  RECEIVE_TAB_STATE,
+  SEND_TAB_STATE,
+  FRESH_APPROVAL_HOME_STATE,
+  CLEAR_APPROVAL_HOME_STATE,
+} from '../constants/actionTypes'
+
+const initNewState = {
+  newMenuList: [],
+  scrollTop: 0,
+}
+const initReceiveState = {
+  tabIndex: 0,
+  itemIndex: -1,
+  searchKey: '',
+  todoCount: 0,
+
+  scrollTop: 0,
+  listData: [],
+  hasMore1: true,
+  pageIndex: 1,
+
+  scrollTop2: 0,
+  listData2: [],
+  hasMore2: true,
+  pageIndex2: 1,
+}
+
+const initSendState = {
+  searchKey: '',
+  sendList: [],
+  sendHasMore: true,
+  scrollTop: 0,
+}
+
+const initListState = {
+  selectedTab: 1,
+  newState: initNewState,
+  receiveState: initReceiveState,
+  sendState: initSendState,
+}
+
+const redApprovalState = (state = initListState, action) => {
+  if (action === undefined) {
+    return state
+  }
+
+  switch (action.type) {
+    case NEW_TAB_STATE:
+      //更新新建菜单数据
+      return {
+        ...state,
+        newState: {
+          ...state.newState,
+          ...action,
+        },
+      }
+    case RECEIVE_TAB_STATE:
+      //更新【我的审批】数据
+      return {
+        ...state,
+        receiveState: {
+          ...state.receiveState,
+          ...action,
+        },
+      }
+    case SEND_TAB_STATE:
+      //更新【我发起的】数据
+      return {
+        ...state,
+        sendState: {
+          ...state.sendState,
+          ...action,
+        },
+      }
+    case CLEAR_NEW_STATE:
+      //清除新建菜单数据
+      return {
+        ...state,
+        newState: {
+          ...initNewState,
+          ...action,
+        },
+      }
+    case CLEAR_RECEIVE_STATE:
+      //清除[我的审批]数据
+      return {
+        ...state,
+        receiveState: {
+          ...initReceiveState,
+          ...action,
+        },
+      }
+    case CLEAR_SEND_STATE:
+      //清除[我发起的]数据
+      return {
+        ...state,
+        sendState: {
+          ...initSendState,
+          ...action,
+        },
+      }
+    case FRESH_APPROVAL_HOME_STATE:
+      //更新首页数据
+      return {
+        ...state,
+        ...action,
+      }
+    case CLEAR_APPROVAL_HOME_STATE:
+      //清空首页数据
+      return initListState
+    default:
+      return state
+  }
+
+}
+
+export default redApprovalState

+ 2 - 0
uas-office-web/uas-mobile/src/redux/utils/redux.utils.js

@@ -6,6 +6,7 @@ import { clearListState } from '../actions/listState'
 import { clearUserInfo } from '../actions/userState'
 import { clearChartState } from '../actions/chartState'
 import { clearScheduleState } from '../actions/scheduleState'
+import { clearApprovalHomeState } from '../actions/approvalState'
 
 /**
  * Created by RaoMeng on 2020/12/14
@@ -24,4 +25,5 @@ export function clearAllRedux () {
   clearUserInfo()
   clearChartState()
   clearScheduleState()
+  clearApprovalHomeState()
 }

BIN
uas-office-web/uas-mobile/src/res/img/approved.png


BIN
uas-office-web/uas-mobile/src/res/img/bg_bind_phone.png


BIN
uas-office-web/uas-mobile/src/res/img/default_header.png


BIN
uas-office-web/uas-mobile/src/res/img/endapproved.png


BIN
uas-office-web/uas-mobile/src/res/img/ic_uas_icon.png


BIN
uas-office-web/uas-mobile/src/res/img/unapproved.png


+ 25 - 0
uas-office-web/uas-mobile/src/utils/common/common.util.js

@@ -516,6 +516,31 @@ export function getOS () {
   return os
 }
 
+export function strMapToObj (m) {
+  if (isObjEmpty(m)) {
+    return ''
+  }
+  var str = '['
+  if (isObjEmpty(m)) {
+    return ''
+  }
+  m.forEach(function (item, key) {
+    var obj = JSON.stringify(_strMapToObj(item))
+    str += obj + ','
+  })
+  str = str.slice(0, str.length - 1)
+  str += ']'
+  return str
+}
+
+export function _strMapToObj (item) {
+  let obj = Object.create(null)
+  for (let [k, v] of item) {
+    obj[k] = v
+  }
+  return obj
+}
+
 /**
  * 保留小数(四舍五入)
  *