瀏覽代碼

备份icss

zhouna 6 年之前
當前提交
c9e9bb94c5
共有 100 個文件被更改,包括 4428 次插入0 次删除
  1. 3 0
      .babelrc
  2. 32 0
      .gitignore
  3. 133 0
      README.md
  4. 38 0
      build/build.js
  5. 9 0
      build/dev-client.js
  6. 76 0
      build/dev-server.js
  7. 49 0
      build/utils.js
  8. 74 0
      build/webpack.base.conf.js
  9. 80 0
      build/webpack.dev.conf.js
  10. 164 0
      build/webpack.prod.conf.js
  11. 7 0
      config/dev.env.js
  12. 26 0
      config/index.js
  13. 4 0
      config/prod.env.js
  14. 13 0
      index.html
  15. 75 0
      package.json
  16. 7 0
      postcss.config.js
  17. 13 0
      server.js
  18. 18 0
      src/common/components/Banner/index.jsx
  19. 30 0
      src/common/components/Banner/index.less
  20. 61 0
      src/common/components/Button/index.jsx
  21. 40 0
      src/common/components/Button/index.less
  22. 75 0
      src/common/components/Calendar/Content/index.jsx
  23. 33 0
      src/common/components/Calendar/Content/index.less
  24. 29 0
      src/common/components/Calendar/ContentItem/index.jsx
  25. 14 0
      src/common/components/Calendar/ContentItem/index.less
  26. 30 0
      src/common/components/Calendar/MonthItem/index.jsx
  27. 19 0
      src/common/components/Calendar/MonthItem/index.less
  28. 217 0
      src/common/components/Calendar/SelectList/index.jsx
  29. 116 0
      src/common/components/Calendar/SelectList/index.less
  30. 60 0
      src/common/components/Calendar/Time/index.jsx
  31. 13 0
      src/common/components/Calendar/Time/index.less
  32. 38 0
      src/common/components/Calendar/YearItem/index.jsx
  33. 18 0
      src/common/components/Calendar/YearItem/index.less
  34. 123 0
      src/common/components/Calendar/index.jsx
  35. 50 0
      src/common/components/Calendar/index.less
  36. 78 0
      src/common/components/CheckBox/Multiple/index.jsx
  37. 48 0
      src/common/components/CheckBox/Multiple/index.less
  38. 64 0
      src/common/components/CheckBox/Select/index.jsx
  39. 42 0
      src/common/components/CheckBox/Select/index.less
  40. 131 0
      src/common/components/CheckBox/index.jsx
  41. 79 0
      src/common/components/CheckBox/index.less
  42. 23 0
      src/common/components/ConfirmModal/NewPortal/index.jsx
  43. 54 0
      src/common/components/ConfirmModal/OldPortal/index.jsx
  44. 二進制
      src/common/components/ConfirmModal/img/close.png
  45. 163 0
      src/common/components/ConfirmModal/index.jsx
  46. 80 0
      src/common/components/ConfirmModal/index.less
  47. 20 0
      src/common/components/DropContainer/index.jsx
  48. 0 0
      src/common/components/DropContainer/index.less
  49. 49 0
      src/common/components/DropList/index.jsx
  50. 19 0
      src/common/components/DropList/index.less
  51. 134 0
      src/common/components/EditableSpan/index.jsx
  52. 14 0
      src/common/components/EditableSpan/index.less
  53. 12 0
      src/common/components/Empty/index.jsx
  54. 5 0
      src/common/components/Empty/index.less
  55. 104 0
      src/common/components/InlineTag/index.jsx
  56. 23 0
      src/common/components/InlineTag/index.less
  57. 29 0
      src/common/components/InspectCommon/index.jsx
  58. 40 0
      src/common/components/InspectCommon/index.less
  59. 43 0
      src/common/components/ItemBox/index.jsx
  60. 29 0
      src/common/components/ItemBox/index.less
  61. 二進制
      src/common/components/Loading/img/loading.gif
  62. 54 0
      src/common/components/Loading/index.jsx
  63. 24 0
      src/common/components/Loading/index.less
  64. 二進制
      src/common/components/Message/imgs/fail.png
  65. 二進制
      src/common/components/Message/imgs/info.png
  66. 二進制
      src/common/components/Message/imgs/ok.png
  67. 56 0
      src/common/components/Message/index.jsx
  68. 45 0
      src/common/components/Message/index.less
  69. 92 0
      src/common/components/MixCheckBox/index.jsx
  70. 68 0
      src/common/components/MixCheckBox/index.less
  71. 24 0
      src/common/components/Modal/body/ModalBody.jsx
  72. 10 0
      src/common/components/Modal/body/index.less
  73. 30 0
      src/common/components/Modal/footer/ModalFooter.jsx
  74. 31 0
      src/common/components/Modal/footer/index.less
  75. 38 0
      src/common/components/Modal/header/ModalHeader.jsx
  76. 46 0
      src/common/components/Modal/header/index.less
  77. 130 0
      src/common/components/Modal/index.jsx
  78. 31 0
      src/common/components/Modal/index.less
  79. 55 0
      src/common/components/Normal/index.jsx
  80. 22 0
      src/common/components/Normal/index.less
  81. 二進制
      src/common/components/Notify/img/close.png
  82. 47 0
      src/common/components/Notify/index.js
  83. 81 0
      src/common/components/Notify/index.less
  84. 83 0
      src/common/components/Notify/notify.js
  85. 81 0
      src/common/components/NumberPan/index.jsx
  86. 20 0
      src/common/components/NumberPan/index.less
  87. 100 0
      src/common/components/NumberUnitPan/index.jsx
  88. 24 0
      src/common/components/NumberUnitPan/index.less
  89. 二進制
      src/common/components/Radio/img/disable.png
  90. 二進制
      src/common/components/Radio/img/no.png
  91. 二進制
      src/common/components/Radio/img/off.png
  92. 二進制
      src/common/components/Radio/img/on.png
  93. 二進制
      src/common/components/Radio/img/select.png
  94. 65 0
      src/common/components/Radio/index.js
  95. 10 0
      src/common/components/Radio/index.less
  96. 63 0
      src/common/components/RadioB/index.jsx
  97. 28 0
      src/common/components/RadioB/index.less
  98. 二進制
      src/common/components/SearchOption/imgs/clear.png
  99. 二進制
      src/common/components/SearchOption/imgs/search.png
  100. 0 0
      src/common/components/SearchOption/index.jsx

+ 3 - 0
.babelrc

@@ -0,0 +1,3 @@
+{
+  "presets":["react","env"]
+}

+ 32 - 0
.gitignore

@@ -0,0 +1,32 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+icssfront.iml
+package-lock.json
+yarn.lock
+*-bak.*
+
+# Dependency directories
+node_modules/
+package-lock.json
+# Optional eslint cache
+.eslintcache
+/.DS_Store
+dist/
+dist
+.idea
+
+.vscode
+/.idea
+/dist
+
+
+# node
+app/
+app/package-lock.json
+app/yarn.lock
+app/logs
+app/node_modules

+ 133 - 0
README.md

@@ -0,0 +1,133 @@
+### ICSS-React项目
+
+#### 注意:
+
+    - 每个模块开发完成后,需要测试ie8下是否正常运行
+    测试方法:
+    --- 首先全局安装 `nodemon` --> npm i -g nodemon
+    1. 项目根目录package.json下执行 
+    npm run build  
+    2. 生成dist目录后, 切换至dist/app下执行
+    npm run server
+    启动成功后,直接访问 127.0.0.1:8088
+    
+
+#### 使用方法
+- 开发环境启动
+```
+npm run dev //启动前端构建服务
+npm run dev-server //启动node层服务n
+```
+- 可以直接修改app下的node文件, 自动刷新node,
+    添加对应业务逻辑, 具体文件作用,
+    请参考开发规范
+
+- 生成服务器文件
+```
+npm run build // 执行后直接上传到服务器
+```
+
+- 服务器开启服务
+```
+1.  git pull
+2.  npm i -g yarn  *注意: 只需在第一次部署时全局安装, 后面就可直接跳过*
+2.1 yarn 
+3.  npm run pm2
+```
+
+#### 目录结构
+- app           node层代码
+    + config    配置文件
+    + controllers 处理路由
+    + logs 日志文件
+    + middleware 中间件文件
+    + services 业务逻辑文件
+- bin/www       需执行的shell
+- config        webpack配置文件
+- src           源文件
+- .babelrc      babel配置文件
+- .eslintrc.js  eslint配置文件
+
+#### 基础组件用法
+- 1. Modal 
+~参数~:
+    + onClickConfirm    {fn}        点击确定按钮的回调函数
+    + onClickCancel     {fn}        点击取消按钮的回调函数
+    + onClickClose      {fn}        点击关闭按钮的回调函数
+    + autoResizeHeight  {bool}      自动改变高度 
+    + width             {num}       自定义宽度 
+    + title             {str}       标题
+    + overflow          {bool}      正文是否溢出滚动
+    + noFooter          {bool}      是否显示底部footer
+    + children          {Component} 子组件
+
+```
+<!--  示例: -->
+<Modal overflow onClickConfirm={()=>{console.log(1)}}>
+    <div>这里放子组件</div>                    
+ </Modal>
+```
+
+-   2. Divider 
+~参数~:
+    + vertical      显示垂直线
+    + horizontal    显示水平线
+
+```
+<!--  示例: -->
+<其他组件/>
+<Divider vertical/>
+<其他组件/>
+```
+
+- 3. Panel组件 面板
+~参数:~
+    + IconLeft      {Component}     左侧的自定义icon
+    + title         {str}           标题
+    + show          {bool}          是否显示content 默认 false
+    + children      {Component}     自定义需要显示的子组件
+```
+<!--  示例: -->
+<Panel IconLeft={<Test/>} title="this is a title">
+    <div>11121</div> // children
+</Panel>
+```
+- 4. Tab组件 切换
+~参数:~
+    + tabPosition {string}              tab组件形式 默认值为horizontal 可选 vertical 即垂直或者水平显示
+    + onTabClick  {function}            点击tab的回调函数
+    + children    {Component|element}   子级元素,可以放入<Icon/>
+    + active      {boolean}             是否显示active样式,主要是文字
+
+    + TabPane组件
+        参数
+        - tab       {string}            tab标题
+        - children  {Component|element} 子级元素
+
+```
+    // 示例
+    <Tabs active tabPosition="vertical" onTabClick={(index)=>{
+         console.log(index);
+     }}>
+        <TabPane key="1" tab="tab1">111</TabPane>
+        <TabPane key="2" tab="tab2">121</TabPane>
+        <TabPane key="3" tab="tab3">131</TabPane>
+        <TabPane key="4" tab="tab4">141</TabPane>
+     </Tabs>
+```
+
+#### 其他
+- app/views/errorPage.html  // 当路由匹配错误会跳转到错误页面, 不会直接4xx/5xx, 将具体错误抛给用户
+
+- 引入classnames模块辅助编写css类名
+
+- ./src/common/less/variables.less 为定义的基础变量样式
+
+- 添加jquery
+ 使用方式: ``` import $ from "jquery"; ```
+
+
+
+
+
+

+ 38 - 0
build/build.js

@@ -0,0 +1,38 @@
+'use strict';
+process.env.NODE_ENV = 'production';
+
+const ora = require('ora');
+const rm = require('rimraf');
+const path = require('path');
+const chalk = require('chalk');
+const webpack = require('webpack');
+const config = require('../config');
+const webpackConfig = require('./webpack.prod.conf');
+const spinner = ora('building for production...');
+spinner.start();
+
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
+    if (err) throw err;
+    webpack(webpackConfig, function (err, stats) {
+        spinner.stop();
+        if (err) throw err;
+        process.stdout.write(stats.toString({
+            colors: true,
+            modules: false,
+            children: false,
+            chunks: false,
+            chunkModules: false
+        }) + '\n\n');
+
+        if (stats.hasErrors()) {
+            console.log(chalk.red('  Build failed with errors.\n'));
+            process.exit(1)
+        }
+
+        console.log(chalk.cyan('  Build complete.\n'));
+        console.log(chalk.yellow(
+            '  Tip: built files are meant to be served over an HTTP server.\n' +
+            '  Opening index.less.html over file:// won\'t work.\n'
+        ));
+    });
+});

+ 9 - 0
build/dev-client.js

@@ -0,0 +1,9 @@
+'use strict';
+require('eventsource-polyfill');
+var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true');
+
+hotClient.subscribe(function (event) {
+  if (event.action === 'reload') {
+    window.location.reload();
+  }
+});

+ 76 - 0
build/dev-server.js

@@ -0,0 +1,76 @@
+'use strict';
+const config = require('../config');
+if (!process.env.NODE_ENV) {
+    process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV);
+}
+const opn = require('opn');
+const path = require('path');
+const express = require('express');
+const webpack = require('webpack');
+const webpackConfig = require('./webpack.dev.conf');
+
+const port = process.env.PORT || config.dev.port;
+const autoOpenBrowser = config.dev.autoOpenBrowser;
+
+const app = express();
+const proxyMiddleWare=require('http-proxy-middleware');
+const proxy_path='http://192.168.2.164:3000';
+const proxy_option ={target:proxy_path,changeOrigin:true};
+const compiler = webpack(webpackConfig);
+
+const devMiddleware = require('webpack-dev-middleware')(compiler, {
+    publicPath: webpackConfig.output.publicPath,
+    quiet: true
+});
+
+const hotMiddleware = require('webpack-hot-middleware')(compiler, {
+    log: false,
+    heartbeat: 2000
+});
+
+app.use(hotMiddleware);
+app.use(require('connect-history-api-fallback')());
+app.use(devMiddleware);
+
+const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory);
+
+app.use(staticPath, express.static('./'));
+
+app.use('/',proxyMiddleWare(proxy_option));
+
+var _resolve;
+var _reject;
+var readyPromise = new Promise((resolve, reject) => {
+    _resolve = resolve;
+    _reject = reject;
+});
+
+var server;
+var portfinder = require('portfinder');
+portfinder.basePort = port;
+
+console.log('> Starting dev server...');
+devMiddleware.waitUntilValid(() => {
+    portfinder.getPort((err, port) => {
+        if (err) {
+            _reject(err)
+        }
+        process.env.PORT = port;
+        // var uri = 'http://localhost:' + port;
+        const uri=`http://localhost:${port}?patientNo=1600&doctorNo=YS001&deptId=D01&recordId=44&hospitalId=A001`;
+        console.log('> Listening at ' + uri + '\n');
+        // when env is testing, don't need open it
+        if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
+            opn(uri)
+        }
+        server = app.listen(port);
+        _resolve();
+    })
+});
+
+module.exports = {
+    ready: readyPromise,
+    close: () => {
+        server.close()
+    }
+};

+ 49 - 0
build/utils.js

@@ -0,0 +1,49 @@
+'use strict';
+const path = require('path');
+const config = require('../config');
+
+exports.assetsPath = function (_path) {
+  const assetsSubDirectory = process.env.NODE_ENV === 'production'
+    ? config.build.assetsSubDirectory
+    : config.dev.assetsSubDirectory;
+  return path.posix.join(assetsSubDirectory, _path)
+};
+
+exports.generateLoaders=function(loader) {
+    var _loader = null;
+    if (loader && loader !== 'css') {
+        _loader = loader + '-loader';
+    }
+
+    if(loader==='styl'){
+      _loader='stylus';
+    }
+
+    var use = [
+        'style-loader', {
+            loader: 'css-loader?minimize',
+            options: {
+                importLoaders: 1
+            }
+        }, {
+            loader: 'postcss-loader',
+            options: {
+                ident: 'postcss',
+                plugins: (loader) => [
+                    require('autoprefixer')({
+                        broswers: ['last 5 versions']
+                    })
+                ]
+            }
+        }
+    ];
+
+    if(_loader){
+        use.push(_loader);
+    }
+
+    return {
+        test: new RegExp('\\.' + loader + '$'),
+        use:use
+    }
+};

+ 74 - 0
build/webpack.base.conf.js

