king
2019-12-12 f22bb55c4ff50a8a63c795487b057c0cebdae649
2019-12-12
12个文件已修改
3个文件已添加
526 ■■■■ 已修改文件
public/hxlogo.png 补丁 | 查看 | 原始文档 | blame | 历史
public/index.html 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.scss 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editthdmenu/index.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editthdmenu/preview/index.jsx 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editthdmenu/preview/index.scss 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/menuelement/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 205 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/settingform/index.jsx 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/source.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/loginform.jsx 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/hxlogo.png
public/index.html
@@ -2,10 +2,10 @@
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
    <script src="%PUBLIC_URL%/options.js"></script>
    <title></title>
src/components/header/index.scss
@@ -12,9 +12,11 @@
  .header-logo {
    float: left;
    width: 170px;
    width: 180px;
    line-height: 48px;
    text-align: center;
    padding-left: 5px;
    box-sizing: border-box;
    opacity: 1;
    transition: width 0.2s, opacity 0.15s;
    img {
@@ -25,13 +27,14 @@
  .header-logo.collapse {
    opacity: 0;
    width: 0px;
    padding-left: 0px;
  }
  .header-collapse {
    float: left;
    width: 80px;
    line-height: 48px;
    padding-left: 30px;
    padding-left: 20px;
    cursor: pointer;
    transition: padding-left 0.15s;
    i {
src/components/sidemenu/editthdmenu/index.jsx
@@ -5,7 +5,7 @@
import HTML5Backend from 'react-dnd-html5-backend'
import { notification, Modal, Button, Spin, Icon, Col, Card, Tabs, Row, Input } from 'antd'
import moment from 'moment'
import Preview from '@/components/preview'
import Preview from './preview'
import TransferForm from '@/components/transferform'
import Utils from '@/utils/utils.js'
import DragElement from '../menuelement'
@@ -53,6 +53,8 @@
    menuConfig: '',
    tempSearchKey: '',
    loading: false,
    preview: null,
    pretemplate: null,
    baseTemplates: [{
      title: '基础表格',
      type: 'CommonTable',
@@ -300,10 +302,11 @@
    })
  }
  previewPicture = (url) => {
  previewPicture = (template) => {
    // 图片预览
    this.setState({
      preview: url
      preview: template.url,
      pretemplate: template
    })
  }
@@ -444,9 +447,8 @@
                      <Col key={template.type} span={8}>
                        <Card
                          title={template.title}>
                          <img onClick={() => {this.previewPicture(template.url)}} src={template.url} alt=""/>
                          <img onClick={() => {this.previewPicture(template)}} src={template.url} alt=""/>
                          <div className="card-operation">
                            {/* <Button type="primary" onClick={() => {this.previewPicture(template.url)}}>预览</Button> */}
                            <Button type="primary" onClick={() => {this.useTemplate(template)}}>使用模板</Button>
                          </div>
                        </Card>
@@ -468,9 +470,8 @@
                        <Col key={template.type + index} span={8}>
                          <Card
                            title={template.title}>
                            <img onClick={() => {this.previewPicture(template.url)}} src={template.url} alt=""/>
                            <img onClick={() => {this.previewPicture(template)}} src={template.url} alt=""/>
                            <div className="card-operation">
                              {/* <Button type="primary" onClick={() => {this.previewPicture(template.url)}}>预览</Button> */}
                              <Button type="primary" onClick={() => {this.useTemplate(template)}}>使用模板</Button>
                            </div>
                          </Card>
@@ -502,7 +503,7 @@
          />
        }
        {/* 图片预览 */}
        <Preview cancel={this.cancelPrePicture} preview={this.state.preview}/>
        <Preview cancel={this.cancelPrePicture} preview={this.state.preview} template={this.state.pretemplate} confirm={this.useTemplate}/>
        {/* 解冻菜单模态框 */}
        <Modal
          title={this.state.dict['header.thawmenu']}
src/components/sidemenu/editthdmenu/preview/index.jsx
New file
@@ -0,0 +1,60 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Button} from 'antd'
import './index.scss'
class Preview extends Component {
  static propTpyes = {
    preview: PropTypes.any,
    cancel: PropTypes.func,
    confirm: PropTypes.func,
    template: PropTypes.object
  }
  state = {
    show: false,
    url: ''
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (nextProps.preview) {
      this.setState({
        url: nextProps.preview
      })
      setTimeout(() => {
        this.setState({
          show: true
        })
      }, 10)
    } else {
      this.setState({
        show: false
      })
      setTimeout(() => {
        this.setState({
          url: ''
        })
      }, 500)
    }
  }
  close = () => {
    this.props.cancel()
  }
  render () {
    return (
      <div>
        {this.state.url &&
          <div className={'preview-box ' + (this.state.show ? 'active' : '')} onClick={this.close}>
            <Button shape="circle" icon="close"></Button>
            <Button type="primary" onClick={() => {this.props.confirm(this.props.template)}}>使用模板</Button>
            {this.state.url && <img src={this.state.url} alt=""/>}
          </div>
        }
      </div>
    )
  }
}
export default Preview
src/components/sidemenu/editthdmenu/preview/index.scss
New file
@@ -0,0 +1,30 @@
.preview-box {
  position: fixed;
  z-index: 1100;
  left: 0;
  right: 0px;
  top: 0px;
  bottom: 0px;
  background: rgba($color: #000000, $alpha: 0.6);
  line-height: 100vh;
  text-align: center;
  opacity: 0;
  transition: opacity 0.5s;
  cursor: zoom-out;
  img {
    max-width: 80vw;
    max-height: 90vh;
  }
  button {
    position: absolute;
    top: 4vh;
    right: 4vw;
  }
  button + button {
    top: calc(4vh + 55px);
    right: calc(4vw - 30px);
  }
}
.active {
  opacity: 1;
}
src/components/sidemenu/menuelement/index.jsx
@@ -39,7 +39,6 @@
      type: 'close'
    })
  }
  const [, drop] = useDrop({ accept: ItemTypes.CARD })
  return (
    <div ref={drop} className="sidemenu-dragboard">
@@ -47,7 +46,7 @@
        <Card
          key={card.id}
          id={`${card.id}`}
          icon={card.PageParam.Icon}
          icon={card.PageParam && card.PageParam.Icon}
          text={card.text}
          moveCard={moveCard}
          editCard={editCard}
src/tabviews/commontable/index.jsx
@@ -127,7 +127,7 @@
        columns: _columns,
        arr_field: _arrField.join(','),
        search: _search ? 'where (' + _search + ')' : '',
        orderColumn: config.setting.orderColumn,
        // orderColumn: config.setting.orderColumn,
        loading: true
      }, () => {
        this.improveSearch()
@@ -255,16 +255,19 @@
  async loadmaindata () {
    const { arr_field, pageIndex, pageSize, orderColumn, orderType, search, setting } = this.state
    console.log(setting)
    // 获取列表数据
    let param = {
      func: 'sPC_Get_TableData',
      func: setting.innerFunc || 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field
    }
    let LText = `select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderColumn} ${orderType}) as rows from ${setting.dataresource} ${search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows`
    let DateCount = `select count(1) as total from ${setting.dataresource} ${search}`
    let orderBy = orderColumn ? (orderColumn + ' ' + orderType) : setting.order
    let LText = `select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${setting.dataresource} ${search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows`
    let DateCount = `select count(1) as total from ${setting.dataresource} ${search}`
    console.log(LText)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
@@ -359,6 +362,8 @@
  UNSAFE_componentWillMount () {
    // 组件加载时,获取菜单数据
    this.loadconfig()
    console.log(Utils.getfunc())
  }
  shouldComponentUpdate (nextProps, nextState) {
src/templates/comtableconfig/index.jsx
@@ -929,26 +929,15 @@
          }
        }
  
        if (this.state.operaType === 'add') {
          _config[res.type] = _config[res.type].map(item => {
            if (item.uuid === res.values.uuid) {
              isupdate = true
              return res.values
            } else {
              return item
            }
          })
          _config[res.type] = _config[res.type].filter(item => !item.origin)
        } else {
          _config[res.type] = _config[res.type].map(item => {
            if (item.uuid === res.values.uuid) {
              isupdate = true
              return res.values
            } else {
              return item
            }
          })
        }
        _config[res.type] = _config[res.type].map(item => {
          if (item.uuid === res.values.uuid) {
            isupdate = true
            return res.values
          } else {
            return item
          }
        })
        _config[res.type] = _config[res.type].filter(item => !item.origin)
  
        if (!isupdate) { // 操作不是修改,添加元素至列表
          _config[res.type].push(res.values)
@@ -1005,6 +994,126 @@
    }
  }
  creatFunc = () => {
    // let _config = JSON.parse(JSON.stringify(this.state.config))
    this.formRef.handleConfirm().then(res => {
      let btn = res.values
      let LText = ''
      if (!btn.innerFunc) {
        notification.warning({
          top: 92,
          message: '请填写内部函数!',
          duration: 10
        })
        return
      }
      new Promise(resolve => {
        // 内部请求
        if (btn.OpenType === 'pop') {
          Api.getSystemConfig({
            func: 'sPC_Get_LongParam',
            MenuID: btn.uuid
          }).then(res => {
            let _LongParam = ''
            if (res.status && res.LongParam) {
              _LongParam = window.decodeURIComponent(window.atob(res.LongParam))
              try {
                _LongParam = JSON.parse(_LongParam)
              } catch (e) {
                _LongParam = ''
              }
            }
            if (_LongParam) {
              resolve(_LongParam)
            } else {
              resolve(false)
              notification.warning({
                top: 92,
                message: '弹窗(表单)按钮,请先配置表单信息!',
                duration: 10
              })
            }
          })
        } else {
          resolve(true)
        }
      }).then(res => {
        if (!res) return
        LText = Utils.formatOptions(Utils.getfunc())
        console.log(LText)
        return Api.getSystemConfig({
          func: 'sPC_Get_TVP',
          TVPName: btn.innerFunc
        })
      }).then(res => {
        console.log(res)
        if (res.status) {
          return true
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
          return false
        }
      }).then(res => {
        console.log(res)
      })
      // let isupdate = false
      // _config.action = _config.action.map(item => {
      //   if (item.uuid === res.values.uuid) {
      //     isupdate = true
      //     return res.values
      //   } else {
      //     return item
      //   }
      // })
      // _config.action = _config.action.filter(item => !item.origin)
      // if (!isupdate) { // 操作不是修改,添加元素至列表
      //   _config.action.push(res.values)
      // }
      // let gridbtn = _config.action.filter(act => act.position === 'grid')
      // let _display = false
      // if (gridbtn.length > 0) {
      //   _display = true
      // }
      // if (_config.gridBtn) {
      //   _config.gridBtn.display = _display
      // } else {
      //   _config.gridBtn = {
      //     display: _display,
      //     Align: 'center',
      //     IsSort: 'false',
      //     uuid: Utils.getuuid(),
      //     label: this.state.dict['header.form.column.action'],
      //     type: 'action',
      //     style: 'button',
      //     show: 'horizontal',
      //     Width: 120
      //   }
      // }
      // this.setState({
      //   config: _config,
      //   actionloading: true
      // }, () => {
      //   this.setState({
      //     actionloading: false
      //   })
      // })
    })
  }
  deleteElement = (element) => {
    let _this = this
    confirm({
@@ -1045,30 +1154,32 @@
    const { config, originMenu } = this.state
    this.menuformRef.handleConfirm().then(res => {
      config.search = config.search.filter(item => !item.origin)
      if (config.search[0] && config.search[0].origin) {
        notification.warning({
          top: 92,
          message: '请设置搜索条件',
          duration: 10
        })
        return
      }
      if (config.action[0] && config.action[0].origin) {
        notification.warning({
          top: 92,
          message: '请设置按钮',
          duration: 10
        })
        return
      }
      if (config.columns[0] && config.columns[0].origin) {
        notification.warning({
          top: 92,
          message: '请设置显示列',
          duration: 10
        })
        return
      }
      config.action = config.action.filter(item => !item.origin)
      config.columns = config.columns.filter(item => !item.origin)
      // if (config.search[0] && config.search[0].origin) {
      //   notification.warning({
      //     top: 92,
      //     message: '请设置搜索条件',
      //     duration: 10
      //   })
      //   return
      // }
      // if (config.action[0] && config.action[0].origin) {
      //   notification.warning({
      //     top: 92,
      //     message: '请设置按钮',
      //     duration: 10
      //   })
      //   return
      // }
      // if (config.columns[0] && config.columns[0].origin) {
      //   notification.warning({
      //     top: 92,
      //     message: '请设置显示列',
      //     duration: 10
      //   })
      //   return
      // }
      let _LongParam = ''
      let _config = {...config, tables: this.state.selectedTables}
@@ -1833,6 +1944,12 @@
          width={700}
          onCancel={() => { this.setState({ visible: false }) }}
          onOk={this.handleSubmit}
          footer={[
            this.state.formtemp === 'action' ?
            <Button key="delete" className="mk-btn mk-purple" onClick={this.creatFunc} loading={this.state.confirmLoading}>{this.state.dict['header.delete']}</Button> : null,
            <Button key="cancel" onClick={() => { this.setState({ visible: false }) }}>{this.state.dict['header.cancel']}</Button>,
            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['header.confirm']}</Button>
          ]}
          destroyOnClose
        >
          {this.state.formtemp === 'search' ?
src/templates/comtableconfig/settingform/index.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Radio, Select } from 'antd'
import { Form, Row, Col, Input, Radio, Select, Tooltip, Icon } from 'antd'
import './index.scss'
const { TextArea } = Input
@@ -10,6 +10,10 @@
    dict: PropTypes.object, // 字典项
    data: PropTypes.object,
    columns: PropTypes.array
  }
  state = {
    interType: this.props.data.interType || 'inner'
  }
  handleConfirm = () => {
@@ -23,6 +27,10 @@
        }
      })
    })
  }
  onChange = (e) => {
    console.log(e.target.value)
  }
  render() {
@@ -79,16 +87,34 @@
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="接口类型">
              {getFieldDecorator('interType', {
                initialValue: data.interType || 'inner'
              })(
                <Radio.Group onChange={this.onChange}>
                  <Radio value="inner">内部</Radio>
                  <Radio value="outer">外部</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="内部函数">
              {getFieldDecorator('innerFunc', {
                initialValue: data.innerFunc || ''
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label="数据源" className="textarea">
            <Form.Item label={
              <Tooltip placement="topLeft" title="">
                <Icon type="question-circle" />
                {'数据源'}
              </Tooltip>
            } className="textarea">
              {getFieldDecorator('dataresource', {
                initialValue: data.dataresource,
                rules: [
                  {
                    required: true,
                    message: dict['form.required.input'] + '数据源!'
                  }
                ]
                initialValue: data.dataresource
              })(<TextArea rows={4} />)}
            </Form.Item>
          </Col>
src/templates/comtableconfig/source.jsx
@@ -15,7 +15,9 @@
      tableType: 'checkbox',
      primaryKey: '',
      order: '',
      dataresource: ''
      dataresource: '',
      interType: 'inner',
      innerFunc: ''
    },
    tables: [],
    search: [
src/utils/utils.js
@@ -296,4 +296,98 @@
    let realurl = url.match(/^http/) || url.match(/^\/\//) ? url : baseurl + url
    return realurl
  }
  /**
   * @description 删除存储过程sql
   * @return {String} name 存储过程名称
   */
  static dropfunc (name) {
    return `IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('${name}') AND type in (N'P', N'PC'))  DROP PROCEDURE ${name}`
  }
  /**
   * @description 创建存储过程
   * @return {String}
   */
  static getfunc (param) {
    param = {
      name: 'ls'
    }
    let Ltext = `create proc ${param.name}
    (
    @BID nvarchar(50)='',
    @ID nvarchar(50)='',
    表单传值,文本用nvarchar(50)='',日期用datetime is null ,数值用decimal(18,小数点位数)=0,
    @sEPTMenuNo='', --传菜单参数
    @lang nvarchar(50)='',
    @debug nvarchar(50)='',
    @LoginUID nvarchar(50)='',
    @SessionUid nvarchar(50)='',
    @UserID nvarchar(50),
    @ErrorCode nvarchar(50) out,
    @retmsg nvarchar(4000) out
    )
    as
    begin
    declare  @BegindateTest datetime,@EnddateTest datetime
    select  @BegindateTest=getdate()
    set @ErrorCode=''
    set @retmsg=''
    BEGIN TRY
      /*事务操作*/
      BEGIN TRAN
        /*具体业务操作*/
         /*
        select top 10 * from sProcExcep order by id desc
        declare @UserName  nvarchar(50),@FullName nvarchar(50)
        select @UserName=UserName,@FullName=FullName from SUsers where UID=@UserID
        insert into 表名 (表单字段) select 对应入参,创建人
        update 表名 set 表单字段=对应入参,modifydate=getdate(),modifyuserid=@UserID
        if 1=2
        begin
          set @ErrorCode='E'
          set @retmsg='在此写报错'
          goto GOTO_RETURN
        end
        insert into sNote (remark,createuserid,CreateUser,CreateStaff)
        select '在此写日志',@UserID,@UserName,@FullName
        */
      COMMIT TRAN
      SET NOCOUNT ON
      RETURN
    END TRY
    BEGIN CATCH
      /*错误处理*/
      ROLLBACK TRAN
      DECLARE @ErrorMessage NVARCHAR(4000);
      DECLARE @ErrorSeverity INT;
      DECLARE @ErrorState INT;
      /*把自定义的友好的错误信息提示加上*/
      set @ErrorCode=cast(ERROR_NUMBER() as nvarchar(50))
      SET @retmsg=ERROR_MESSAGE();
      SELECT @ErrorMessage=ERROR_MESSAGE(),
        @ErrorSeverity=ERROR_SEVERITY(),
        @ErrorState=ERROR_STATE();
      RAISERROR(@ErrorMessage, /*-- Message text.*/
        @ErrorSeverity, /*-- Severity.*/
        @ErrorState  /*-- State.*/
        );
    END CATCH
    GOTO_RETURN:
      ROLLBACK TRAN
    END`
    return Ltext.replace(/\n\s{4}/ig, '\'char(13)\'')
  }
}
src/views/login/index.jsx
@@ -66,12 +66,12 @@
          sessionStorage.setItem('LoginUID', res.LoginUID)
          localStorage.setItem('lang', param.lang)
    
          let _url = window.location.href.split('#')[0]
          if (param.remember) { // 记住密码时账号密码存入localStorage
            localStorage.setItem('username', param.username)
            localStorage.setItem('password', param.password)
            localStorage.setItem(_url, window.btoa(window.encodeURIComponent(JSON.stringify({username: param.username, password: param.password}))))
          } else {
            localStorage.removeItem('username')
            localStorage.removeItem('password')
            localStorage.removeItem(_url)
          }
    
          if (this.props.location.state && this.props.location.state.from.pathname) {
src/views/login/index.scss
@@ -7,6 +7,7 @@
  .logo {
    height: 100px;
    padding-top: 30px;
    line-height: 80px;
    border-bottom: 2px solid #06b4f7;
    img {
      max-height: 100%;
src/views/login/loginform.jsx
@@ -16,7 +16,10 @@
    platName: PropTypes.string
  }
  state = {}
  state = {
    username: '',
    password: ''
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
@@ -52,9 +55,32 @@
  }
  componentDidMount () {
    const input = document.getElementById('username')
    if (input) {
      input.focus()
    let _url = window.location.href.split('#')[0]
    let _user = localStorage.getItem(_url)
    if (_user) {
      try {
        _user = JSON.parse(window.decodeURIComponent(window.atob(_user)))
      } catch {
        _user = ''
      }
    }
    if (_user) {
      this.setState({
        username: _user.username,
        password: _user.password
      }, () => {
        const input = document.getElementById('username')
        if (input) {
          input.focus()
        }
      })
    } else {
      const input = document.getElementById('username')
      if (input) {
        input.focus()
      }
    }
  }
@@ -67,7 +93,7 @@
        <Form.Item>
          {getFieldDecorator('username', {
            rules: [{ required: true, message: this.props.dict['login.username.empty'] }],
            initialValue: localStorage.getItem('username') || '',
            initialValue: this.state.username || '',
          })(
            <Input
              prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
@@ -77,7 +103,7 @@
        </Form.Item>
        <Form.Item>
          {getFieldDecorator('password', {
            initialValue: localStorage.getItem('password') || '',
            initialValue: this.state.password || '',
            rules: [
              {
                required: true,