king
2024-06-21 2bccb9ec7bdefe23292a22bc153463cfa1479a49
src/views/appmanage/index.jsx
@@ -1,147 +1,132 @@
import React, {Component} from 'react'
import { fromJS } from 'immutable'
import { Spin, notification, Button, Table, Modal, ConfigProvider, Typography } from 'antd'
import { Spin, notification, Input, Button, Table, Modal, Typography, Row, Col, Tooltip } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import enUS from 'antd/es/locale/en_US'
import zhCN from 'antd/es/locale/zh_CN'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import { langs } from '@/store/options.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { confirm } = Modal
const { Paragraph } = Typography
const { Search } = Input
const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const Header = asyncComponent(() => import('@/mob/header'))
const Header = asyncComponent(() => import('./header'))
const MutilForm = asyncComponent(() => import('./mutilform'))
const TransForm = asyncComponent(() => import('./transform'))
const ScriptForm = asyncComponent(() => import('./scriptform'))
const SubMutilForm = asyncComponent(() => import('./submutilform'))
const TransMenu = asyncComponent(() => import('./transmenu'))
let base_url = ''
if (process.env.NODE_ENV === 'production') {
  base_url = document.location.origin + '/' + window.GLOB.service
} else {
  base_url = window.GLOB.location + '/' + window.GLOB.service
const skinStyle = {
  bg_black_style_blue: {name: '蓝色', color: '#1890ff'},
  bg_black_style_red: {name: '红色', color: '#f5222d'},
  bg_black_style_orange_red: {name: '橙红色', color: '#fa541c'},
  bg_black_style_orange: {name: '橙色', color: '#fa8c16'},
  bg_black_style_orange_yellow: {name: '橙黄色', color: '#faad14'},
  bg_black_style_yellow: {name: '黄色', color: '#fadb14'},
  bg_black_style_yellow_green: {name: '黄绿色', color: '#a0d911'},
  bg_black_style_green: {name: '绿色', color: '#52c41a'},
  bg_black_style_cyan: {name: '青色', color: '#13c2c2'},
  bg_black_style_blue_purple: {name: '蓝紫色', color: '#2f54eb'},
  bg_black_style_purple: {name: '紫色', color: '#722ed1'},
  bg_black_style_magenta: {name: '洋红色', color: '#eb2f96'},
  bg_black_style_grass_green: {name: '草绿色', color: '#aeb303'},
  bg_black_style_deep_red: {name: '深红色', color: '#c32539'},
  bg_black_style_deep_blue: {name: '深红色', color: '#1d3661'}
}
sessionStorage.setItem('isEditState', 'true')
class AppManage extends Component {
  state = {
    loading: false,
    applist: [],
    columns: [
      { title: '应用名称', dataIndex: 'remark', key: 'remark', align: 'center' },
      { title: '应用编码', dataIndex: 'kei_no', key: 'kei_no', align: 'center' },
      { title: '应用名称', dataIndex: 'remark', key: 'remark', align: 'center', width: '30%' },
      { title: '应用编码', dataIndex: 'kei_no', key: 'kei_no', align: 'center', width: '30%' },
      {
        title: '操作',
        key: 'action',
        align: 'center',
        render: (text, record) => (<Button type="link" onClick={() => this.deleteApp(record)} style={{color: '#ff4d4f'}}>删除</Button>),
      },
    ],
    subcolumns: [
      {
        title: '应用类型', dataIndex: 'typename', key: 'typename', align: 'center'
      },
      {
        title: '语言', dataIndex: 'lang', key: 'lang', align: 'center',
        render: (text, record) => text === 'en-US' ? '英文' : '中文'
      },
      {
        title: '登录', dataIndex: 'login_types', key: 'login_types', align: 'center',
        render: (text, record) => text === 'false' ? '不需要' : '需要'
      },
      {
        title: '权限管理', dataIndex: 'role_type', key: 'role_type', align: 'center',
        render: (text, record) => text === 'false' ? '不启用' : '启用'
      },
      {
        title: '用户绑定', dataIndex: 'user_binding', key: 'user_binding', align: 'center',
        render: (text, record) => {
          let val = ''
          if (!text) return '无'
          if (text.indexOf('uname_pwd') > -1) {
            val = '用户名'
          }
          if (text.indexOf('sms_vcode') > -1) {
            val = val ? val + ',手机号' : '手机号'
          }
          return val
        }
      },
      {
        title: '皮肤', dataIndex: 'css', key: 'css', align: 'center',
        render: (text, record) => {
          const style = {
            bg_black_style_blue: '蓝黑色系',
            bg_white_style_blue: '蓝白色系',
            bg_black_style_red: '红黑色系',
            bg_white_style_red: '红白色系',
            bg_black_style_orange_red: '橙红黑色系',
            bg_white_style_orange_red: '橙红白色系',
            bg_black_style_orange: '橙黑色系',
            bg_white_style_orange: '橙白色系',
            bg_black_style_orange_yellow: '橙黄黑色系',
            bg_white_style_orange_yellow: '橙黄白色系',
            bg_black_style_yellow: '黄黑色系',
            bg_white_style_yellow: '黄白色系',
            bg_black_style_yellow_green: '黄绿黑色系',
            bg_white_style_yellow_green: '黄绿白色系',
            bg_black_style_green: '绿黑色系',
            bg_white_style_green: '绿白色系',
            bg_black_style_cyan: '青黑色系',
            bg_white_style_cyan: '青白色系',
            bg_black_style_blue_purple: '蓝紫黑色系',
            bg_white_style_blue_purple: '蓝紫白色系',
            bg_black_style_purple: '紫黑色系',
            bg_white_style_purple: '紫白色系',
            bg_black_style_magenta: '洋红黑色系',
            bg_white_style_magenta: '洋红白色系',
            bg_black_style_grass_green: '草绿黑色系',
            bg_white_style_grass_green: '草绿白色系',
            bg_black_style_deep_red: '深红黑色系',
            bg_white_style_deep_red: '深红白色系'
          }
          return style[text] || '蓝黑色系'
        }
      },
      {
        title: '标题', dataIndex: 'title', key: 'title', align: 'center', width: '170px'
      },
      {
        title: '图标', dataIndex: 'favicon', key: 'favicon', align: 'center', width: '120px',
        render: (text, record) => (text ? <img style={{width: '32px', height: '32px'}} src={text} alt="" /> : null)
      },
      {
        title: '操作',
        key: 'action',
        align: 'center',
        width: '250px',
        width: '40%',
        render: (text, record) => (
          <div>
            <Button type="link" onClick={() => this.deleteSubApp(record)} style={{color: '#ff4d4f'}}>删除</Button>
            <Button type="link" onClick={() => this.jumpApp(record)}>编辑应用</Button>
            <Paragraph style={{display: 'inline-block', margin: 0}} copyable={{ text: `${base_url}${record.typename === 'pad' ? 'mob' : record.typename}/index.html#/index/${this.state.selectApp.kei_no}/${record.lang}` }}></Paragraph>
            <Button type="link" onClick={() => this.setState({ selectApp: record, visible: 'edit' })} style={{color: '#8E44AD'}}>修改</Button>
            <Button type="link" onClick={() => this.deleteApp(record)} style={{color: '#ff4d4f'}}>删除</Button>
            <Button type="link" onClick={() => this.setState({ selectSubApp: record, subVisible: 'plus' })} style={{color: '#26C281'}}>添加子应用</Button>
          </div>
        )
        ),
      },
    ],
    selectApp: null,
    selectSubApp: null,
    selectedRowKeys: [],
    selectedSubRowKeys: [],
    visible: false,
    subVisible: false
    subVisible: false,
    transcolumns: [
      { title: '传输号', dataIndex: 'VersionName', key: 'VersionName', align: 'left', render: (text, record) => (
        <Paragraph copyable={{text}}>{text}</Paragraph>
      )},
      { title: '说明', dataIndex: 'ProgramName', key: 'ProgramName', align: 'left' },
      { title: '状态', dataIndex: 'StatusName', key: 'StatusName', align: 'left' },
      { title: '创建时间', dataIndex: 'CreateDate', key: 'CreateDate', align: 'left' },
      {
        title: '操作',
        key: 'action',
        align: 'center',
        width: '230px',
        render: (text, record) => (
          <div onClick={() => this.forbid = true}>
            <Button type="link" onClick={() => this.setState({ editTran: record, transVisible: 'edit' })} style={{color: '#8E44AD'}}>修改</Button>
            <Button type="link" onClick={() => this.deleteTran(record)} style={{color: '#ff4d4f'}}>删除</Button>
            <Button type="link" onClick={() => this.enableTran(record)} style={{color: '#26C281'}}>启用</Button>
          </div>
        ),
      },
    ],
    transVisible: false,
    translist: [],
    tranSearchKey: '',
    selectTran: null,
    editTran: null,
    transIndex: 1,
    transTotal: 0,
    scriptcolumns: [
      { title: '关键字', dataIndex: 'KeyWords', key: 'KeyWords', align: 'left' },
      { title: '描述', dataIndex: 'Remark', key: 'Remark', align: 'left' },
      { title: '类型', dataIndex: 'TypeName', key: 'TypeName', align: 'left' },
      { title: '排序', dataIndex: 'Sort', key: 'Sort', align: 'left' },
    ],
    scriptVisible: false,
    scriptlist: [],
    scriptSearchKey: '',
    scriptIndex: 1,
    scriptTotal: 0,
  }
  forbid = false
  UNSAFE_componentWillMount() {
    if (sessionStorage.getItem('devError') === 'true') {
      sessionStorage.clear()
      window.history.replaceState(null, null, window.location.href.split('#')[0] + '#/login')
      window.location.reload()
      return
    }
    if (!sessionStorage.getItem('UserID')) {
      this.props.history.replace('/login')
      return
    }
    window.GLOB.developing = true
    document.body.className = ''
    this.getAppList()
    this.getSmStemp()
    this.getTransList()
  }
  /**
@@ -153,10 +138,324 @@
    }
  }
  getTransList = () => {
    const { tranSearchKey, transIndex } = this.state
    let param = {
      func: 's_get_sVersion',
      dataM: 'Y',
      PageSize: 10,
      PageIndex: transIndex,
      OrderCol: 'ID desc'
    }
    if (tranSearchKey) {
      param.VersionName = tranSearchKey
      param.ProgramName = tranSearchKey
    }
    this.setState({
      loading: true
    })
    Api.getCloudConfig(param).then(result => {
      if (result.status) {
        this.setState({
          loading: false,
          translist: result.data,
          selectTran: null,
          scriptlist: [],
          transTotal: result.total
        })
      } else {
        this.setState({
          loading: false
        })
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  getScriptList = () => {
    const { scriptSearchKey, scriptIndex, selectTran } = this.state
    if (!selectTran || !selectTran.ID) {
      notification.warning({
        top: 92,
        message: '缺少传输号ID!',
        duration: 3
      })
      return
    }
    let param = {
      func: 's_get_sVersionDetail',
      dataM: 'Y',
      PageSize: 10,
      PageIndex: scriptIndex,
      OrderCol: 'Sort desc',
      BID: selectTran.ID,
    }
    if (scriptSearchKey) {
      param.TypeName = scriptSearchKey
      param.KeyWords = scriptSearchKey
      param.Remark = scriptSearchKey
    }
    this.setState({
      loading: true
    })
    Api.getCloudConfig(param).then(result => {
      if (result.status) {
        this.setState({
          loading: false,
          scriptlist: result.data,
          scriptTotal: result.total,
          selectScriptKeys: []
        })
      } else {
        this.setState({
          loading: false
        })
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  scriptSearch = (value) => {
    this.setState({scriptSearchKey: value, scriptIndex: 1}, () => {
      this.getScriptList()
    })
  }
  changeScriptTable = (pagination) => {
    this.setState({
      scriptIndex: pagination.current
    }, () => {
      this.getScriptList()
    })
  }
  changeTable = (pagination) => {
    this.setState({
      transIndex: pagination.current
    }, () => {
      this.getTransList()
    })
  }
  tranSearch = (value) => {
    this.setState({tranSearchKey: value, transIndex: 1}, () => {
      this.getTransList()
    })
  }
  submitTrans = () => {
    const { transVisible, editTran } = this.state
    this.transRef.handleConfirm().then(res => {
      this.setState({
        confirmloading: true
      })
      let param = {}
      if (transVisible === 'plus') {
        param.func = 's_sVersion_add'
        param.VersionName = res.VersionName
        param.ProgramName = res.ProgramName
      } else {
        param.func = 's_sVersion_upt'
        param.ProgramName = res.ProgramName
        param.ID = editTran.ID
      }
      Api.getCloudConfig(param).then(result => {
        if (result.status) {
          notification.success({
            top: 92,
            message: '操作成功!',
            duration: 3
          })
          this.setState({
            confirmloading: false,
            transVisible: false
          })
          this.getTransList()
        } else {
          this.setState({
            confirmloading: false
          })
          notification.warning({
            top: 92,
            message: result.message,
            duration: 5
          })
        }
      }, () => {
        this.setState({
          confirmloading: false
        })
      })
    })
  }
  submitScript = () => {
    const { selectTran } = this.state
    this.scriptRef.handleConfirm().then(res => {
      this.setState({
        confirmloading: true
      })
      let kei_no = res.appId.split(',')[1]
      let lang = res.subAppId ? res.subAppId.split(',')[1] : ''
      let kei_no_detail = res.subAppId ? res.subAppId.split(',')[2] : ''
      let param = {
        func: 's_sVersionDetail_CloudAdd',
        kei_no: kei_no,
        kei_no_detail: kei_no_detail,
        lang: lang,
        BID: selectTran.ID
      }
      if (res.VType === 'subapp') {
        param.VType = 'mob_menu'
        param.TrdMenuID = ''
        param.upid = md5(window.GLOB.appkey + kei_no + kei_no_detail + lang)
      } else if (res.VType === 'view') {
        param.VType = 'mob_menu'
        param.TrdMenuID = res.viewId
      } else if (res.VType === 'role') {
        param.VType = 'mob_roletree'
        param.upid = md5(window.GLOB.appkey + kei_no + kei_no_detail + lang)
      } else if (res.VType === 'app') {
        param.VType = 'Vkei'
      }
      Api.getCloudConfig(param).then(result => {
        if (result.status) {
          notification.success({
            top: 92,
            message: '操作成功!',
            duration: 3
          })
          this.setState({
            scriptIndex: 1,
            confirmloading: false,
            scriptVisible: false
          }, () => {
            this.getScriptList()
          })
        } else {
          this.setState({
            confirmloading: false
          })
          notification.warning({
            top: 92,
            message: result.message,
            duration: 5
          })
        }
      }, () => {
        this.setState({
          confirmloading: false
        })
      })
    })
  }
  deleteTran = (record) => {
    const _this = this
    let param = {
      func: 's_sVersion_del',
      ID: record.ID
    }
    confirm({
      content: '确定删除该传输号吗?',
      onOk() {
        return new Promise(resolve => {
          Api.getCloudConfig(param).then(result => {
            if (result.status) {
              notification.success({
                top: 92,
                message: '操作成功!',
                duration: 3
              })
              _this.getTransList()
            } else {
              notification.warning({
                top: 92,
                message: result.message,
                duration: 5
              })
            }
            resolve()
          }, () => {
            resolve()
          })
        })
      },
      onCancel() {}
    })
  }
  enableTran = (record) => {
    const _this = this
    let param = {
      func: 's_sVersion_sub',
      ID: record.ID
    }
    confirm({
      content: '确定启用该传输号吗?',
      onOk() {
        return new Promise(resolve => {
          Api.getCloudConfig(param).then(result => {
            if (result.status) {
              notification.success({
                top: 92,
                message: '操作成功!',
                duration: 3
              })
              _this.getTransList()
            } else {
              Modal.error({
                title: result.message,
              })
            }
            resolve()
          }, () => {
            resolve()
          })
        })
      },
      onCancel() {}
    })
  }
  getAppList = () => {
    let param = {
      func: 's_get_kei'
    }
    this.setState({
      loading: true
    })
    Api.getCloudConfig(param).then(result => {
      if (result.status) {
@@ -165,6 +464,47 @@
          item.sublist = item.data_detail || []
          item.sublist = item.sublist.map(cell => {
            cell.ID = cell.d_id
            if (cell.customize_param) {
              let _param = {}
              try {
                _param = JSON.parse(window.decodeURIComponent(window.atob(cell.customize_param)))
              } catch (e) {
                _param = {}
              }
              // cell.copyright = _param.copyright || ''
              // cell.logo = _param.logo || ''
              cell.apptype = _param.apptype || ''
              cell.delay = _param.delay || 0
              cell.statusBarColor = _param.statusBarColor || 'black'
              cell.sysBgColor = _param.sysBgColor || '#ffffff'
              cell.direction = _param.direction || 'vertical'
              cell.adapter = _param.adapter || ''
              cell.topHeight = _param.topHeight || ''
              cell.share = _param.share || 'false' // 分享
              cell.share_des = _param.share_des || '' // 分享描述
              cell.share_url = _param.share_url || '' // 分享图片
              cell.share_link = _param.share_link || '' // 分享链接
              if (cell.adapter && (cell.adapter === 'true' || cell.adapter === 'false')) {
                cell.adapter = ''
              }
              cell.userbind = _param.userbind || ''
              cell.instantMessage = _param.instantMessage || ''
            }
            if (cell.user_binding !== 'true') {
              cell.user_binding = 'false'
            }
            if (cell.share !== 'true') {
              cell.share = 'false'
            }
            if (!cell.adapter && cell.apptype) {
              cell.adapter = 'app'
            }
            return cell
          })
@@ -174,13 +514,41 @@
          return item
        })
        if (!selectApp && applist[0]) {
          let record = localStorage.getItem(window.GLOB.sysSign + 'app_record')
          record = record ? JSON.parse(record) : null
          if (record && record.dates) {
            let ids = applist.map(item => item.ID)
            let reset = false
            Object.keys(record.dates).forEach(key => {
              if (!ids.includes(key)) {
                delete record.dates[key]
                reset = true
              }
            })
            applist.sort((a, b) => {
              return (record.dates[b.ID] || 0) - (record.dates[a.ID] || 0)
            })
            if (reset) {
              localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify(record))
            }
          }
        }
        if (!selectApp && applist[0]) {
          selectApp = applist[0]
        }
        this.setState({
          loading: false,
          applist: applist,
          selectApp
        })
      } else {
        this.setState({
          loading: false
@@ -195,24 +563,25 @@
  }
  getSmStemp = () => {
    let _sql = `select ID,TemplateCode,SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a
      inner join (select openid from sapp where id='${window.GLOB.appkey}') b
    let _sql = `select ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a
      inner join (select openid from sapp where id='${window.GLOB.appkey}') b
      on a.openid=b.openid`
    _sql = Utils.formatOptions(_sql)
    _sql = Utils.formatOptions(_sql, 'x')
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: _sql,
      obj_name: 'data',
      arr_field: 'ID,TemplateCode,SignName'
      arr_field: 'ID,TemplateCode,SignName',
      exec_type: 'x'
    }
    
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.secretkey = Utils.encrypt('', param.timestamp)
    param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
    
    Api.getSystemConfig(param).then(res => {
    Api.getCloudConfig(param).then(res => {
      let msgs = []
      if (!res.status) {
        notification.warning({
@@ -249,14 +618,15 @@
              })
              _this.setState({
                selectedRowKeys: [],
                selectedSubRowKeys: [],
                selectApp: null,
                selectSubApp: null,
                loading: true
              })
              _this.getAppList()
            } else {
              if (result.message.indexOf('kei_no已被菜单使用,不可删除') > -1) {
                result.message = 'kei_no已被菜单使用,不可删除'
              }
              notification.warning({
                top: 92,
                message: result.message,
@@ -280,22 +650,31 @@
    let param = {
      func: 's_kei_addupt',
      ID: selectApp.ID,
      exec_type: 'y',
      exec_type: 'x',
      remark: selectApp.remark,
      kei_no: selectApp.kei_no,
      LText: ''
      cus_param_type: 'A'
    }
    param.del_typename = record.typename
    param.lang = record.lang
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt('', param.timestamp)
    let sublist = fromJS(selectApp.sublist).toJS()
    sublist = sublist.filter(item => item.ID !== record.ID)
    sublist = sublist.map(item => {
      if (item.typename !== 'pc') {
        item.userbind = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{8}/, 'userbind')
        item.instantMessage = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{14}/, 'instantmessage')
      }
      return item
    })
    // param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}'`)
    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || ''}','${item.sms_id || ''}'`)
    // 子应用ID、typename、应用ID、CloudUserID、appkey、login_types(是否需要登录,已弃用)、link_type(是否使用短连接,已弃用)、role_type(是否使用角色管理)、lang、css(皮肤)、title(标题)、favicon(图标)、user_binding(用户绑定)、sms_id(短信模板ID)、自定义
    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
    param.LText = param.LText.join(' union all ')
    param.LText = Utils.formatOptions(param.LText)
    param.LText = Utils.formatOptions(param.LText, 'x')
    
    confirm({
      content: '确定删除该子应用吗?',
@@ -310,7 +689,6 @@
              })
      
              _this.setState({
                selectedSubRowKeys: [],
                selectSubApp: null,
                loading: true
              })
@@ -335,104 +713,226 @@
  jumpApp = (item) => {
    const { selectApp } = this.state
    let record = localStorage.getItem(window.GLOB.sysSign + 'app_record')
    record = record ? JSON.parse(record) : null
    if (!record || !record.dates) {
      localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify({preId: selectApp.ID, activeId: selectApp.ID, dates: {[selectApp.ID]: new Date().getTime()}}))
    } else {
      if (record.preId === selectApp.ID || record.activeId === selectApp.ID) {
        localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify({preId: selectApp.ID, activeId: selectApp.ID, dates: {...record.dates, [selectApp.ID]: new Date().getTime()}}))
      } else {
        localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify({...record, preId: selectApp.ID}))
      }
    }
    let route = 'mobdesign'
    if (item.typename === 'pc') {
      route = 'pcdesign'
    }
    window.open(window.location.href.replace(/#.+/ig, `#/${route}/${window.btoa(window.encodeURIComponent(JSON.stringify({...item, kei_no: selectApp.kei_no, remark: selectApp.remark, type: 'app'})))}`))
    let applangList = []
    if (item.lang === 'zh-CN') {
      selectApp.sublist.forEach(cell => {
        if (cell.typename === item.typename && cell.lang !== 'zh-CN') {
          applangList.push(cell.lang)
        }
      })
    }
    if (applangList.length) {
      applangList.unshift('zh-CN')
      applangList = JSON.stringify(applangList)
    } else {
      applangList = ''
    }
    let param = {...item, kei_no: selectApp.kei_no, remark: selectApp.remark, applangList, type: 'app'}
    window.open(window.location.href.replace(/#.+/ig, `#/${route}/${window.btoa(window.encodeURIComponent(JSON.stringify(param)))}`))
  }
  /**
   *
   */
  jumpMenu = (item) => {
    const { selectApp } = this.state
    let applangList = []
    if (item.lang === 'zh-CN') {
      selectApp.sublist.forEach(cell => {
        if (cell.typename === item.typename && cell.lang !== 'zh-CN') {
          applangList.push(cell.lang)
        }
      })
    }
    if (applangList.length) {
      applangList.unshift('zh-CN')
      applangList = JSON.stringify(applangList)
    } else {
      applangList = ''
    }
    window.open(window.location.href.replace(/#.+/ig, `#/role/${window.btoa(window.encodeURIComponent(JSON.stringify({...item, kei_no: selectApp.kei_no, remark: selectApp.remark, applangList, type: 'app'})))}`))
  }
  onSelectChange = selectedRowKeys => {
    const { applist } = this.state
    let selectApp = applist.filter(item => item.ID === selectedRowKeys[0])[0]
    this.setState({ selectedRowKeys, selectApp })
    this.setState({ selectApp })
  }
  /**
   *
   */
  onSubChange = selectedSubRowKeys => {
    this.setState({ selectedSubRowKeys })
  onScriptChange = selectedRowKeys => {
    this.setState({ selectScriptKeys: selectedRowKeys })
  }
  onScriptSelect = (record) => {
    const { selectScriptKeys } = this.state
    if (selectScriptKeys.includes(record.ID)) {
      this.setState({ selectScriptKeys: selectScriptKeys.filter(key => key !== record.ID) })
    } else {
      this.setState({ selectScriptKeys: [...selectScriptKeys, record.ID]})
    }
  }
  deleteScripts = () => {
    const { selectScriptKeys, selectTran } = this.state
    if (selectScriptKeys.length === 0) {
      notification.warning({
        top: 92,
        message: '请选择要删除的脚本!',
        duration: 3
      })
      return
    }
    let params = selectScriptKeys.map(key => {
      return {
        func: 's_sVersionDetail_del',
        BID: selectTran.ID,
        ID: key
      }
    })
    const _this = this
    confirm({
      content: '确定要执行吗?',
      onOk() {
        return new Promise(resolve => {
          let deffers = params.map((param, i) => {
            return new Promise(resolve => {
              setTimeout(() => {
                Api.getCloudConfig(param).then(res => {
                  resolve(res)
                }, () => {
                  resolve({status: false, message: '删除失败!'})
                })
              }, i * 150)
            })
          })
          Promise.all(deffers).then(result => {
            let errorMsg = ''
            result.forEach(res => {
              if (!res.status) {
                errorMsg = res.message
              }
            })
            if (errorMsg) {
              notification.warning({
                top: 92,
                message: errorMsg,
                duration: 3
              })
            } else {
              notification.success({
                top: 92,
                message: '执行成功。',
                duration: 3
              })
              _this.setState({
                scriptIndex: 1
              }, () => {
                _this.getScriptList()
              })
            }
            resolve()
          })
        })
      },
      onCancel() {}
    })
  }
  onTransChange = selectedRowKeys => {
    const { translist, selectTran } = this.state
    let _selectTran = translist.filter(item => item.ID === selectedRowKeys[0])[0]
    this.setState({ selectTran: _selectTran })
    if (!selectTran || selectTran.ID !== _selectTran.ID) {
      this.setState({ scriptIndex: 1 }, () => {
        this.getScriptList()
      })
    }
  }
  onTransSelect = (record) => {
    const { selectTran } = this.state
    this.setState({ selectTran: record })
    if (!selectTran || selectTran.ID !== record.ID) {
      this.setState({ scriptIndex: 1 }, () => {
        this.getScriptList()
      })
    }
  }
  /**
   * @description 点击整行,触发切换, 判断是否可选,单选或多选,进行对应操作
   */
  changeRow = (record) => {
    this.setState({ selectedRowKeys: [record.ID], selectApp: record })
    this.setState({ selectApp: record })
  }
  /**
   * @description 点击整行,触发切换, 判断是否可选,单选或多选,进行对应操作
   */
  changeSubRow = (record) => {
    this.setState({ selectedSubRowKeys: [record.ID], selectSubApp: record })
  }
  trigerApp = (type) => {
    if (type === 'edit' && !this.state.selectApp) {
      notification.warning({
        top: 92,
        message: '请选择需要编辑的应用!',
        duration: 5
      })
      return
    }
    this.setState({
      visible: type
    })
  }
  trigerSubApp = (type) => {
    if (type === 'edit' && !this.state.selectSubApp) {
      notification.warning({
        top: 92,
        message: '请选择需要编辑的子应用!',
        duration: 5
      })
      return
    } else if (!this.state.selectApp) {
      notification.warning({
        top: 92,
        message: '请选择应用!',
        duration: 5
      })
      return
    }
    this.setState({
      subVisible: type
    })
  }
  
  submitCard = () => {
    const { selectApp, visible } = this.state
    const { selectApp, visible, applist } = this.state
    this.mobcardRef.handleConfirm().then(res => {
      this.setState({
        confirmloading: true
      })
      let ID = ''
      if (visible === 'edit') {
        ID = selectApp.ID
      } else {
        let lowerKei = res.kei_no.toLowerCase()
        if (['mob', 'pad', 'pc', 'admin'].includes(lowerKei)) {
          notification.warning({
            top: 92,
            message: '应用编码不允许使用mob、pad、pc、admin!',
            duration: 3
          })
          return
        } else if (applist.filter(app => app.kei_no.toLowerCase() === lowerKei).length > 0) {
          notification.warning({
            top: 92,
            message: '应用编码已存在!',
            duration: 3
          })
          return
        }
        ID = md5(window.GLOB.appkey + res.kei_no)
      }
      this.setState({
        confirmloading: true
      })
      let param = {
        func: 's_kei_addupt',
        ID: ID,
        exec_type: 'y',
        exec_type: 'x',
        remark: res.remark,
        kei_no: res.kei_no,
        cus_param_type: 'A',
        LText: ''
      }
@@ -440,10 +940,17 @@
      param.secretkey = Utils.encrypt('', param.timestamp)
      if (visible === 'edit') {
        // param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}'`)
        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || ''}','${item.sms_id || ''}'`)
        selectApp.sublist = selectApp.sublist.map(item => {
          if (item.typename !== 'pc') {
            item.userbind = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{8}/, 'userbind')
            item.instantMessage = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{14}/, 'instantmessage')
          }
          return item
        })
        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
        param.LText = param.LText.join(' union all ')
        param.LText = Utils.formatOptions(param.LText)
        param.LText = Utils.formatOptions(param.LText, 'x')
      }
      Api.getCloudConfig(param).then(result => {
@@ -455,8 +962,6 @@
          })
          this.setState({
            selectedRowKeys: [],
            selectedSubRowKeys: [],
            selectApp: null,
            selectSubApp: null,
            confirmloading: false,
@@ -501,9 +1006,10 @@
      let param = {
        func: 's_kei_addupt',
        ID: selectApp.ID,
        exec_type: 'y',
        exec_type: 'x',
        remark: selectApp.remark,
        kei_no: selectApp.kei_no,
        cus_param_type: 'A',
        LText: ''
      }
@@ -527,10 +1033,17 @@
        })
      }
      // param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}'`)
      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || ''}','${item.sms_id || ''}'`)
      sublist = sublist.map(item => {
        if (item.typename !== 'pc') {
          item.userbind = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{8}/, 'userbind')
          item.instantMessage = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{14}/, 'instantmessage')
        }
        return item
      })
      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
      param.LText = param.LText.join(' union all ')
      param.LText = Utils.formatOptions(param.LText)
      param.LText = Utils.formatOptions(param.LText, 'x')
      Api.getCloudConfig(param).then(result => {
        if (result.status) {
@@ -541,7 +1054,6 @@
          })
          this.setState({
            selectedSubRowKeys: [],
            selectSubApp: null,
            confirmloading: false,
            subVisible: false,
@@ -567,76 +1079,224 @@
  }
  render () {
    const { loading, visible, subVisible, columns, applist, selectedRowKeys, selectedSubRowKeys, subcolumns, selectApp, selectSubApp } = this.state
    const { loading, visible, subVisible, columns, transcolumns, applist, translist, transVisible, selectApp, selectTran, selectSubApp, scriptVisible, scriptlist, scriptcolumns, selectScriptKeys } = this.state
    return (
      <div className="mk-app-manage">
        <ConfigProvider locale={_locale}>
          <Header view="manage" />
          {loading ?
            <div className="loading-mask">
              <div className="ant-spin-blur"></div>
              <Spin />
            </div> : null
          }
          <div className="app-table">
            <div className="app-action">
              <Button className="mk-green" onClick={() => this.trigerApp('plus')}>添加</Button>
              <Button className="mk-purple" onClick={() => this.trigerApp('edit')}>修改</Button>
        <Header view="manage" />
        {loading ?
          <div className="loading-mask">
            <Spin size="large" />
          </div> : null
        }
        <div className="view-wrap">
          <div className="left-view">
            <div className="app-table">
              <div className="app-action">
                <Button className="mk-green" onClick={() => this.setState({ visible: 'plus' })}>添加应用</Button>
              </div>
              <Table
                rowKey="ID"
                columns={columns}
                dataSource={applist}
                pagination={false}
                rowSelection={{ type: 'radio', selectedRowKeys: selectApp ? [selectApp.ID] : [], onChange: this.onSelectChange }}
                onRow={(record) => ({ onClick: () => this.setState({ selectApp: record })})}
              />
            </div>
            <Table
              rowKey="ID"
              columns={columns}
              dataSource={applist}
              pagination={false}
              rowSelection={{ type: 'radio', selectedRowKeys, onChange: this.onSelectChange }}
              onRow={(record) => ({ onClick: () => {this.changeRow(record)} })}
            />
          </div>
          <div className="app-table">
            <div className="sub-app-title"><span>子应用</span></div>
            <div className="app-action">
              <Button className="mk-green" onClick={() => this.trigerSubApp('plus')}>添加</Button>
              <Button className="mk-purple" onClick={() => this.trigerSubApp('edit')}>修改</Button>
            <div className={'trans-table' + (this.state.transTotal <= 10 ? ' no-footer' : '')}>
              <div className="app-action">
                <Button className="mk-green" onClick={() => this.setState({ transVisible: 'plus' })}>添加传输号</Button>
                <Search placeholder="综合搜索" onSearch={value => this.tranSearch(value)} enterButton />
              </div>
              <Table
                rowKey="ID"
                columns={transcolumns}
                dataSource={translist}
                pagination={{
                  current: this.state.transIndex,
                  pageSize: 10,
                  total: this.state.transTotal || 0,
                  showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
                }}
                rowSelection={{ type: 'radio', selectedRowKeys: selectTran ? [selectTran.ID] : [], onChange: this.onTransChange }}
                onRow={(record) => ({ onClick: () => {
                  if (this.forbid) {
                    this.forbid = false
                    return
                  }
                  this.onTransSelect(record)
                }})}
                onChange={this.changeTable}
              />
            </div>
            <Table
              rowKey="ID"
              columns={subcolumns}
              dataSource={selectApp ? selectApp.sublist : []}
              pagination={false}
              rowSelection={{ type: 'radio', selectedRowKeys: selectedSubRowKeys, onChange: this.onSubChange }}
              onRow={(record) => ({ onClick: () => {this.changeSubRow(record)} })}
            />
            {selectTran ? <div className="script-table">
              <div className="app-action">
                <Button className="mk-green" onClick={() => this.setState({ scriptVisible: true })}>添加脚本</Button>
                <Button className="mk-danger" onClick={this.deleteScripts} style={{marginLeft: '15px'}}>删除</Button>
                <Search placeholder="综合搜索" defaultValue={this.state.scriptSearchKey} onSearch={value => this.scriptSearch(value)} enterButton />
              </div>
              <Table
                rowKey="ID"
                columns={scriptcolumns}
                dataSource={scriptlist}
                pagination={{
                  current: this.state.scriptIndex,
                  pageSize: 10,
                  total: this.state.scriptTotal || 0,
                  showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
                }}
                rowSelection={{ type: 'checkbox', selectedRowKeys: selectScriptKeys, onChange: this.onScriptChange }}
                onRow={(record) => ({ onClick: () => this.onScriptSelect(record)})}
                onChange={this.changeScriptTable}
              />
            </div> : null}
          </div>
          <Modal
            title={'编辑应用'}
            width={'600px'}
            maskClosable={false}
            visible={!!visible}
            onCancel={() => this.setState({visible: false})}
            confirmLoading={this.state.confirmloading}
            onOk={this.submitCard}
            cancelText="取消"
            okText="确定"
            destroyOnClose
          >
            <MutilForm type={visible} card={visible === 'edit' ? selectApp : ''} wrappedComponentRef={(inst) => this.mobcardRef = inst} inputSubmit={this.submitCard} />
          </Modal>
          <Modal
            title={'编辑子应用'}
            width={'850px'}
            maskClosable={false}
            visible={!!subVisible}
            onCancel={() => this.setState({subVisible: false})}
            confirmLoading={this.state.confirmloading}
            onOk={this.submitSubCard}
            cancelText="取消"
            okText="确定"
            destroyOnClose
          >
            <SubMutilForm type={subVisible} card={subVisible === 'edit' ? selectSubApp : ''} wrappedComponentRef={(inst) => this.submobcardRef = inst} inputSubmit={this.submitSubCard} />
          </Modal>
        </ConfigProvider>
          <div className="right-view">
            {selectApp ? <div className="app-title">{selectApp.remark}</div> : null}
            {selectApp && selectApp.sublist.map((item, index) => {
              let css = skinStyle[item.css] ? skinStyle[item.css].name : ''
              let color = skinStyle[item.css] ? skinStyle[item.css].color : '#e8e8e8'
              let binding = ''
              if (item.user_binding === 'true') {
                binding = '用户绑定'
              }
              if (item.share === 'true') {
                binding = binding ? binding + '、分享' : '分享'
              }
              return (
                <div className="sub-app" key={index} style={{borderColor: color}}>
                  <Row>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">应用类型:</div>
                        <div className="content" style={{fontSize: '18px', fontWeight: 600}}>{item.typename}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">语言:</div>
                        <div className="content" style={{textDecoration: 'underline'}}>{langs[item.lang]}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">权限管理:</div>
                        <div className="content">{item.role_type === 'false' ? '不启用' : '启用'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        {/* <div className="label">皮肤:</div>
                        <div className="content" style={{color: color}}>{css}</div> */}
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">皮肤:</div>
                        <div className="content" style={{color: color}}>{css}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        {/* {binding ? <div className="label">
                          <Tooltip placement="topLeft" title="微信公众号登录时,系统用户与微信用户的绑定方式。">
                            <QuestionCircleOutlined className="mk-form-tip" />
                            用户绑定:
                          </Tooltip>
                        </div> : null} */}
                        {binding ? <div className="label">
                          <Tooltip placement="topLeft" title="微信公众号或小程序中,绑定系统用户、自定义分享等功能。">
                            <QuestionCircleOutlined className="mk-form-tip" />
                            扩展功能:
                          </Tooltip>
                        </div> : null}
                        <div className="content">{binding}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">标题:</div>
                        <div className="content">{item.title || '无'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">网站头像:</div>
                        <div className="content">{item.favicon ? <img style={{width: '18px', height: '18px', borderRadius: '4px'}} src={item.favicon} alt="" /> : '无'}</div>
                      </div>
                    </Col>
                  </Row>
                  <div className="action">
                    {item.lang !== 'zh-CN' ? <TransMenu app={item} supApp={selectApp} /> : null}
                    <Button type="link" onClick={() => this.jumpMenu(item)} style={{color: 'rgba(30, 228, 224, 1)'}}>菜单&权限</Button>
                    <Button type="link" onClick={() => this.setState({ selectSubApp: item, subVisible: 'edit' })} style={{color: '#8E44AD'}}>修改</Button>
                    <Button type="link" onClick={() => this.deleteSubApp(item)} style={{color: '#ff4d4f'}}>删除</Button>
                    <Button type="link" onClick={() => this.jumpApp(item)}>编辑应用</Button>
                    <Paragraph style={{display: 'inline-block', margin: 0}} copyable={{ text: `${window.GLOB.baseurl}${item.typename === 'pad' ? 'mob' : item.typename}/index.html#/index/${this.state.selectApp.kei_no}/${item.typename !== 'pc' ? item.typename + '/' : ''}${item.lang}` }}></Paragraph>
                  </div>
                </div>
              )
            })}
          </div>
        </div>
        <Modal
          title={'编辑应用'}
          width={'600px'}
          maskClosable={false}
          visible={visible !== false}
          onCancel={() => this.setState({visible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitCard}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <MutilForm type={visible} card={visible === 'edit' ? selectApp : ''} wrappedComponentRef={(inst) => this.mobcardRef = inst} inputSubmit={this.submitCard} />
        </Modal>
        <Modal
          title={transVisible === 'plus' ? '添加传输号' : '编辑传输号'}
          width={'600px'}
          maskClosable={false}
          visible={transVisible !== false}
          onCancel={() => this.setState({transVisible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitTrans}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <TransForm type={transVisible} card={transVisible === 'edit' ? this.state.editTran : ''} wrappedComponentRef={(inst) => this.transRef = inst} inputSubmit={this.submitTrans} />
        </Modal>
        <Modal
          title={'添加脚本'}
          width={900}
          maskClosable={false}
          visible={scriptVisible}
          onCancel={() => this.setState({scriptVisible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitScript}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <ScriptForm applist={applist} wrappedComponentRef={(inst) => this.scriptRef = inst} inputSubmit={this.submitScript} />
        </Modal>
        <Modal
          title={subVisible === 'plus' ? '添加子应用' : '编辑子应用'}
          width={'850px'}
          maskClosable={false}
          visible={subVisible !== false}
          onCancel={() => this.setState({subVisible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitSubCard}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <SubMutilForm type={subVisible} card={subVisible === 'edit' ? selectSubApp : ''} wrappedComponentRef={(inst) => this.submobcardRef = inst} inputSubmit={this.submitSubCard} />
        </Modal>
      </div>
    )
  }