浏览代码

前端代码

sunyadv 5 年之前
父节点
当前提交
e2dac2624e
共有 65 个文件被更改,包括 14568 次插入0 次删除
  1. 5 0
      fhKeeper/formulahousekeeper/timesheet/.babelrc
  2. 8 0
      fhKeeper/formulahousekeeper/timesheet/.gitignore
  3. 21 0
      fhKeeper/formulahousekeeper/timesheet/LICENSE
  4. 0 0
      fhKeeper/formulahousekeeper/timesheet/README.md
  5. 35 0
      fhKeeper/formulahousekeeper/timesheet/build/build.js
  6. 48 0
      fhKeeper/formulahousekeeper/timesheet/build/check-versions.js
  7. 9 0
      fhKeeper/formulahousekeeper/timesheet/build/dev-client.js
  8. 89 0
      fhKeeper/formulahousekeeper/timesheet/build/dev-server.js
  9. 72 0
      fhKeeper/formulahousekeeper/timesheet/build/utils.js
  10. 12 0
      fhKeeper/formulahousekeeper/timesheet/build/vue-loader.conf.js
  11. 67 0
      fhKeeper/formulahousekeeper/timesheet/build/webpack.base.conf.js
  12. 38 0
      fhKeeper/formulahousekeeper/timesheet/build/webpack.dev.conf.js
  13. 124 0
      fhKeeper/formulahousekeeper/timesheet/build/webpack.prod.conf.js
  14. 6 0
      fhKeeper/formulahousekeeper/timesheet/config/dev.env.js
  15. 51 0
      fhKeeper/formulahousekeeper/timesheet/config/index.js
  16. 3 0
      fhKeeper/formulahousekeeper/timesheet/config/prod.env.js
  17. 二进制
      fhKeeper/formulahousekeeper/timesheet/favicon.ico
  18. 48 0
      fhKeeper/formulahousekeeper/timesheet/index.html
  19. 9567 0
      fhKeeper/formulahousekeeper/timesheet/package-lock.json
  20. 77 0
      fhKeeper/formulahousekeeper/timesheet/package.json
  21. 59 0
      fhKeeper/formulahousekeeper/timesheet/src/App.vue
  22. 17 0
      fhKeeper/formulahousekeeper/timesheet/src/api/api.js
  23. 3 0
      fhKeeper/formulahousekeeper/timesheet/src/api/index.js
  24. 539 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/demo.css
  25. 377 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/demo_index.html
  26. 53 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.css
  27. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.eot
  28. 1 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.js
  29. 53 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.svg
  30. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.ttf
  31. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.woff
  32. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.woff2
  33. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/047_S.jpg
  34. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/404.png
  35. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/background.png
  36. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/close.gif
  37. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/head_logo.png
  38. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/login_center.png
  39. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/login_logo.png
  40. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/noPic.jpg
  41. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/noPic.png
  42. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/userHead.jpg
  43. 二进制
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/userHead.png
  44. 72 0
      fhKeeper/formulahousekeeper/timesheet/src/common/js/util.js
  45. 0 0
      fhKeeper/formulahousekeeper/timesheet/src/components/.gitkeep
  46. 198 0
      fhKeeper/formulahousekeeper/timesheet/src/http.js
  47. 110 0
      fhKeeper/formulahousekeeper/timesheet/src/main.js
  48. 118 0
      fhKeeper/formulahousekeeper/timesheet/src/port.js
  49. 86 0
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  50. 61 0
      fhKeeper/formulahousekeeper/timesheet/src/views/404.vue
  51. 628 0
      fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue
  52. 123 0
      fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue
  53. 214 0
      fhKeeper/formulahousekeeper/timesheet/src/views/desktop/detail.vue
  54. 141 0
      fhKeeper/formulahousekeeper/timesheet/src/views/desktop/index.vue
  55. 91 0
      fhKeeper/formulahousekeeper/timesheet/src/views/desktop/unusual.vue
  56. 264 0
      fhKeeper/formulahousekeeper/timesheet/src/views/message.vue
  57. 192 0
      fhKeeper/formulahousekeeper/timesheet/src/views/system/index.vue
  58. 100 0
      fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue
  59. 311 0
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  60. 192 0
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/statistics.vue
  61. 7 0
      fhKeeper/formulahousekeeper/timesheet/src/vuex/actions.js
  62. 4 0
      fhKeeper/formulahousekeeper/timesheet/src/vuex/getters.js
  63. 29 0
      fhKeeper/formulahousekeeper/timesheet/src/vuex/store.js
  64. 0 0
      fhKeeper/formulahousekeeper/timesheet/static/.gitkeep
  65. 245 0
      fhKeeper/formulahousekeeper/timesheet/static/css/public.css

+ 5 - 0
fhKeeper/formulahousekeeper/timesheet/.babelrc

@@ -0,0 +1,5 @@
+{
+  "presets": ["es2015", "stage-2"],
+  "plugins": ["transform-runtime"],
+  "comments": false
+}

+ 8 - 0
fhKeeper/formulahousekeeper/timesheet/.gitignore

@@ -0,0 +1,8 @@
+.DS_Store
+node_modules/
+npm-debug.log
+.editorconfig
+dist/
+.idea/misc.xml
+.idea/modules.xml
+.idea/workspace.xml

+ 21 - 0
fhKeeper/formulahousekeeper/timesheet/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016-present taylorchen709
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 0 - 0
fhKeeper/formulahousekeeper/timesheet/README.md


+ 35 - 0
fhKeeper/formulahousekeeper/timesheet/build/build.js

@@ -0,0 +1,35 @@
+require('./check-versions')()
+
+process.env.NODE_ENV = 'production'
+
+var ora = require('ora')
+var rm = require('rimraf')
+var path = require('path')
+var chalk = require('chalk')
+var webpack = require('webpack')
+var config = require('../config')
+var webpackConfig = require('./webpack.prod.conf')
+
+var 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')
+
+    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.html over file:// won\'t work.\n'
+    ))
+  })
+})

+ 48 - 0
fhKeeper/formulahousekeeper/timesheet/build/check-versions.js

@@ -0,0 +1,48 @@
+var chalk = require('chalk')
+var semver = require('semver')
+var packageConfig = require('../package.json')
+var shell = require('shelljs')
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
+}
+
+var versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  },
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  })
+}
+
+module.exports = function () {
+  var warnings = []
+  for (var i = 0; i < versionRequirements.length; i++) {
+    var mod = versionRequirements[i]
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
+      warnings.push(mod.name + ': ' +
+        chalk.red(mod.currentVersion) + ' should be ' +
+        chalk.green(mod.versionRequirement)
+      )
+    }
+  }
+
+  if (warnings.length) {
+    console.log('')
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log()
+    for (var i = 0; i < warnings.length; i++) {
+      var warning = warnings[i]
+      console.log('  ' + warning)
+    }
+    console.log()
+    process.exit(1)
+  }
+}

+ 9 - 0
fhKeeper/formulahousekeeper/timesheet/build/dev-client.js

@@ -0,0 +1,9 @@
+/* eslint-disable */
+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()
+  }
+})

+ 89 - 0
fhKeeper/formulahousekeeper/timesheet/build/dev-server.js

@@ -0,0 +1,89 @@
+require('./check-versions')()
+
+var config = require('../config')
+if (!process.env.NODE_ENV) {
+  process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
+}
+
+var opn = require('opn')
+var path = require('path')
+var express = require('express')
+var webpack = require('webpack')
+var proxyMiddleware = require('http-proxy-middleware')
+var webpackConfig = require('./webpack.dev.conf')
+
+// default port where dev server listens for incoming traffic
+var port = process.env.PORT || config.dev.port
+// automatically open browser, if not set will be false
+var autoOpenBrowser = !!config.dev.autoOpenBrowser
+// Define HTTP proxies to your custom API backend
+// https://github.com/chimurai/http-proxy-middleware
+var proxyTable = config.dev.proxyTable
+
+var app = express()
+var compiler = webpack(webpackConfig)
+
+var devMiddleware = require('webpack-dev-middleware')(compiler, {
+  publicPath: webpackConfig.output.publicPath,
+  quiet: true
+})
+
+var hotMiddleware = require('webpack-hot-middleware')(compiler, {
+  log: () => {}
+})
+// force page reload when html-webpack-plugin template changes
+compiler.plugin('compilation', function (compilation) {
+  compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
+    hotMiddleware.publish({ action: 'reload' })
+    cb()
+  })
+})
+
+// proxy api requests
+Object.keys(proxyTable).forEach(function (context) {
+  var options = proxyTable[context]
+  if (typeof options === 'string') {
+    options = { target: options }
+  }
+  app.use(proxyMiddleware(options.filter || context, options))
+})
+
+// handle fallback for HTML5 history API
+app.use(require('connect-history-api-fallback')())
+
+// serve webpack bundle output
+app.use(devMiddleware)
+
+// enable hot-reload and state-preserving
+// compilation error display
+app.use(hotMiddleware)
+
+// serve pure static assets
+var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
+app.use(staticPath, express.static('./static'))
+
+var uri = 'http://localhost:' + port
+
+var _resolve
+var readyPromise = new Promise(resolve => {
+  _resolve = resolve
+})
+
+console.log('> Starting dev server...')
+devMiddleware.waitUntilValid(() => {
+  console.log('> Listening at ' + uri + '\n')
+  // when env is testing, don't need open it
+  if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
+    opn(uri)
+  }
+  _resolve()
+})
+
+var server = app.listen(port)
+
+module.exports = {
+  ready: readyPromise,
+  close: () => {
+    server.close()
+  }
+}

+ 72 - 0
fhKeeper/formulahousekeeper/timesheet/build/utils.js

@@ -0,0 +1,72 @@
+var path = require('path')
+var config = require('../config')
+var ExtractTextPlugin = require('extract-text-webpack-plugin')
+
+exports.assetsPath = function (_path) {
+    var assetsSubDirectory = process.env.NODE_ENV === 'production'
+        ? config.build.assetsSubDirectory
+        : config.dev.assetsSubDirectory
+    return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function (options) {
+    options = options || {}
+
+    var cssLoader = {
+        loader: 'css-loader',
+        options: {
+        //minimize: process.env.NODE_ENV === 'production',
+        sourceMap: options.sourceMap
+        }
+    }
+
+    // generate loader string to be used with extract text plugin
+    function generateLoaders (loader, loaderOptions) {
+        var loaders = [cssLoader]
+        if (loader) {
+        loaders.push({
+            loader: loader + '-loader',
+            options: Object.assign({}, loaderOptions, {
+            sourceMap: options.sourceMap
+            })
+        })
+        }
+
+        // Extract CSS when that option is specified
+        // (which is the case during production build)
+        if (options.extract) {
+            return ExtractTextPlugin.extract({
+                use: loaders,
+                fallback: 'vue-style-loader',
+                publicPath: '../../'
+            })
+        } else {
+            return ['vue-style-loader'].concat(loaders)
+        }
+    }
+
+    // https://vue-loader.vuejs.org/en/configurations/extract-css.html
+    return {
+        css: generateLoaders(),
+        postcss: generateLoaders(),
+        less: generateLoaders('less'),
+        sass: generateLoaders('sass', { indentedSyntax: true }),
+        scss: generateLoaders('sass'),
+        stylus: generateLoaders('stylus'),
+        styl: generateLoaders('stylus')
+    }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function (options) {
+    var output = []
+    var loaders = exports.cssLoaders(options)
+    for (var extension in loaders) {
+        var loader = loaders[extension]
+        output.push({
+            test: new RegExp('\\.' + extension + '$'),
+            use: loader
+        })
+    }
+    return output
+}

+ 12 - 0
fhKeeper/formulahousekeeper/timesheet/build/vue-loader.conf.js

@@ -0,0 +1,12 @@
+var utils = require('./utils')
+var config = require('../config')
+var isProduction = process.env.NODE_ENV === 'production'
+
+module.exports = {
+  loaders: utils.cssLoaders({
+    sourceMap: isProduction
+      ? config.build.productionSourceMap
+      : config.dev.cssSourceMap,
+    extract: isProduction
+  })
+}

+ 67 - 0
fhKeeper/formulahousekeeper/timesheet/build/webpack.base.conf.js

@@ -0,0 +1,67 @@
+var path = require('path')
+var utils = require('./utils')
+var config = require('../config')
+var vueLoaderConfig = require('./vue-loader.conf')
+var webpack = require("webpack")
+
+function resolve(dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+module.exports = {
+    entry: {
+        //app: './src/main.js'
+        app: ["babel-polyfill", "./src/main.js"]
+    },
+    output: {
+        path: config.build.assetsRoot,
+        filename: '[name].js',
+        publicPath: process.env.NODE_ENV === 'production'
+        ? config.build.assetsPublicPath
+        : config.dev.assetsPublicPath
+    },
+    resolve: {
+        extensions: ['.js', '.vue', '.json'],
+        alias: {
+        'vue$': 'vue/dist/vue.esm.js',
+        '@': resolve('src'),
+        'scss_vars': '@/styles/vars.scss'
+        }
+    },
+    plugins: [
+        new webpack.ProvidePlugin({
+        jQuery: 'jquery',
+        $: 'jquery'
+        })
+    ],
+    module: {
+        rules: [
+            {
+                test: /\.vue$/,
+                loader: 'vue-loader',
+                options: vueLoaderConfig
+            },
+            {
+                test: /\.js$/,
+                loader: 'babel-loader',
+                include: [resolve('src'), resolve('test')]
+            },
+            {
+                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+                loader: 'url-loader',
+                options: {
+                limit: 10000,
+                name: utils.assetsPath('img/[name].[hash:7].[ext]')
+                }
+            },
+            {
+                test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+                loader: 'url-loader',
+                options: {
+                limit: 10000,
+                name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+                }
+            }
+        ]
+    }
+}

+ 38 - 0
fhKeeper/formulahousekeeper/timesheet/build/webpack.dev.conf.js

@@ -0,0 +1,38 @@
+var utils = require('./utils')
+var webpack = require('webpack')
+var config = require('../config')
+var merge = require('webpack-merge')
+var baseWebpackConfig = require('./webpack.base.conf')
+var HtmlWebpackPlugin = require('html-webpack-plugin')
+var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+
+// add hot-reload related code to entry chunks
+Object.keys(baseWebpackConfig.entry).forEach(function (name) {
+  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
+})
+
+module.exports = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: '#cheap-module-eval-source-map',
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': config.dev.env,
+      'BASE_URL' : '"/api"',
+      'LINK_URL' : '"/ips"'
+    }),
+    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
+    new webpack.HotModuleReplacementPlugin(),
+    new webpack.NoEmitOnErrorsPlugin(),
+    // https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: 'index.html',
+      template: 'index.html',
+      inject: true,
+      favicon: './favicon.ico'
+    }),
+    new FriendlyErrorsPlugin()
+  ]
+})

+ 124 - 0
fhKeeper/formulahousekeeper/timesheet/build/webpack.prod.conf.js