@@ -0,0 +1,74 @@
+'use strict';
+const path = require('path');
+const resolve = function (src) {
+    return path.resolve(__dirname, src);
+};
+const config = require('../config');
+const utils = require('./utils');
+const env = process.env.NODE_ENV;
+
+
+const urlPath = env === 'production' ? utils.assetsPath('img/[name].[hash:7].[ext]') : "img/[name].[hash:7].[ext]";
+const fontPath = env === 'production' ? utils.assetsPath('font/[name].[hash:7].[ext]') : "font/[name].[hash:7].[ext]";
+
+module.exports = {
+    entry: {
+        main:['./src/main.js']
+    },// 配置需要打包的入口文件
+    output: {
+        path: config.build.assetsRoot,// 输出文件根目录
+        filename: '[name].js',//输出文件路径和名字
+        publicPath: env === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
+    },
+    resolve: {
+        extensions: [".js",'.jsx',".json"],
+        alias: {
+            '@': resolve('../src'),
+            '@src': resolve('../src'),
+            '@common': resolve('../src/common'),
+            '@commonComp': resolve('../src/common/components'),
+            '@less': resolve('../src/common/less'),
+            '@mixin': resolve('../src/common/less/mixin.less'),
+            '@images': resolve('../src/common/images'),
+            '@components': resolve('../src/components'),
+            '@containers': resolve('../src/containers'),
+            '@modules': resolve('../src/module'),
+            '@mock': resolve('../src/mock/'),
+            '@utils': resolve('../src/utils'),
+            '@lib': resolve('../src/lib'),
+            '@store':  resolve('../src/store'),
+            '@asyncActions':  resolve('../src/store/async-actions'),
+            '@actions':  resolve('../src/store/actions'),
+            '@reducers':  resolve('../src/store/reducers'),
+            '@types':  resolve('../src/store/types'),
+            '@config':resolve('../src/config')
+        }
+    },
+    module: {
+        rules: [
+            {
+                test: /\.(js|jsx)$/,
+                loader: 'babel-loader',
+                exclude: /node_modules/
+            },
+            {
+                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+                loader: 'url-loader',
+                options: {
+                    limit: 8196,
+                    publicPath: '../../',
+                    name:urlPath,
+                }
+            },
+            {
+                test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+                loader: 'url-loader',
+                options: {
+                    limit: 8196,
+                    publicPath: '../../',
+                    name:fontPath,
+                }
+            }
+        ]
+    }
+};

+ 80 - 0
build/webpack.dev.conf.js

@@ -0,0 +1,80 @@
+'use strict';
+const config = require('../config');
+const webpack = require('webpack');
+const merge = require('webpack-merge');
+const baseWebpackConfig = require('./webpack.base.conf');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
+const cssSourceMap = config.dev.cssSourceMap;
+
+baseWebpackConfig.entry.main=[
+    'react-hot-loader/patch',
+    'webpack-hot-middleware/client?noInfo=true&reload=true',
+    './src/main.js'
+];
+
+module.exports = merge(baseWebpackConfig, {
+    devtool: '#cheap-module-eval-source-map',
+    resolve: {
+        alias: {
+          'react': 'anujs/dist/ReactIE',
+          'react-server': 'anujs/dist/ReactDOMServer',
+          'react-dom': 'anujs/dist/ReactIE',
+          'prop-types': 'anujs/lib/ReactPropTypes'
+        }
+    },
+    module: {
+        rules: [
+            {
+                test: /\.css$/,
+                use: [
+                    'style-loader',
+                    {
+                        loader: 'css-loader',
+                        options: {
+                            minimize: false,
+                            sourceMap: cssSourceMap,
+                            localIdentName: '[path][hash:base64:5]',
+                            module: true
+                        }
+                    }
+                ]
+            },
+            {
+                test: /\.less/,
+                use: [
+                    'style-loader',
+                    {
+                        loader: 'css-loader',
+                        options: {
+                            minimize: false,
+                            sourceMap: cssSourceMap,
+                            importLoaders: 1,
+                            localIdentName: '[path][hash:base64:5]',
+                            module: true
+                        }
+                    },
+                    {
+                        loader: 'less-loader',
+                        options: {
+                            sourceMap: cssSourceMap
+                        }
+                    }]
+
+            }
+        ]
+    },
+    plugins: [
+        new webpack.DefinePlugin({
+            'process.env': config.dev.env
+        }),
+        new webpack.HotModuleReplacementPlugin(),
+        new webpack.NoEmitOnErrorsPlugin(),
+        new HtmlWebpackPlugin({
+            filename: 'index.html',
+            template: 'index.html',
+            inject: 'body'
+        }),
+        new FriendlyErrorsPlugin()
+    ]
+});

+ 164 - 0
build/webpack.prod.conf.js

@@ -0,0 +1,164 @@
+'use strict';
+const path = require('path');
+const utils = require('./utils');
+const webpack = require('webpack');
+const config = require('../config');
+const merge = require('webpack-merge');
+const baseWebpackConfig = require('./webpack.base.conf');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const ExtractTextPlugin = require('extract-text-webpack-plugin');
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
+const es3ifyPlugin=require('es3ify-webpack-plugin');
+const env = config.build.env;
+const cssSourceMap=config.build.cssSourceMap;
+
+
+const webpackConfig = merge(baseWebpackConfig, {
+    devtool: config.build.productionSourceMap ? '#source-map' : false,
+    output: {
+        path: config.build.assetsRoot,
+        publicPath: "./",
+        filename: utils.assetsPath('js/[name].[chunkhash].js'),
+        chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+    },
+    resolve: {
+        alias: {
+          'react': 'anujs/dist/ReactIE',
+          'react-dom': 'anujs/dist/ReactIE',
+          'prop-types': 'anujs/lib/ReactPropTypes'
+        }
+    },
+    module: {
+        rules: [
+            {
+                test: /\.(js|jsx)$/,
+                loader: 'babel-loader',
+                exclude: /node_modules/
+            },
+            {
+                test: /\.css$/,
+                use: ExtractTextPlugin.extract({
+                    fallback: 'style-loader?sourceMap',
+                    use: [{
+                        loader: 'css-loader',
+                        options: {
+                            minimize: false,
+                            sourceMap: cssSourceMap,
+                            localIdentName: '[path][hash:base64:5]',
+                            module:true
+                        }
+                    }]
+                })
+
+            },
+            {
+                test: /\.less/,
+                use: ExtractTextPlugin.extract({
+                    fallback: 'style-loader?sourceMap',
+                    use: [{
+                        loader: 'css-loader',
+                        options: {
+                            minimize: false,
+                            sourceMap: cssSourceMap,
+                            importLoaders: 1,
+                            localIdentName: '[path][hash:base64:5]',
+                            module:true
+                        }
+                    },
+                        {
+                            loader: 'less-loader',
+                            options: {
+                                sourceMap: cssSourceMap
+                            }
+                        }
+                    ]
+                })
+
+            }
+        ]
+    },
+    plugins: [
+        new webpack.DefinePlugin({
+            'process.env': env
+        }),
+        new UglifyJsPlugin({
+            sourceMap: true,
+            uglifyOptions:{
+                ie8:true,
+                ecma:5,
+                warnings: false,
+                mangle:{
+                    reserved:['export','default','$','exports','import','module']
+                },
+                compress:{
+                    // booleans:false,
+                    // comparisons:false,
+                    // computed_props:false,
+                    // conditionals:false,
+                    // evaluate:false,
+                    // hoist_props:false,
+                    // if_return:false,
+                    // inline:false,
+                    // join_vars:false,
+                    // loops:false,
+                    // negate_iife:false,
+                    // properties:false,
+                    // pure_getters:true,
+                    reduce_funcs:false,//确定影响IE8的报错的配置
+                    // reduce_vars:false,
+                    // sequences:false,
+                },
+                output:{
+                    comments:false
+                }
+            }
+        }),
+        new HtmlWebpackPlugin({
+            filename: config.build.index,
+            template: 'index.html',
+            inject: 'body',
+            minify: {
+                removeComments: true,
+                collapseWhitespace: true,
+                removeAttributeQuotes: true
+            },
+            chunksSortMode: 'dependency',
+        }),
+        new ExtractTextPlugin({
+            filename: utils.assetsPath('css/[name].[contenthash].css')
+        }),
+        new OptimizeCSSPlugin({
+            cssProcessorOptions: {
+                safe: true
+            }
+        }),
+        // new es3ifyPlugin(),
+        new webpack.HashedModuleIdsPlugin(),
+        new webpack.optimize.CommonsChunkPlugin({
+            name: 'vendor',
+            minChunks: function (module) {
+                return (
+                    module.resource &&
+                    /\.js$/.test(module.resource) &&
+                    module.resource.indexOf(
+                        path.join(__dirname, '../node_modules')
+                    ) === 0
+                )
+            }
+        }),
+        new webpack.optimize.CommonsChunkPlugin({
+            name: 'manifest',
+            chunks: ['vendor']
+        }),
+        new CopyWebpackPlugin([
+            {
+                from: path.join(__dirname, "../static/"),
+                to:path.join( __dirname , "../app/public/static")
+            }
+          ])
+    ]
+});
+
+module.exports = webpackConfig;

+ 7 - 0
config/dev.env.js

@@ -0,0 +1,7 @@
+'use strict';
+const merge=require('webpack-merge');
+const prodEnv=require('./prod.env');
+
+module.exports=merge(prodEnv,{
+    NODE_ENV: '"development"'
+});

+ 26 - 0
config/index.js

@@ -0,0 +1,26 @@
+'use strict';
+const path=require('path');
+const resolve=function (src) {
+  return  path.resolve(__dirname,src);
+};
+
+module.exports={
+    build:{
+        env:require('./prod.env'),
+        index:resolve('../app/public/index.html'),
+        assetsRoot: resolve('../app/public/'),
+        assetsPublicPath:'/',
+        assetsSubDirectory:'static',
+        cssSourceMap: false,
+        productionSourceMap: false
+    },
+    dev:{
+        env: require('./dev.env'),
+        port: process.env.PORT || 8080,
+        assetsPublicPath: '/',
+        assetsSubDirectory:'/',
+        autoOpenBrowser: true,
+        cssSourceMap: false,
+        proxyTable: {}
+    }
+};

+ 4 - 0
config/prod.env.js

@@ -0,0 +1,4 @@
+'use strict';
+module.exports = {
+    NODE_ENV: '"production"'
+};

+ 13 - 0
index.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <!--[if lt IE 9]>
+    <script src="/static/polyfill/html5shiv.min.js"></script>
+    <![endif]-->
+    <title>ICSS</title>
+</head>
+<body>
+<div id="root"></div>
+</body>
+</html>

+ 75 - 0
package.json

@@ -0,0 +1,75 @@
+{
+  "name": "icss",
+  "version": "1.0.0",
+  "description": "icss项目react重构",
+  "main": "index.js",
+  "scripts": {
+    "dev": "node build/dev-server.js",
+    "build": "node build/build.js",
+    "dev-server": "set NODE_ENV=dev&&nodemon  bin/www",
+    "pm2": "cross-env NODE_ENV=pro && pm2 start bin/www",
+    "server": "node server.js"
+  },
+  "author": "LevanDu",
+  "license": "ISC",
+  "browserslist": [
+    "ie 8",
+    "> 1%"
+  ],
+  "devDependencies": {
+    "babel-core": "^6.26.0",
+    "babel-loader": "^7.1.4",
+    "babel-preset-env": "^1.6.1",
+    "babel-preset-react": "^6.24.1",
+    "browserslist": "^3.1.2",
+    "classnames": "~2.0.0",
+    "copy-webpack-plugin": "^4.5.1",
+    "cross-env": "^5.1.4",
+    "css-loader": "^0.28.10",
+    "es3ify-webpack-plugin": "0.0.1",
+    "eventsource-polyfill": "^0.9.6",
+    "express": "^4.16.2",
+    "extract-text-webpack-plugin": "^3.0.2",
+    "file-loader": "^1.1.11",
+    "friendly-errors-webpack-plugin": "^1.6.1",
+    "html-webpack-plugin": "^3.0.6",
+    "http-proxy-middleware": "^0.18.0",
+    "jquery-form": "^4.2.2",
+    "koa": "^2.5.0",
+    "koa-better-http-proxy": "^0.2.4",
+    "koa-static": "^4.0.2",
+    "koa2-simple-proxy": "^1.0.0",
+    "less": "^2.3.1",
+    "less-loader": "^2.2.3",
+    "mockjs": "^1.0.1-beta3",
+    "optimize-css-assets-webpack-plugin": "^3.0.0",
+    "ora": "^2.0.0",
+    "precss": "^2.0.0",
+    "prop-types": "15.6.1",
+    "react": "^16.2.0",
+    "react-dom": "^16.2.0",
+    "react-hot-loader": "^4.3.3",
+    "style-loader": "^0.18.2",
+    "uglifyjs-webpack-plugin": "^1.2.5",
+    "url-loader": "^1.0.1",
+    "webpack": "3.9.1",
+    "webpack-dev-middleware": "1.12.2",
+    "webpack-dev-server": "2.9.5",
+    "webpack-hot-middleware": "2.21.0",
+    "webpack-merge": "4.1.1"
+  },
+  "dependencies": {
+    "anujs": "1.4.8",
+    "axios": "^0.18.0",
+    "babel-polyfill": "6.26.0",
+    "jquery": "1.12.4",
+    "koa-body": "^4.0.4",
+    "koa-router": "^7.4.0",
+    "koa2-cors": "^2.0.6",
+    "log4js": "^3.0.4",
+    "react-redux": "4.4.9",
+    "react-server": "^0.8.1",
+    "redux": "3.5.2",
+    "redux-thunk": "2.2.0"
+  }
+}

+ 7 - 0
postcss.config.js

@@ -0,0 +1,7 @@
+'use strict';
+module.exports = {
+    plugins: [
+        require('precss'),
+        require('autoprefixer')
+    ]
+};

+ 13 - 0
server.js

@@ -0,0 +1,13 @@
+const app = new (require('koa'));
+const proxy = require('koa-better-http-proxy');
+app.use(require('koa-static')(`${__dirname}/app/public`));
+app.use(proxy('192.168.2.164',{
+    port:3000
+}));
+
+app.listen(process.env.PORT || 3003, function (err) {
+    if (err) {
+        console.info('服务启动失败');
+    }
+    console.info(`服务启动监听端口${process.env.PORT || 3003}`);
+});

+ 18 - 0
src/common/components/Banner/index.jsx

@@ -0,0 +1,18 @@
+import React, { Component } from "react";
+import style from "./index.less";
+import logo from '../../images/logoa.png'
+import setup from '../../images/setup.png';
+class Banner extends Component {
+  render(){
+    const {src,text, children} = this.props;
+
+    return <div className={style['banner-wrapper']+" "+"clearfix"}>
+         <div className={style['logo']}> <img src={logo}/><span >|&nbsp;&nbsp;智能辅助临床决策系统</span>
+            <div className={style['buon']}><img className={style['st']} src={setup}/>设置</div>
+            </div>
+      {children?<div className='fl'>{children}</div>:''}
+    </div>;
+  }
+}
+
+export default Banner;

+ 30 - 0
src/common/components/Banner/index.less