@@ -0,0 +1,124 @@
+var path = require('path')
+var utils = require('./utils')
+var webpack = require('webpack')
+var config = require('../config')
+var merge = require('webpack-merge')
+var baseWebpackConfig = require('./webpack.base.conf')
+var CopyWebpackPlugin = require('copy-webpack-plugin')
+var HtmlWebpackPlugin = require('html-webpack-plugin')
+var ExtractTextPlugin = require('extract-text-webpack-plugin')
+var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+
+var env = config.build.env
+
+var webpackConfig = merge(baseWebpackConfig, {
+    module: {
+        rules: utils.styleLoaders({
+        sourceMap: config.build.productionSourceMap,
+            extract: true
+        })
+    },
+    devtool: config.build.productionSourceMap ? '#source-map' : false,
+    output: {
+        publicPath: './',
+        path: config.build.assetsRoot,
+        filename: utils.assetsPath('js/[name].[chunkhash].js'),
+        chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+    },
+    plugins: [
+        // http://vuejs.github.io/vue-loader/en/workflow/production.html
+        new webpack.DefinePlugin({
+        'process.env': env,
+        'BASE_URL' : '"/api"',
+        'LINK_URL' : '"/ips"'
+        }),
+        new webpack.optimize.UglifyJsPlugin({
+        compress: {
+            warnings: false
+        },
+        sourceMap: true
+        }),
+        // extract css into its own file
+        new ExtractTextPlugin({
+        filename: utils.assetsPath('css/[name].[contenthash].css')
+        }),
+        // Compress extracted CSS. We are using this plugin so that possible
+        // duplicated CSS from different components can be deduped.
+        new OptimizeCSSPlugin({
+        cssProcessorOptions: {
+            safe: true
+        }
+        }),
+        // generate dist index.html with correct asset hash for caching.
+        // you can customize output by editing /index.html
+        // see https://github.com/ampedandwired/html-webpack-plugin
+        new HtmlWebpackPlugin({
+        filename: config.build.index,
+        template: 'index.html',
+        inject: true,
+        favicon: './favicon.ico',
+        minify: {
+            removeComments: true,
+            collapseWhitespace: true,
+            removeAttributeQuotes: true
+            // more options:
+            // https://github.com/kangax/html-minifier#options-quick-reference
+        },
+        // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+        chunksSortMode: 'dependency'
+        }),
+        // split vendor js into its own file
+        new webpack.optimize.CommonsChunkPlugin({
+        name: 'vendor',
+        minChunks: function (module, count) {
+            // any required modules inside node_modules are extracted to vendor
+            return (
+            module.resource &&
+            /\.js$/.test(module.resource) &&
+            module.resource.indexOf(
+                path.join(__dirname, '../node_modules')
+            ) === 0
+            )
+        }
+        }),
+        // extract webpack runtime and module manifest to its own file in order to
+        // prevent vendor hash from being updated whenever app bundle is updated
+        new webpack.optimize.CommonsChunkPlugin({
+        name: 'manifest',
+        chunks: ['vendor']
+        }),
+        // copy custom static assets
+        new CopyWebpackPlugin([
+        {
+            from: path.resolve(__dirname, '../static'),
+            to: config.build.assetsSubDirectory,
+            ignore: ['.*']
+        }
+        ])
+    ]
+})
+
+if (config.build.productionGzip) {
+    var CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+    webpackConfig.plugins.push(
+        new CompressionWebpackPlugin({
+        asset: '[path].gz[query]',
+        algorithm: 'gzip',
+        test: new RegExp(
+            '\\.(' +
+            config.build.productionGzipExtensions.join('|') +
+            ')$'
+        ),
+        threshold: 10240,
+        minRatio: 0.8
+        })
+    )
+}
+
+if (config.build.bundleAnalyzerReport) {
+    var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+    webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig

+ 6 - 0
fhKeeper/formulahousekeeper/timesheet/config/dev.env.js

@@ -0,0 +1,6 @@
+var merge = require('webpack-merge')
+var prodEnv = require('./prod.env')
+
+module.exports = merge(prodEnv, {
+    NODE_ENV: '"development"'
+})

+ 51 - 0
fhKeeper/formulahousekeeper/timesheet/config/index.js

@@ -0,0 +1,51 @@
+var path = require('path')
+
+var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
+for (var i in ifaces) {
+    for (var j in ifaces[i]) {
+        var val = ifaces[i][j]
+        if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
+            ip = val.address
+        }
+    }
+}
+
+module.exports = {
+  build: {
+    env: require('./prod.env'),
+    index: path.resolve(__dirname, '../dist/index.html'),
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: './',
+    productionSourceMap: true,
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+    bundleAnalyzerReport: process.env.npm_config_report
+  },
+  dev: {
+    env: require('./dev.env'),
+    port: 10086,
+    autoOpenBrowser: true,
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {
+        '/api': {    
+            target: 'http://'+ ip +':8099',
+            secure: true,
+            changeOrigin: true,
+            pathRewrite: {
+                '^/api': '/' 
+            }
+        },
+        '/ips': {    
+            target: 'http://'+ ip +':8080',
+            secure: true,
+            changeOrigin: true,
+            pathRewrite: {
+                '^/ips': '/' 
+            }
+        },
+    },
+    cssSourceMap: false
+  }
+}

+ 3 - 0
fhKeeper/formulahousekeeper/timesheet/config/prod.env.js

@@ -0,0 +1,3 @@
+module.exports = {
+    NODE_ENV: '"production"'
+}

二进制
fhKeeper/formulahousekeeper/timesheet/favicon.ico


+ 48 - 0
fhKeeper/formulahousekeeper/timesheet/index.html

@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>工时管家</title>
+        <link rel="shortcut icon" type="image/x-icon" href="./favicon.ico"/>
+        <link href="./static/css/public.css" rel="stylesheet" type="text/css"/> 
+        <style>
+            /* 滚动条样式修改 */
+            /*滚动条凹槽的颜色,还可以设置边框属性 */
+            ::-webkit-scrollbar-track-piece {
+                background-color:#f8f8f8;
+                -webkit-border-radius: 2em;
+                -moz-border-radius: 2em;
+                border-radius: 2em;
+            }
+            /*滚动条的宽度*/
+            ::-webkit-scrollbar {
+                width:9px;
+            height: 9px;}
+            /*滚动条的设置*/
+            ::-webkit-scrollbar-thumb {
+                background-color:#dddddd;
+                background-clip:padding-box;
+                -webkit-border-radius: 2em;
+                -moz-border-radius: 2em;
+                border-radius: 2em;}
+
+            /*滚动条鼠标移上去*/
+            ::-webkit-scrollbar-thumb:hover {
+                background-color:#bbb;
+            }
+
+            /*取消消息列表弹出框的内边距*/
+            .popover-self {
+                padding: 0 !important;
+            }
+
+            /*自定义颜色*/
+            #nprogress .bar {
+                background:#f58220 !important; 
+            }
+        </style>
+    </head>
+    <body>
+        <div id="app"></div>
+    </body>
+</html>

文件差异内容过多而无法显示
+ 9567 - 0
fhKeeper/formulahousekeeper/timesheet/package-lock.json


+ 77 - 0
fhKeeper/formulahousekeeper/timesheet/package.json

@@ -0,0 +1,77 @@
+{
+  "name": "ym_admin",
+  "version": "1.0.5",
+  "description": "ym_admin project",
+  "author": "taylor <709161610@qq.com>",
+  "license": "MIT",
+  "scripts": {
+    "dev": "node build/dev-server.js",
+    "start": "node build/dev-server.js",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "axios": "^0.15.3",
+    "echarts": "^3.8.5",
+    "element-ui": "^2.13.0",
+    "font-awesome": "^4.7.0",
+    "jquery": "^3.4.1",
+    "nprogress": "^0.2.0",
+    "vue": "^2.6.10",
+    "vue-clipboard2": "^0.3.0",
+    "vue-router": "^2.3.0",
+    "vuex": "^2.0.0-rc.6"
+  },
+  "devDependencies": {
+    "autoprefixer": "^6.7.2",
+    "axios-mock-adapter": "^1.7.1",
+    "babel-core": "^6.22.1",
+    "babel-loader": "^6.2.10",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-polyfill": "^6.26.0",
+    "babel-preset-env": "^1.2.1",
+    "babel-preset-es2015": "^6.0.0",
+    "babel-preset-stage-2": "^6.22.0",
+    "babel-register": "^6.22.0",
+    "chalk": "^1.1.3",
+    "connect-history-api-fallback": "^1.3.0",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.26.1",
+    "eventsource-polyfill": "^0.9.6",
+    "express": "^4.14.1",
+    "extract-text-webpack-plugin": "^2.0.0",
+    "file-loader": "^0.10.0",
+    "friendly-errors-webpack-plugin": "^1.1.3",
+    "function-bind": "^1.0.2",
+    "html-webpack-plugin": "^2.28.0",
+    "http-proxy-middleware": "^0.17.3",
+    "json-loader": "^0.5.4",
+    "mockjs": "^1.0.1-beta3",
+    "node-sass": "^4.5.0",
+    "opn": "^4.0.2",
+    "optimize-css-assets-webpack-plugin": "^1.3.0",
+    "ora": "^1.0.0",
+    "qs": "^6.7.0",
+    "rimraf": "^2.6.0",
+    "sass-loader": "^6.0.0",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "url-loader": "^0.5.8",
+    "vue-loader": "^11.1.4",
+    "vue-style-loader": "^2.0.0",
+    "vue-template-compiler": "^2.2.4",
+    "webpack": "^2.7.0",
+    "webpack-bundle-analyzer": "^2.2.1",
+    "webpack-dev-middleware": "^1.10.0",
+    "webpack-hot-middleware": "^2.16.1",
+    "webpack-merge": "^2.6.1"
+  },
+  "engines": {
+    "node": ">= 4.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 59 - 0
fhKeeper/formulahousekeeper/timesheet/src/App.vue

@@ -0,0 +1,59 @@
+<template>
+	<div id="app">
+		<transition name="fade" mode="out-in">
+			<router-view></router-view>
+		</transition>
+	</div>
+</template>
+
+<script>
+    export default {
+        name: 'app',
+        components: {}
+    }
+</script>
+
+<style lang="scss">
+    body {
+        margin: 0px;
+        padding: 0px;
+        font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
+        font-size: 14px;
+        -webkit-font-smoothing: antialiased;
+    }
+
+    #app {
+        position: absolute;
+        top: 0px;
+        bottom: 0px;
+        width: 100%;
+    }
+
+    .el-submenu [class^=fa] {
+        vertical-align: baseline;
+        margin-right: 10px;
+    }
+
+    .el-menu-item [class^=fa] {
+        vertical-align: baseline;
+        margin-right: 10px;
+    }
+
+    .toolbar {
+        background: #f2f2f2;
+        padding: 10px;
+        .el-form-item {
+            margin-bottom: 10px;
+        }
+    }
+
+    .fade-enter-active,
+    .fade-leave-active {
+        transition: all .2s ease;
+    }
+
+    .fade-enter,
+    .fade-leave-active {
+        opacity: 0;
+    }
+</style>

+ 17 - 0
fhKeeper/formulahousekeeper/timesheet/src/api/api.js

@@ -0,0 +1,17 @@
+import axios from 'axios';
+
+let base = '';
+
+export const requestLogin = params => { return axios.post(`${base}/login`, params).then(res => res.data); };
+
+export const getUserList = params => { return axios.get(`${base}/user/list`, { params: params }); };
+
+export const getUserListPage = params => { return axios.get(`${base}/user/listpage`, { params: params }); };
+
+export const removeUser = params => { return axios.get(`${base}/user/remove`, { params: params }); };
+
+export const batchRemoveUser = params => { return axios.get(`${base}/user/batchremove`, { params: params }); };
+
+export const editUser = params => { return axios.get(`${base}/user/edit`, { params: params }); };
+
+export const addUser = params => { return axios.get(`${base}/user/add`, { params: params }); };

+ 3 - 0
fhKeeper/formulahousekeeper/timesheet/src/api/index.js

@@ -0,0 +1,3 @@
+import * as api from './api';
+
+export default api;

+ 539 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}

+ 377 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/demo_index.html

@@ -0,0 +1,377 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>IconFont Demo</title>
+  <link rel="shortcut icon" href="https://gtms04.alicdn.com/tps/i4/TB1_oz6GVXXXXaFXpXXJDFnIXXX-64-64.ico" type="image/x-icon"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 代码高亮 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+      <a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=1313295" target="_blank" class="nav-more">查看项目</a>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61f;</span>
+                <div class="name">地图</div>
+                <div class="code-name">&amp;#xe61f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe669;</span>
+                <div class="name">编辑</div>
+                <div class="code-name">&amp;#xe669;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe612;</span>
+                <div class="name">项目管理</div>
+                <div class="code-name">&amp;#xe612;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe639;</span>
+                <div class="name">监测</div>
+                <div class="code-name">&amp;#xe639;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe76b;</span>
+                <div class="name">默认头像</div>
+                <div class="code-name">&amp;#xe76b;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe871;</span>
+                <div class="name">setting-fill</div>
+                <div class="code-name">&amp;#xe871;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe644;</span>
+                <div class="name">模型</div>
+                <div class="code-name">&amp;#xe644;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe8ec;</span>
+                <div class="name">caret-down</div>
+                <div class="code-name">&amp;#xe8ec;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe868;</span>
+                <div class="name">地图</div>
+                <div class="code-name">&amp;#xe868;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 引用</h2>
+          <hr>
+
+          <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+          <ul>
+            <li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
+            <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+            <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+          </ul>
+          <blockquote>
+            <p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式</p>
+          </blockquote>
+          <p>Unicode 使用步骤如下:</p>
+          <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+</code></pre>
+          <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont icon-map"></span>
+            <div class="name">
+              地图
+            </div>
+            <div class="code-name">.icon-map
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-bianji"></span>
+            <div class="name">
+              编辑
+            </div>
+            <div class="code-name">.icon-bianji
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-ic_dashboard"></span>
+            <div class="name">
+              项目管理
+            </div>
+            <div class="code-name">.icon-ic_dashboard
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-jiance"></span>
+            <div class="name">
+              监测
+            </div>
+            <div class="code-name">.icon-jiance
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-morentouxiang"></span>
+            <div class="name">
+              默认头像
+            </div>
+            <div class="code-name">.icon-morentouxiang
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-setting-fill"></span>
+            <div class="name">
+              setting-fill
+            </div>
+            <div class="code-name">.icon-setting-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-moxing"></span>
+            <div class="name">
+              模型
+            </div>
+            <div class="code-name">.icon-moxing
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-caret-down"></span>
+            <div class="name">
+              caret-down
+            </div>
+            <div class="code-name">.icon-caret-down
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-ditu"></span>
+            <div class="name">
+              地图
+            </div>
+            <div class="code-name">.icon-ditu
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 引用</h2>
+        <hr>
+
+        <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+        <p>与 Unicode 使用方式相比,具有如下特点:</p>
+        <ul>
+          <li>兼容性良好,支持 IE8+,及所有现代浏览器。</li>
+          <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+          <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+          <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+        </blockquote>
+      </div>
+      </div>
+      <div class="content symbol">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-map"></use>
+                </svg>
+                <div class="name">地图</div>
+                <div class="code-name">#icon-map</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-bianji"></use>
+                </svg>
+                <div class="name">编辑</div>
+                <div class="code-name">#icon-bianji</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-ic_dashboard"></use>
+                </svg>
+                <div class="name">项目管理</div>
+                <div class="code-name">#icon-ic_dashboard</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-jiance"></use>
+                </svg>
+                <div class="name">监测</div>
+                <div class="code-name">#icon-jiance</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-morentouxiang"></use>
+                </svg>
+                <div class="name">默认头像</div>
+                <div class="code-name">#icon-morentouxiang</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-setting-fill"></use>
+                </svg>
+                <div class="name">setting-fill</div>
+                <div class="code-name">#icon-setting-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-moxing"></use>
+                </svg>
+                <div class="name">模型</div>
+                <div class="code-name">#icon-moxing</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-caret-down"></use>
+                </svg>
+                <div class="name">caret-down</div>
+                <div class="code-name">#icon-caret-down</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-ditu"></use>
+                </svg>
+                <div class="name">地图</div>
+                <div class="code-name">#icon-ditu</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 引用</h2>
+          <hr>
+
+          <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+            这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+          <ul>
+            <li>支持多色图标了,不再受单色限制。</li>
+            <li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+            <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+            <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+          </ul>
+          <p>使用步骤如下:</p>
+          <h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>

文件差异内容过多而无法显示
+ 53 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.css


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.eot


文件差异内容过多而无法显示
+ 1 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.js


文件差异内容过多而无法显示
+ 53 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.svg


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.ttf


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.woff


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/iconfont/iconfont.woff2


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/047_S.jpg


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/404.png


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/background.png


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/close.gif


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/head_logo.png


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/login_center.png


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/login_logo.png


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/noPic.jpg


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/noPic.png


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/userHead.jpg


二进制
fhKeeper/formulahousekeeper/timesheet/src/assets/image/userHead.png


+ 72 - 0
fhKeeper/formulahousekeeper/timesheet/src/common/js/util.js

@@ -0,0 +1,72 @@
+var SIGN_REGEXP = /([yMdhsm])(\1*)/g;
+var DEFAULT_PATTERN = 'yyyy-MM-dd';
+function padding(s, len) {
+    var len = len - (s + '').length;
+    for (var i = 0; i < len; i++) { s = '0' + s; }
+    return s;
+};
+
+export default {
+    getQueryStringByName: function (name) {
+        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
+        var r = window.location.search.substr(1).match(reg);
+        var context = "";
+        if (r != null)
+            context = r[2];
+        reg = null;
+        r = null;
+        return context == null || context == "" || context == "undefined" ? "" : context;
+    },
+    formatDate: {
+        format: function (date, pattern) {
+            pattern = pattern || DEFAULT_PATTERN;
+            return pattern.replace(SIGN_REGEXP, function ($0) {
+                switch ($0.charAt(0)) {
+                    case 'y': return padding(date.getFullYear(), $0.length);
+                    case 'M': return padding(date.getMonth() + 1, $0.length);
+                    case 'd': return padding(date.getDate(), $0.length);
+                    case 'w': return date.getDay() + 1;
+                    case 'h': return padding(date.getHours(), $0.length);
+                    case 'm': return padding(date.getMinutes(), $0.length);
+                    case 's': return padding(date.getSeconds(), $0.length);
+                }
+            });
+        },
+        parse: function (dateString, pattern) {
+            var matchs1 = pattern.match(SIGN_REGEXP);
+            var matchs2 = dateString.match(/(\d)+/g);
+            if (matchs1.length == matchs2.length) {
+                var _date = new Date(1970, 0, 1);
+                for (var i = 0; i < matchs1.length; i++) {
+                    var _int = parseInt(matchs2[i]);
+                    var sign = matchs1[i];
+                    switch (sign.charAt(0)) {
+                        case 'y': _date.setFullYear(_int); break;
+                        case 'M': _date.setMonth(_int - 1); break;
+                        case 'd': _date.setDate(_int); break;
+                        case 'h': _date.setHours(_int); break;
+                        case 'm': _date.setMinutes(_int); break;
+                        case 's': _date.setSeconds(_int); break;
+                    }
+                }
+                return _date;
+            }
+            return null;
+        },
+        dateDiff: function(sDate1, sDate2) {
+            var aDate, oDate1, oDate2, iDays;
+            sDate1 = sDate1.split(" ")[0];
+            aDate = sDate1.split("-")
+            oDate1 = new Date(aDate[1] + '-' + aDate[2] + '-' + aDate[0]);
+            aDate = sDate2.split("-")
+            oDate2 = new Date(aDate[1] + '-' + aDate[2] + '-' + aDate[0]);
+            if((oDate1 - oDate2) < 0){
+                iDays = "已失效"
+            } else {
+                iDays = parseInt(Math.abs(oDate1 - oDate2) / 1000 / 60 / 60 / 24) + "天" //把相差的毫秒数转换为天数 
+            }
+            return iDays
+        }
+    }
+
+};

+ 0 - 0
fhKeeper/formulahousekeeper/timesheet/src/components/.gitkeep


+ 198 - 0
fhKeeper/formulahousekeeper/timesheet/src/http.js

@@ -0,0 +1,198 @@
+import axios from 'axios'
+import qs from 'qs'
+
+const TIME_OUT_MS = 60 * 1000 // 默认请求超时时间
+
+/*
+ * @param response 返回数据列表
+ */
+function handleResults (response) {
+    let remoteResponse = response.data;
+    return remoteResponse
+}
+
+function handleUrl (url) {
+    if(url.indexOf('.do') > -1) {
+        url = LINK_URL + url;
+    } else {
+        url = BASE_URL + url;
+    }
+    return url
+}
+
+/*
+ * @param data 参数列表
+ * @return
+ */
+function handleParams (data) {
+    return data
+}
+
+export default {
+    /*
+     * @param url
+     * @param data
+     * @param response 请求成功时的回调函数
+     * @param exception 异常的回调函数
+     */
+    post (url, data, response, exception) {
+        var user = sessionStorage.getItem('user') , token = "";
+        if(user != null){
+            token = JSON.parse(user).headImgurl
+            data.token = token
+        }
+        axios({
+            method: 'post',
+            url: handleUrl(url),
+            data: handleParams(qs.stringify(data)),
+            // timeout: TIME_OUT_MS,
+            headers: {
+                //'Content-Type': 'application/json; charset=UTF-8'
+                'Content-type': ' application/x-www-form-urlencoded; charset=UTF-8',
+            }
+        }).then(
+            (result) => {
+                response(handleResults(result))
+            }
+        ).catch(
+            (error) => {
+                if (exception) {
+                    exception(error)
+                } else {
+                    console.log(error)
+                }
+            }
+        )
+    },
+    /*
+     * get 请求
+     * @param url
+     * @param response 请求成功时的回调函数
+     * @param exception 异常的回调函数
+     */
+    get (url , response, exception) {
+        var user = sessionStorage.getItem('user') , token = "";
+        if(user != null){
+            token = JSON.parse(user).headImgurl
+        }
+        axios({
+            method: 'get',
+            url: handleUrl(url),
+            headers: {
+                'Content-Type': 'application/json; charset=UTF-8'
+            }
+        }).then(
+            (result) => {
+                response(handleResults(result))
+            }
+        ).catch(
+            (error) => {
+                if (exception) {
+                    exception(error)
+                } else {
+                    console.log(error)
+                }
+            }
+        )
+    },
+    /*
+     * 导入文件
+     * @param url
+     * @param data
+     * @param response 请求成功时的回调函数
+     * @param exception 异常的回调函数
+     */
+    uploadFile (url, data, response, exception) {
+        var user = sessionStorage.getItem('user') , token = "";
+        if(user != null){
+            token = JSON.parse(user).headImgurl
+            data.append("token", token);
+        }
+        axios({
+            method: 'post',
+            url: handleUrl(url),
+            data: handleParams(data),
+            dataType: 'json',
+            processData: false,
+            contentType: false
+        }).then(
+            (result) => {
+                response(handleResults(result, data))
+            }
+        ).catch(
+            (error) => {
+                if (exception) {
+                    exception(error)
+                } else {
+                    console.log(error)
+                }
+            }
+        )
+    },
+    /*
+     * 下载文件用,导出 Excel 表格可以用这个方法
+     * @param url
+     * @param param
+     * @param fileName 如果是导出 Excel 表格文件名后缀最好用.xls 而不是.xlsx,否则文件可能会因为格式错误导致无法打开
+     * @param exception 异常的回调函数
+     */
+    downloadFile (url, data, fileName, exception) {
+        var user = sessionStorage.getItem('user') , token = "";
+        if(user != null){
+            token = JSON.parse(user).headImgurl
+        }
+        axios({
+            method: 'post',
+            url: handleUrl(url),
+            data: handleParams(data),
+            responseType: 'blob'
+        }).then(
+            (result) => {
+                const excelBlob = result.data
+                if ('msSaveOrOpenBlob' in navigator) {
+                    window.navigator.msSaveOrOpenBlob(excelBlob, fileName)
+                } else {
+                    const elink = document.createElement('a')
+                    elink.download = fileName
+                    elink.style.display = 'none'
+                    const blob = new Blob([excelBlob])
+                    elink.href = URL.createObjectURL(blob)
+                    document.body.appendChild(elink)
+                    elink.click()
+                    document.body.removeChild(elink)
+                }
+            }
+        ).catch(
+            (error) => {
+                if (exception) {
+                    exception(error)
+                } else {
+                    console.log(error)
+                }
+            }
+        )
+    },
+    uploadFileFormData (url, data, response, exception) {
+        axios({
+            method: 'post',
+            url: handleUrl(url),
+            data: data,
+            // timeout: TIME_OUT_MS,
+            headers: {
+                'Content-Type': 'multipart/form-data'
+            }
+        }).then(
+            (result) => {
+                response(handleResults(result))
+            }
+        ).catch(
+            (error) => {
+                if (exception) {
+                    exception(error)
+                } else {
+                    console.log(error)
+                }
+            }
+        )
+    }
+}

+ 110 - 0
fhKeeper/formulahousekeeper/timesheet/src/main.js