@@ -0,0 +1,30 @@
+@import "~@less/variables.less";
+
+.logo{
+    background-image: linear-gradient(-90deg, #93CEE3 7%,#3B9ED0 98%);
+    height: 70px;
+    img{
+        vertical-align: middle;
+        margin: 20px 15px 4px 18px;
+    }
+    span{
+        display: inline-block;
+        vertical-align: middle;
+        margin-top: 20px;
+        color: #FFFFFF;
+        font-size: 14px;
+    }
+    .buon{
+        float: right;
+        display: inline-block;
+        margin: 20px 15px 4px 10px;
+        color: #FFFFFF;
+        font-size: 16px;
+    
+    }
+    .st{
+        margin: 10px 10px 10px 10px;
+        border: 0 solid #FFFFFF;
+       text-align: center;
+    }
+}

+ 61 - 0
src/common/components/Button/index.jsx

@@ -0,0 +1,61 @@
+/**
+ * Created by ZN on 2018/5/03.
+ */
+import React, {Component} from 'react';
+/*import PropTypes from 'prop-types';*/
+import style from './index.less';
+
+/**
+ * Button组件
+ *可配置属性:
+ * type: 默认(即不配置type,蓝色实心70*30),normal(蓝边空心70*30),warning(橙色100%40),model(蓝色实心80*30)
+ * disabled:
+ * onClick:
+ * 示例:<Button disabled><Icon type='confirm' />确定</Button>
+ * **/
+/*const propTypes = {
+    icon: PropTypes.oneOf(['confirm','close','add','aptmts','cancel','print','qa','search','setting','update','tick','submit','more','info']),
+    onClick: PropTypes.func
+};*/
+
+class Button extends Component {
+    constructor(props) {
+        super(props);
+        /* this.handleClick = this.handleClick.bind(this);
+         this.handleLeave = this.handleLeave.bind(this);*/
+    }
+
+    /*handleClick(){
+        this.props.onClick&&this.props.onClick();
+    }*/
+
+    render() {
+        let props = this.props;
+        let type = props.type ? style[props.type] : '';
+        let classes = style["button"] + " " + type;
+        const spanStyle = {
+            position: "relative",
+            left: "-3px",
+            lineHeight: "30px"
+        };
+        if (props.disabled) {
+            return <button contenteditable="false" className={classes} style={props.style}  {...props} disabled>
+                {
+                    React.Children.map(props.children, function (child) {
+                        return <span style={spanStyle}>{child}</span>;
+                    })
+                }
+            </button>;
+        }
+        return <button contenteditable="false" className={classes} style={props.style} {...props}>
+            {
+                React.Children.map(props.children, function (child) {
+                    return <span style={spanStyle}>{child}</span>;
+                })
+            }
+        </button>;
+    }
+}
+/*Button.propTypes = propTypes;*/
+
+export default Button;

+ 40 - 0
src/common/components/Button/index.less

@@ -0,0 +1,40 @@
+@import "~@less/variables.less";
+
+.button{
+  width: 70px;
+  height: 30px;
+  outline: none;
+  border-radius: 2px;
+  cursor: pointer;
+  color: @btn-text-color;
+  border: none;
+  cursor: pointer;
+  background: @blue;
+
+}
+.text {
+    position: relative;
+    left: -4px;
+    top: -2px;
+}
+.button[disabled]{
+  opacity: .5;
+  filter:alpha(opacity=50);
+  cursor: not-allowed;
+}
+.normal{
+  background: @blue;
+  border: 1px @blue solid;
+  color: @blue;
+}
+.warning{
+  min-width: 100px;
+  height: 40px;
+  background: @orange;
+}
+.model{
+  min-width: 80px;
+  height: 30px;
+  font-size: @font-size-base;
+  background: @blue;
+}

+ 75 - 0
src/common/components/Calendar/Content/index.jsx

@@ -0,0 +1,75 @@
+import React from 'react'
+import styles from './index.less'
+import PropTypes from 'prop-types'
+import Item from '../ContentItem'
+
+class Content extends React.Component {
+    constructor() {
+        super();
+        this.state= {
+            now: new Date().getTime()
+        }
+    }
+
+    genItems(){
+        let is_now_month=this.props.selectTime.year===this.props.year && this.props.selectTime.month===this.props.month;
+        const Items=[];
+        const first_day=new Date(this.props.year,this.props.month-1,1).getDay();
+        let key=0;
+        if(first_day!==7){
+            let pre_day=new Date(this.props.year,this.props.month-1,0).getDate()-first_day+1;
+            for(let i=0;i<first_day;i++){
+                Items.push(<Item value={pre_day++} key={key++} clazzKey={'gray'} handleClick={this.props.handleClick}/>);
+            }
+        }
+        const last_date=new Date(this.props.year,this.props.month,0);
+        const day = last_date.getDate();
+        for(let i=1,len=day;i<=len;i++){
+            const currentTime = new Date(this.props.year,this.props.month-1,i);
+            const exceed = +currentTime > this.state.now&&!this.props.canSelectFuture;
+            let itemClassName = "";
+            if(exceed) {
+                itemClassName = "gray";
+            }else{
+                itemClassName = (is_now_month && i===this.props.selectTime.day)?'select':'';
+            }
+            Items.push(<Item value={i} key={key++} handleClick={this.props.handleClick} clazzKey={itemClassName}/>);
+        }
+        if(last_date.getDay()!==6){
+            let next_month_first_day=new Date(this.props.year,this.props.month,1).getDay();
+            for(let i=1,len=7-next_month_first_day;i<=len;i++){
+                Items.push(<Item value={i} key={key++} clazzKey={'gray'} handleClick={this.props.handleClick}/>);
+            }
+        }
+        return Items;
+    }
+
+    render() {
+        return (
+            <div className={styles.wrapper}>
+                <ol className={styles.week}>
+                    <li>日</li>
+                    <li>一</li>
+                    <li>二</li>
+                    <li>三</li>
+                    <li>四</li>
+                    <li>五</li>
+                    <li>六</li>
+                </ol>
+                <ol className={styles.day}>
+                    {this.genItems()}
+                </ol>
+            </div>
+        )
+    }
+}
+
+export default Content;
+
+Content.propTypes={
+    year:PropTypes.number,
+    month:PropTypes.number,
+    selectTime:PropTypes.object,
+    handleClick:PropTypes.func,
+    canSelectFuture:PropTypes.bool
+};

+ 33 - 0
src/common/components/Calendar/Content/index.less

@@ -0,0 +1,33 @@
+@import "~@less/mixin.less";
+
+.wrapper {
+  width: 282px;
+  margin-top: 10px;
+  border-top: 1px solid #b1d2ec;
+  border-left: 1px solid #b1d2ec;
+  user-select: none;
+  line-height: 20px;
+  .week {
+    border-right: 1px solid #b1d2ec;
+    border-bottom: 1px solid #b1d2ec;
+    background-color: #deecf8;
+  }
+  .day {
+    li {
+      border-right: 1px solid #b1d2ec;
+      border-bottom: 1px solid #b1d2ec;
+      cursor: pointer;
+      &:hover {
+        background-color: #ECF4FB;
+      }
+    }
+  }
+  li {
+    position: relative;
+    display: inline-block;
+    text-align: center;
+    width: 40px;
+    height: 20px;
+    vertical-align: top;
+  }
+}

+ 29 - 0
src/common/components/Calendar/ContentItem/index.jsx

@@ -0,0 +1,29 @@
+import React from 'react'
+import styles from './index.less'
+import PropTypes from 'prop-types'
+
+class Item extends React.Component {
+    handleClick(){
+        if(this.props.clazzKey==='gray'){
+            return;
+        }
+        const info={
+            day:this.props.value
+        };
+        this.props.handleClick(info);
+    }
+
+    render() {
+        return (
+            <li className={styles[this.props.clazzKey]} onClick={()=>this.handleClick()}>{this.props.value}</li>
+        )
+    }
+}
+
+export default Item;
+
+Item.propTypes={
+    value:PropTypes.number,
+    clazzKey:PropTypes.string,
+    handleClick:PropTypes.func
+};

+ 14 - 0
src/common/components/Calendar/ContentItem/index.less

@@ -0,0 +1,14 @@
+@import "~@less/mixin.less";
+
+&.gray{
+  color: @gray !important;
+  cursor: not-allowed !important;
+  &:hover{
+    color: @gray !important;
+    background-color: #fff !important;
+  }
+}
+
+&.select{
+  background-color: #deecf8;
+}

+ 30 - 0
src/common/components/Calendar/MonthItem/index.jsx

@@ -0,0 +1,30 @@
+import React from 'react'
+import style from './index.less'
+import PropTypes from 'prop-types'
+
+class Item extends React.Component{
+    getClazz(){
+        if(this.props.value===this.props.select){
+            return `${style.item} ${style.active}`
+        }
+        return style.item;
+    }
+
+    handleClick(){
+        this.props.handleClick(this.props.value);
+    }
+
+    render(){
+        return (
+            <span className={this.getClazz()} onClick={()=>this.handleClick()}>{`${this.props.value}月`}</span>
+        )
+    }
+}
+
+Item.propTypes={
+    value:PropTypes.number,
+    handleClick:PropTypes.func,
+    select:PropTypes.number
+};
+
+export default Item;

+ 19 - 0
src/common/components/Calendar/MonthItem/index.less

@@ -0,0 +1,19 @@
+@import "~@less/mixin.less";
+
+.item{
+  display: inline-block;
+  width: 42px;
+  height: 24px;
+  margin: 5px 0 0 5px;
+  text-align: center;
+  font-size: @font-size-h5;
+  line-height: 24px;
+  cursor: pointer;
+  vertical-align: middle;
+  &.gray{
+    color:@gray;
+  }
+  &.active{
+    background-color:#deecf8;
+  }
+}

+ 217 - 0
src/common/components/Calendar/SelectList/index.jsx

@@ -0,0 +1,217 @@
+import React from 'react'
+import style from './index.less'
+import PropTypes from 'prop-types'
+import YearItem from '../YearItem'
+import MonthItem from '../MonthItem'
+import $ from 'jquery'
+
+class YearList extends React.Component {
+    constructor(props) {
+        super(props);
+        this.max=props.canSelectFuture?Infinity:new Date().getFullYear();
+        this.state={
+            start:props.select-7,
+            listIsShow:false
+        }
+    }
+
+
+    genItems(){
+        const Items=[];
+        for(let i=this.state.start,li=this.state.start+14;i<li;i++){
+            Items.push(<YearItem key={i} value={i} select={this.props.select} handleClick={this.props.handleChange} max={this.max}/>)
+        }
+        return Items;
+    }
+
+    handleYearUp(){
+        this.setState((preState)=>({start:preState.start-14}));
+    }
+    handleYearDown(){
+        if(this.state.start+14>=this.max){
+            return;
+        }
+        this.setState((preState)=>({start:preState.start+14}));
+    }
+
+    handleYearLeft(){
+        const year=this.props.select-1;
+        this.props.handleChange(year);
+        if(year<this.state.start){
+            this.setState((preState)=>({start:preState.start-14}));
+        }
+    }
+
+    handleYearRight(){
+        const year=this.props.select+1;
+        if(year>this.max){
+            return;
+        }
+        this.props.handleChange(year);
+        if(year-this.state.start>=14){
+            this.setState((preState)=>({start:preState.start+14}));
+        }
+    }
+
+    handleShowList(){
+        this.setState({
+            start:this.props.select-7,
+        });
+        $(this.list).slideDown(()=>{
+            this.setState({
+                listIsShow:true
+            })
+        })
+    }
+
+    handleHideList(){
+        $(this.list).slideUp(()=>{
+            this.setState({
+                listIsShow:false
+            })
+        })
+    }
+
+    genListStyle(){
+        return {
+            display:this.state.listIsShow?'block':'none'
+        }
+    }
+
+    render() {
+        return (
+            <div className={style.wrapper} onMouseLeave={()=>this.handleHideList()}>
+                <div className={`${style.toggle} ${style.left}`} onClick={()=>this.handleYearLeft()}>
+                    <div className={style.arrow}/>
+                </div>
+                <div className={style.text} onClick={()=>this.handleShowList()}>
+                    <span>{`${this.props.select}年`}</span>
+                    <div className={style.arrow}/>
+                </div>
+                <div className={`${style.toggle} ${style.right}`} onClick={()=>this.handleYearRight()}>
+                    <div className={style.arrow}/>
+                </div>
+                <div className={style.list} ref={(list)=>this.list=list} style={this.genListStyle()}>
+                    <div className={`${style.toggle} ${style.up}`} onClick={()=>this.handleYearUp()}>
+                        <div className={style.arrow}/>
+                    </div>
+                    <div className={style.items}>
+                        {this.genItems()}
+                    </div>
+                    <div className={`${style.toggle} ${style.down}`} onClick={()=>{this.handleYearDown()}}>
+                        <div className={style.arrow}/>
+                    </div>
+                </div>
+            </div>
+        )
+    }
+
+    componentWillReceiveProps(nextProps){
+        if(nextProps.canSelectFuture!==this.props.canSelectFuture){
+            this.max=nextProps.canSelectFuture?Infinity:new Date().getFullYear();
+        }
+    }
+}
+
+
+YearList.propTypes={
+    select:PropTypes.number,
+    handleChange:PropTypes.func,
+    canSelectFuture:PropTypes.bool
+};
+
+
+class MonthList extends React.Component {
+    constructor() {
+        super();
+        const date=new Date();
+        this.year=date.getFullYear();
+        this.month=date.getMonth()+1;
+        this.state={
+            listIsShow:false
+        }
+    }
+
+    genItems(){
+        const Items=[];
+        const len=this.props.canSelectFuture?12:this.props.year===this.year?this.month:12;
+        for(let i=1;i<=len;i++){
+            Items.push(<MonthItem key={i} value={i} select={this.props.select} handleClick={this.props.handleChange}/>)
+        }
+        return Items;
+    }
+
+    handleMonthLeft(){
+        let month=this.props.select-1;
+        if(month<1){
+            month=1;
+        }
+        this.props.handleChange(month);
+    }
+
+    handleMonthRight(){
+        let month=this.props.select+1;
+        if(month>12 || (!this.props.canSelectFuture && (this.props.year===this.year && month>this.month))){
+            return;
+        }
+        this.props.handleChange(month);
+    }
+
+    handleShowList(){
+        $(this.list).slideDown(()=>{
+            this.setState({
+                listIsShow:true
+            })
+        })
+    }
+
+    handleHideList(){
+        $(this.list).slideUp(()=>{
+            this.setState({
+                listIsShow:false
+            })
+        })
+    }
+
+    genListStyle(){
+        return {
+            display:this.state.listIsShow?'block':'none'
+        }
+    }
+
+    render() {
+        return (
+            <div className={`${style.wrapper} ${style.month}`} onMouseLeave={()=>this.handleHideList()}>
+                <div className={`${style.toggle} ${style.left}`} onClick={()=>this.handleMonthLeft()}>
+                    <div className={style.arrow}/>
+                </div>
+                <div className={style.text} onClick={()=>this.handleShowList()}>
+                    <span>{`${this.props.select}月`}</span>
+                    <div className={style.arrow}/>
+                </div>
+                <div className={`${style.toggle} ${style.right}`} onClick={()=>this.handleMonthRight()}>
+                    <div className={style.arrow}/>
+                </div>
+                <div className={style.list} ref={(list)=>this.list=list} style={this.genListStyle()}>
+                    <div className={style.items}>
+                        {this.genItems()}
+                    </div>
+                </div>
+            </div>
+        )
+    }
+}
+
+
+MonthList.propTypes={
+    select:PropTypes.number,
+    handleChange:PropTypes.func,
+    year:PropTypes.number,
+    canSelectFuture:PropTypes.bool
+};
+
+
+export {
+    YearList,
+    MonthList
+};

+ 116 - 0
src/common/components/Calendar/SelectList/index.less

@@ -0,0 +1,116 @@
+@import "~@less/mixin.less";
+
+.wrapper{
+  border: 1px solid #B1D2EC;
+  position: relative;
+  height: 26px;
+  font-size: 0;
+  vertical-align: top;
+  user-select: none;
+  z-index: 1;
+  .toggle{
+    width: 100%;
+    height: 15px;
+    position: relative;
+    cursor: pointer;
+    background-color: #deecf8;
+    &:hover{
+      background-color: #ECF4FB;
+    }
+    .arrow{
+      position: absolute;
+      left: 50%;
+      top: 50%;
+      margin-left: -5px;
+      margin-top: -5px;
+      width: 0;
+      height: 0;
+      border: 5px solid transparent;
+    }
+    &.left{
+      float: left;
+      width: 21px;
+      height: 100%;
+      border-right: 1px solid #b1d2ec;
+      .arrow{
+        border-right: 5px solid #3081C2;
+        margin-left: -8px;
+      }
+
+    }
+    &.right{
+      float: left;
+      width: 21px;
+      height: 100%;
+      border-left: 1px solid #b1d2ec;
+      .arrow{
+        border-left: 5px solid #3081C2;
+        margin-left: 0;
+      }
+
+    }
+    &.up{
+      border-bottom: 1px solid #b1d2ec;
+      .arrow{
+        border-bottom: 5px solid #3081C2;
+        margin-top: -7px;
+      }
+    }
+    &.down{
+      border-top: 1px solid #b1d2ec;
+      .arrow{
+        border-top: 5px solid #3081C2;
+        margin-top: -2px;
+      }
+    }
+  }
+  .text{
+    width: 79px;
+    height: 24px;
+    font-size: @font-size-h4;
+    float: left;
+    background-color: #fff;
+    text-align: left;
+    line-height: 24px;
+    padding: 0 10px;
+    position: relative;
+    cursor: pointer;
+    .arrow{
+      border: 5px solid transparent;
+      border-top:5px solid #3081C2;
+      right: 10px;
+      top: 50%;
+      margin: -2px 0 0 -5px;
+      position: absolute;
+      width: 0;
+      height: 0;
+      overflow: hidden;
+      cursor: pointer;
+    }
+  }
+  .list{
+    width: 122px;
+    border: 1px solid #b1d2ec;
+    position: absolute;
+    left: -1px;
+    top: 24px;
+    box-shadow: 2px 2px 5px rgba(0,0,0,.1);
+    background-color: #fff;
+    .items{
+      font-size: 0;
+    }
+  }
+}
+.wrapper.month{
+  .text{
+    width: 57px;
+    label{
+      right: 8px;
+    }
+  }
+  .list{
+    width: 100px;
+    padding-bottom: 4px;
+  }
+}
+

+ 60 - 0
src/common/components/Calendar/Time/index.jsx

@@ -0,0 +1,60 @@
+import React from 'react'
+import styles from './index.less'
+import PropTypes from 'prop-types'
+
+
+class Time extends React.Component {
+    constructor() {
+        super();
+    }
+
+    handleHourChange(value){
+        if(value!==value){value=0}
+        else if(value>=24) {value=23}
+        else if(value<0) {value=0}
+        this.props.handleChange({
+            hour:value,
+            minute:this.props.minute,
+            second:this.props.second,
+        });
+    }
+
+    handleMinuteChange(value){
+        if(value!==value){value=0}
+        else if(value>=60) {value=59}
+        else if(value<0) {value=0}
+        this.props.handleChange({
+            hour:this.props.hour,
+            minute:value,
+            second:this.props.second,
+        });
+    }
+
+    handleSecondChange(value){
+        if(value!==value){value=0}
+        else if(value>=60) {value=59}
+        else if(value<0) {value=0}
+        this.props.handleChange({
+            hour:this.props.hour,
+            minute:this.props.minute,
+            second:value,
+        });
+    }
+
+    render() {
+        return (
+            <div className={styles.wrapper}>
+                <input value={this.props.hour} onInput={(e)=>this.handleHourChange(window.parseInt(e.target.value))} />&nbsp;{'时'}&nbsp;<input value={this.props.minute} onInput={(e)=>this.handleMinuteChange(window.parseInt(e.target.value))}/>&nbsp;{'分'}&nbsp;<input value={this.props.second} onInput={(e)=>this.handleSecondChange(window.parseInt(e.target.value))}/>&nbsp;{'秒'}
+            </div>
+        )
+    }
+}
+
+export default Time;
+
+Time.propTypes={
+    hour:PropTypes.number,
+    minute:PropTypes.number,
+    second:PropTypes.number,
+    handleChange:PropTypes.func
+};

+ 13 - 0
src/common/components/Calendar/Time/index.less

@@ -0,0 +1,13 @@
+@import "~@less/mixin.less";
+
+.wrapper{
+  margin-top: 5px;
+  text-align: center;
+  input{
+    width: 40px;
+    border: 1px solid @border-color;
+    height: 22px;
+    font-size: @font-size-h5;
+    line-height: 22px;
+  }
+}

+ 38 - 0
src/common/components/Calendar/YearItem/index.jsx

@@ -0,0 +1,38 @@
+import React from 'react'
+import style from './index.less'
+import PropTypes from 'prop-types'
+
+class Item extends React.Component{
+    getClazz(){
+        if(this.props.value>this.props.max){
+            return `${style.item} ${style.gray}`
+        }
+        if(this.props.value===this.props.select){
+            return `${style.item} ${style.active}`
+        }
+        return style.item;
+    }
+
+    handleClick(){
+        if(this.props.value<=this.props.max){
+            this.props.handleClick(this.props.value);
+        }
+    }
+
+    render(){
+        return (
+            <div className={this.getClazz()} onClick={()=>this.handleClick()}>{`${this.props.value}年`}</div>
+        )
+    }
+}
+
+
+Item.propTypes={
+    value:PropTypes.number,
+    handleClick:PropTypes.func,
+    select:PropTypes.number,
+    max:PropTypes.number
+};
+
+
+export default Item;

+ 18 - 0
src/common/components/Calendar/YearItem/index.less

@@ -0,0 +1,18 @@
+@import "~@less/mixin.less";
+
+.item{
+  display: inline-block;
+  width: 60px;
+  height: 15px;
+  text-align: center;
+  font-size: @font-size-h5;
+  line-height: 15px;
+  cursor: pointer;
+  &.gray{
+    color:@gray;
+    cursor: not-allowed;
+  }
+  &.active{
+    background-color:#deecf8;
+  }
+}

+ 123 - 0
src/common/components/Calendar/index.jsx

@@ -0,0 +1,123 @@
+import React from 'react'
+import style from './index.less'
+import PropTypes from 'prop-types'
+import {YearList, MonthList} from './SelectList'
+import Content from './Content'
+import Time from './Time'
+
+
+/**
+ * handleChange: 时间改变时会触发的方法(在点击具体日期和输入改变时分秒时触发)
+ *               该方法会传入一个对象如{year:2018,month:1,day:1,hour:1,minute:1,second:1}
+ * needTime:是否显示下方时间输入控件  不显示则默认的时分秒为0
+ */
+class Calendar extends React.Component {
+    constructor() {
+        super();
+        const date=new Date();
+        this.year=date.getFullYear();
+        this.month=date.getMonth()+1;
+        this.day=date.getDate();
+        this.inputing=false;
+        this.state = {
+            year:  this.year,
+            month:  this.month,
+            select:{
+                year:  this.year,
+                month:  this.month,
+                day: 0,
+                hour:0,
+                minute:0,
+                second:0
+            }
+        }
+    }
+
+    handleYearSelect(year) {
+        if(year===this.year && this.state.month>this.month){
+            this.setState({
+                year: year,
+                month:this.month
+            });
+        }else{
+            this.setState({
+                year: year
+            });
+        }
+    }
+
+    handleMonthSelect(month) {
+        this.setState({
+            month: month
+        });
+    }
+
+    handleChange(info){
+        if(this.inputing){
+            return;
+        }
+        this.inputing=true;
+        info.year=this.state.year;
+        info.month=this.state.month;
+        if(info.hour==null){
+            info.hour=this.state.select.hour;
+            info.minute=this.state.select.minute;
+            info.second=this.state.select.second;
+        }
+        this.props.handleChange(Object.assign({},info));
+        this.setState({
+            select:info
+        });
+    }
+
+    handleTodayClick(){
+        const info={
+            year:this.year,
+            month:this.month,
+            day:this.day,
+            hour:this.state.select.hour,
+            minute:this.state.select.minute,
+            second:this.state.select.second
+        };
+        this.setState({
+            select:info
+        });
+        this.props.handleChange(info);
+    }
+
+    genTimeComponent(){
+        return this.props.needTime?<Time hour={this.state.select.hour} minute={this.state.select.minute} second={this.state.select.second} handleChange={(info)=>{this.handleChange(info)}}/>:null;
+    }
+
+    render() {
+        return (
+            <div className={style.wrapper}>
+                <div className={style.top}>
+                    <div className={style.year}>
+                        <YearList select={this.state.year} canSelectFuture={this.props.canSelectFuture} handleChange={(info) => this.handleYearSelect(info)}/>
+                    </div>
+                    <div className={style.month}>
+                        <MonthList year={this.state.year} canSelectFuture={this.props.canSelectFuture} select={this.state.month} handleChange={(info) => this.handleMonthSelect(info)}/>
+                    </div>
+                    <div className={style.button}>
+                        <button onClick={()=>this.handleTodayClick()}>{'今天'}</button>
+                    </div>
+                </div>
+                <Content selectTime={this.state.select} year={this.state.year} month={this.state.month} handleClick={(info)=>this.handleChange(info)} canSelectFuture={this.props.canSelectFuture}/>
+                {this.genTimeComponent()}
+            </div>
+        )
+    }
+
+    componentDidUpdate(){
+        this.inputing=false;
+    }
+}
+
+export default Calendar;
+
+Calendar.propTypes = {
+    handleChange: PropTypes.func,
+    needTime:PropTypes.bool,
+    canSelectFuture:PropTypes.bool
+};

+ 50 - 0
src/common/components/Calendar/index.less

@@ -0,0 +1,50 @@
+@import "~@less/mixin.less";
+
+.wrapper{
+  width: 294px;
+  padding: 5px;
+  font-size: 0;
+  color:#1F547E;
+  background-color: #fff;
+  border-radius: 3px;
+  position: absolute;
+  top: 10px;
+    right: 0;
+  z-index: 100;
+  border: 1px solid #ccc;
+  box-sizing: border-box;
+  .top{
+    height: 26px;
+  }
+  .year{
+    width: 123px;
+    margin-right: 6px;
+    display: inline-block;
+  }
+  .month{
+    width: 101px;
+    margin-right: 6px;
+    display: inline-block;
+  }
+  .button{
+    display: inline-block;
+    width: 46px;
+    height: 26px;
+    position: relative;
+    button{
+      position: absolute;
+      top: 2px;
+      border: 1px solid #b1d2ec;
+      color:#1F547E;
+      background-color: #deecf8;
+      outline: none;
+      &:hover{
+        background-color: #ECF4FB;
+      }
+      &:active{
+        box-shadow: @active-box-shadow;
+        border-radius: 2px;
+      }
+    }
+  }
+}

+ 78 - 0
src/common/components/CheckBox/Multiple/index.jsx

@@ -0,0 +1,78 @@
+import React,{Component} from 'react';
+import style from './index.less';
+import PropTypes from 'prop-types';
+
+class Multiple extends React.Component{
+  constructor(props){
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.state = {
+      ban:false,
+      wu:false,
+      noBanWu:false//不点伴无
+    }
+  }
+
+  handleClick(e){
+    e.stopPropagation();
+  }
+
+  handleChange(item,e){
+    e.stopPropagation();
+    const {handleClick} = this.props;
+   // handleClick && handleClick(item.name); 
+   // console.log(2222,item);
+
+  }
+
+  getSelectedStyle(it){
+    // const {isSelect,first,then} = this.props;
+    const isSelect = it.isSelect;
+    const {ban,wu} = this.state;
+    if(ban && isSelect){//伴、初为
+      return style.selectBtn;
+    }
+    else if(wu && isSelect){//无、后为
+      return `${style.selectBtn} ${style.thenSel}`;
+    }
+    else if(isSelect){
+      return style.selectBtn;
+    }
+    else{
+       return style.btn
+    }
+
+  }
+
+  getTabs(){
+    const {datas} =this.props;
+    let pushData = datas && datas.filter(function(item){
+      return item.name
+    });
+    // 没有标签的暂时过滤
+    let list = pushData && pushData.map((it,i)=>{
+        return <p onClick={this.handleChange.bind(this,it)} contentEditable='false' className={this.getSelectedStyle(it)}>{it.name}</p>
+      })
+      return list;
+  }
+
+  render(){
+    const selectStyle = this.props.style;
+    const {name} = this.props;
+    return <div className={style['multiple']} onClick={this.handleClick.bind(this)} style={selectStyle}>
+      {this.props.children}
+      <div className={style['multiple-con']}>
+        {/*<p onClick={this.handleChange.bind(this,name)} contentEditable='false' className={this.getSelectedStyle()}>{name}</p>*/}
+        {this.getTabs()}
+      </div>
+    </div>
+  }
+}
+
+Multiple.propTypes = {
+    handleClick:PropTypes.func,
+    isSelect:PropTypes.bool,
+    name:PropTypes.string
+};
+
+export default Multiple;

+ 48 - 0
src/common/components/CheckBox/Multiple/index.less

@@ -0,0 +1,48 @@
+
+.multiple{
+  // width: 200px;
+  // height: 44px;
+  // line-height: 44px;
+  margin-left: 10px;
+  display: inline-block;
+  vertical-align: top;
+
+  .btn{
+    height: 44px;
+    line-height: 44px;
+    // width: 100%;
+    font-size: 12px;
+    text-align: left;
+    border: none;
+    color:#000000;
+    background: #fff;
+    // padding-left: 40px;
+    padding: 0 10px 0 30px;
+    cursor: pointer;
+  }
+  .selectBtn{
+    height: 44px;
+    line-height: 44px;
+    // width: 100%;
+    font-size: 12px;
+    text-align: left;
+    border: none;
+    color:#000000;
+    background: rgba(59,158,208,0.1);
+    // padding-left: 40px;
+    padding: 0 10px 0 30px;
+    cursor: pointer;
+    background-image: url(../../../images/first.png);
+    background-repeat: no-repeat;
+    background-position: 12px 15px;
+  }
+
+  .thenSel{
+    background-image: url(../../../images/then.png);
+  }
+  
+  .multiple-con{
+
+  }
+}
+

+ 64 - 0
src/common/components/CheckBox/Select/index.jsx

@@ -0,0 +1,64 @@
+import React,{Component} from 'react';
+import style from './index.less';
+import PropTypes from 'prop-types';
+
+/*
+多选组件
+datas:父组件传来的数据(数组)
+name:标签名;
+isSelect:是否选中;
+noSpecialFlag:无殊标识, 2选中其他 1选中无殊 0默认无选中;
+*/
+
+class Select extends React.Component{
+  constructor(props){
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleClick(e){
+    e.stopPropagation();
+  }
+
+  handleChange(name,e){
+    e.stopPropagation();
+    const {handleClick,parentId,checkBoxId,flag} = this.props;
+    const items = {
+      name,
+      parentId,
+      checkBoxId,
+      flag
+    }
+   handleClick && handleClick(items);     
+  }
+
+  getTab(){
+    const {noSpecialFlag,datas} = this.props;
+    if(noSpecialFlag==2){//无殊
+      let list = datas.map((it,i)=>{
+        return <p contentEditable='false' className={`${style['btn']} ${style['nospecialDis']}`}>{it.name}</p>
+      })
+      return list;
+    }else{
+      let list = datas.map((it,i)=>{
+        return <p onClick={this.handleChange.bind(this,it.name)} contentEditable='false' className={!it.isSelect ? style['btn']:style['selectBtn']}>{it.name}</p>
+      })
+      return list;
+    }
+  }
+
+  render(){
+    return <div className={style['select']} onClick={this.handleClick.bind(this)}>
+      {this.props.children}
+      {this.getTab()}
+    </div>
+  }
+}
+
+Select.propTypes = {
+    handleClick:PropTypes.func,
+    handleChange:PropTypes.func,
+    datas:PropTypes.array
+};
+
+export default Select;

+ 42 - 0
src/common/components/CheckBox/Select/index.less

@@ -0,0 +1,42 @@
+// @import "~@less/variables.less";
+.select{
+  // width: 200px;
+  // height: 44px;
+  // line-height: 44px;
+  display: inline-block;
+  vertical-align: top;
+  margin-left: 10px;
+  .btn{
+    height: 44px;
+    line-height: 44px;
+    // width: 100%;
+    font-size: 12px;
+    text-align: left;
+    border: none;
+    color:#000000;
+    background: #fff;
+    padding: 0 10px 0 30px;
+    cursor: pointer;
+  }
+  .selectBtn{
+    height: 44px;
+    line-height: 44px;
+    width: 100%;
+    font-size: 12px;
+    text-align: left;
+    border: none;
+    color:#000000;
+    background: rgba(59,158,208,0.1);
+    padding: 0 10px 0 30px;
+    cursor: pointer;
+    background-image: url(../../../images/first.png);
+    background-repeat: no-repeat;
+    background-position: 12px 15px;
+  } 
+
+  .nospecialDis{
+    color:#000000;
+    opacity: 0.3;
+    cursor: auto;
+  }
+}

+ 131 - 0
src/common/components/CheckBox/index.jsx

@@ -0,0 +1,131 @@
+import React,{Component} from 'react';
+import PropTypes from 'prop-types';
+import style from './index.less';
+import Select from './Select';
+import Multiple from './Multiple';
+
+class CheckBox extends React.Component{
+  constructor(props){
+    super(props);
+    this.handleBtnConfirm = this.handleBtnConfirm.bind(this);
+    this.handleBtnClear = this.handleBtnClear.bind(this);
+    this.handleFirst = this.handleFirst.bind(this);
+    this.handleThen = this.handleThen.bind(this);
+    this.handleNospencial = this.handleNospencial.bind(this);
+    this.preventClick = this.preventClick.bind(this);
+    this.handleSpenc = this.handleSpenc.bind(this);
+    this.state={
+      widthStyle:'small',//控制下拉框的宽度big--初为 后为;small--一列展示
+      multiple:false,//true为三列,false为一列
+    }
+  }
+
+
+  preventClick(e){
+    //阻止冒泡,冒泡会使下拉框消失
+    e.stopPropagation();
+  }
+
+  getCheckItems(){
+    const items = [];
+    const {selectVal,isClear,checks,noSpecialFlag} = this.props;
+    const that = this;
+    checks&&checks.map((v,i)=>{
+      if(that.state.multiple){//三列显示
+        items[i] = <Multiple {...v} handleClick={this.props.handleCheckBoxClick} key={v.id} selectVal={selectVal} isClear={isClear} />
+      }else{//一列
+        items[i] = <Select {...v} handleClick={this.props.handleCheckBoxClick} key={v.id} selectVal={selectVal} isClear={isClear} noSpecialFlag={noSpecialFlag} />
+      }
+      
+    })
+    return items;
+  }
+
+  handleSpenc(e,code){
+    e.stopPropagation();
+    // console.log(3333,e,code);
+    if(code == 1){//伴
+
+    }else if(code == 2){//无
+
+    }
+  }
+
+
+  getTabs(){
+    //datas为questionDetailList
+    const {datas,handleCheckBoxClick,firstChoo} = this.props; 
+    let list = datas.length>0 && datas.map((it,ind)=>{
+      if(it.code){
+          return <p contentEditable='false' onClick={(e)=>{this.handleSpenc(e,it.code)}} className={firstChoo?`${style['nospecial']} ${style['firstSel']}`:style['nospecial']}>{it.name}</p>
+        }else {
+          return <Multiple {...it} handleClick={this.props.handleCheckBoxClick} key={it.id} />
+        }    
+    })
+    return list;
+  }
+
+  handleBtnConfirm(e){//确定
+    e.stopPropagation();
+    const {confirmCheckBox,showCheckBox,checkBoxId} = this.props;
+    const data = {
+      showCheckBox,
+    }
+    confirmCheckBox && confirmCheckBox(checkBoxId);   
+  }
+
+  handleBtnClear(e,){//清空
+    e.stopPropagation();
+    const {clearCheckBox,showCheckBox,checkBoxId} = this.props;
+    clearCheckBox && clearCheckBox(checkBoxId);
+  }
+
+  handleFirst(){//初为
+    const {firstChoo} = this.props;
+    firstChoo && firstChoo(true);
+  }
+
+  handleThen(){//后为
+    const {thenChoo} = this.props;
+    thenChoo && thenChoo(false);
+  }
+
+  handleNospencial(e){
+    e.stopPropagation();
+    const {noSpecialClick} = this.props;
+    noSpecialClick && noSpecialClick();
+  }
+
+  getNoSpecial(){
+    // noSpecialFlag 0默认无选中,1选中标签,2选中无殊
+    const {noSpecial,noSpecialFlag,noSpecialClick} = this.props;
+    return noSpecialFlag==1?<p className={`${style['nospecial']} ${style['nospecialDis']}`} style={{display:this.state.multiple?'none':'block'}}>个人史无殊</p> : <p className={noSpecial?`${style['nospecial']} ${style['firstSel']}`:style['nospecial']} style={{display:this.state.multiple?'none':'block'}} onClick={this.handleNospencial}>个人史无殊</p>
+  }
+
+  render(){
+    const {showCheckBox,selectVal,firstC,thenC,firstArr,showDrop} = this.props;
+    const firstStyle = firstC;
+    const thenStyle = thenC;
+    {/*return <div className={`cb-box ${style['cb-container']}`} style={{display:'inline-block'}} onClick={this.preventClick}>*/}
+    return <div style={{display:'inline-block'}} onClick={this.preventClick}>
+      {this.getTabs()}
+      {/*<div className={style['multiple-tab']} style={{display:this.state.multiple?'inline-block':'none'}}>
+        <p contentEditable='false' onClick={this.handleFirst} className={firstStyle?`${style['nospecial']} ${style['firstSel']}`:style['nospecial']}>初为</p>
+        <p contentEditable='false' onClick={this.handleThen} className={thenStyle?`${style['nospecial']} ${style['thenSel']}`:style['nospecial']}>后为</p>
+      </div>
+      {this.state.multiple?'':this.getNoSpecial()}
+      <div className={style['multiple-con']}>{this.getCheckItems()}</div>
+      <div className={style['btn']}>
+        <button onClick={this.handleBtnClear} className={style['clear']}>清空选项</button>
+        <button onClick={this.handleBtnConfirm} className={style['confirm']}>确定</button> 
+      </div>*/}       
+    </div>
+  }
+}
+
+CheckBox.propTypes = {
+    handleClick:PropTypes.func,
+    datas:PropTypes.array
+};
+export default CheckBox;
+

+ 79 - 0
src/common/components/CheckBox/index.less

@@ -0,0 +1,79 @@
+
+.cb-container{
+  // width: 277px;
+  min-width: 216px;
+  padding: 10px;
+  position: absolute;
+  top: 25px;
+  left: 0px;
+  background: #fff;
+  z-index: 10;
+  box-shadow: 0 10px 20px 0 rgba(194,194,194,0.50);
+}
+.clear{
+  width: 88px;
+  height: 44px;
+  line-height: 44px;
+  font-size: 12px;
+  color:#FF0000;
+  border: none;
+  background: #fff;
+  float: left;
+  margin-top: 10px;
+}
+.confirm{
+  width: 88px;
+  height: 44px;
+  line-height: 44px;
+  color:#3B9ED0;
+  font-size: 12px;
+  border: 1px solid #3B9ED0;
+  background: #fff;
+  margin-left: 20px;
+  float: right;
+  margin-top: 10px;
+}
+.multiple-tab{
+  // width: 200px;
+  vertical-align: top;
+  // p{
+  //   width: 200px;
+  //   height: 44px;
+  //   line-height: 44px;
+  //   cursor: pointer;
+  //   padding-left: 40px;
+  // }
+}
+.multiple-con{
+  // width: 440px;
+  display: inline-block;
+}
+.btn{
+
+}
+.nospecial{
+  // width: 200px;
+  height: 44px;
+  line-height: 44px;
+  cursor: pointer;
+  color:#000000;
+  padding: 0 10px 0 30px;
+  border-bottom: 1px solid #EAEDF1;
+}
+.nospecialDis{
+  color:#000000;
+  opacity: 0.3;
+  cursor: auto;
+}
+.firstSel{
+  background: rgba(59,158,208,0.1);
+  background-image: url(../../images/first.png);
+  background-repeat: no-repeat;
+  background-position: 12px 15px;
+}
+.thenSel{
+  background: rgba(59,158,208,0.1);
+  background-image: url(../../images/then.png);
+  background-repeat: no-repeat;
+  background-position: 12px 15px;
+}

+ 23 - 0
src/common/components/ConfirmModal/NewPortal/index.jsx

@@ -0,0 +1,23 @@
+import React, { Component } from 'react';
+import ReactDOM from 'react-dom';
+
+//传送门,将dom渲染到body节点
+class NewPortal extends Component {
+    constructor(props) {
+        super(props)
+        // 初始化创建渲染的父元素并添加到body下
+        this.node = document.createElement('div');
+        document.body.appendChild(this.node);
+    }
+
+    render() {
+        const { visible,children } = this.props;
+        
+        return visible && ReactDOM.createPortal(
+            children,
+            this.node
+        )
+    }
+}
+
+export default NewPortal;

+ 54 - 0
src/common/components/ConfirmModal/OldPortal/index.jsx

@@ -0,0 +1,54 @@
+import React, { Component } from 'react';
+import ReactDOM from 'react-dom';
+
+//传送门,将dom渲染到body节点
+class OldPortal extends Component {
+    constructor(props) {
+        super(props)
+    }
+
+    componentWillReceiveProps(props) {
+        if(props.visible) {
+            this.renderPortal((props))
+        } else {
+            this.closePortal()
+        }
+    }
+
+    componentDidMount() {
+        const { visible } = this.props;
+        if (visible) {
+            this.renderPortal(this.props);
+        }
+    }
+
+    renderPortal(props) {
+        if (!this.node) {
+            //防止多次创建node
+            this.node = document.createElement('div');
+        }
+        //将当前node添加到body中
+        document.body.appendChild(this.node);
+
+        ReactDOM.unstable_renderSubtreeIntoContainer(
+            this,   // 上下文指定当前的实例
+            props.children,   // 渲染的元素为当前的children
+            this.node   // 将元素渲染到我们新建的node中,这里我们不使用第四个参数回调.
+        )
+    }
+
+    closePortal() {
+        if (this.node) {
+            // 卸载元素中的组件
+            ReactDOM.unmountComponentAtNode(this.node)
+            // 移除元素
+            document.body.removeChild(this.node)
+        }
+    }
+
+    render() {
+        return null
+    }
+}
+
+export default OldPortal;

二進制
src/common/components/ConfirmModal/img/close.png


+ 163 - 0
src/common/components/ConfirmModal/index.jsx

@@ -0,0 +1,163 @@
+import React, { Component } from 'react';
+import styles from './index.less';
+import OldPortal from './OldPortal';
+import NewPortal from './NewPortal'
+import PropTypes from 'prop-types';
+import close from "./img/close.png";
+
+/***
+ * 弹窗组件
+ * author:zxc@2018-11-19
+ * 接收参数:
+ * visible: Boolean,对话框是否可见
+ * title: 弹窗标题, String
+ * titleBg: 标题背景颜色
+ * children: 包含的子组件
+ * noFooter: 是否包含底部,Boolean, 默认为false
+ * confirm: 点击确认回调
+ * close:点击遮罩层或右上角叉
+ * cancel: 点击取消按钮的回调
+ * closable: 是否显示右上角的关闭按钮, Boolean, 默认为true
+ * mask:是否显示遮罩, Boolean, 默认为true
+ * maskClosable: 点击蒙层是否允许关闭, Boolean, 默认为false
+ * okText: 确认按钮文字,String,默认为确认
+ * okColor: 确认按钮文字颜色
+ * okBorderColor: 确认按钮边框颜色
+ * oKBg: 确认按钮背景颜色
+ * cancelText: 取消按钮文字, String,默认为取消
+ * cancelColor: 取消按钮文字颜色
+ * cancelBorderColor:取消按钮边框颜色
+ * cancelBg: 取消按钮背景颜色
+ * width: 宽度, string|number, 默认为300
+ * height: 弹窗高度, string|number, 默认为200
+ ***/
+
+const propTypes = {
+    visible: PropTypes.bool,
+    confirm: PropTypes.func,
+    cancel: PropTypes.func,
+    close: PropTypes.func,
+    title: PropTypes.string,
+    titleBg: PropTypes.string,
+    noFooter: PropTypes.bool,
+    okText: PropTypes.string,
+    okColor: PropTypes.string,
+    okBorderColor: PropTypes.string,
+    oKBg: PropTypes.string,
+    cancelText: PropTypes.string,
+    cancelColor: PropTypes.string,
+    cancelBorderColor: PropTypes.string,
+    cancelBg: PropTypes.string,
+
+
+
+}
+
+const defaultProps = {
+    titleBg: '#fff',
+    noFooter: false,
+    mask: true,
+    maskClosable: false,
+    closable: true,
+    okText: '确认',
+    okColor: 'red',
+    okBorderColor: 'red',
+    oKBg:'#fff',
+    cancelText: '取消',
+    cancelColor: '#414141',
+    cancelBorderColor: '#414141',
+    cancelBg: '#fff',
+    width: '300px',
+};
+
+class ConfirmModal extends Component {
+    constructor(props) {
+        super(props);
+
+        this.confirm = this.confirm.bind(this);
+        this.cancel = this.cancel.bind(this);
+        this.maskClick = this.maskClick.bind(this);
+        this.closeModal = this.closeModal.bind(this)
+
+    }
+    
+    
+
+    closeModal() {
+        const { close } = this.props
+        close && close()
+    }
+
+    confirm() {
+        const { confirm } = this.props
+        confirm && confirm()
+    }
+    cancel() {
+        const { cancel } = this.props
+        cancel && cancel()
+    }
+
+    maskClick() {
+        const { close } = this.props
+        close && close()
+    }
+
+    render() {
+        const {
+            visible,
+            title, 
+            titleBg,
+            children, 
+            mask, 
+            maskClosable,
+            okText, 
+            okColor,
+            okBorderColor,
+            oKBg,
+            cancelText, 
+            cancelColor,
+            cancelBorderColor,
+            cancelBg,
+            width, 
+            height, 
+            closable, 
+            noFooter
+        } = this.props;
+        return (
+            <NewPortal visible={visible}>
+                <div className={styles['modal-wrapper']} id='confirm'>
+                    <div className={styles[['modal']]} style = {{width: width, height:height}}>
+                        <div className={styles['modal-title']} style={{background: titleBg}}>{title ? title : ''} {closable ? <img onClick={this.closeModal} className={styles['modal-close']} src = {close}/> : false}</div>
+                        <div className={styles['modal-content']}>{children}</div>
+                        {noFooter ? '' : <div className={styles['modal-operator']+' clearfix'}>
+                            <div className={styles['modal-btn-box']}>
+                                <button 
+                                    onClick={this.confirm} 
+                                    className={styles['modal-operator-confirm']}
+                                    style={{borderColor: okBorderColor, background: oKBg, color: okColor}}>
+                                    { okText}
+                                </button>
+                            </div>
+                            <div className={styles['modal-btn-box']}>
+                                <button 
+                                onClick={this.cancel} 
+                                className={styles['modal-operator-close']}
+                                style={{borderColor: cancelBorderColor, background: cancelBg, color: cancelColor}}>
+                                { cancelText}
+                            </button>
+                            </div>
+                        </div>}
+                    </div>
+                    {mask ? <div className={styles['mask']}
+                        onClick = {maskClosable === true ? this.maskClick : ()=>{}}
+                    ></div> : ''}
+                </div>
+            </NewPortal>
+        )
+    }
+}
+
+ConfirmModal.propTypes = propTypes;
+ConfirmModal.defaultProps = defaultProps;
+
+export default ConfirmModal;

+ 80 - 0
src/common/components/ConfirmModal/index.less

@@ -0,0 +1,80 @@
+.modal {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%,-50%);
+    margin: auto;
+    border-radius: 5px;
+    background: #fff;
+    overflow: hidden;
+    z-index: 9999;
+}
+
+.modal-title {
+    width: 100%;
+    height: 50px;
+    line-height: 50px;
+    padding: 0 10px;
+    background: #e5e5e5
+}
+
+.modal-close {
+    position: absolute;
+    right: 0px;
+    width: 40px;
+    height: 40px;
+}
+
+.modal-content {
+    width: 100%;
+    padding: 0 10px;
+}
+
+.modal-operator {
+    width: 100%;
+    height: 70px;
+}
+
+.modal-btn-box {
+    width: 50%;
+    float: left;
+    text-align: center;
+}
+
+.modal-operator-close, .modal-operator-confirm {
+    width: 100px;
+    border: none;
+    outline: none;
+    margin: auto;
+    height: 34px;
+    line-height: 24px;
+    opacity: 1;
+    color: #fff;
+    cursor: pointer;
+    border-radius: 4px;
+    border: 1px solid #78bddd;
+}
+.modal-operator-confirm {
+    background: #78bddd;
+}
+
+.modal-operator-close{
+    background: #fff;
+    color: #78bddd;
+}
+
+.modal-operator-close:active, .modal-operator-confirm:active {
+    opacity: .6;
+    transition: opacity .3s;
+}
+
+.mask {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: #000;
+    opacity: .6;
+    z-index: 9998;
+}

+ 20 - 0
src/common/components/DropContainer/index.jsx

@@ -0,0 +1,20 @@
+/***
+ * author:zn@2018-11-08
+ * 下拉框容器
+ * 生成在鼠标位置下方
+ * 接收参数:
+ * children:下拉内容
+ *
+ * ***/
+import React,{Component} from 'react';
+
+class DropContainer extends Component {
+  render(){
+    const {children} = this.props;
+    return <div className="container">
+              {children}
+            </div>;
+  }
+}
+
+export default DropContainer;

+ 0 - 0
src/common/components/DropContainer/index.less


+ 49 - 0
src/common/components/DropList/index.jsx

@@ -0,0 +1,49 @@
+import React,{Component} from 'react';
+import classNames from 'classnames';
+
+import style from "./index.less";
+/****
+ * 单选下拉内容框(不含输入本身)
+ * author:zn@2018-11.13
+ * 接收参数:
+ * data: json数组
+ * show:true/false
+ * onSelect: 选中事件
+ *
+ * ***/
+
+class DropList extends Component{
+  constructor(props){
+    super(props);
+    this.handleSelect = this.handleSelect.bind(this);
+    this.handleClear = this.handleClear.bind(this);
+  }
+  getClass(){
+    let name = style['text-list'];
+    let isHide = this.props.show?'':style['hide'];
+    return classNames(style['list'],name,isHide);
+  }
+  handleSelect(e,item){
+    e.stopPropagation();
+    const {onSelect} = this.props;
+    onSelect&&onSelect(item);
+  }
+  handleClear(e){
+    e.stopPropagation();
+    const {onSelect} = this.props;
+    onSelect&&onSelect(undefined);
+  }
+  render(){
+    const {data} = this.props;
+    return <div className={this.getClass()} contentEditable='false'>
+      <ul>
+        {data&&data.map((it)=>{
+          return <li onClick={(e)=>this.handleSelect(e,it)} className={it.selected||(it.selected!==false&&+it.defaultSelect===1)?style['selected']:''}>{it.labelPrefix}{it.name}{it.labelSuffix}</li>
+        })}
+        <li onClick={(e)=>this.handleClear(e)} className='red'>清空选项</li>
+      </ul>
+    </div>
+  }
+}
+
+export default DropList;

+ 19 - 0
src/common/components/DropList/index.less

@@ -0,0 +1,19 @@
+@import "~@less/variables.less";
+.list{
+  .pop;
+  padding: 0 0 10px;
+  color: @text-color;
+  li{
+    line-height: 35px;
+    border:1px #fff solid;
+    padding: 0 15px;
+    white-space: nowrap;
+    cursor: pointer;
+  }
+  li:hover,.selected{
+    border-color:#3B9ED0;
+  }
+}
+.hide{
+  display: none;
+}

+ 134 - 0
src/common/components/EditableSpan/index.jsx

@@ -0,0 +1,134 @@
+import React,{Component} from 'react';
+import style from './index.less';
+import config from "@config/index";
+import {filterArr,handleEnter} from '@utils/tools.js';
+import Notify from '../Notify/index.js';
+/*****
+ * author:zn@2018-12-10
+ * 自由文本输入组件
+ * 接收参数:
+ * value:默认显示文字
+ * handleChange:输入变化时触发函数,接收以下参数:
+ * * boxMark:病例项标识
+ * * i:标签index
+ * * text:标签内文字
+ *
+ * ****/
+
+class EditableSpan extends Component{
+  constructor(props){
+    super(props);
+    this.state={
+      timer:null,
+      clearTimer:null,
+      oldText:props.value,
+      labelVal:'',  //存放标签原有的值--主诉字数限制用
+    };
+    this.$span = React.createRef();
+    this.handleFocus = this.handleFocus.bind(this);
+    this.onChange = this.onChange.bind(this);
+    this.handleBlur = this.handleBlur.bind(this);
+  }
+  handleFocus(e){
+    e.stopPropagation();
+    const {setFocusIndex,i,boxMark}= this.props;
+    let text = e.target.innerText;
+    setFocusIndex&&setFocusIndex({i,boxMark,dom:this.$span});
+    this.setState({
+      labelVal:text
+    });
+  }
+  onChange(e){
+    e.stopPropagation();
+    const {handleChange,boxMark,i,handleSearch,value,mainSaveText,mainIds} = this.props;
+    const {labelVal,oldText} = this.state;
+    const text1 =e.target.innerText;
+    let mainText = filterArr(mainSaveText);//主诉字数
+    if(+boxMark==1){
+      if(mainText.length >= config.limited){
+        if(text1.length > labelVal.length){
+          e.target.innerText = labelVal;
+          Notify.info(config.limitText);
+          return
+        }else if(text1.length == labelVal.length){
+          this.setState({
+            labelVal:text1
+          });
+        }else{
+          handleChange&&handleChange({text1,boxMark,i});
+        }
+        return
+      }
+    }
+    this.setState({
+      labelVal:text1
+    });
+
+    const that = this;
+    handleChange&&handleChange({text1,boxMark,i});
+
+    //延迟搜索
+    clearTimeout(this.state.timer);
+    const timer = setTimeout(function(){
+      let newText = e.target.innerText;
+      let temp = '';
+      let search='';
+      clearTimeout(that.state.timer);
+      // temp = newText.replace(oldText.replace(/(^\s*)|(\s*$)/g,''),'');
+      temp = newText.replace(labelVal.replace(/(^\s*)|(\s*$)/g,''),'');
+      search = temp.replace(/(^\s*)|(\s*$)/g,'');
+      // console.log(111,labelVal,333,newText,444,search);
+      handleSearch&&handleSearch({text:search,boxMark,mainIds});
+      /*that.setState({
+        oldText:newText.replace(search,'')
+      })*/
+    },config.delayTime);
+    this.setState({
+      timer
+    });
+  }
+
+  handleBlur(e){//为了阻止冒泡事件
+    const {boxMark,handleClear,handleChange,i} = this.props;
+    e.stopPropagation();
+    // 延时清空搜索结果,不延时会影响选中
+    clearTimeout(this.state.clearTimer);
+    const clearTimer = setTimeout(function(){
+      handleClear && handleClear({boxMark})
+    },config.delayTime);
+    this.setState({
+      clearTimer
+    });
+  }
+  /*shouldComponentUpdate(next){
+    if(JSON.stringify(next) == JSON.stringify(this.props)){
+      return false;
+    }
+    return true;
+  }*/
+  componentWillReceiveProps(next){
+    const isRead = this.props.isRead;
+    if(next.isRead != isRead){
+      this.$span.current.innerText = next.value||'';
+    }
+  }
+  componentDidMount(){
+    const {value} = this.props;
+    if(value){
+      this.$span.current.innerText = value||'';
+    }
+  }
+
+  render() {
+    return <span className={style['editable-span']}
+                      contentEditable='true'
+                      ref={this.$span}
+                      onInput={this.onChange}
+                      onFocus={this.handleFocus}
+                      onBlur={this.handleBlur}
+                      onkeydown={handleEnter}></span>;
+
+  }
+}
+
+export default EditableSpan;

+ 14 - 0
src/common/components/EditableSpan/index.less

@@ -0,0 +1,14 @@
+.editable-span{
+  display: inline-block;
+  outline: none;
+  word-break: break-word;
+  min-width: 10px;
+  // line-height: 2;
+  /*height: 20px;*/
+  line-height: 16px;
+  /*vertical-align: middle;*/
+  text-align: center;
+}
+.full{
+  width: 100%;
+}

+ 12 - 0
src/common/components/Empty/index.jsx

@@ -0,0 +1,12 @@
+import React from 'react'
+import style from './index.less'
+
+class Empty extends React.Component{
+    render(){
+        return (
+            <div className={style.empty}></div>
+        )
+    }
+}
+
+export default Empty;

+ 5 - 0
src/common/components/Empty/index.less

@@ -0,0 +1,5 @@
+.empty{
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+}

+ 104 - 0
src/common/components/InlineTag/index.jsx

@@ -0,0 +1,104 @@
+import React, { Component } from "react";
+import style from "./index.less";
+import classNames from 'classnames';
+import {handleEnter} from '@utils/tools.js';
+/***
+ * 标签组件
+ * author:zn@2018-11-08
+ * 接收参数:
+ * prefix:前缀文字
+ * value:输入的值
+ * placeholder
+ * suffix:后缀文字
+ * canEditable: 切换父元素框(主诉同级框)的可编辑属性,
+ *              PS:父元素框可编辑时子元素onBlur无法触发,因为此时focus的元素为父元素框
+ *
+ ***/
+class InlineTag extends Component {
+  constructor(props){
+    super(props);
+    this.$box = React.createRef();
+    this.$span = React.createRef();
+    this.state = {
+      editable:false,
+      value:props.value
+    };
+    this.changeToEdit = this.changeToEdit.bind(this);
+    this.changeToClick = this.changeToClick.bind(this);
+    this.handleBlur = this.handleBlur.bind(this);
+    this.handleInput = this.handleInput.bind(this);
+    this.handleFocus = this.handleFocus.bind(this);
+  }
+  changeToEdit(e){
+    const {handledbClick,id} = this.props;
+    this.setState({
+      editable:true
+    });
+    //埋点记录
+    handledbClick&&handledbClick({id});
+  }
+  changeToClick(event){
+    event.returnValue = true;
+    const {canEditable} = this.props;
+    canEditable&&canEditable();
+    this.setState({
+      editable:false
+    });
+  }
+  handleInput(e){       //输入时保存临时值,在修改灰显为黑色时判断用
+    const text = e.target.innerText;console.log(text)
+    this.setState({
+      value:text
+    });
+   // e.target.innerText = text;
+  }
+  handleBlur(e){         //鼠标离开是保存值到store中
+    const {value} = this.state;
+    const {handleInput,ikey,prefix,suffix} = this.props;
+    this.$span.current.innerText='';      //修改生成文字变成输入的2倍bug
+    handleInput&&handleInput({text:value,ikey,prefix,suffix});
+  }
+  handleFocus(e){
+    e.stopPropagation();
+    const text = e.target.innerText;
+    const {placeholder} = this.props;
+    if(text==placeholder){
+      e.target.innerText = '';
+    }
+  }
+  getStyle(){
+    const {value} = this.state;
+    const {hideTag} = this.props;
+    if(hideTag){
+      if(value){
+        return classNames(style['selected-no-tag']);
+      }
+      return style['no-tag'];
+    }
+    if(!value){
+      return classNames(style['gray']);
+    }
+    return style['selected-tag'];
+  }
+ 
+  render(){
+    const {placeholder,value,prefix,suffix} = this.props;
+    const inp = this.state.value;
+    return <div className={this.getStyle()}
+                 onDoubleClick={this.changeToEdit}
+                 onkeydown={handleEnter}
+                 onBlur={this.changeToClick} ref={this.$box} contentEditable={this.state.editable}>
+                {prefix}
+                <span className={style['free-in']}
+                      contentEditable={true}
+                      onBlur={this.handleBlur}
+                      onInput={this.handleInput}
+                      onFocus={this.handleFocus}
+                      onkeydown={handleEnter}
+                      ref={this.$span}>{value||(inp?'':placeholder)}</span>
+                {suffix}
+            </div>;
+    }
+}
+
+export default InlineTag;

+ 23 - 0
src/common/components/InlineTag/index.less

@@ -0,0 +1,23 @@
+@import "~@less/variables.less";
+.selected-tag{
+  .selected-tag;
+  .free-in{
+    border-bottom:none;
+  }
+}
+.selected-no-tag{
+  .selected-tag;
+  .free-in{
+    border-bottom:none;
+  }
+  border-bottom: none;
+}
+.gray{
+   .tag;
+ }
+.free-in{
+  display: inline-block;
+  min-width: 30px;
+  /*border-bottom: 1px @placeholder-color solid;*/
+  outline: none;
+}

+ 29 - 0
src/common/components/InspectCommon/index.jsx

@@ -0,0 +1,29 @@
+import React from 'react';
+import style from "./index.less";
+import PropTypes from "prop-types";
+
+/**
+ * 
+ */
+class InspectCommon extends React.Component {
+    constructor(props) {
+        super(props);
+    }
+
+    render() {
+        const { children,handleClear,handleConfirm} = this.props;
+        return <div className={ style.wrapper} id="inspectFill">
+            {children}
+            <div className={style.btnWrap}>
+                <span className={style.clear + ' red'} onClick={handleClear}>清空选项</span>
+                <span className={style.sure} onClick={handleConfirm}>确 定</span>
+            </div>
+        </div>
+    }
+}
+
+InspectCommon.propTypes = {
+    handleClear: PropTypes.func,
+    handleConfirm: PropTypes.func
+};
+export default InspectCommon;

+ 40 - 0
src/common/components/InspectCommon/index.less

@@ -0,0 +1,40 @@
+@import "~@less/variables.less";
+.wrapper {
+    position: absolute;
+    top: 40px;
+    z-index: 20;
+    background-color: #fff;
+    padding:28px 8px 8px 8px;
+    min-width: 300px;
+    max-width: 600px;
+    box-sizing: border-box;
+    box-shadow: 0 6px 20px 0 #989DA3;
+    // border: 1px solid #989DA3;
+}
+.btnWrap{
+    span {
+        display: inline-block;
+        width: 88px;
+        height: 44px;
+        line-height: 44px;
+        text-align: center;
+        border: 1px solid transparent;
+        box-sizing: border-box;
+    }
+    .sure {
+        float: right;
+        color: @blue;
+        border: 1px solid @blue;
+    }
+    .clear {
+        float: left;
+    }
+}
+
+.searchResult {
+    .searchResultT {
+        img {
+            float: right;
+        }
+    }
+}

+ 43 - 0
src/common/components/ItemBox/index.jsx

@@ -0,0 +1,43 @@
+import React,{Component} from 'react';
+import style from './index.less';
+/***
+ * author:zn@2018-11-13
+ * 电子病历项内容框
+ * 接收参数:
+ * boxHeight:框高度
+ * boxWidth:框宽度
+ * title:框名称(如主诉、现病史)
+ * editable:是否可编辑
+ * children:框内内容
+ * border:边框样式,
+ * style
+ *
+ * ***/
+class ItemBox extends Component {
+  constructor(props){
+    super(props);
+    this.handleClick = this.handleClick.bind(this);
+  }
+  getBoxStyle(){
+    const {boxHeight,boxWidth,boxLineHeight,marginTop} = this.props;
+    return {width:boxWidth?boxWidth:undefined,height:boxHeight?boxHeight:undefined,lineHeight:boxLineHeight?boxLineHeight:'22px',marginTop:marginTop};
+  }
+
+  handleClick(e){
+    const {handleClick} = this.props;
+    handleClick && handleClick(e);//为了获取鼠标位置,显示搜索结果框;
+  }
+
+  render(){
+    const {title,children,editable,className,handleFocus,onchange,fuzhen,border,handleBlur,titleTop} = this.props;
+    // console.log(title,editable)
+    return <div className={style["box"]+" "+"clearfix"} >
+      <div className={style["title"] + ' ' + className} style={{marginTop:titleTop?'22px':''}}>{title}</div>
+      <div className={`${style["content"]} ${border?style["border"]:''}`} contentEditable={editable} style={this.getBoxStyle()} onFocus={handleFocus} onInput={onchange} onClick={(e)=>{this.handleClick(e);}} onBlur={handleBlur}>
+        {fuzhen?children||fuzhen:children}
+      </div>
+    </div>
+  }
+}
+
+export default ItemBox;

+ 29 - 0
src/common/components/ItemBox/index.less

@@ -0,0 +1,29 @@
+@import "~@less/variables.less";
+
+.box{
+  margin: 2px 20px;
+  .title{
+    width: 65px;
+    float: left;
+    text-align: right;
+    padding-right: 5px;
+    margin-top: 10px;
+    font-size: 14px;
+    font-weight: bold;
+  }
+  .title:after{
+    content: ":";
+  }
+  .content{
+    // height:120px;
+    min-height: 38px;
+    margin-left: 60px;
+    position: relative;
+    padding:5px;
+    outline: none;
+    border-bottom:1px @part-border-color dashed;
+  }
+  .border {
+      border:1px @part-border-color dashed !important;
+  }
+}

二進制
src/common/components/Loading/img/loading.gif


+ 54 - 0
src/common/components/Loading/index.jsx

@@ -0,0 +1,54 @@
+/**
+ * Created by ZN on 2018/5/03.
+ * 可配置属性:
+ * show:为true是才显示,false不显示
+ * text:显示在图标下的文字
+ * img:自定义图标
+ */
+import React, {Component} from 'react';
+/*import PropTypes from 'prop-types';*/
+import style from './index.less';
+import icon from './img/loading.gif';
+
+/*const propTypes = {
+    text: PropTypes.string,
+    show: PropTypes.bool,
+    shadeIsShow: PropTypes.bool
+};
+const defaultProps = {
+    text: '拼命加载中...',
+    shadeIsShow: true
+};*/
+
+// function Loading(props) {
+//     const {text, img, show} = props;
+//     return (
+//         <div className={style['loading']} style={{display: show ? 'block' : 'none'}}>
+//             {props.shadeIsShow?<div className={style['cover']}/>:''}
+//             <div className={style['info']}>
+//                 <img src={img}/>
+//                 <p>{text}</p>
+//             </div>
+//         </div>
+//     )
+// }
+
+class Loading extends React.Component{
+    render(){
+        const {text, img, show} = this.props;
+        return (
+            <div className={style['loading']} style={{display: show ? 'block' : 'none'}}>
+                {this.props.shadeIsShow?<div className={style['cover']}/>:null}
+                <div className={style['info']}>
+                    <img src={icon}/>
+                    <p>{text}</p>
+                </div>
+            </div>
+        )
+    }
+}
+
+/*Loading.propTypes = propTypes;
+Loading.defaultProps = defaultProps;*/
+
+export default Loading;

+ 24 - 0
src/common/components/Loading/index.less

@@ -0,0 +1,24 @@
+.loading{
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 999;
+  .cover{
+    width: 100%;
+    height: 100%;
+    background: #333;
+    opacity: .4;
+    filter:alpha(opacity=40);
+  }
+  .info{
+    position: absolute;
+    top: 40%;
+    left: 45%;//calc(50% - 50px);
+    text-align: center;
+  }
+  p{
+    color: #fff;
+  }
+}

二進制
src/common/components/Message/imgs/fail.png


二進制
src/common/components/Message/imgs/info.png


二進制
src/common/components/Message/imgs/ok.png


+ 56 - 0
src/common/components/Message/index.jsx

@@ -0,0 +1,56 @@
+import React,{Component} from "react";
+import $ from 'jquery';
+import PropTypes from 'prop-types';
+import style from './index.less';
+import ReactDom from "react-dom";
+
+/***
+ * 信息提示框组件(操作结果提示组件变更为Notify)
+ * author: zxc@2018-11-26
+ * 接收参数:
+ * show: 信息提示框是否可见, Boolean
+ * type: 信息提示框类型, 包括success、error、warn。
+ * text: 信息提示框文本内容
+ * 
+***/
+
+
+class Message extends Component{
+    constructor(props){
+        super(props);
+        this.hideMsg = this.hideMsg.bind(this);
+    }
+    hideMsg(){
+        $(this.message).hide();
+    }
+    getStyle(){
+        const {show} = this.props;
+        return {
+            display:show?"block":"none"
+        }
+    }
+    render(){
+        const imgs={
+            success:require("./imgs/ok.png"),
+            error:require("./imgs/fail.png"),
+            warn:require("./imgs/info.png")};
+        const styles = {
+            success: {background:'#f0f9eb',bordeColor:'#e1f3d8',color:'#67c23a'},
+            error: {background:'#fdf6ec',bordeColor:'#faecd8',color:'#e6a23c'},
+            warn:{background:'#fefef0',bordeColor:'#fde2e2',color:'#f56c6c'}
+        }
+        const {text,icon,type} = this.props;
+        const msg = type=='success'?'操作成功':'操作失败';
+        const domNode = document.getElementById('root');
+        return  ReactDom.createPortal(<div className={style["container"]} style={this.getStyle()} ref={(ref) =>this.message = ref}>
+                    <div className={style["message-box"]} style={styles[type]}>
+                        <img src={icon||imgs[type]} />
+                        <p className={style["msg"]}>{text||msg}</p>
+                        <span className={style["close"]} onClick={this.hideMsg}>X</span>
+                    </div>
+                </div>,domNode);
+        };
+}
+
+
+export default Message;

+ 45 - 0
src/common/components/Message/index.less

@@ -0,0 +1,45 @@
+.container{
+  width: 100%;
+  height: 100%;
+  position: fixed;
+  left: 0;
+  top: 0;
+  z-index: 9999;
+}
+.message-box{
+  width: 350px;
+  height:70px;
+  position: absolute;
+  top:50%;
+  left:50%;
+  margin:-35px 0 0  -175px;
+  text-align: center;
+  border-radius: 10px;
+  line-height: 70px;
+  box-sizing: border-box;
+  border: 1px solid;
+  img{
+    position: absolute;
+    // margin: 38px 0 20px;
+    width: 36px;
+    height: 36px;
+    left: 20px;
+    top: 17px;
+  }
+}
+.msg{
+  width: 224px;
+  height: 70px;
+  overflow: hidden;
+  position: absolute;
+  left: 66px;
+  top: 0;
+  text-align: left;
+  font-size: 14px;
+}
+.close{
+  position: absolute;
+  right: 34px;
+  top: 0;
+  color: #464547;
+}

+ 92 - 0
src/common/components/MixCheckBox/index.jsx

@@ -0,0 +1,92 @@
+import React,{Component} from 'react';
+import PropTypes from 'prop-types';
+import style from './index.less';
+import Select from '../CheckBox/Select';
+import Radio from '../RadioB';
+import Normal from '../Normal';
+import CheckBox from '../CheckBox';
+import className from 'classnames';
+import Multiple from '../CheckBox/Multiple';
+
+/***
+单选多选混合组件
+接收参数:
+datas:数据源,为数组,必须;
+showDrop:控制填写单显示与隐藏,必须;
+confirmCheckBox:点击确定,必须
+clearCheckBox:点击清空,必须
+noSpecial:无殊选中标识,true为选中,有无殊时必须;
+noSpecialFlag:互斥标识,2选中其他 1选中无殊 0默认无选中;
+noSpecialClick:无殊点击事件;
+handleRadioClick:单选点击事件,有单选列时必须;
+handleCheckBoxClick:多选点击事件,有多选时必须;
+**/
+
+class MixCheckBox extends React.Component{
+  constructor(props){
+    super(props);
+    this.handleBtnConfirm = this.handleBtnConfirm.bind(this);
+    this.handleBtnClear = this.handleBtnClear.bind(this);
+  }
+
+  getLabs(){
+    const {datas,noSpecial,noSpecialFlag,noSpecialClick,checkBoxId,flag} = this.props;
+    let list = datas && datas.map((v,i)=>{
+      if(+v.formPosition == 1){//正常无殊
+         return <Normal datas={v.questionDetailList} noSpecialFlag={noSpecialFlag} noSpecial={noSpecial} noSpecialClick={noSpecialClick}/>
+      }else{
+        if(v.controlType==1 && v.formPosition !== 1){//单选
+          return <Radio datas={v.questionDetailList} handleClick={this.props.handleCheckBoxClick} parentId={v.id} disabled={noSpecialFlag}/>;
+        }else if(v.controlType==2){//2多选
+          return <Select datas={v.questionDetailList} handleClick={this.props.handleCheckBoxClick} parentId={v.id} noSpecialFlag={noSpecialFlag} checkBoxId={checkBoxId} flag={flag}/>
+        }
+        /*else if(v.controlType==4 || v.controlType==99){//4 伴/无 99推送
+          return <Multiple datas={v.questionDetailList} handleClick={this.props.handleCheckBoxClick} parentId={v.id} />
+        }*/
+      }
+    })
+    return list;
+  }
+
+  handleBtnConfirm(e){//确定
+    e.stopPropagation();
+    const {confirmCheckBox,checkBoxId,flag} = this.props;
+    let item = {
+      checkBoxId,
+      flag
+    };
+    confirmCheckBox && confirmCheckBox(item);   
+  }
+
+  handleBtnClear(e){//清空
+    e.stopPropagation();
+    const {clearCheckBox,checkBoxId,flag} = this.props;
+    let item = {
+      checkBoxId,
+      flag
+    };
+    clearCheckBox && clearCheckBox(item);
+  }
+
+  getContainerStyle(){
+    const {showDrop} = this.props;
+    const isShow = showDrop?'':style['ishide'];
+    return className(style['cb-container'],isShow);
+  }
+  render(){
+    return <div className={this.getContainerStyle()} >
+          <div style={{whiteSpace: 'nowrap'}}>{this.getLabs()}</div>
+          <div className={style['btn']}>
+            <button onClick={this.handleBtnClear} className={style['clear']}>清空选项</button>
+            <button onClick={this.handleBtnConfirm} className={style['confirm']}>确定</button> 
+          </div>         
+        </div>
+    }
+}
+
+MixCheckBox.propTypes = {
+    handleClick:PropTypes.func,
+    items:PropTypes.array
+};
+export default MixCheckBox;
+

+ 68 - 0
src/common/components/MixCheckBox/index.less

@@ -0,0 +1,68 @@
+@import "~@less/variables.less";
+.cb-container{
+  // width: 277px;
+  min-width: 216px;
+  padding: 10px;
+  position: absolute;
+  top: 25px;
+  left: -62px;
+  background: #fff;
+  z-index: 12;
+  box-shadow: 0 10px 20px 0 rgba(194,194,194,0.50);
+}
+.clear{
+  width: 88px;
+  height: 44px;
+  line-height: 44px;
+  font-size: 12px;
+  color:#FF0000;
+  border: none;
+  background: #fff;
+  float: left;
+}
+.confirm{
+  width: 88px;
+  height: 44px;
+  line-height: 44px;
+  color:#3B9ED0;
+  font-size: 12px;
+  border: 1px solid #3B9ED0;
+  background: #fff;
+  margin-left: 20px;
+  float: right;
+}
+.sentence{
+  width: 100%;
+  height: 54px;
+  border-bottom: 1px solid #EAEDF1;
+  margin-bottom: 15px;
+  span{
+    color:#000000;
+    display: inline-block;
+    height: 44px;
+    line-height: 44px;
+    padding: 0 10px 0 30px;
+  }
+}
+.selected-span{
+  background: rgba(59,158,208,0.1);
+  background-image: url(../../images/first.png);
+  background-repeat: no-repeat;
+  background-position: 12px 15px;
+}
+.disabled{
+  opacity: 0.3;
+}
+.multiple-tab{
+  // width: 200px;
+  vertical-align: top;
+}
+.multiple-con{
+  // width: 140px;
+  margin-left: 10px;
+  display: inline-block;
+  vertical-align: top;
+}
+.ishide{
+  .hide;
+}

+ 24 - 0
src/common/components/Modal/body/ModalBody.jsx

@@ -0,0 +1,24 @@
+import React, {Component} from "react";
+import classNames from 'classnames';
+
+import styles from "./index.less";
+
+class ModalBody extends Component {
+    constructor(props) {
+        super(props);
+    }
+
+    render() {
+        const  {overflow, children} = this.props;
+        let bodyStyle = {
+            overflowY: overflow ? "auto": "hide"
+        };
+        return (
+            <div className={styles['modal-body']} style={bodyStyle}>
+                {children ? children : <div className="paragraph"> </div>}
+            </div>
+        );
+    }
+}
+
+export default ModalBody;

+ 10 - 0
src/common/components/Modal/body/index.less

@@ -0,0 +1,10 @@
+@media print {
+    .modal-body{
+        overflow-y: visible!important;
+        page-break-after:always;
+    }
+}
+.modal-body {
+    padding: 10px 20px 0 20px;
+    height: 85%;
+}

+ 30 - 0
src/common/components/Modal/footer/ModalFooter.jsx

@@ -0,0 +1,30 @@
+import React, {Component} from "react";
+import classNames from 'classnames';
+
+import styles from "./index.less";
+
+class ModalFooter extends Component {
+
+
+    render() {
+        const {btnName, handleCancel, handleConfirm} = this.props;
+        const cancelClass = {
+            overflow: "hidden",
+            position: "relative",
+            'WebkitTransition':'color .2s linear,background-color .3s linear',
+            'transition': 'color .2s linear,background-color .3s linear',
+            'color':'#8e8e93',
+            'backgroundColor': 'transparent'
+        }
+        const btnClass = classNames(`${styles.btn} ${styles[btnName] || styles['primary']}`);
+
+        return (
+            <div className={styles['modal-footer']}>
+                <button className={btnClass} onClick={handleConfirm}>确定</button>
+                <button className={btnClass} style={cancelClass} onClick={handleCancel}>取消</button>
+            </div>
+        );
+    }
+}
+
+export default ModalFooter;

+ 31 - 0
src/common/components/Modal/footer/index.less

@@ -0,0 +1,31 @@
+
+.modal-footer {
+    position: absolute;
+    bottom: 20px;
+    right: 30px;
+}
+.primary {
+    overflow: hidden;
+    position: relative;
+    color: #fff;
+    background-color: #34c3ff;
+}
+
+.btn {
+    display: inline-block;
+    margin-bottom: 0;
+    font-weight: 400;
+    text-align: center;
+    vertical-align: middle;
+    outline: 0!important;
+    white-space: nowrap;
+    border: none;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    padding: 8px 12px;
+    font-size: 14px;
+    line-height: 1.42857143;
+    border-radius: 6px;
+}

+ 38 - 0
src/common/components/Modal/header/ModalHeader.jsx

@@ -0,0 +1,38 @@
+import React, {Component} from "react";
+import { findDOMNode } from 'react-dom';
+import classNames from 'classnames';
+import $ from 'jquery'
+
+import styles from "./index.less";
+
+class ModalHeader extends Component {
+    constructor(props) {
+        super(props);
+        this.handleClickClose = this.handleClickClose.bind(this);
+    }
+    handleClickClose() {
+        const {handleClose} = this.props;
+        if(handleClose) {
+            handleClose();
+        }
+		if($('#stateShow').length) {
+			$("#stateShow").css("display","none");
+		}
+		$(".src-modules-pageLeft-1SHS6").css("z-index","8")
+    }
+    render() {
+        const {title} = this.props;
+
+        return (
+            
+            <div className={styles['modal-header']}>
+                <button type="button" className={styles['close']} aria-label="Close" onClick={this.handleClickClose}>
+                    <span aria-hidden="true">X</span>
+                </button>
+                {title ? <h4 className={styles['title']}>{title}</h4>: null}
+            </div>
+        );
+    }
+}
+
+export default ModalHeader;

+ 46 - 0
src/common/components/Modal/header/index.less

@@ -0,0 +1,46 @@
+@import "~@less/variables.less";
+
+@media print{
+    .modal-header{
+        .close{
+            display: none;
+        }
+    }
+}
+
+.modal-header {
+    padding:0 20px;   
+    padding:10px 20px 0px 20px\0;
+    min-height: 40px;
+    line-height: 40px;
+    background: #e5e5e5;
+    border-top-left-radius: @border-radius;
+    border-top-right-radius: @border-radius;
+    .close{
+        outline: 0;
+        position: absolute;
+        right: 20px;
+        top: 10px;
+        font-size: 12px;
+        line-height: 1.66666667;
+        color: #272c36;
+        width: 20px;
+        padding: 0 4px;
+        background: none;
+        border-style: none;
+    }
+    .title {
+        display: block;
+        color: #272c36;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        width: 100%;
+        line-height: 0\0;  //ie8打印修正
+    }
+}
+@media screen and(-ms-high-contrast:active),(-ms-high-contrast:none) {
+    .modal-header{
+        padding:5px 20px 0px;
+    }
+}

+ 130 - 0
src/common/components/Modal/index.jsx

@@ -0,0 +1,130 @@
+/**
+ * 模态框
+ * Created by DELL on 2018/4/24.
+ */
+import React, {Component} from "react";
+/*import PropTypes from 'prop-types';*/
+import { findDOMNode } from 'react-dom';
+import classNames from 'classnames';
+import {$$} from '@lib';
+
+// import $ from "jquery";
+import ModalHeader from "./header/ModalHeader.jsx";
+import ModalBody from "./body/ModalBody.jsx";
+import ModalFooter from "./footer/ModalFooter.jsx";
+
+import styles from "./index.less";
+
+/*const propTypes = {
+    autoResizeHeight: PropTypes.bool,
+    overflow: PropTypes.bool,
+    onClickCancel: PropTypes.func,
+    onClickConfirm: PropTypes.func,
+    onClickClose: PropTypes.func
+}
+const defaultProps = {
+    overflow: true,
+    autoResizeHeight: true
+};*/
+
+class Modal extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            modalStyle : {},
+            bodyStyles: {},
+            maxHeight: null,
+            overflow: null,
+            show: this.props.show || true
+        }
+        
+        this.handleConfirm = this.handleConfirm.bind(this);
+        this.handleCancel = this.handleCancel.bind(this);
+        this.handleClose = this.handleClose.bind(this);
+        
+        this.handleWindowResize = this.handleWindowResize.bind(this);
+        this.getStyles = this.getStyles.bind(this);
+    }
+    handleConfirm() {
+        this.setState({
+            show: false
+        });
+        const {onClickConfirm} = this.props;
+        onClickConfirm && onClickConfirm();
+    }
+    handleCancel() {
+        this.setState({
+            show: false
+        });
+        const {onClickCancel} = this.props;
+        onClickCancel && onClickCancel();
+        
+    }
+    handleClose() {
+
+        const that = this;
+        const {onClickClose} = this.props;
+        onClickClose && onClickClose(function () {
+            that.setState({
+                show: false
+            });
+        });
+    }
+    getStyles() {
+        const styles = {};
+        const {autoResizeHeight} = this.props;
+        if (autoResizeHeight) {
+            const excludeHeight = 150;
+            const contentHeight = $$.getHeight(window) - excludeHeight;
+
+            styles.bodyStyles = {
+              maxHeight: contentHeight
+            };
+        }
+        return styles;
+    }
+    handleWindowResize() {
+        this.setState(this.getStyles());
+    }
+    componentDidMount() {
+       this.setState(this.getStyles());
+       $$.$window.on("resize", this.handleWindowResize);
+    }
+    render() {
+        const {
+            width,
+            title,
+            overflow,
+            noFooter,
+            children
+        } = this.props;
+        
+        this.state.modalStyle= {
+            display: this.state.show ? "block" : "none",
+            padding: "0 20px"
+        };
+
+        let maxHeight = this.state.bodyStyles.maxHeight;
+        
+        let contentClass = classNames(`${styles['content']}`);
+        return (
+            <div style={this.state.modalStyle} ref={(ref) => {this.dialog = ref;}} >
+                <div className={styles['backdrop']}></div>
+                <div className={contentClass} style={{width,  height:maxHeight}} >
+                    <ModalHeader title={title||"title"} handleClose={this.handleClose}/>
+                    <ModalBody children={children} overflow={overflow}/>
+                    {noFooter ? null : <ModalFooter handleCancel={this.handleCancel} handleConfirm={this.handleConfirm}/>}
+                </div>
+            </div>
+        );
+    }
+}
+
+/*Modal.propTypes = propTypes;
+Modal.defaultProps = defaultProps;*/
+
+Modal.header = ModalHeader;
+Modal.body = ModalBody;
+Modal.footer = ModalFooter;
+
+export default Modal;