@@ -0,0 +1,110 @@
+import Vue from 'vue'
+import App from './App'
+import store from './vuex/store'
+import routes from './routes'
+
+import VueRouter from 'vue-router'
+Vue.use(VueRouter)
+
+import ElementUI from 'element-ui'
+
+Vue.use(ElementUI)
+
+import Vuex from 'vuex'
+Vue.use(Vuex)
+
+import http from './http'
+import port from './port'
+import echarts from 'echarts'
+import $ from 'jquery'
+
+Vue.prototype.http = http
+Vue.prototype.port = port
+Vue.prototype.echarts = echarts
+
+import VueClipboard from 'vue-clipboard2'
+Vue.use(VueClipboard)
+
+import 'element-ui/lib/theme-chalk/index.css'
+import 'font-awesome/css/font-awesome.min.css'
+import './assets/iconfont/iconfont.css'
+
+const router = new VueRouter({
+    routes
+})
+
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+
+router.beforeEach((to, from, next) => {
+    NProgress.start();
+    if(to.name != '邀请') {
+        if (to.path == '/login') {
+            sessionStorage.removeItem('user');
+        }
+    
+        let user = JSON.parse(sessionStorage.getItem('user'));
+        if (!user && to.path != '/login') {
+            next({ path: '/login' })
+        } else {
+            if(user){
+                for(var i in routes){
+                    if(routes[i].name == "基础管理" && user.parentId != 0){
+                        routes[i].hidden = true
+                    } else if(routes[i].name == "基础管理"){
+                        routes[i].hidden = false
+                    }
+                    
+                    if(routes[i].name == "项目管理" && user.parentId > 1){
+                        var children = routes[i].children;
+                        for(var j in children){
+    
+                            if(children[j].name == "人员管理"){
+                                if(user.isManager == 0){
+                                    children[j].hidden = true
+                                } else {
+                                    children[j].hidden = false
+                                }
+                            }
+    
+                            if(children[j].name == "权限管理"){
+                                if(user.isManager == 0){
+                                    children[j].hidden = true
+                                } else {
+                                    children[j].hidden = false
+                                }
+                            }
+                        }
+                    } else if(routes[i].name == "项目管理") {
+                        var children = routes[i].children;
+                        for(var j in children){
+                            if(children[j].name != "项目详情"){
+                                children[j].hidden = false
+                            }
+                            
+                            if(children[j].name == "权限管理"){
+                                if((user.parentId == 0 || user.parentId == 1) && user.isManager == 0){
+                                    children[j].hidden = true
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            next()
+        }
+    } else {
+        next()
+    }
+})
+
+router.afterEach(() => {
+    NProgress.done()
+})
+
+new Vue({
+    router,
+    store,
+    render: h => h(App)
+}).$mount('#app')
+

+ 118 - 0
fhKeeper/formulahousekeeper/timesheet/src/port.js

@@ -0,0 +1,118 @@
+export default {
+    manage: {
+        login: '/user/login', // 登录
+    },
+    //消息提示相关
+    notice: {
+        list: '/vnoticeuser/list',  // 消息列表
+        read: '/vnoticeuser/read'  // 消息读取
+    },
+    pwd: {
+        resetPwd: '/user/updatePassword' // 重置密码
+    },
+    map: { 
+        mapList: '/company/getCoutomCompanyAndMouldsByUser', // 生产方公司和公司下所属的模具
+        newMap: '/mould/listMap' // 获取地图
+    },
+    project: {
+        addUser: '/user/add',  // 添加或修改用户
+        userList: '/user/list',  // 用户列表
+        delUser: '/user/delete',  // 删除用户
+
+        addProject: '/project/add', // 添加或修改项目
+        projectList: '/project/list', // 项目列表
+        projectDetail: '/project/detail', // 项目详情
+        projects: '/project/projectList', // 筛选模具列表时作为筛选条件所加载的项目列表
+        projectByUser: '/project/getProjectListByUserAndCompany',// 获取创建人员分配项目时根据当前人和公司获取项目列表
+
+        uploadFile: '/projectfile/uploadFile', //项目文档的上传
+        dowloadFile: '/projectfile/dowloadFile', //项目文档的下载
+        fileList: '/projectfile/list', //项目文档列表
+        delFile: '/projectfile/delFile', //项目文档的删除
+        operList: '/projectoperationdynamics/list', //项目操作记录列表
+
+        getUserList: '/user/getUserList', //获取用户列表
+        getUserById: '/user/getUserListByCompanyIds', // 给项目分配参与人的时候根据公司id获取公司下的人员
+
+        inviteUser: '/invitationrecord/inviteUser', //添加邀请记录并产生链接
+
+        powerList: '/power/list', // 权限列表
+        powerUpdate: '/power/update', //修改权限
+    },
+    //模具
+    mold: {
+        addMold: '/mould/addOrUpdate', //添加/修改模具设备
+        molds: '/mould/list', //模具列表
+        modelList: '/mould/modelList', //给项目分配模具获取该公司下的模具列表
+        delMold: '/mould/delMould', //删除模具
+
+        moldDetail: '/mould/detail', //模具详情
+        moldFileList: '/mouldfile/list', //获取模具文档
+        moldFileListAll: '/mouldfile/allList', //获取全部模具文档
+        moldFileUpload: '/mouldfile/uploadFile', //上传模具文档
+        moldFileDowload: '/mouldfile/dowloadFile', //模具文档的下载
+        moldFileDowloadList: '/mouldfile/fileList', //获取模具文档下载列表
+
+        moldFileDowloadFile: '/mouldfile/downloadfileList', //批量下载
+        moldFileCheck: '/mouldfile/check', //审批模具文档 
+        exportOperationExcel: '/mouldfile/downloadFileListExcel', //下载操作记录
+
+        chooseModelList: '/mould/chooseModelList', //编辑项目时显示的模具列表
+
+        moldFileDelete: '/mouldfile/delFile', //项目文档的删除
+        moldOperationList: '/mouldoperationdynamics/list', //项目操作记录列表
+
+        partList: '/part/list', //零件列表
+        addPart: '/part/addOrUpdate', //单个零件添加
+        importPart: '/part/importAppLogin',//零件的excel导入
+        partUpload: '/mouldfile/uploadPartFileList', //零件文档的批量上传
+
+        download: '/mouldfile/download',
+
+        moldMaintain: '/mouldmaintain/maintain', //维护
+        moldMaintainList: '/mouldmaintain/list', //获取列表
+        moldMaintainListGet: '/mould/maintainMouldList', //主页获取保养模具列表
+        moldDiscardListGet: '/mould/scrapMouldList', //主页获取报废模具列表
+        moldChange: '/mould/changeMouldEquipment', //处理告警
+        moldChangeRequirement: '/mouldequipment/getEquipmentListByOldMouldAndUser' //处理告警所需的设备
+    },
+    //基础管理
+    base: {
+        addCompany: '/company/add', // 添加资产方
+        companyList: '/company/list', // 资产方列表
+        delCompany: '/company/delete', // 删除资产方
+
+        getCompanyList: '/company/getCompanyList', // 管理员创建人员时显示公司
+        
+        getCompanys: '/company/getCompanys', // 云模盒所属公司
+
+        addCompanyListToProject: '/company/addCompanyListToProject', // 编辑项目时获取生产方公司
+
+        relationList: '/company/relationList', // 获取关联公司列表
+
+        //ownerComps: '/company/ownerRelateCompany', // 返回当前公司的关联公司列表
+
+        getProduceCompany: '/company/getProduceCompany', // 根据项目id获取生产方列表
+        
+        getInfo: '/company/getProduceCompanyByCurrentUser', // 根据当前人登录人所能看到的公司进行筛选
+
+        addFactory: '/factory/add',  // 添加生产方
+        factoryList: '/factory/list',   // 生产方列表
+        delFactory: '/factory/delete',  // 删除生产方
+
+        editMould: '/mouldequipment/addOrUpdate', // 添加 / 修改云模盒
+        mouldeList: '/mouldequipment/getEquipmentList', // 云模盒列表
+        enableMould: '/mouldequipment/use', // 启用云模盒
+
+        moulds: '/mouldequipment/getMouldEquipmentList', // 创建模具时获取资产方的云模盒列表
+        importMouldEquipmentExcel: '/mouldequipment/importMouldEquipmentExcel', //批量导入云模盒
+        
+        setPacket: '/mouldequipment/use',// 云平台下行配置数据包接口
+        openingAndClosingTimesChart: '/mouldhistory/openingAndClosingTimesChart', //获取云模盒的每日开合次数图表 (时间/次数)
+        openingAndClosingTimesChartCycle: '/mouldhistory/openingAndClosingTimesChartCycle', //获取云模盒的每日开合次数周期 (时间/次数)
+
+    },
+    file: {
+        view: '/pdffile/getPdfFile' // 文件预览
+    }
+}

+ 86 - 0
fhKeeper/formulahousekeeper/timesheet/src/routes.js

@@ -0,0 +1,86 @@
+import Login from './views/Login.vue'
+import NotFound from './views/404.vue'
+import Home from './views/Home.vue'
+
+// new router
+// 今日桌面
+import desktop from './views/desktop'
+import desktopDetail from './views/desktop/detail.vue'
+import unusual from './views/desktop/unusual.vue'
+
+// 工作报告
+import statistics from './views/workReport/statistics.vue'
+import daily from './views/workReport/daily.vue'
+
+// 团队管理
+import team from './views/team/index.vue'
+
+// 系统管理
+import system from './views/system/index.vue'
+
+let routes = [
+    {
+        path: '/login',
+        component: Login,
+        name: '',
+        hidden: true
+    },
+    //今日桌面
+    {
+        path: '/',
+        component: Home,
+        name: '今日桌面',
+        iconCls: 'fa fa-desktop',
+        children: [
+            { path: '/desktop', component: desktop, name: '桌面查看' },
+            { path: '/desktop/:id', component: desktopDetail, name: '个人桌面', hidden: true },
+            { path: '/unusual', component: unusual, name: '异常统计' },
+        ]
+    },
+    //工作报告
+    {
+        path: '/',
+        component: Home,
+        name: '工作报告',
+        iconCls: 'fa fa-sticky-note',
+        children: [
+            { path: '/statistics', component: statistics, name: '工时统计' },
+            { path: '/daily', component: daily, name: '工作日报' },
+        ]
+    },
+    //团队管理
+    {
+        path: '/',
+        component: Home,
+        name: '',
+        iconCls: 'fa fa-users',
+        leaf: true,//只有一个节点
+        children: [
+            { path: '/team', component: team, name: '团队管理' },
+        ]
+    },
+    //系统管理
+    {
+        path: '/',
+        component: Home,
+        name: '',
+        iconCls: 'fa fa-cog',
+        leaf: true,//只有一个节点
+        children: [
+            { path: '/system', component: system, name: '系统管理' },
+        ]
+    },
+    {
+        path: '/404',
+        component: NotFound,
+        name: '',
+        hidden: true
+    },
+    {
+        path: '*',
+        hidden: true,
+        redirect: { path: '/404' }
+    }
+];
+
+export default routes;

+ 61 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/404.vue

@@ -0,0 +1,61 @@
+<template>
+    <div>
+        <div class="page-img">
+            <img src="../assets/image/404.png" />
+        </div>
+        <p class="page-container"><b>Error</b>  非常抱歉你访问的页面不存在!!!</p>
+        <div class="page-button">
+            <el-button type="primary" round @click="back" icon="el-icon-s-promotion">返回首页</el-button>
+        </div>
+    </div>
+</template>
+
+<script>
+    export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+            back() {
+                this.$router.push('/map');
+            }
+        },
+        created() {
+           
+        },
+		mounted() {
+        }
+	}
+</script>
+
+<style lang="scss" scoped>
+    .page-img {
+        text-align: center;
+        padding: 100px 0 0 0 ;
+
+        img {
+            width: 600px;
+        }
+    }
+
+    .page-container {
+        font-size: 20px;
+        text-align: center;
+        color: rgb(192, 204, 218);
+        b {
+            margin-right: 30px;
+            font-size: 26px;
+        }
+    }
+
+    .page-button {
+        text-align: center;
+        margin-top: 40px;
+        .el-button.is-round {
+            width: 150px;
+            margin-right:80px;
+        }
+    }
+</style>

+ 628 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue

@@ -0,0 +1,628 @@
+<template>
+    <el-row class="container">
+        <el-col :span="24" class="header">
+            <el-col :span="10" class="logo" :class="collapsed?'logo-collapse-width':'logo-width'" :style="collapsed?'padding:0':''">
+                <img v-if="collapsed" class="headImg" src="../assets/image/head_logo.png" />
+                <div v-else class="logo-sys">
+                    <img class="headImg" src="../assets/image/head_logo.png" />
+                    <span>{{sysName}}</span>
+                </div>
+            </el-col>
+            <el-col :span="10">
+                <div class="tools" @click.prevent="collapse">
+                    <i class="fa fa-align-justify"></i>
+                </div>
+            </el-col>
+            <el-col :span="6" class="userinfo">
+                <el-badge class="itemNew" :value="unreadCount[3]" :hidden="unreadCount[3] == 0">
+                    <i class="el-icon-message-solid" style="font-size:24px" v-popover:popover1></i>
+                    <!-- 消息中心 -->
+                    <el-popover ref="popover1" placement="bottom" width="400" trigger="hover" popper-class="popover-self">
+                        <!-- 消息盒子中间部分 -->
+                        <el-tabs v-model="activePage" @tab-click="handleClick" stretch>
+                            <!-- 审批的页面 -->
+                            <el-tab-pane name="0">
+                                <span slot="label">
+                                <span v-if="unreadCount[0] == 0">审批</span>
+                                <span v-else>审批({{unreadCount[0]}})</span>
+                                </span>
+                                <div class="popover-item" v-if="popoverData[0].length == 0">暂无审批消息</div>
+                                <div class="popover-item" v-for="item in popoverData[0]">
+                                <div
+                                    style="cursor: pointer;"
+                                    @click="locationHerf(item.id, item.refId, item.noticeType, item.belongType)"
+                                >
+                                    <p class="popover-title">
+                                    <span v-if="item.isRead == 1" class="isRead">{{item.projectName}}</span>
+                                    <span v-else>{{item.projectName}}</span>
+                                    </p>
+                                    <p v-if="item.isRead == 1" class="isRead">{{item.content}}</p>
+                                    <p v-else>{{item.content}}</p>
+                                </div>
+                                </div>
+                            </el-tab-pane>
+
+                            <!-- 警告的页面 -->
+                            <el-tab-pane name="1">
+                                <span slot="label">
+                                <span v-if="unreadCount[1] == 0">警告</span>
+                                <span v-else>警告({{unreadCount[1]}})</span>
+                                </span>
+                                <div class="popover-item" v-if="popoverData[1].length == 0">暂无警告消息</div>
+                                <div class="popover-item" v-for="item in popoverData[1]">
+                                <div
+                                    style="cursor: pointer;"
+                                    @click="locationHerf(item.id, item.refId, item.noticeType, null)"
+                                >
+                                    <p class="popover-title">
+                                    <span v-if="item.isRead == 1" class="isRead">{{item.projectName}}</span>
+                                    <span v-else>{{item.projectName}}</span>
+                                    </p>
+                                    <p v-if="item.isRead == 1" class="isRead">{{item.content}}</p>
+                                    <p v-else>{{item.content}}</p>
+                                </div>
+                                </div>
+                            </el-tab-pane>
+
+                            <!-- 保养的页面 -->
+                            <el-tab-pane name="2">
+                                <span slot="label">
+                                <span v-if="unreadCount[2] == 0">保养</span>
+                                <span v-else>保养({{unreadCount[2]}})</span>
+                                </span>
+                                <div class="popover-item" v-if="popoverData[2].length == 0">暂无保养消息</div>
+                                <div class="popover-item" v-for="item in popoverData[2]">
+                                <div
+                                    style="cursor: pointer;"
+                                    @click="locationHerf(item.id, item.refId, item.noticeType, null)"
+                                >
+                                    <p class="popover-title">
+                                    <span v-if="item.isRead == 1" class="isRead">{{item.projectName}}</span>
+                                    <span v-else>{{item.projectName}}</span>
+                                    </p>
+                                    <p v-if="item.isRead == 1" class="isRead">{{item.content}}</p>
+                                    <p v-else>{{item.content}}</p>
+                                </div>
+                                </div>
+                            </el-tab-pane>
+                        </el-tabs>
+
+                        <!-- 查看全部的按钮 -->
+                        <router-link :to="'/message'" tag="div" class="popover-button">查看全部</router-link>
+                    </el-popover>
+                </el-badge>
+
+                <el-dropdown trigger="hover">
+                    <span class="el-dropdown-link userinfo-inner">
+                        <img src="../assets/image/userHead.png" />
+                        {{sysUserName}}
+                    </span>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item @click.native="reset">修改密码</el-dropdown-item>
+                        <el-dropdown-item @click.native="editInfoOpen">修改信息</el-dropdown-item>
+                        <el-dropdown-item divided @click.native="logout">退出登录</el-dropdown-item>
+                    </el-dropdown-menu>
+                </el-dropdown>
+            </el-col>
+        </el-col>
+
+        <el-col :span="24" class="main">
+            <aside :class="collapsed?'menu-collapsed':'menu-expanded'">
+                <!--导航菜单-->
+                <el-menu :default-active="$route.path" class="el-menu-vertical-demo" unique-opened router v-if="!collapsed">
+                    <template v-for="(item,index) in $router.options.routes" v-if="!item.hidden">
+                        <el-submenu :index="index+''" v-if="!item.leaf">
+                            <template slot="title">
+                                <i :class="item.iconCls"></i>
+                                <span class="itemName">{{item.name}}</span>
+                            </template>
+                            <el-menu-item v-for="child in item.children" :index="child.path" :key="child.path" v-if="!child.hidden">{{child.name}}</el-menu-item>
+                        </el-submenu>
+                        <el-menu-item v-if="item.leaf && item.children.length > 0" :index="item.children[0].path">
+                            <i :class="item.iconCls"></i> {{item.children[0].name}}
+                        </el-menu-item>
+                    </template>
+                </el-menu>
+
+                <!--导航菜单-折叠后-->
+                <ul class="el-menu el-menu-vertical-demo collapsed" v-if="collapsed" ref="menuCollapsed">
+                    <li v-for="(item,index) in $router.options.routes" v-if="!item.hidden" class="el-submenu item" :style="{overflow:!item.leaf?'':'hidden'}">
+                        <template v-if="!item.leaf">
+                            <div class="el-submenu__title" style="padding-left: 20px;" @mouseover="showMenu(index,true)" @mouseout="showMenu(index,false)">
+                                <i :class="item.iconCls"></i>
+                            </div>
+                            <ul class="el-menu submenu" :class="'submenu-hook-'+index" @mouseover="showMenu(index,true)" @mouseout="showMenu(index,false)">
+                                <li v-for="child in item.children" v-if="!child.hidden" :key="child.path" class="el-menu-item" style="padding-left: 40px;" :class="$route.path==child.path?'is-active':''" @click="$router.push(child.path)">{{child.name}}</li>
+                            </ul>
+                        </template>
+                        <template v-else>
+                            <li class="el-submenu">
+                                <div class="el-submenu__title el-menu-item" :class="$route.path==item.children[0].path?'is-active':''" @click="$router.push(item.children[0].path)"
+                                    style="padding-left: 20px;height: 56px;line-height: 56px;padding: 0 20px;">
+                                    <i :class="item.iconCls"></i>
+                                </div>
+                            </li>
+                        </template>
+                    </li>
+                </ul>
+            </aside>
+
+            <section class="content-container">
+                <div class="grid-content bg-purple-light">
+                    <el-col :span="24" class="content-wrapper">
+                        <transition name="fade" mode="out-in">
+                            <router-view></router-view>
+                        </transition>
+                    </el-col>
+                </div>
+
+                <!--修改密码-->
+                <el-dialog title="修改密码" width='450px' v-if="editPassWord" :visible.sync="editPassWord" :close-on-click-modal="false" customClass="customWidth">
+                    <el-form :model="addForm" label-width="80px" :rules="passRule" ref="addForm">
+                        <el-form-item label="新密码" prop="password">
+                            <el-input v-model="addForm.password" autocomplete="off" placeholder="请输入新密码" show-password></el-input>
+                        </el-form-item>
+                    </el-form>
+                    <div slot="footer" class="dialog-footer">
+                        <el-button @click.native="editPassWord = false">取消</el-button>
+                        <el-button type="primary" @click.native="resetPwd" :loading="editLoading">提交</el-button>
+                    </div>
+                </el-dialog>
+
+                <!--修改信息-->
+                <el-dialog title="修改信息" width='450px' v-if="editInformation" :visible.sync="editInformation" :close-on-click-modal="false" customClass="customWidth">
+                    <el-form :model="editInfoForm" label-width="80px" :rules="passRule" ref="editInfoForm">
+                        <el-form-item label="姓名" prop="username">
+                            <el-input v-model="editInfoForm.username" autocomplete="off" placeholder="请输入姓名"></el-input>
+                        </el-form-item>
+                    </el-form>
+                    <el-form :model="editInfoForm" label-width="80px" :rules="passRule" ref="editInfoForm">
+                        <el-form-item label="手机号" prop="mobile">
+                        <el-input v-model="editInfoForm.mobile" autocomplete="off" placeholder="请输入手机号" :disabled="true"></el-input>
+                        </el-form-item>
+                    </el-form>
+                    <div slot="footer" class="dialog-footer">
+                        <el-button @click.native="editInformation = false">取消</el-button>
+                        <el-button type="primary" @click.native="editInfo" :loading="editLoading2">提交</el-button>
+                    </div>
+                </el-dialog>
+            </section>
+        </el-col>
+    </el-row>
+</template>
+
+<script>
+    export default {
+        data() {
+            return {
+                user: sessionStorage.getItem("user"),
+                sysName: "工时管家",
+                collapsed: false,
+                sysUserName: "",
+
+                editInformation: false,
+                editPassWord: false,
+                editLoading: false,
+                editLoading2: false,
+                addForm: {
+                    id: "",
+                    password: ""
+                },
+                editInfoForm: {
+                    id: "",
+                    username: "",
+                    mobile: "",
+                    companyName: ""
+                },
+                passRule: {
+                    password: [{ required: true, message: "请输入新密码", trigger: "blur" }],
+                    username: [{ required: true, message: "请输入姓名", trigger: "blur" }]
+                },
+                //消息数据
+                popoverData: ["", "", ""],
+                unreadCount: [],
+                activePage: 0,
+
+                //时间
+                activeDate: new Date()
+            };
+        },
+        methods: {
+            //退出登录
+            logout: function() {
+                var _this = this;
+                this.$confirm("确认退出吗?", "提示", {
+                    //type: 'warning'
+                }).then(() => {
+                    sessionStorage.removeItem("user");
+                    _this.$router.push("/login");
+                });
+            },
+
+            //折叠导航栏
+            collapse: function() {
+                this.collapsed = !this.collapsed;
+            },
+
+            showMenu(i, status) {
+                this.$refs.menuCollapsed.getElementsByClassName(
+                    "submenu-hook-" + i
+                )[0].style.display = status ? "block" : "none";
+            },
+
+            //打开编辑信息界面
+            editInfoOpen() {
+                this.editInformation = true;
+                this.editInfoForm.id = JSON.parse(sessionStorage.getItem("user")).id;
+                this.editInfoForm.username = JSON.parse(
+                    sessionStorage.getItem("user")
+                ).username;
+                this.editInfoForm.mobile = JSON.parse(
+                    sessionStorage.getItem("user")
+                ).account;
+                this.editInfoForm.companyName = JSON.parse(
+                    sessionStorage.getItem("user")
+                ).companyName;
+            },
+
+            //编辑信息
+            editInfo() {
+                this.$refs.editInfoForm.validate(valid => {
+                    if (valid) {
+                    this.editLoading2 = true;
+                    this.http.post(
+                        this.port.pwd.resetPwd,
+                        { id: this.editInfoForm.id, username: this.editInfoForm.username },
+                        res => {
+                        this.editLoading2 = false;
+                        this.editInformation = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                            message: "修改成功",
+                            type: "success"
+                            });
+                            //读取并覆盖session storage
+                            var userObject = JSON.parse(sessionStorage.getItem("user"));
+                            userObject.username = this.editInfoForm.username;
+                            sessionStorage.setItem("user", JSON.stringify(userObject));
+                            this.sysUserName = this.editInfoForm.username;
+                        } else {
+                            this.$message({
+                            message: res.msg,
+                            type: "error"
+                            });
+                        }
+                        },
+                        error => {
+                        this.editLoading2 = false;
+                        this.editInformation = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                    }
+                });
+            },
+
+            reset() {
+                this.editPassWord = true;
+                this.addForm.id = JSON.parse(sessionStorage.getItem("user")).id;
+                this.addForm.account = JSON.parse(sessionStorage.getItem("user")).account;
+                },
+
+                resetPwd() {
+                this.$refs.addForm.validate(valid => {
+                    if (valid) {
+                    this.editLoading = true;
+                    this.http.post(
+                        this.port.pwd.resetPwd,
+                        this.addForm,
+                        res => {
+                        this.editLoading = false;
+                        this.editPassWord = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                            message: "修改成功,请重新登录",
+                            type: "success"
+                            });
+                            this.$router.push("/login");
+                        } else {
+                            this.$message({
+                            message: res.msg,
+                            type: "error"
+                            });
+                        }
+                        },
+                        error => {
+                        this.editLoading = false;
+                        this.editPassWord = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                    }
+                });
+            },
+            //读取消息提示
+            loadNotice() {
+                this.http.post(
+                    this.port.notice.list,
+                    {
+                    pageNum: 1,
+                    pageSize: 5
+                    },
+                    res => {
+                    if (res.code == "ok") {
+                        this.popoverData = [];
+                        this.popoverData.push(res.data[0].approvelList.list);
+                        this.popoverData.push(res.data[1].matainList.list);
+                        this.popoverData.push(res.data[2].emergencyList.list);
+                        this.unreadCount = [];
+                        this.unreadCount.push(res.data[0].isNotReadCount);
+                        this.unreadCount.push(res.data[1].isNotReadCount);
+                        this.unreadCount.push(res.data[2].isNotReadCount);
+                        this.unreadCount.push(
+                        this.unreadCount[0] + this.unreadCount[1] + this.unreadCount[2]
+                        );
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                    },
+                    error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                    }
+                );
+            },
+            //点击消息的跳转
+            locationHerf(id, refid, type, approval) {
+                this.http.post(
+                    this.port.notice.read,
+                    {
+                    id: id
+                    },
+                    res => {
+                    if (res.code == "ok") {
+                        //重新读取一次消息
+                        this.loadNotice();
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                    },
+                    error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                    }
+                );
+                //本页面再点的话强制转移一下
+                var currentRoute = this.$route.path.split("/");
+                if (currentRoute.length == 4 && currentRoute[1] == "moldList") {
+                    this.$router.go(0);
+                }
+                if (type == 0) {
+                    //审批 跳转到模具详情
+                    this.$router.push("/moldList/" + refid + "/" + approval);
+                } else if (type == 1) {
+                    //警告 跳转到运行监测
+                    this.$router.push("/detection");
+                } else if (type == 2) {
+                    //保养 跳转到运行监测详情
+                    this.$router.push("/detection/" + refid);
+                }
+            },
+
+            //标签页面切换时
+            handleClick(tab, event) {
+                this.activeTab = tab.name;
+            }
+        },
+        mounted() {
+            if (this.user) {
+                var user = JSON.parse(this.user);
+                this.user = user;
+                this.sysUserName = user.username || "";
+                this.loadNotice();
+            } else {
+                this.$router.push("/login");
+            }
+        }
+    };
+</script>
+
+<style scoped lang="scss">
+    .el-menu-vertical-demo i {
+        margin-right: 10px;
+    }
+
+    .container {
+        position: absolute;
+        top: 0px;
+        bottom: 0px;
+        width: 100%;
+        .header {
+            height: 60px;
+            line-height: 60px;
+            background: #20a0ff;
+            color: #fff;
+            .userinfo {
+                text-align: right;
+                padding-right: 35px;
+                float: right;
+                .userinfo-inner {
+                    cursor: pointer;
+                    color: #fff;
+                    img {
+                        width: 40px;
+                        height: 40px;
+                        border-radius: 20px;
+                        margin: 10px 10px 10px 10px;
+                        float: left;
+                    }
+                }
+                .itemNew {
+                    height: 25px;
+                    margin-right: 25px;
+                    i {
+                        vertical-align: top;
+                    }
+                }
+            }
+            .logo {
+                height: 60px;
+                font-size: 21px;
+                padding-left: 20px;
+                padding-right: 20px;
+                border-color: rgba(238, 241, 146, 0.3);
+                border-right-width: 1px;
+                border-right-style: solid;
+                img {
+                    width: 40px;
+                    float: left;
+                    margin: 10px 10px 10px 18px;
+                }
+                img.headImg {
+                    margin: 0;
+                    width: 40px;
+                    height: 40px;
+                    margin: 10px 0 0 10px;
+                }
+                .logo-sys {
+                    height: 100%;
+                    line-height: 100%;
+                    img.headImg {
+                        width: 40px;
+                        height: 40px;
+                        margin: 10px 0 0 10px;
+                        vertical-align: middle;
+                    }
+                    span {
+                        display: inline-block;
+                        height: 100%;
+                        line-height: 100%;
+                        margin-left: 15px;
+                        margin: 20px 0 0 15px;
+                        vertical-align: middle;
+                    }
+                }
+                .txt {
+                    color: #fff;
+                }
+            }
+            .logo-width {
+                width: 230px;
+            }
+            .logo-collapse-width {
+                width: 60px;
+            }
+            .tools {
+                padding: 0px 23px;
+                width: 14px;
+                height: 60px;
+                line-height: 60px;
+                cursor: pointer;
+            }
+        }
+        .main {
+            display: flex;
+            position: absolute;
+            top: 60px;
+            bottom: 0px;
+            overflow: hidden;
+            aside {
+                flex: 0 0 230px;
+                width: 230px;
+                .el-menu {
+                    height: 100%;
+                }
+                .collapsed {
+                    width: 60px;
+                    .item {
+                        position: relative;
+                    }
+                    .submenu {
+                        position: absolute;
+                        top: 0px;
+                        left: 60px;
+                        z-index: 99999;
+                        height: auto;
+                        display: none;
+                    }
+                }
+            }
+            .menu-collapsed {
+                flex: 0 0 60px;
+                width: 60px;
+            }
+            .menu-expanded {
+                flex: 0 0 230px;
+                width: 230px;
+            }
+            .content-container {
+                flex: 1;
+                width: 80%;
+                padding: 10px;
+                overflow-y: auto;
+                .breadcrumb-container {
+                    .title {
+                        width: 200px;
+                        float: left;
+                        color: #475669;
+                    }
+                    .breadcrumb-inner {
+                        float: right;
+                    }
+                }
+                .content-wrapper {
+                    background-color: #fff;
+                    box-sizing: border-box;
+                }
+            }
+        }
+    }
+
+    .popover-item {
+        padding: 10px;
+        border-bottom: 1px #eee solid;
+    }
+
+    .popover-item > div > p {
+        margin: 0;
+        line-height: 18px;
+    }
+
+    .popover-title {
+        color: #409eff;
+        padding-bottom: 8px;
+    }
+
+    .popover-type {
+        color: #aaa;
+        font-size: 8px;
+        float: right;
+    }
+
+    .popover-button {
+        font-weight: 900;
+        padding: 10px;
+        text-align: center;
+        cursor: pointer;
+    }
+
+    .isRead {
+        color: #999 !important;
+    }
+</style>

+ 123 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue

@@ -0,0 +1,123 @@
+<template>
+    <div class="login">
+        <div class="login-par">
+            <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-position="left" label-width="0px" class="demo-ruleForm login-container">
+                <div class="login-logo">
+                    <img src="../assets/image/login_logo.png" style="width:80px;height:80px;"/>
+                </div>
+                <h3 class="title">工时管家</h3>
+                <el-form-item class="login-input" prop="account">
+                    <el-input type="text" v-model="ruleForm.account" autocomplete="off" placeholder="账号" clearable prefix-icon="el-icon-user-solid"></el-input>
+                </el-form-item>
+                <el-form-item class="login-input" prop="password">
+                    <el-input type="password" v-model="ruleForm.password" @keyup.enter.native="handleSubmit" autocomplete="off" placeholder="密码" show-password prefix-icon="el-icon-lock"></el-input>
+                </el-form-item>
+                <el-form-item class="login-button" style="width:100%;">
+                    <el-button type="primary" style="width:100%;" @click.native.prevent="handleSubmit" :loading="logining">登录</el-button>
+                </el-form-item>
+            </el-form>
+        </div>
+    </div>
+</template>
+
+<script>
+    export default {
+        data() {
+            return {
+                logining: false,
+                // 登录信息
+                ruleForm: {
+                    account: '',
+                    password: ''
+                },
+                rules: {
+                    account: [{ required: true, message: '请输入账号', trigger: 'blur' },],
+                    password: [{ required: true, message: '请输入密码', trigger: 'blur' },]
+                }
+            };
+        },
+        methods: {
+            handleReset2() {
+                this.$refs.ruleForm.resetFields();
+            },
+
+            handleSubmit(ev) {
+                this.$refs.ruleForm.validate((valid) => {
+                    if (valid) {
+                        var _this = this;
+                        this.logining = true;
+                        this.http.post(this.port.manage.login, this.ruleForm , res => {
+                            this.logining = false;
+                            if (res.code == "ok") {
+                                sessionStorage.setItem('user', JSON.stringify(res.data));
+                                this.$router.push({ path: '/desktop' });
+                            } else {
+                                this.$message({
+                                    message: res.msg,
+                                    type: 'error'
+                                });
+                            }
+                        }, error => {
+                            this.logining = false;
+                            this.$message({
+                                message: error,
+                                type: 'error'
+                            });
+                        })
+                    }
+                });
+            }
+        }
+    }
+</script>
+
+<style lang="scss" scoped>
+    .login {
+        height: 100%;
+        .login-par {
+            width: 100%;
+            min-height: 100%;
+            background: #f0f2f5 url('../assets/image/background.png') no-repeat 50%;
+            background-size: 100%;
+            padding: 110px 0 144px;
+            position: relative;
+            box-sizing: border-box;
+            .login-logo {
+                text-align: center;
+                margin: 0 0 20px 0;
+            }
+            .login-container {
+                -webkit-border-radius: 5px;
+                border-radius: 5px;
+                -moz-border-radius: 5px;
+                background-clip: padding-box;
+                width: 315px;
+                height: 365px;
+                padding: 25px 35px 25px 35px;
+                background: #fff;
+                border: 1px solid #eaeaea;
+                box-shadow: 0 0 5px #cac6c6;
+                border-top: 10px solid #20a0ff;
+                margin:auto;
+                .title {
+                    font-size: 20px;
+                    margin: 0px auto 40px auto;
+                    text-align: center;
+                    color: #505458;
+                }
+                .remember {
+                    margin: 0px 0px 35px 0px;
+                }
+                .login-input {
+                    margin: 30px 0 0 0;
+                }
+                .login-button {
+                    margin: 30px 0 0 0;
+                }
+                .login-button .el-button {
+                    padding: 14px;
+                }
+            }
+        }
+    }
+</style>

+ 214 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/desktop/detail.vue

@@ -0,0 +1,214 @@
+<template>
+    <section>
+        <!--工具条-->
+        <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+            <el-form :inline="true">
+                <el-form-item>
+                    <el-button type="text" @click="backToList" icon="el-icon-back" class="back">返回</el-button>
+                </el-form-item>
+                <el-form-item class="divLine"></el-form-item>
+                <el-form-item>
+                    <span class="workName">{{uName}} / {{uTime}}</span>
+                </el-form-item>
+                <el-form-item style="float:right;">
+                    今日工作时长:<span class="workHours">{{uHours}}h</span>
+                </el-form-item>
+            </el-form>
+        </el-col>
+
+        <!-- 卡片列表 -->
+        <div>
+            <el-col :span="24" class="one_div">
+                <div id="pie_echarts"></div>
+            </el-col>
+            <el-col :span="6" v-for="(item, index) in 12" :key="item" class="one_div">
+                <el-card :body-style="{ padding: '0px' }" shadow="hover" class="one_card">
+                    <div class="one_card_img">
+                        <el-image :src="index==0?require('../../assets/image/047_S.jpg'):require('../../assets/image/noPic.png')" :preview-src-list="getSrcList(index)" class="image" lazy></el-image>
+                    </div>
+                    <div class="one_card_txt">
+                        <span>在玩游戏呢!!!!!</span>
+                        <div class="bottom clearfix">
+                            <time class="time">9点59分59秒</time>
+                        </div>
+                    </div>
+                </el-card>
+            </el-col>
+        </div>
+    </section>
+</template>
+
+<script>
+    import util from "../../common/js/util";
+    export default {
+        data() {
+            return {
+                detailId: this.$route.params.id,
+                user: JSON.parse(sessionStorage.getItem('user')),
+                uName: '周瑞霆',
+                uTime: '2020-01-03',
+                uHours: 20,
+                srcList: [
+                    require('../../assets/image/047_S.jpg'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                    require('../../assets/image/noPic.png'),
+                ],
+                myChart: null,
+            };
+        },
+        methods: {
+            //返回
+            backToList() {
+                this.$router.go(-1);
+            },
+
+            setEcharts() {
+                var myChart = this.echarts.init(document.getElementById('pie_echarts'));
+                this.myChart = myChart;
+                var option = {
+                    title: {
+                        text: '工作时长分配',
+                        left: 'left'
+                    },
+                    tooltip: {
+                        trigger: 'item',
+                        formatter: '{a} <br/>{b} : {c} ({d}%)'
+                    },
+                    legend: {
+                        type: 'scroll',
+                        orient: 'vertical',
+                        right: 0,
+                        top: 30,
+                        bottom: 20,
+                        data: ['rose1', 'rose2', 'rose3', 'rose4', 'rose5', 'rose6', 'rose7', 'rose8']
+                    },
+                    toolbox: {
+                        show: true,
+                        feature: {
+                            mark: {show: true},
+                            dataView: {show: true, readOnly: false},
+                            magicType: {
+                                show: true,
+                                type: ['pie', 'funnel']
+                            },
+                            restore: {show: true},
+                            saveAsImage: {show: true}
+                        }
+                    },
+                    series: [
+                        {
+                            name: '面积模式',
+                            type: 'pie',
+                            radius: [30, 110],
+                            roseType: 'area',
+                            data: [
+                                {value: 10, name: 'rose1'},
+                                {value: 5, name: 'rose2'},
+                                {value: 15, name: 'rose3'},
+                                {value: 25, name: 'rose4'},
+                                {value: 20, name: 'rose5'},
+                                {value: 35, name: 'rose6'},
+                                {value: 30, name: 'rose7'},
+                                {value: 40, name: 'rose8'}
+                            ]
+                        }
+                    ]
+                };
+                myChart.setOption(option);
+            },
+
+            getSrcList(index){
+                return this.srcList.slice(index).concat(this.srcList.slice(0,index))
+            },
+
+            getSrcList1(index) {
+                return this.srcList1.slice(index).concat(this.srcList1.slice(0,index))
+            }
+        },
+
+        created() {
+        },
+
+        mounted() {
+            this.setEcharts();
+            var _this = this;
+            window.addEventListener("resize", function () {
+                _this.myChart.resize();
+            });
+        }
+    };
+</script>
+
+<style lang="scss" scoped>
+    .toolbar {
+        .el-form-item {
+            font-size: 14px;
+            vertical-align: middle;
+        }
+        .back {
+            font-size:16px; 
+            cursor: pointer;
+        }
+        .divLine {
+            width: 2px;
+            background: #c3c3c3;
+            height: 100%;
+        }
+        .workName {
+            color: #333;
+            font-size: 18px;
+        }
+        .workHours {
+            color: #20a0ff;
+            font-size: 18px;
+        }
+    }
+
+    .one_div {
+        padding: 15px;
+        .one_card {
+            .image {
+                width: 100%;
+            }
+            .one_card_txt {
+                padding: 13px;
+                .bottom {
+                    margin-top: 13px;
+                    line-height: 12px;
+                    i {
+                        color: #9ED0FF;
+                        margin-right: 5px;
+                    }
+                    .time {
+                        margin-top: 2px;
+                        color: #999;
+                    }
+                }
+            } 
+        }
+        #pie_echarts {
+            display: inline-block;
+            width: 100%;
+            height: 100%;
+            min-height: 350px;
+        }
+    }
+</style>
+
+<style lang="scss">
+    .image {
+        .el-image__inner {
+            height: 11.6vw!important;
+        }
+    }
+</style>

+ 141 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/desktop/index.vue

@@ -0,0 +1,141 @@
+<template>
+	<section>
+        <!--工具条-->
+		<el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+			<div class="nowTime">
+                <i class="fa fa-clock-o"></i>
+                {{currentTime}}
+            </div>
+		</el-col>
+
+        <!-- 卡片列表 -->
+        <div>
+            <el-col :span="6" v-for="(item, index) in 12" :key="item" class="one_div">
+                <el-card :body-style="{ padding: '0px' }" shadow="hover" class="one_card">
+                    <div class="one_card_img">
+                        <el-image :src="index==0?require('../../assets/image/047_S.jpg'):require('../../assets/image/noPic.png')" class="image" lazy></el-image>
+                        <div :id="'over'+index" class="over">
+                            <el-button type="primary" plain @click.native="jumpTo(item)"><i class="fa fa-link"></i> 所有截图</el-button>
+                        </div>
+                    </div>
+                    <div class="one_card_txt">
+                        <span>在玩游戏呢!!!!!</span>
+                        <div class="bottom clearfix">
+                            <el-link><i class="fa fa-circle"></i> 吴涛涛</el-link>
+                            <time class="time">9点59分59秒</time>
+                        </div>
+                    </div>
+                </el-card>
+            </el-col>
+        </div>
+	</section>
+</template>
+
+<script>
+    import util from '../../common/js/util'
+	export default {
+		data() {
+			return {
+				filters: {
+					keyName: ''
+                },
+                user: JSON.parse(sessionStorage.getItem('user')),
+                timer: "",
+                currentTime: util.formatDate.format(new Date(new Date()), 'yyyy-MM-dd hh:mm:ss'),
+			}
+		},
+		methods: {
+            getTime() {
+                var _this = this; //声明一个变量指向Vue实例this,保证作用域一致
+                this.timer = setInterval(function() {
+                    _this.currentTime = util.formatDate.format(new Date(new Date()), 'yyyy-MM-dd hh:mm:ss');
+                }, 1000);
+            },
+            jumpTo(id) {
+                this.$router.push('/desktop/' + id);
+            }
+        },
+        created() {
+            this.getTime();
+        },
+		mounted() {
+        },
+        beforeDestroy() {
+            if (this.timer) {
+                clearInterval(this.timer);
+            }
+        }
+	}
+</script>
+
+<style lang="scss" scoped>
+    .nowTime {
+        height: 35px;
+        line-height: 28px;
+        font-size: 18px;
+        color: #20a0ff;
+        margin-left: 10px;
+        i {
+            margin-right: 10px;
+        }
+    }
+
+    .one_div {
+        padding: 15px;
+        .one_card {
+            .one_card_img {
+                position: relative;
+                .image {
+                    width: 100%;
+                }
+                .over {
+                    display: none;
+                    width: 100%;
+                    height: 98%;
+                    background: rgba(0,0,0,0.2);
+                    position: absolute;
+                    top: 0;
+                    text-align: center;
+                }
+            }
+            .one_card_txt {
+                padding: 13px;
+                .bottom {
+                    margin-top: 13px;
+                    line-height: 12px;
+                    i {
+                        color: #9ED0FF;
+                        margin-right: 5px;
+                    }
+                    .time {
+                        float: right;
+                        margin-top: 2px;
+                        color: #999;
+                    }
+                }
+            } 
+        }
+        .one_card:hover {
+            .one_card_img {
+                .over {
+                    display: block!important;
+                }
+            }
+        }
+    }
+</style>
+<style lang="scss">
+    .image {
+        .el-image__inner {
+            height: 11.6vw!important;
+        }
+    }
+
+    .one_card_img {
+        .over {
+            .el-button {
+                margin-top: 25%;
+            }
+        }
+    }
+</style>

+ 91 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/desktop/unusual.vue

@@ -0,0 +1,91 @@
+<template>
+	<section>
+        <!--工具条-->
+		<el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+			<div class="nowTime">
+                非工作情况统计
+            </div>
+		</el-col>
+
+        <!--列表-->
+		<el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+			<el-table-column type="index" width="60"></el-table-column>
+            <el-table-column prop="name" label="姓名" width="140" sortable></el-table-column>
+            <el-table-column prop="behavior" label="行为"></el-table-column>
+			<el-table-column prop="indate" label="创建时间" width="180" sortable></el-table-column>
+		</el-table>
+
+		<!--工具条-->
+		<el-col :span="24" class="toolbar">
+			<el-pagination
+                @size-change="handleSizeChange"
+                @current-change="handleCurrentChange"
+                :page-sizes="[20 , 50 , 80 , 100]"
+                :page-size="20"
+                layout="total, sizes, prev, pager, next"
+                :total="total"
+                style="float:right;">
+            </el-pagination>
+		</el-col>
+    </section> 
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+                user: JSON.parse(sessionStorage.getItem('user')),
+
+                tableHeight: 0,
+                listLoading: false,
+                total: 0,
+                page: 1,
+                size: 20,
+                list:[
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                ]
+			}
+		},
+		methods: {
+            //分页
+			handleCurrentChange(val) {
+				this.page = val;
+				this.getProject();
+            },
+
+            handleSizeChange(val) {
+                this.size = val;
+				this.getProject();
+            },
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 195;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 195;    
+            };
+        },
+        mounted() {
+        }
+	}
+</script>
+
+<style lang="scss" scoped>
+    .nowTime {
+        height: 35px;
+        line-height: 28px;
+        font-size: 18px;
+        color: #333;
+        margin-left: 10px;
+        i {
+            margin-right: 10px;
+        }
+    }
+</style>