+ 31 - 0
src/common/components/Modal/index.less

@@ -0,0 +1,31 @@
+
+@import "~@less/variables.less";
+
+.backdrop {
+    position: fixed;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 1001;
+    background-color: #272c36;
+    -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; /*IE8*/  
+    // filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);//兼容ie8及以下/
+    filter: alpha(opacity=30);  /*IE5、IE5.5、IE6、IE7*/  
+    opacity: .3;
+}
+.content {
+    background: #fff;
+    height: 485px;
+    min-height: 400px;
+    width: 720px;
+    min-width: 666px;
+    margin: 0 auto;
+    margin-top: 65px;
+    overflow-y: auto;
+
+    position: relative;
+    max-width: 720px;
+    z-index: 1050;
+    border-radius: @border-radius;
+}

+ 55 - 0
src/common/components/Normal/index.jsx

@@ -0,0 +1,55 @@
+
+import React,{Component} from 'react';
+import PropTypes from 'prop-types';
+import style from './index.less';
+/***
+下拉框无殊组件
+datas:父组件传来的数据,为数组,必须
+noSpecialFlag:互斥标识,2选中其他 1选中无殊 0默认无选中;
+noSpecial:选中标识,true选中,
+noSpecialClick:点击事件
+**/
+class Normal extends React.Component{
+  constructor(props){
+    super(props);
+    this.preventS = this.preventS.bind(this);
+  }
+
+  preventS(e){
+    e.stopPropagation();
+  }
+
+  handleClick(name){
+    const {noSpecialClick} =this.props;
+    noSpecialClick && noSpecialClick(name);
+  }
+
+  getLabs(){
+    const {noSpecialFlag,noSpecial,noSpecialClick,datas} =this.props;
+    if(noSpecialFlag ==1){
+      let list = datas.map((it,i)=>{
+        return <span className={style['disabled']} >{it.name}</span>
+      })
+      return list;
+    }else{
+      let list = datas.map((it,i)=>{
+        return <span className={noSpecial?style['selected-span']:''} onClick={()=>{this.handleClick(it.name)}}>{it.name}</span>
+      })
+      return list;
+    }
+  }
+
+  render(){
+    return <div className={style['sentence']} contentEditable='false' onClick={this.preventS}>
+      {this.getLabs()}
+    </div>
+  }
+}
+
+Normal.propTypes = {
+    handleClick:PropTypes.func,
+    noSpecial:PropTypes.bool,
+    datas:PropTypes.array
+};
+
+export default Normal;

+ 22 - 0
src/common/components/Normal/index.less

@@ -0,0 +1,22 @@
+.sentence{
+  width: 100%;
+  height: 54px;
+  border-bottom: 1px solid #EAEDF1;
+  margin-bottom: 15px;
+  span{
+    color:#000000;
+    display: inline-block;
+    height: 44px;
+    line-height: 44px;
+    padding: 0 10px 0 30px;
+  }
+}
+.selected-span{
+  background: rgba(59,158,208,0.1);
+  background-image: url(../../images/first.png);
+  background-repeat: no-repeat;
+  background-position: 12px 15px;
+}
+.disabled{
+  opacity: 0.3;
+}

二進制
src/common/components/Notify/img/close.png


+ 47 - 0
src/common/components/Notify/index.js

@@ -0,0 +1,47 @@
+import React from 'react'
+import ReactDOM from 'react-dom'
+import Notify from './notify'
+
+/***
+ * 信息提示框组件
+ * author: zxc@2018-11-28
+ * 接收参数:
+ * type: 信息提示框类型, 包括success、error、info。
+ * content: 信息提示框文本内容
+ * duration: 自动关闭的延时,单位毫秒。默认3000毫秒,设为 0 时不自动关闭。
+ * 用法如下:
+ * Notify.success('删除成功')
+***/
+
+function createNotification() {
+    const div = document.createElement('div')
+    document.body.appendChild(div)
+    const notification = ReactDOM.render(<Notify />, div)
+    return {
+        addNotice(notice) {
+            return notification.addNotice(notice)
+        },
+        destroy() {
+            ReactDOM.unmountComponentAtNode(div)
+            document.body.removeChild(div)
+        }
+    }
+}
+
+let notification
+const notice = (type, content, duration=3000, onClose) => {
+    if (!notification) notification = createNotification()
+    return notification.addNotice({ type, content, duration, onClose })
+}
+
+export default {
+    info(content, duration, onClose) {
+        return notice('info', content, duration, onClose)
+    },
+    success(content = '操作成功', duration, onClose) {
+        return notice('success', content, duration, onClose)
+    },
+    error(content, duration , onClose) {
+        return notice('error', content, duration, onClose)
+    }
+}