+ 264 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/message.vue

@@ -0,0 +1,264 @@
+<template>
+  <section>
+    <!--工具条-->
+    <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+      <el-form :inline="true">
+        <el-col :span="2">
+          <el-form-item>消息中心</el-form-item>
+        </el-col>
+      </el-form>
+    </el-col>
+
+    <!--选项卡-->
+    <el-col :span="24">
+      <el-tabs v-model="activePage" @tab-click="handleClick" type="card">
+        <el-tab-pane name="0" label="审批">
+          <div :style="heightString">
+            <span v-if="messages[0].length == 0">目前暂无消息</span>
+            <div
+              class="message-div"
+              v-for="item in messages[0]"
+              @click="locationHerf(item.id, item.refId, item.noticeType, item.belongType)"
+            >
+              <p>
+                <span class="message-title isRead" v-if="item.isRead == 1">{{item.projectName}}</span>
+                <span class="message-title" v-else>{{item.projectName}}</span>
+                <span class="message-time">{{item.indate}}</span>
+              </p>
+              <p class="message-article">{{item.content}}</p>
+            </div>
+          </div>
+          <!--分页1-->
+          <el-col :span="24" class="toolbar">
+            <el-pagination
+              @size-change="handleSizeChange0"
+              @current-change="handleCurrentChange0"
+              :page-sizes="[20 , 50 , 80 , 100 , 200]"
+              :page-size="20"
+              layout="total, sizes, prev, pager, next"
+              :total="total[0]"
+              style="float:right;"
+            ></el-pagination>
+          </el-col>
+        </el-tab-pane>
+        <el-tab-pane name="1" label="警告">
+          <div :style="heightString">
+            <span v-if="messages[1].length == 0">目前暂无消息</span>
+            <div
+              class="message-div"
+              v-for="item in messages[1]"
+              @click="locationHerf(item.id, item.refId, item.noticeType, null)"
+            >
+              <p>
+                <span class="message-title isRead" v-if="item.isRead == 1">{{item.projectName}}</span>
+                <span class="message-title" v-else>{{item.projectName}}</span>
+                <span class="message-time">{{item.indate}}</span>
+              </p>
+              <p class="message-article">{{item.content}}</p>
+            </div>
+          </div>
+          <!--分页2-->
+          <el-col :span="24" class="toolbar">
+            <el-pagination
+              @size-change="handleSizeChange1"
+              @current-change="handleCurrentChange1"
+              :page-sizes="[20 , 50 , 80 , 100 , 200]"
+              :page-size="20"
+              layout="total, sizes, prev, pager, next"
+              :total="total[1]"
+              style="float:right;"
+            ></el-pagination>
+          </el-col>
+        </el-tab-pane>
+        <el-tab-pane name="2" label="保养">
+          <div :style="heightString">
+            <span v-if="messages[2].length == 0">目前暂无消息</span>
+            <div
+              class="message-div"
+              v-for="item in messages[2]"
+              @click="locationHerf(item.id, item.refId, item.noticeType, null)"
+            >
+              <p>
+                <span class="message-title isRead" v-if="item.isRead == 1">{{item.projectName}}</span>
+                <span class="message-title" v-else>{{item.projectName}}</span>
+                <span class="message-time">{{item.indate}}</span>
+              </p>
+              <p class="message-article">{{item.content}}</p>
+            </div>
+          </div>
+          <!--分页3-->
+          <el-col :span="24" class="toolbar">
+            <el-pagination
+              @size-change="handleSizeChange2"
+              @current-change="handleCurrentChange2"
+              :page-sizes="[20 , 50 , 80 , 100 , 200]"
+              :page-size="20"
+              layout="total, sizes, prev, pager, next"
+              :total="total[2]"
+              style="float:right;"
+            ></el-pagination>
+          </el-col>
+        </el-tab-pane>
+      </el-tabs>
+    </el-col>
+  </section>
+</template>
+
+<script>
+import util from "../common/js/util";
+export default {
+  data() {
+    return {
+      messages: [[], [], []],
+      page0: 1,
+      page1: 1,
+      page2: 1,
+      size: 20,
+      total: [0, 0, 0],
+      tableHeight: 0,
+      activePage: 0,
+      heightString: ""
+    };
+  },
+  methods: {
+    //分页1
+    handleCurrentChange0(val) {
+      this.page0 = val;
+      this.loadNotice();
+    },
+    handleSizeChange0(val) {
+      this.size1 = val;
+      this.loadNotice();
+    },
+    //分页2
+    handleCurrentChange1(val) {
+      this.page2 = val;
+      this.loadNotice();
+    },
+    handleSizeChange1(val) {
+      this.size = val;
+      this.loadNotice();
+    },
+    //分页3
+    handleCurrentChange2(val) {
+      this.page = val;
+      this.loadNotice();
+    },
+    handleSizeChange2(val) {
+      this.size = val;
+      this.loadNotice();
+    },
+    //标签页面切换时
+    handleClick(tab, event) {
+      this.activeTab = tab.name;
+    },
+    //读取消息提示
+    loadNotice() {
+      this.http.post(
+        this.port.notice.list,
+        {
+          pageNum: this.page,
+          pageSize: this.size
+        },
+        res => {
+          if (res.code == "ok") {
+            this.messages = [];
+            this.messages.push(res.data[0].approvelList.list);
+            this.messages.push(res.data[1].matainList.list);
+            this.messages.push(res.data[2].emergencyList.list);
+            this.total[0] = res.data[0].approvelList.total;
+            this.total[1] = res.data[1].matainList.total;
+            this.total[2] = res.data[2].emergencyList.total;
+          } else {
+            this.$message({
+              message: res.msg,
+              type: "error"
+            });
+          }
+        },
+        error => {
+          this.$message({
+            message: error,
+            type: "error"
+          });
+        }
+      );
+    },
+    //点击消息的跳转
+    locationHerf(id, refid, type, approval) {
+      this.http.post(
+        this.port.notice.read,
+        {
+          id: id
+        },
+        res => {
+          if (res.code == "ok") {
+          } else {
+            this.$message({
+              message: res.msg,
+              type: "error"
+            });
+          }
+        },
+        error => {
+          this.$message({
+            message: error,
+            type: "error"
+          });
+        }
+      );
+      if (type == 0) {
+        //审批 跳转到模具详情
+        this.$router.push("/moldList/" + refid + "/" + approval);
+      } else if (type == 1) {
+        //警告 跳转到运行监测
+        this.$router.push("/detection");
+      } else if (type == 2) {
+        //保养 跳转到运行监测详情
+        this.$router.push("/detection/" + refid);
+      }
+    }
+  },
+  created() {
+    let height = window.innerHeight;
+    this.tableHeight = height - 260;
+    this.heightString = "height: " + this.tableHeight + "px";
+  },
+  mounted() {
+    this.loadNotice();
+  }
+};
+</script>
+
+<style scoped>
+.message-div {
+  cursor: pointer;
+  padding: 5px 0;
+}
+
+.message-div > p {
+  line-height: 25px;
+  margin: 0;
+}
+
+.message-type {
+  font-weight: 700;
+}
+
+.message-time {
+  padding-left: 30px;
+  color: #777;
+}
+
+.message-title {
+  color: #409eff;
+}
+
+.message-article {
+  color: #555;
+}
+
+.isRead {
+  color: #999 !important;
+}
+</style>