文件差異過大導致無法顯示
+ 81 - 0
src/common/components/Notify/index.less


+ 83 - 0
src/common/components/Notify/notify.js

@@ -0,0 +1,83 @@
+import React, { Component } from 'react';
+import style from './index.less';
+import className from 'classnames'
+import close from "./img/close.png";
+
+class NotifyBox extends Component {
+    constructor() {
+        super()
+        this.transitionTime = 300
+        this.state = { notices: [] ,timer:null}
+        this.removeNotice = this.removeNotice.bind(this)
+    }
+
+    getNoticeKey() {
+        const { notices } = this.state
+        return `notice-${new Date().getTime()}-${notices.length}`
+    }
+
+    addNotice(notice) {
+        const { notices } = this.state
+        notice.key = this.getNoticeKey()
+
+        // notices.push(notice);//展示所有的提示
+        notices[0] = notice;//仅展示最后一个提示
+        
+        this.setState({ notices })
+        if (notice.duration > 0) {
+            clearTimeout(this.state.timer);
+            const timer = setTimeout(() => {
+                this.removeNotice(notice.key)
+            }, notice.duration)
+            this.setState({timer})
+        }
+        return () => { this.removeNotice(notice.key) }
+    }
+
+    removeNotice(key) {
+        const { notices } = this.state
+        this.setState({
+            notices: notices.filter((notice) => {
+                if (notice.key === key) {
+                    if (notice.onClose) setTimeout(notice.onClose, this.transitionTime)
+                    return false
+                }
+                return true
+            })
+        })
+    }
+
+    render() {
+        const { notices } = this.state
+        const icons = {
+            info: 'notify-info',
+            success: 'notify-success',
+            error: 'notify-error',
+        }
+        const styles = {
+            success: {background:'#000',color:'#fff',opacity:'0.8'},
+            error: {background:'#000',color:'#fff',opacity:'0.8'},
+            info:{background:'#000',color:'#fff',opacity:'0.8'}
+            // success: {background:'#7F7F7F',color:'#fff'},
+            // error: {background:'#7F7F7F',color:'#fff'},
+            // info:{background:'#7F7F7F',color:'#fff'}
+        }
+        return (
+            <div className={style["notify"]}>
+                {
+                    notices.map(notice => (
+                        <div className={style["notify-bg"]} key={notice.key}>
+                            <div className={style['notify-box']} style={styles[notice.type]}>
+                                <div className={style[`${icons[notice.type]}`]}></div>
+                                <div className={style['notify-text']}>{notice.content}</div>
+                                <img  className={style['notify-close']} onClick={()=>{this.removeNotice(notice.key)}} src={close}/>
+                            </div>
+                        </div>
+                    ))
+                }
+            </div>
+        )
+    }
+}
+
+export default NotifyBox

+ 81 - 0
src/common/components/NumberPan/index.jsx

@@ -0,0 +1,81 @@
+import React,{Component} from 'react';
+import style from './index.less';
+
+class NumberPan extends Component{
+  constructor(props){
+    super(props);
+    this.state = {
+      value:''
+    }
+  }
+  handleSelect(e){
+    e.stopPropagation();
+    const text = e.target.innerText;
+    const value = this.props.toClear?'':this.state.value;     //键盘输入替换已有的值
+    const onSelect = this.props.handleSelect;
+    this.setState({
+      value: value+text
+    });
+    onSelect&&onSelect(value+text);
+  }
+  handleClear(e){
+    e.stopPropagation();
+    const onSelect = this.props.handleSelect;
+    this.setState({
+      value: ''
+    });
+    onSelect&&onSelect('');
+  }
+  handleClose(e){
+    e.stopPropagation();
+    //关闭弹窗
+    const {onClose} = this.props;
+    onClose&&onClose();
+  }
+  handleBack(e){
+    e.stopPropagation();
+    const value = this.state.value;
+    const len = value.length-1;
+    if(len<0){
+      return;
+    }
+    const onSelect = this.props.handleSelect;
+    const text = value.substring(0,len);
+    this.setState({
+      value:text
+    });
+    onSelect&&onSelect(text);
+  }
+  render(){
+    const select = this.handleSelect.bind(this);
+    const {show} = this.props;      //table onBlur阻止冒泡是为了修复multSpread中数字键盘点击触发最外层数字组件onBlur事件
+    return <table className={style['pan']} onBlur={(e)=>e.stopPropagation()} style={{display:show?'table':'none'}}>
+      <tr>
+        <td><button onClick={select}>1</button></td>
+        <td><button onClick={select}>2</button></td>
+        <td><button onClick={select}>3</button></td>
+        <td><button onClick={select}>/</button></td>
+      </tr>
+      <tr>
+        <td><button onClick={select}>4</button></td>
+        <td><button onClick={select}>5</button></td>
+        <td><button onClick={select}>6</button></td>
+        <td><button onClick={this.handleBack.bind(this)}>回退</button></td>
+      </tr>
+      <tr>
+        <td><button onClick={select}>7</button></td>
+        <td><button onClick={select}>8</button></td>
+        <td><button onClick={select}>9</button></td>
+        <td><button onClick={this.handleClear.bind(this)}>清空</button></td>
+      </tr>
+      <tr>
+        <td><button onClick={select}>.</button></td>
+        <td><button onClick={select}>0</button></td>
+        <td><button onClick={select}>~</button></td>
+        <td><button onClick={this.handleClose.bind(this)}>确定</button></td>
+      </tr>
+    </table>
+  }
+}
+
+export default NumberPan;