+ 192 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/system/index.vue

@@ -0,0 +1,192 @@
+<template>
+	<section>
+		<!--工具条-->
+		<el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+			<el-form :inline="true">
+				<el-form-item>
+					<el-date-picker v-model="date" :editable="false" format="yyyy-MM-dd" value-format="yyyy-MM-dd" @change='getList' :clearable="false" type="date" placeholder="选择日期"></el-date-picker>
+				</el-form-item>
+				<el-form-item style="float:right;">
+                    <el-link type="primary" :underline="false" @click="handleAdd">异常申请</el-link>
+				</el-form-item>
+			</el-form>
+		</el-col>
+
+		<!--列表-->
+		<el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+			<el-table-column type="index" width="60"></el-table-column>
+			<el-table-column prop="projectName" label="姓名" width="140" sortable></el-table-column>
+            <el-table-column prop="ownerCompanyName" label="手机" width="180"></el-table-column>
+            <el-table-column prop="customCompaniesStr" label="编程"></el-table-column>
+            <el-table-column prop="manager" label="设计" sortable></el-table-column>
+            <el-table-column prop="manager" label="办公" sortable></el-table-column>
+            <el-table-column prop="manager" label="娱乐" sortable></el-table-column>
+            <el-table-column prop="manager" label="浏览" sortable></el-table-column>
+			<el-table-column prop="indate" label="总时长" width="180" sortable></el-table-column>
+		</el-table>
+
+		<!--工具条-->
+		<el-col :span="24" class="toolbar">
+			<el-pagination
+                @size-change="handleSizeChange"
+                @current-change="handleCurrentChange"
+                :page-sizes="[20 , 50 , 80 , 100]"
+                :page-size="20"
+                layout="total, sizes, prev, pager, next"
+                :total="total"
+                style="float:right;">
+            </el-pagination>
+		</el-col>
+
+        <!--新增界面-->
+		<el-dialog title="异常申请列表" v-if="addFormVisible" :visible.sync="addFormVisible" :close-on-click-modal="false" customClass='customWidth'>
+			<el-table :data="list" highlight-current-row v-loading="listLoading" height="400" style="width: 100%;">
+                <el-table-column type="index" width="60"></el-table-column>
+                <el-table-column prop="projectName" label="姓名" width="140" sortable></el-table-column>
+                <el-table-column prop="indate" label="工作时长" width="100" sortable></el-table-column>
+                <el-table-column prop="indate" label="异常原因" width="180" sortable></el-table-column>
+                <el-table-column prop="indate" label="时间" sortable></el-table-column>
+            </el-table>
+			<div slot="footer" class="dialog-footer">
+				<el-button @click.native="addFormVisible = false">取消</el-button>
+			</div>
+		</el-dialog>
+	</section>
+</template>
+
+<script>
+	import util from '../../common/js/util'
+
+	export default {
+		data() {
+			return {
+                user: JSON.parse(sessionStorage.getItem('user')),
+
+                date: new Date(),
+
+                tableHeight: 0,
+                listLoading: false,
+				total: 0,
+                page: 1,
+                size: 20,
+                list: [],
+                
+                addFormVisible: false,
+				addLoading: false,
+			}
+		},
+		methods: {
+			//分页
+			handleCurrentChange(val) {
+				this.page = val;
+				this.getList();
+            },
+
+            handleSizeChange(val) {
+                this.size = val;
+				this.getList();
+            },
+            
+			//获取项目列表
+			getList() {
+				this.listLoading = true;
+				this.http.post(this.port.project.projectList, {
+                    keyName: '',
+                    pageNum: this.page,
+                    pageSize: this.size,
+                }, res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data.list;
+                        for(var i in list){
+                            var customCompaniesStr = "";
+                            for(var j in list[i].customCompanies){
+                                if(j == list[i].customCompanies.length -1){
+                                    customCompaniesStr += list[i].customCompanies[j].companyName;
+                                } else {
+                                    customCompaniesStr += list[i].customCompanies[j].companyName + "、";
+                                }
+                            }
+                            list[i].customCompaniesStr = customCompaniesStr;
+                        }
+                        this.list = list;
+                        this.total = res.data.total;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: 'error'
+                        });
+                    }
+                }, error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: 'error'
+                    });
+                })
+            },
+
+            //显示新增界面
+			handleAdd() {
+                this.getUnusual();
+				this.addFormVisible = true;
+            },
+
+            // 获取异常列表
+            getUnusual() {
+                this.listLoading = true;
+				this.http.post(this.port.project.projectList, {
+                    keyName: '',
+                    pageNum: this.page,
+                    pageSize: this.size,
+                }, res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data.list;
+                        for(var i in list){
+                            var customCompaniesStr = "";
+                            for(var j in list[i].customCompanies){
+                                if(j == list[i].customCompanies.length -1){
+                                    customCompaniesStr += list[i].customCompanies[j].companyName;
+                                } else {
+                                    customCompaniesStr += list[i].customCompanies[j].companyName + "、";
+                                }
+                            }
+                            list[i].customCompaniesStr = customCompaniesStr;
+                        }
+                        this.list = list;
+                        this.total = res.data.total;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: 'error'
+                        });
+                    }
+                }, error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: 'error'
+                    });
+                })
+            },
+
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 195;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 195;    
+            };
+        },
+		mounted() {
+            this.getList();
+		}
+	}
+
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 100 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue

@@ -0,0 +1,100 @@
+<template>
+	<section>
+        <!--工具条-->
+		<el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+			<el-form :inline="true">
+				<el-form-item style="float:right;">
+                    <el-link type="primary" :underline="false">添加人员</el-link>
+				</el-form-item>
+                <el-form-item style="float:right;">
+                    <el-link type="primary" :underline="false">批量导入</el-link>
+				</el-form-item>
+			</el-form>
+		</el-col>
+
+        <!--列表-->
+		<el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+			<el-table-column type="index" width="60"></el-table-column>
+            <el-table-column prop="name" label="姓名" sortable></el-table-column>
+            <el-table-column prop="behavior" label="手机"></el-table-column>
+			<el-table-column label="操作">
+                <template slot-scope="scope">
+                    <el-button size="small" type="danger" @click="handleDel(scope.row)">删除</el-button>
+                </template>
+            </el-table-column>
+		</el-table>
+
+		<!--工具条-->
+		<el-col :span="24" class="toolbar">
+			<el-pagination
+                @size-change="handleSizeChange"
+                @current-change="handleCurrentChange"
+                :page-sizes="[20 , 50 , 80 , 100]"
+                :page-size="20"
+                layout="total, sizes, prev, pager, next"
+                :total="total"
+                style="float:right;">
+            </el-pagination>
+		</el-col>
+    </section> 
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+                user: JSON.parse(sessionStorage.getItem('user')),
+
+                tableHeight: 0,
+                listLoading: false,
+                total: 0,
+                page: 1,
+                size: 20,
+                list:[
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                    {name:'张三',behavior:'上班打游戏',indate:'2019-12-14'},
+                ]
+			}
+		},
+		methods: {
+            //分页
+			handleCurrentChange(val) {
+				this.page = val;
+				// this.getProject();
+            },
+
+            handleSizeChange(val) {
+                this.size = val;
+				// this.getProject();
+            },
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 195;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 195;    
+            };
+        },
+        mounted() {
+        }
+	}
+</script>
+
+<style lang="scss" scoped>
+    .nowTime {
+        height: 35px;
+        line-height: 28px;
+        font-size: 18px;
+        color: #333;
+        margin-left: 10px;
+        i {
+            margin-right: 10px;
+        }
+    }
+</style>

+ 311 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -0,0 +1,311 @@
+<template>
+	<section>
+		<!--工具条-->
+		<el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+			<el-form :inline="true">
+				<el-form-item>
+					<el-date-picker v-model="date" :editable="false" format="yyyy-MM" value-format="yyyy-MM" @change='changeMonth()' :clearable="false" type="month" placeholder="选择月份"></el-date-picker>
+				</el-form-item>
+                <el-form-item style="float:right;">
+                    <el-link type="primary" :underline="false" @click="handleAdd">导出日报</el-link>
+				</el-form-item>
+                <el-form-item style="float:right;">
+                    <el-link type="primary" :underline="false" @click="handleAdd">项目管理</el-link>
+				</el-form-item>
+			</el-form>
+		</el-col>
+
+		<!--列表-->
+		<div>
+            <el-card class="box-card daily" shadow="never" :style="'height:'+tableHeight +'px'">
+                <div slot="header" class="clearfix">
+                    <span>日期:</span>
+                    <span v-for="(item,index) in allDate" :id="'day'+index" :class="index==choseDay?'chooseDate date_item':'date_item'" @click="choseDate(index)">{{item}}</span>
+                </div>
+                <div class="allDaily">
+                    <div class="one_daily">
+                        <el-link><i class="fa fa-circle"></i> 吴涛涛</el-link>
+                        <div class="one_daily_body">
+                            <el-timeline>
+                                <el-timeline-item>
+                                    <el-card shadow="never">
+                                        <p>项目:<b>工时管家开发项目</b></p>
+                                        <p>时长:1.5h</p>
+                                        <p>事项:1.重新设计工作日报模块<br>
+
+                                            2.绘制原型图<br>
+
+                                            3.敲代码<br>
+                                        </p>
+                                    </el-card>
+                                </el-timeline-item>
+                            </el-timeline>
+                        </div>
+                    </div>
+                    <div class="one_daily">
+                        <el-link><i class="fa fa-circle"></i> 吴涛涛</el-link>
+                        <div class="one_daily_body">
+                            <el-timeline>
+                                <el-timeline-item>
+                                    <el-card shadow="never">
+                                        <p>项目:<b>工时管家开发项目</b></p>
+                                        <p>时长:1.5h</p>
+                                        <p>事项:1.重新设计工作日报模块<br>
+
+                                            2.绘制原型图<br>
+
+                                            3.敲代码<br>
+                                        </p>
+                                    </el-card>
+                                </el-timeline-item>
+                            </el-timeline>
+                        </div>
+                    </div>
+                    <div class="one_daily">
+                        <el-link><i class="fa fa-circle"></i> 吴涛涛</el-link>
+                        <div class="one_daily_body">
+                            <el-timeline>
+                                <el-timeline-item>
+                                    <el-card shadow="never">
+                                        <p>项目:<b>工时管家开发项目</b></p>
+                                        <p>时长:1.5h</p>
+                                        <p>事项:1.重新设计工作日报模块<br>
+
+                                            2.绘制原型图<br>
+
+                                            3.敲代码<br>
+                                        </p>
+                                    </el-card>
+                                </el-timeline-item>
+                                <el-timeline-item>
+                                    <el-card shadow="never">
+                                        <p>项目:<b>工时管家开发项目</b></p>
+                                        <p>时长:1.5h</p>
+                                        <p>事项:1.重新设计工作日报模块<br>
+
+                                            2.绘制原型图<br>
+
+                                            3.敲代码<br>
+                                        </p>
+                                    </el-card>
+                                </el-timeline-item>
+                            </el-timeline>
+                        </div>
+                    </div>
+                </div>
+            </el-card>
+        </div>
+	</section>
+</template>
+
+<script>
+	import util from '../../common/js/util'
+
+	export default {
+		data() {
+			return {
+                user: JSON.parse(sessionStorage.getItem('user')),
+
+                allDate: [],
+                date:  util.formatDate.format(new Date(new Date()), 'yyyy-MM'),
+                choseDay: 0,
+
+                tableHeight: 0,
+                listLoading: false,
+				total: 0,
+                page: 1,
+                size: 20,
+                list: [],
+                
+                addFormVisible: false,
+				addLoading: false,
+			}
+		},
+		methods: {
+            changeMonth() {
+                this.getAllDate();
+                this.getList();
+            },
+
+            choseDate(i) {
+                this.choseDay = i;
+            },
+
+            getAllDate() {
+                var dayArry = [];
+                var day = this.getCountDays();
+                for (var k = 1; k <= day; k++) {
+                    var str = new Date(this.date.replace(/-/g,'/')).getMonth() + 1 + "月" + k + "日";
+                    if(new Date(this.date.replace(/-/g,'/')).getFullYear() == new Date(new Date()).getFullYear() &&
+                        new Date(this.date.replace(/-/g,'/')).getMonth() == new Date(new Date()).getMonth()) {
+                            if(new Date().getDate() == k) {
+                                this.choseDay = k-1;
+                            }
+                    } else {
+                        this.choseDay = 0;
+                    }
+                    dayArry.push(str);
+                }
+                this.allDate = dayArry;
+            },
+
+            getCountDays() {
+                var newstr = this.date.replace(/-/g,'/'); 
+                var curDate = new Date(newstr);
+                var curMonth = curDate.getMonth();
+                curDate.setMonth(curMonth + 1);
+                curDate.setDate(0);
+                return curDate.getDate();
+            },
+
+			//分页
+			handleCurrentChange(val) {
+				this.page = val;
+				this.getList();
+            },
+
+            handleSizeChange(val) {
+                this.size = val;
+				this.getList();
+            },
+            
+			//获取项目列表
+			getList() {
+				this.listLoading = true;
+				this.http.post(this.port.project.projectList, {
+                    keyName: '',
+                    pageNum: this.page,
+                    pageSize: this.size,
+                }, res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data.list;
+                        for(var i in list){
+                            var customCompaniesStr = "";
+                            for(var j in list[i].customCompanies){
+                                if(j == list[i].customCompanies.length -1){
+                                    customCompaniesStr += list[i].customCompanies[j].companyName;
+                                } else {
+                                    customCompaniesStr += list[i].customCompanies[j].companyName + "、";
+                                }
+                            }
+                            list[i].customCompaniesStr = customCompaniesStr;
+                        }
+                        this.list = list;
+                        this.total = res.data.total;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: 'error'
+                        });
+                    }
+                }, error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: 'error'
+                    });
+                })
+            },
+
+            //显示新增界面
+			handleAdd() {
+                this.getUnusual();
+				this.addFormVisible = true;
+            },
+
+            // 获取异常列表
+            getUnusual() {
+                this.listLoading = true;
+				this.http.post(this.port.project.projectList, {
+                    keyName: '',
+                    pageNum: this.page,
+                    pageSize: this.size,
+                }, res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data.list;
+                        for(var i in list){
+                            var customCompaniesStr = "";
+                            for(var j in list[i].customCompanies){
+                                if(j == list[i].customCompanies.length -1){
+                                    customCompaniesStr += list[i].customCompanies[j].companyName;
+                                } else {
+                                    customCompaniesStr += list[i].customCompanies[j].companyName + "、";
+                                }
+                            }
+                            list[i].customCompaniesStr = customCompaniesStr;
+                        }
+                        this.list = list;
+                        this.total = res.data.total;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: 'error'
+                        });
+                    }
+                }, error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: 'error'
+                    });
+                })
+            },
+
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 170;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 170; 
+            };
+        },
+		mounted() {
+            this.getAllDate();
+            this.getList();
+		}
+	}
+
+</script>
+
+<style lang="scss" scoped>
+    .clearfix {
+        overflow-x: auto;
+        white-space: nowrap;
+        padding: 15px 0;
+        .date_item {
+            padding:0 15px;
+            cursor: pointer;
+        }
+        .chooseDate {
+            color: #20a0ff;
+        }
+    }
+
+    .one_daily {
+        i {
+            color: #9ED0FF;
+            margin-right: 5px;
+        }
+        .one_daily_body {
+            padding: 15px 0px;
+            p {
+                margin: 0;
+                line-height: 30px;
+            }
+        }
+        ul {
+            padding: 0;
+        }
+    }
+</style>
+<style lang="scss">
+    .daily {
+        .el-card__body {
+            height: 82%;
+            overflow-y: auto;
+        }
+    }
+</style>

+ 192 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/statistics.vue

@@ -0,0 +1,192 @@
+<template>
+	<section>
+		<!--工具条-->
+		<el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+			<el-form :inline="true">
+				<el-form-item>
+					<el-date-picker v-model="date" :editable="false" format="yyyy-MM-dd" value-format="yyyy-MM-dd" @change='getList' :clearable="false" type="date" placeholder="选择日期"></el-date-picker>
+				</el-form-item>
+				<el-form-item style="float:right;">
+                    <el-link type="primary" :underline="false" @click="handleAdd">异常申请</el-link>
+				</el-form-item>
+			</el-form>
+		</el-col>
+
+		<!--列表-->
+		<el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+			<el-table-column type="index" width="60"></el-table-column>
+			<el-table-column prop="projectName" label="姓名" width="140" sortable></el-table-column>
+            <el-table-column prop="ownerCompanyName" label="手机" width="180"></el-table-column>
+            <el-table-column prop="customCompaniesStr" label="编程"></el-table-column>
+            <el-table-column prop="manager" label="设计" sortable></el-table-column>
+            <el-table-column prop="manager" label="办公" sortable></el-table-column>
+            <el-table-column prop="manager" label="娱乐" sortable></el-table-column>
+            <el-table-column prop="manager" label="浏览" sortable></el-table-column>
+			<el-table-column prop="indate" label="总时长" width="180" sortable></el-table-column>
+		</el-table>
+
+		<!--工具条-->
+		<el-col :span="24" class="toolbar">
+			<el-pagination
+                @size-change="handleSizeChange"
+                @current-change="handleCurrentChange"
+                :page-sizes="[20 , 50 , 80 , 100]"
+                :page-size="20"
+                layout="total, sizes, prev, pager, next"
+                :total="total"
+                style="float:right;">
+            </el-pagination>
+		</el-col>
+
+        <!--新增界面-->
+		<el-dialog title="异常申请列表" v-if="addFormVisible" :visible.sync="addFormVisible" :close-on-click-modal="false" customClass='customWidth'>
+			<el-table :data="list" highlight-current-row v-loading="listLoading" height="400" style="width: 100%;">
+                <el-table-column type="index" width="60"></el-table-column>
+                <el-table-column prop="projectName" label="姓名" width="140" sortable></el-table-column>
+                <el-table-column prop="indate" label="工作时长" width="100" sortable></el-table-column>
+                <el-table-column prop="indate" label="异常原因" width="180" sortable></el-table-column>
+                <el-table-column prop="indate" label="时间" sortable></el-table-column>
+            </el-table>
+			<div slot="footer" class="dialog-footer">
+				<el-button @click.native="addFormVisible = false">取消</el-button>
+			</div>
+		</el-dialog>
+	</section>
+</template>
+
+<script>
+	import util from '../../common/js/util'
+
+	export default {
+		data() {
+			return {
+                user: JSON.parse(sessionStorage.getItem('user')),
+
+                date: new Date(),
+
+                tableHeight: 0,
+                listLoading: false,
+				total: 0,
+                page: 1,
+                size: 20,
+                list: [],
+                
+                addFormVisible: false,
+				addLoading: false,
+			}
+		},
+		methods: {
+			//分页
+			handleCurrentChange(val) {
+				this.page = val;
+				this.getList();
+            },
+
+            handleSizeChange(val) {
+                this.size = val;
+				this.getList();
+            },
+            
+			//获取项目列表
+			getList() {
+				this.listLoading = true;
+				this.http.post(this.port.project.projectList, {
+                    keyName: '',
+                    pageNum: this.page,
+                    pageSize: this.size,
+                }, res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data.list;
+                        for(var i in list){
+                            var customCompaniesStr = "";
+                            for(var j in list[i].customCompanies){
+                                if(j == list[i].customCompanies.length -1){
+                                    customCompaniesStr += list[i].customCompanies[j].companyName;
+                                } else {
+                                    customCompaniesStr += list[i].customCompanies[j].companyName + "、";
+                                }
+                            }
+                            list[i].customCompaniesStr = customCompaniesStr;
+                        }
+                        this.list = list;
+                        this.total = res.data.total;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: 'error'
+                        });
+                    }
+                }, error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: 'error'
+                    });
+                })
+            },
+
+            //显示新增界面
+			handleAdd() {
+                this.getUnusual();
+				this.addFormVisible = true;
+            },
+
+            // 获取异常列表
+            getUnusual() {
+                this.listLoading = true;
+				this.http.post(this.port.project.projectList, {
+                    keyName: '',
+                    pageNum: this.page,
+                    pageSize: this.size,
+                }, res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data.list;
+                        for(var i in list){
+                            var customCompaniesStr = "";
+                            for(var j in list[i].customCompanies){
+                                if(j == list[i].customCompanies.length -1){
+                                    customCompaniesStr += list[i].customCompanies[j].companyName;
+                                } else {
+                                    customCompaniesStr += list[i].customCompanies[j].companyName + "、";
+                                }
+                            }
+                            list[i].customCompaniesStr = customCompaniesStr;
+                        }
+                        this.list = list;
+                        this.total = res.data.total;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: 'error'
+                        });
+                    }
+                }, error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: 'error'
+                    });
+                })
+            },
+
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 195;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 195;    
+            };
+        },
+		mounted() {
+            this.getList();
+		}
+	}
+
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 7 - 0
fhKeeper/formulahousekeeper/timesheet/src/vuex/actions.js

@@ -0,0 +1,7 @@
+//test
+export const increment = ({commit}) => {
+    commit('INCREMENT')
+}
+export const decrement = ({commit}) => {
+    commit('DECREMENT')
+}

+ 4 - 0
fhKeeper/formulahousekeeper/timesheet/src/vuex/getters.js

@@ -0,0 +1,4 @@
+//test
+export const getCount = state => {
+    return state.count
+}

+ 29 - 0
fhKeeper/formulahousekeeper/timesheet/src/vuex/store.js

@@ -0,0 +1,29 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import * as actions from './actions'
+import * as getters from './getters'
+
+Vue.use(Vuex)
+
+// 应用初始状态
+const state = {
+    count: 10
+}
+
+// 定义所需的 mutations
+const mutations = {
+    INCREMENT(state) {
+        state.count++
+    },
+    DECREMENT(state) {
+        state.count--
+    }
+}
+
+// 创建 store 实例
+export default new Vuex.Store({
+    actions,
+    getters,
+    state,
+    mutations
+})

+ 0 - 0
fhKeeper/formulahousekeeper/timesheet/static/.gitkeep


+ 245 - 0
fhKeeper/formulahousekeeper/timesheet/static/css/public.css

@@ -0,0 +1,245 @@
+/*! normalize.css v1.1.2 | MIT License | git.io/normalize */
+article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary {
+	display: block
+}
+
+audio,canvas,video {
+	display: inline-block;
+	*display: inline;
+	*zoom: 1
+}
+
+audio:not([controls]) {
+	display: none;
+	height: 0
+}[hidden] {
+	display: none
+}
+
+html {
+	font-size: 100%;
+	-ms-text-size-adjust: 100%;
+	-webkit-text-size-adjust: 100%
+}
+
+html,button,input,select,textarea {
+	font-family: sans-serif
+}
+
+body {
+	margin: 0
+}
+
+a:focus {
+	outline: thin dotted
+}
+
+a:active,a:hover {
+	outline: 0
+}
+
+h1 {
+	font-size: 2em;
+	margin: .67em 0
+}
+
+h2 {
+	font-size: 1.5em;
+	margin: .83em 0
+}
+
+h3 {
+	font-size: 1.17em;
+	margin: 1em 0
+}
+
+h4 {
+	font-size: 1em;
+	margin: 1.33em 0
+}
+
+h5 {
+	font-size: .83em;
+	margin: 1.67em 0
+}
+
+h6 {
+	font-size: .67em;
+	margin: 2.33em 0
+}
+
+abbr[title] {
+	border-bottom: 1px dotted
+}
+
+b,strong {
+	font-weight: bold
+}
+
+blockquote {
+	margin: 1em 40px
+}
+
+dfn {
+	font-style: italic
+}
+
+hr {
+	-moz-box-sizing: content-box;
+	box-sizing: content-box;
+	height: 0
+}
+
+mark {
+	background: #ff0;
+	color: #000
+}
+
+p,pre {
+	margin: 1em 0
+}
+
+code,kbd,pre,samp {
+	font-family: monospace,serif;
+	_font-family: 'courier new',monospace;
+	font-size: 1em
+}
+
+pre {
+	white-space: pre;
+	white-space: pre-wrap;
+	word-wrap: break-word
+}
+
+q {
+	quotes: none
+}
+
+q:before,q:after {
+	content: '';
+	content: none
+}
+
+small {
+	font-size: 80%
+}
+
+sub,sup {
+	font-size: 75%;
+	line-height: 0;
+	position: relative;
+	vertical-align: baseline
+}
+
+sup {
+	top: -0.5em
+}
+
+sub {
+	bottom: -0.25em
+}
+
+dl,menu,ol,ul {
+	margin: 1em 0
+}
+
+dd {
+	margin: 0 0 0 40px
+}
+
+menu,ol,ul {
+	padding: 0 0 0 40px
+}
+
+nav ul,nav ol {
+	list-style: none;
+	list-style-image: none
+}
+
+img {
+	border: 0;
+	-ms-interpolation-mode: bicubic
+}
+
+svg:not(:root) {
+	overflow: hidden
+}
+
+figure {
+	margin: 0
+}
+
+form {
+	margin: 0
+}
+
+fieldset {
+	border: 1px solid #c0c0c0;
+	margin: 0 2px;
+	padding: .35em .625em .75em
+}
+
+legend {
+	border: 0;
+	padding: 0;
+	white-space: normal;
+	*margin-left: -7px
+}
+
+button,input,select,textarea {
+	font-size: 100%;
+	margin: 0;
+	vertical-align: baseline;
+	*vertical-align: middle
+}
+
+button,input {
+	line-height: normal
+}
+
+button,select {
+	text-transform: none
+}
+
+button,html input[type="button"],input[type="reset"],input[type="submit"] {
+	-webkit-appearance: button;
+	cursor: pointer;
+	*overflow: visible
+}
+
+button[disabled],html input[disabled] {
+	cursor: default
+}
+
+input[type="checkbox"],input[type="radio"] {
+	box-sizing: border-box;
+	padding: 0;
+	*height: 13px;
+	*width: 13px
+}
+
+input[type="search"] {
+	-webkit-appearance: textfield;
+	-moz-box-sizing: content-box;
+	-webkit-box-sizing: content-box;
+	box-sizing: content-box
+}
+
+input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration {
+	-webkit-appearance: none
+}
+
+button::-moz-focus-inner,input::-moz-focus-inner {
+	border: 0;
+	padding: 0
+}
+
+textarea {
+	overflow: auto;
+	vertical-align: top
+}
+
+table {
+	border-collapse: collapse;
+	border-spacing: 0
+}