+ 20 - 0
src/common/components/NumberPan/index.less

@@ -0,0 +1,20 @@
+@import "~@less/variables.less";
+.pan{
+  width: 280px;
+  .pop;
+  td{
+    width: 68px;
+    height:44px;
+  }
+  button{
+    border:1px #fff solid;
+    outline: none;
+    background: none;
+    display: inline-block;
+    width: 100%;
+    height: 100%;
+  }
+  button:hover{
+    border-color: @blue;
+  }
+}

+ 100 - 0
src/common/components/NumberUnitPan/index.jsx

@@ -0,0 +1,100 @@
+import React,{Component} from 'react';
+import style from './index.less';
+import config from '@config/index.js';
+import Notify from '../Notify/index.js';
+
+class NumberUnitPan extends Component{
+  constructor(props){
+    super(props);
+    this.state = {
+      value:''
+    }
+    this.handleSelect = this.handleSelect.bind(this);
+  }
+  handleSelect(e){
+    e.stopPropagation();
+    const text = e.target.innerText;
+    const preValue = this.state.value;
+    if(+text==0 && !preValue){//第一位不能是0
+      Notify.info("请输入正确时间");
+      return false;
+    }
+    const value = this.props.toClear?'':this.state.value;     //键盘输入替换已有的值
+    const onSelect = this.props.handleSelect;
+    this.setState({
+      value: value+text
+    });
+    onSelect&&onSelect(value+text);
+  }
+  handleClear(e){
+    e.stopPropagation();
+    const onSelect = this.props.handleSelect;
+    this.setState({
+      value: ''
+    });
+    onSelect&&onSelect('');
+  }
+  handleClose(e){
+    e.stopPropagation();
+    //关闭弹窗
+    const {onClose} = this.props;
+    onClose&&onClose();
+  }
+  handleBack(e){
+    e.stopPropagation();
+    // const value = this.state.value;
+    const value = this.props.value;
+    const len = value.length-1;
+    if(len<0){
+      return;
+    }
+    const onSelect = this.props.handleSelect;
+    const text = value.substring(0,len);
+    this.setState({
+      value:text
+    });
+    onSelect&&onSelect(text);
+  }
+  render(){
+    // const select = this.handleSelect.bind(this);
+    const {show} = this.props;      //table onBlur阻止冒泡是为了修复multSpread中数字键盘点击触发最外层数字组件onBlur事件
+    return <table className={style['pan']} onBlur={(e)=>e.stopPropagation()} style={{display:show?'table':'none'}}>
+      <tr>
+        <td><span onClick={this.handleSelect}>1</span></td>
+        <td><span onClick={this.handleSelect}>2</span></td>
+        <td><span onClick={this.handleSelect}>3</span></td>
+        <td><span onClick={this.handleSelect}>/</span></td>
+      </tr>
+      <tr>
+        <td><span onClick={this.handleSelect}>4</span></td>
+        <td><span onClick={this.handleSelect}>5</span></td>
+        <td><span onClick={this.handleSelect}>6</span></td>
+        <td><span onClick={this.handleBack.bind(this)}>回退</span></td>
+      </tr>
+      <tr>
+        <td><span onClick={this.handleSelect}>7</span></td>
+        <td><span onClick={this.handleSelect}>8</span></td>
+        <td><span onClick={this.handleSelect}>9</span></td>
+        <td><span onClick={this.handleClear.bind(this)}>清空</span></td>
+      </tr>
+      <tr>
+        <td><span onClick={this.handleSelect}>.</span></td>
+        <td><span onClick={this.handleSelect}>0</span></td>
+        <td><span onClick={this.handleSelect}>~</span></td>
+        <td><span onClick={this.handleClose.bind(this)}>确定</span></td>
+      </tr>
+      <tr>
+        <td><span onClick={this.handleSelect}>{config.timeUnit.minute}</span></td>
+        <td><span onClick={this.handleSelect}>{config.timeUnit.hour}</span></td>
+        <td><span onClick={this.handleSelect}>{config.timeUnit.day}</span></td>
+      </tr>
+      <tr>
+        <td><span onClick={this.handleSelect}>{config.timeUnit.week}</span></td>
+        <td><span onClick={this.handleSelect}>{config.timeUnit.month}</span></td>
+        <td><span onClick={this.handleSelect}>{config.timeUnit.year}</span></td>
+      </tr>
+    </table>
+  }
+}
+
+export default NumberUnitPan;

+ 24 - 0
src/common/components/NumberUnitPan/index.less

@@ -0,0 +1,24 @@
+@import "~@less/variables.less";
+.pan{
+  width: 280px;
+  .pop;
+  td{
+    width: 68px;
+    height:44px;
+  }
+  span{
+    border:1px #fff solid;
+    outline: none;
+    background: none;
+    display: inline-block;
+    width: 100%;
+    height: 100%;
+    text-align: center;
+    line-height: 44px;
+    color: #666;
+    cursor: pointer;
+  }
+  span:hover{
+    border-color: @blue;
+  }
+}

二進制
src/common/components/Radio/img/disable.png


二進制
src/common/components/Radio/img/no.png


二進制
src/common/components/Radio/img/off.png


二進制
src/common/components/Radio/img/on.png


二進制
src/common/components/Radio/img/select.png


+ 65 - 0
src/common/components/Radio/index.js

@@ -0,0 +1,65 @@
+import React from 'react';
+/*import PropTypes from 'prop-types';*/
+import on from './img/on.png';
+import off from './img/off.png';
+import disable from './img/disable.png';
+import style from './index.less';
+
+/**
+ * 单选按钮
+ * handleClick:点击触发按键 会将输入的props信息作为参数传入
+ * isSelect:是否选中
+ * name:右侧显示文字
+ */
+class Radio extends React.Component {
+    constructor(props){
+        super(props);
+        this.handleClick = this.handleClick.bind(this);
+    }
+
+    handleClick(id){
+        this.props.handleClick(id);
+    }
+
+    getStyle(){
+        if(this.props.display=='block'){
+            return {
+                display:'block',
+                // marginBottom:'10px'
+            }
+        }
+        return {
+            display:'inline-block',
+            marginLeft:'10px'
+        }
+    }
+
+    render() {
+        const {id,name,isSelect,disabled} = this.props;
+        if(disabled){
+            return (
+                <div className={style['radio']}
+                     style={this.getStyle()}>
+                    <img src={isSelect?disable:off}/>
+                    <span style={{color:'#aaa'}}>{name}</span>
+                </div>
+            )
+        }
+        return (
+            <div className={style['radio']}
+                 onClick={() =>this.handleClick(id)}
+                 style={this.getStyle()}>
+                <img src={isSelect?on:off}/>
+                <span>{name}</span>
+            </div>
+        )
+    }
+}
+
+/*Radio.propTypes = {
+    handleClick:PropTypes.func,
+    isSelect:PropTypes.bool,
+    name:PropTypes.string
+};*/
+
+export default Radio;

+ 10 - 0
src/common/components/Radio/index.less

@@ -0,0 +1,10 @@
+.radio{
+  width: 120px;
+  height: 44px;
+  line-height: 44px;
+  cursor: pointer;
+  img{
+    vertical-align: middle;
+    margin-right: 6px;
+  }
+}

+ 63 - 0
src/common/components/RadioB/index.jsx

@@ -0,0 +1,63 @@
+import React,{Component} from 'react';
+import PropTypes from 'prop-types';
+import style from './index.less';
+
+/**
+多列单选组件
+datas:父组件传来的数组,必须...
+parentId:每一列的id
+id:标签的id
+isSelect:是否选中
+disabled:禁用标识(互斥)
+*/
+
+class RadioB extends React.Component{
+  constructor(props){
+    super(props);
+    this.handleClick = this.handleClick.bind(this);
+  }
+
+  handlePreventClick(e){
+    e.stopPropagation();
+  }
+
+  handleClick(id){
+    const {handleClick,parentId} = this.props;
+    const items = {
+      id,
+      parentId
+    }
+    handleClick && handleClick(items);   
+  }
+
+  getLabs(){
+    const {disabled,datas} = this.props;
+    if(disabled==2){
+      return <div className={style['radio']} contentEditable='false' onClick={this.handlePreventClick}>
+          {datas.map((item,i)=>{
+            return <p className={`${style['tab']} ${style['disabled']}`} contentEditable='false'>{item.name.length>8?item.name.slice(0,7)+'...':item.name}</p>
+          })}
+      </div>
+    }
+    let list = datas.map((item,i)=>{
+            return <div className={item.isSelect?`${style['radio']} ${style['selected']}`:style['radio']} contentEditable='false' onClick={this.handlePreventClick}>
+              <p onClick={()=>this.handleClick(item.id)} className={style['tab']} contentEditable='false'>{item.name.length>8?item.name.slice(0,7)+'...':item.name}</p>
+            </div>
+          })
+    return list;
+  }
+
+  render(){
+    return <div className={style['radio-box']}>
+      {this.getLabs()}
+    </div>
+  }
+}
+
+RadioB.propTypes = {
+  handleClick:PropTypes.func,
+  isSelect:PropTypes.bool,
+  datas:PropTypes.array
+};
+
+export default RadioB;

+ 28 - 0
src/common/components/RadioB/index.less

@@ -0,0 +1,28 @@
+
+.radio-box{
+  display: inline-block;
+  vertical-align: top;
+  margin-left: 10px;
+}
+.radio{
+  // width: 120px;
+  height: 44px;
+  line-height: 44px;
+  cursor: pointer;
+  display: block;
+  padding-left: 10px;
+  
+  .tab{
+    color:#000000;
+    padding:0 10px 0 20px;
+  }
+  .disabled{
+    opacity: 0.3;
+  }
+}
+.selected{
+    background: rgba(59,158,208,0.1);
+    background-image: url(../../images/first.png);
+    background-repeat: no-repeat;
+    background-position: 12px 15px;
+  }

二進制
src/common/components/SearchOption/imgs/clear.png


二進制
src/common/components/SearchOption/imgs/search.png


+ 0 - 0
src/common/components/SearchOption/index.jsx


部分文件因文件數量過多而無法顯示